master 7b05bf1b3460 cached
117 files
154.1 KB
40.8k tokens
248 symbols
1 requests
Download .txt
Repository: rocketjob/rails_semantic_logger
Branch: master
Commit: 7b05bf1b3460
Files: 117
Total size: 154.1 KB

Directory structure:
gitextract_hgorv55i/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .rubocop.yml
├── Appraisals
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── TESTING.md
├── gemfiles/
│   ├── rails_6.1.gemfile
│   ├── rails_7.0.gemfile
│   ├── rails_7.0b.gemfile
│   ├── rails_7.1.1.gemfile
│   ├── rails_7.1.gemfile
│   ├── rails_7.1b.gemfile
│   ├── rails_7.2.gemfile
│   ├── rails_8.0.gemfile
│   └── rails_8.1.gemfile
├── lib/
│   ├── rails_semantic_logger/
│   │   ├── action_controller/
│   │   │   └── log_subscriber.rb
│   │   ├── action_mailer/
│   │   │   └── log_subscriber.rb
│   │   ├── action_view/
│   │   │   └── log_subscriber.rb
│   │   ├── active_job/
│   │   │   └── log_subscriber.rb
│   │   ├── active_record/
│   │   │   └── log_subscriber.rb
│   │   ├── delayed_job/
│   │   │   └── plugin.rb
│   │   ├── engine.rb
│   │   ├── extensions/
│   │   │   ├── action_cable/
│   │   │   │   └── tagged_logger_proxy.rb
│   │   │   ├── action_controller/
│   │   │   │   └── live.rb
│   │   │   ├── action_dispatch/
│   │   │   │   └── debug_exceptions.rb
│   │   │   ├── action_view/
│   │   │   │   └── streaming_template_renderer.rb
│   │   │   ├── active_job/
│   │   │   │   └── logging.rb
│   │   │   ├── active_model_serializers/
│   │   │   │   └── logging.rb
│   │   │   ├── active_support/
│   │   │   │   ├── log_subscriber.rb
│   │   │   │   ├── logger.rb
│   │   │   │   └── tagged_logging.rb
│   │   │   ├── mongoid/
│   │   │   │   └── config.rb
│   │   │   ├── rack/
│   │   │   │   └── server.rb
│   │   │   ├── rackup/
│   │   │   │   └── server.rb
│   │   │   ├── rails/
│   │   │   │   └── server.rb
│   │   │   └── sidekiq/
│   │   │       └── sidekiq.rb
│   │   ├── options.rb
│   │   ├── rack/
│   │   │   └── logger.rb
│   │   ├── sidekiq/
│   │   │   ├── defaults.rb
│   │   │   ├── job_logger.rb
│   │   │   └── loggable.rb
│   │   └── version.rb
│   └── rails_semantic_logger.rb
├── rails_semantic_logger.gemspec
└── test/
    ├── action_controller_test.rb
    ├── action_mailer_test.rb
    ├── active_job_test.rb
    ├── active_record_test.rb
    ├── controllers/
    │   ├── articles_controller_test.rb
    │   ├── dashboard_controller_test.rb
    │   └── welcome_controller_test.rb
    ├── dummy/
    │   ├── README.rdoc
    │   ├── Rakefile
    │   ├── app/
    │   │   ├── assets/
    │   │   │   ├── javascripts/
    │   │   │   │   ├── application.js
    │   │   │   │   └── articles.js
    │   │   │   └── stylesheets/
    │   │   │       ├── application.css
    │   │   │       ├── articles.css
    │   │   │       └── welcome.css
    │   │   ├── controllers/
    │   │   │   ├── application_controller.rb
    │   │   │   ├── application_metal_controller.rb
    │   │   │   ├── articles_controller.rb
    │   │   │   ├── dashboard_controller.rb
    │   │   │   └── welcome_controller.rb
    │   │   ├── helpers/
    │   │   │   ├── application_helper.rb
    │   │   │   ├── articles_helper.rb
    │   │   │   └── welcome_helper.rb
    │   │   ├── jobs/
    │   │   │   ├── bad_job.rb
    │   │   │   └── simple_job.rb
    │   │   ├── mailers/
    │   │   │   └── .gitkeep
    │   │   ├── models/
    │   │   │   ├── .gitkeep
    │   │   │   └── sample.rb
    │   │   └── views/
    │   │       ├── articles/
    │   │       │   └── new.html.erb
    │   │       ├── layouts/
    │   │       │   └── application.html.erb
    │   │       └── welcome/
    │   │           └── index.html.erb
    │   ├── bin/
    │   │   ├── bundle
    │   │   ├── puma
    │   │   ├── rails
    │   │   ├── rake
    │   │   └── setup
    │   ├── config/
    │   │   ├── application.rb
    │   │   ├── boot.rb
    │   │   ├── database.yml
    │   │   ├── environment.rb
    │   │   ├── environments/
    │   │   │   ├── development.rb
    │   │   │   ├── production.rb
    │   │   │   └── test.rb
    │   │   ├── initializers/
    │   │   │   ├── backtrace_silencers.rb
    │   │   │   ├── inflections.rb
    │   │   │   ├── mime_types.rb
    │   │   │   ├── payload_collector.rb
    │   │   │   ├── secret_token.rb
    │   │   │   ├── session_store.rb
    │   │   │   ├── sidekiq.rb
    │   │   │   └── wrap_parameters.rb
    │   │   ├── locales/
    │   │   │   └── en.yml
    │   │   ├── routes.rb
    │   │   └── secrets.yml
    │   ├── config.ru
    │   ├── db/
    │   │   ├── migrate/
    │   │   │   └── 20170525020551_create_samples.rb
    │   │   └── schema.rb
    │   ├── lib/
    │   │   └── assets/
    │   │       └── .gitkeep
    │   ├── log/
    │   │   └── .gitkeep
    │   ├── public/
    │   │   ├── 404.html
    │   │   ├── 422.html
    │   │   └── 500.html
    │   ├── script/
    │   │   └── rails
    │   └── test/
    │       └── fixtures/
    │           └── samples.yml
    ├── payload_collector.rb
    ├── rails_test.rb
    ├── sidekiq_test.rb
    └── test_helper.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: reidmorrison


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
### Environment

Provide at least:
* Ruby Version.
* Rails Version.
* Semantic Logger Version.
* Rails Semantic Logger Version.
* Other Application/framework names and versions (e.g. Puma, etc.).
* Rails configuration. Only need the settings related to Rails Semantic Logger and Semantic Logger.
* Full Stack Trace, if an exception is being raised.

Note:
* Issues reported here should be related to monkey patches applied to Rails to make it use Semantic Logger. 
* For other logging and appender related issues, please report the issue at [Semantic Logger](https://github.com/reidmorrison/semantic_logger/issues.

### Expected Behavior

* Describe your expectation of how Semantic Logger should behave, perhaps by showing how the builtin Rails logger behaves.
* Provide a standalone Ruby script or a link to an example repository that helps reproduce the issue.

### Actual Behavior

* Describe or show the actual behavior.
* Provide text or screen capture showing the behavior.

### Pull Request

* Consider submitting a Pull Request with a fix for the issue.
    * This is particularly helpful when running newer Rails versions, since we are not running it yet.
* Or, even a Pull request that only includes a test that reproduces the problem. 


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
### Issue # (if available)


### Description of changes


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


================================================
FILE: .github/workflows/ci.yml
================================================
name: build

on:
  - push
  - pull_request

jobs:
  test:
    name: "Test: Rails ${{ matrix.rails }} on Ruby ${{ matrix.ruby }}"
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - rails: "6.1"
            ruby: "3.2"

          - rails: "7.0"
            ruby: "3.2"
          - rails: "7.0b"
            ruby: "3.2"

          - rails: "7.1"
            ruby: "3.2"
          - rails: "7.1b"
            ruby: "3.2"
          - rails: "7.1.1"
            ruby: "3.2"

          - rails: "7.2"
            ruby: "3.3"

          - rails: "8.0"
            ruby: "3.4"

          - rails: "8.1"
            ruby: "3.4"

    env:
      BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails }}.gemfile
      DISPLAY: ":99.0"

    steps:
      - uses: actions/checkout@v3
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          # runs 'bundle install' and caches installed gems automatically
          bundler-cache: true

      - name: Gemfile
        run: echo $BUNDLE_GEMFILE

      - name: Ruby Version
        run: ruby --version

      - name: Run Tests
        run: bundle exec rake test


================================================
FILE: .gitignore
================================================
.bundle/
*.log
pkg/
test/dummy/tmp/
test/dummy/db/test.sqlite3-*
test/dummy/.sass-cache
*.gem
/.idea
tags
*.DS_Store
Gemfile.lock
/gemfiles/*.lock

*.sqlite3
.rakeTasks
TODO.md

.tool-versions
test/dummy/db/test.sqlite3
mise.toml


================================================
FILE: .rubocop.yml
================================================
AllCops:
  Exclude:
    - ".git/**/*"
    - "docs/**/*"
    - "gemfiles/*"
  NewCops: enable
  TargetRubyVersion: 2.5

#
# RuboCop built-in settings.
#   For documentation on all settings see: https://docs.rubocop.org/en/stable
#

# Trailing periods.
Layout/DotPosition:
  EnforcedStyle: trailing

# Turn on auto-correction of equals alignment.
Layout/EndAlignment:
  AutoCorrect: true

# Prevent accidental windows line endings
Layout/EndOfLine:
  EnforcedStyle: lf

# Use a table layout for hashes
Layout/HashAlignment:
  EnforcedHashRocketStyle: table
  EnforcedColonStyle: table

# Soften limits
Layout/LineLength:
  Max: 128
  Exclude:
    - "**/test/**/*"

# Match existing layout
Layout/SpaceInsideHashLiteralBraces:
  EnforcedStyle: no_space

# TODO: Soften Limits for phase 1 only
Metrics/AbcSize:
  Max: 40

# Support long block lengths for tests
Metrics/BlockLength:
  Exclude:
    - "test/**/*"
    - "**/*/cli.rb"
  AllowedMethods:
    - "aasm"
    - "included"

# Soften limits
Metrics/ClassLength:
  Max: 250
  Exclude:
    - "test/**/*"

# TODO: Soften Limits for phase 1 only
Metrics/CyclomaticComplexity:
  Max: 15

# Soften limits
Metrics/MethodLength:
  Max: 50

# Soften limits
Metrics/ModuleLength:
  Max: 250

Metrics/ParameterLists:
  CountKeywordArgs: false

# TODO: Soften Limits for phase 1 only
Metrics/PerceivedComplexity:
  Max: 21

# Initialization Vector abbreviation
Naming/MethodParameterName:
  AllowedNames: [ "iv", "_", "io", "ap", "id", "_id" ]

# Does not allow Symbols to load
Security/YAMLLoad:
  AutoCorrect: false

# Needed for testing DateTime
Style/DateTime:
  Exclude: [ "test/**/*" ]

# TODO: Soften Limits for phase 1 only
Style/Documentation:
  Enabled: false

# One line methods
Style/EmptyMethod:
  EnforcedStyle: expanded

# Ruby 3 compatibility feature
Style/FrozenStringLiteralComment:
  Enabled: false

Style/NumericPredicate:
  AutoCorrect: true

# Incorrectly changes job.fail to job.raise
Style/SignalException:
  Enabled: false

# Since English may not be loaded, cannot force its use.
Style/SpecialGlobalVars:
  Enabled: false

# Make it easier for developers to move between Elixir and Ruby.
Style/StringLiterals:
  EnforcedStyle: double_quotes


================================================
FILE: Appraisals
================================================
appraise "rails_6.1" do
  gem "rails", "~> 6.1.0"
  gem "sidekiq", "~> 5.2"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.0" do
  gem "rails", "~> 7.0.0"
  gem "sidekiq", "~> 6.2.0"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.0b" do
  gem "rails", "~> 7.0.0"
  gem "sidekiq", "~> 6.5"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.1.1" do
  gem "rails", "7.1.1"
  gem "sidekiq", "~> 7.0.9"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.1" do
  gem "rails", "~> 7.1.0"
  gem "sidekiq", "~> 7.1.6"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.1b" do
  gem "rails", "~> 7.1.0"
  gem "sidekiq", "~> 7.3.0"
  gem "sqlite3", "~> 1.4"
end

appraise "rails_7.2" do
  gem "rails", "~> 7.2.0"
  gem "sidekiq", "~> 7.2.4"
end

appraise "rails_8.0" do
  gem "rails", "~> 8.0.0"
  gem "sidekiq", "~> 7.2.4"
end

appraise "rails_8.1" do
  gem "rails", "~> 8.1.1"
  gem "sidekiq", "~> 7.2.4"
end


================================================
FILE: Gemfile
================================================
source "https://rubygems.org"

gemspec

gem "appraisal"
gem "puma"

gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"

gem "rails", "~> 8.1.0"
gem "sidekiq", "~> 7.2.4"
gem "sqlite3"

gem "rubocop"


================================================
FILE: LICENSE.txt
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2012, 2013, 2014, 2015 Reid Morrison

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Rails Semantic Logger
[![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://github.com/reidmorrison/rails_semantic_logger/workflows/build/badge.svg)](https://github.com/reidmorrison/rails_semantic_logger/actions?query=workflow%3Abuild) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg)

Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](https://logger.rocketjob.io/)

When any large Rails application is deployed to production one of the first steps is to move to centralized logging, so that logs can be viewed and searched from a central location.

Centralized logging quickly falls apart when trying to consume the current human readable log files:
- Log entries often span multiple lines, resulting in unrelated log lines in the centralized logging system. For example, stack traces.
- Complex Regular Expressions are needed to parse the text lines and make them machine readable. For example to build queries, or alerts that are looking for specific elements in the message.
- Writing searches, alerts, or dashboards based on text logs is incredibly brittle, since a small change to the text logged can often break the parsing of those logs.
- Every log entry often has a completely different format, making it difficult to make consistent searches against the data.

For these and many other reasons switching to structured logging, or logs in JSON format, in testing and production makes centralized logging incredibly powerful.

For example, adding these lines to `config/application.rb` and removing any other log overrides from other environments, will switch automatically to structured logging when running inside Kubernetes:
~~~ruby
    # Setup structured logging
    config.semantic_logger.application = "my_application"
    config.semantic_logger.environment = ENV["STACK_NAME"] || Rails.env
    config.log_level = ENV["LOG_LEVEL"] || :info

    # Switch to JSON Logging output to stdout when running on Kubernetes
    if ENV["LOG_TO_CONSOLE"] || ENV["KUBERNETES_SERVICE_HOST"]
      config.rails_semantic_logger.add_file_appender = false
      config.semantic_logger.add_appender(io: $stdout, formatter: :json)
    end
~~~

Then configure the centralized logging system to tell it that the data is in JSON format, so that it will parse it for you into a hierarchy.

For example, the following will instruct [Observe](https://www.observeinc.com/) to parse the JSON data and create machine readable data from it:
~~~ruby
interface "log", "log":log

make_col event:parse_json(log)

make_col
   time:parse_isotime(event.timestamp),
   application:string(event.application),
   environment:string(event.environment),
   duration:duration_ms(event.duration_ms),
   level:string(event.level),
   name:string(event.name),
   message:string(event.message),
   named_tags:event.named_tags,
   payload:event.payload,
   metric:string(event.metric),
   metric_amount:float64(event.metric_amount),
   tags:array(event.tags),
   exception:event.exception,
   host:string(event.host),
   pid:int64(event.pid),
   thread:string(event.thread),
   file:string(event.file),
   line:int64(event.line),
   dimensions:event.dimensions,
   backtrace:array(event.backtrace),
   level_index:int64(event.level_index)

set_valid_from(time)
drop_col timestamp, log, event, stream
rename_col timestamp:time
~~~

Now queries can be built to drill down into each of these fields, including `payload` which is a nested object.

For example to find all failed Sidekiq job calls where the causing exception class name is `NoMethodError`:
~~~ruby
filter environment = "uat2"
filter level = "error"
filter metric = "sidekiq.job.perform"
filter (string(exception.cause.name) = "NoMethodError")
~~~

Example: create a dashboard showing the duration of all successful Sidekiq jobs:
~~~ruby
filter environment = "production"
filter level = "info"
filter metric = "sidekiq.job.perform"
timechart duration:avg(duration), group_by(name)
~~~

Example: create a dashboard showing the queue latency of all Sidekiq jobs. 
The queue latency is the time between when the job was enqueued and when it was started:
~~~ruby
filter environment = "production"
filter level = "info"
filter metric = "sidekiq.queue.latency"
timechart latency:avg(metric_amount/1000), group_by(string(named_tags.queue))
~~~

* http://github.com/reidmorrison/rails_semantic_logger

## Documentation

For complete documentation see: https://logger.rocketjob.io/rails

## Upgrading to Semantic Logger V4.16 - Sidekiq Metrics Support

Rails Semantic Logger now supports Sidekiq metrics. 
Below are the metrics that are now available when the JSON logging format is used:
- `sidekiq.job.perform`
  - The duration of each Sidekiq job.
  - `duration` contains the time in milliseconds that the job took to run.
- `sidekiq.queue.latency` 
  - The time between when a Sidekiq job was enqueued and when it was started.
  - `metric_amount` contains the time in milliseconds that the job was waiting in the queue.

## Upgrading to Semantic Logger v4.15 & V4.16 - Sidekiq Support

Rails Semantic Logger introduces direct support for Sidekiq v4, v5, v6, and v7. 
Please remove any previous custom patches or configurations to make Sidekiq work with Semantic Logger.
To see the complete list of patches being made, and to contribute your own changes, see: [Sidekiq Patches](https://github.com/reidmorrison/rails_semantic_logger/blob/master/lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb)

## Upgrading to Semantic Logger v4.4

With some forking frameworks it is necessary to call `reopen` after the fork. With v4.4 the
workaround for Ruby 2.5 crashes is no longer needed. 
I.e. Please remove the following line if being called anywhere:

~~~ruby
SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
~~~

## New Versions of Rails, etc.

The primary purpose of the Rails Semantic Logger gem is to patch other gems, primarily Rails, to make them support structured logging though Semantic Logger.

When new versions of Rails and other gems are published they often make changes to the internals, so the existing patches stop working.

Rails Semantic Logger survives only when someone in the community upgrades to a newer Rails or other supported libraries, runs into problems, 
and then contributes the fix back to the community by means of a pull request.

Additionally, when new popular gems come out, we rely only the community to supply the necessary patches in Rails Semantic Logger to make those gems support structured logging.

## Supported Platforms

For the complete list of supported Ruby and Rails versions, see the [Testing file](https://github.com/reidmorrison/rails_semantic_logger/blob/master/.github/workflows/ci.yml).

## Author

[Reid Morrison](https://github.com/reidmorrison)

[Contributors](https://github.com/reidmorrison/rails_semantic_logger/graphs/contributors)

## Versioning

This project uses [Semantic Versioning](http://semver.org/).


================================================
FILE: Rakefile
================================================
# Setup bundler to avoid having to run bundle exec all the time.
require "rubygems"
require "bundler/setup"

require "rake/testtask"
require_relative "lib/rails_semantic_logger/version"

task :gem do
  system "gem build rails_semantic_logger.gemspec"
end

task publish: :gem do
  system "git tag -a v#{RailsSemanticLogger::VERSION} -m 'Tagging #{RailsSemanticLogger::VERSION}'"
  system "git push --tags"
  system "gem push rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
  system "rm rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
end

Rake::TestTask.new(:test) do |t|
  t.pattern = "test/**/*_test.rb"
  t.verbose = true
  t.warning = false
end

# By default run tests against all appraisals
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
  require "appraisal"
  task default: :appraisal
else
  task default: :test
end


================================================
FILE: TESTING.md
================================================
## Installation

Install all needed gems to run the tests:

    appraisal install

The gems are installed into the global gem list.
The Gemfiles in the `gemfiles` folder are also re-generated.

## Run Tests

For all supported Rails/ActiveRecord versions:

    rake

Or for specific rails version:

    appraisal rails_4.2 rake

Or for one particular test file:

    appraisal rails_5.0 ruby test/controllers/articles_controller_test.rb 

Or down to one test case:

    appraisal rails_5.0 ruby test/controllers/articles_controller_test.rb  -n "/shows new article/"


================================================
FILE: gemfiles/rails_6.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 6.1.0"
gem "sidekiq", "~> 5.2"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.0.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 7.0.0"
gem "sidekiq", "~> 6.2.0"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.0b.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 7.0.0"
gem "sidekiq", "~> 6.5"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.1.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "7.1.1"
gem "sidekiq", "~> 7.0.9"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 7.1.0"
gem "sidekiq", "~> 7.1.6"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.1b.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 7.1.0"
gem "sidekiq", "~> 7.3.0"
gem "sqlite3", "~> 1.4"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_7.2.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 7.2.0"
gem "sidekiq", "~> 7.2.4"
gem "sqlite3"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_8.0.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 8.0.0"
gem "sidekiq", "~> 7.2.4"
gem "sqlite3"
gem "rubocop"

gemspec path: "../"


================================================
FILE: gemfiles/rails_8.1.gemfile
================================================
# This file was generated by Appraisal

source "https://rubygems.org"

gem "appraisal"
gem "puma"
gem "active_model_serializers"
gem "amazing_print"
gem "minitest"
gem "minitest-rails"
gem "rake"
gem "sprockets", "< 4.0"
gem "rails", "~> 8.1.1"
gem "sidekiq", "~> 7.2.4"
gem "sqlite3"
gem "rubocop"

gemspec path: "../"


================================================
FILE: lib/rails_semantic_logger/action_controller/log_subscriber.rb
================================================
module RailsSemanticLogger
  module ActionController
    class LogSubscriber < ActiveSupport::LogSubscriber
      INTERNAL_PARAMS = %w[controller action format _method only_path].freeze

      class << self
        attr_accessor :action_message_format
      end

      # Log as debug to hide Processing messages in production
      def start_processing(event)
        controller_logger(event).debug { action_message("Processing", event.payload) }
      end

      def process_action(event)
        controller_logger(event).info do
          payload = event.payload.dup

          # Unused, but needed for Devise 401 status code monkey patch to still work.
          ::ActionController::Base.log_process_action(payload)

          params = payload[:params]

          if params.is_a?(Hash) || params.is_a?(::ActionController::Parameters)
            # According to PR https://github.com/reidmorrison/rails_semantic_logger/pull/37/files
            # params is not always a Hash.
            payload[:params] = params.to_unsafe_h unless params.is_a?(Hash)
            payload[:params] = params.except(*INTERNAL_PARAMS)

            if payload[:params].empty?
              payload.delete(:params)
            elsif params["file"]
              # When logging to JSON the entire tempfile is logged, so convert it to a string.
              payload[:params]["file"] = params["file"].inspect
            end
          end

          format           = payload[:format]
          payload[:format] = format.to_s.upcase if format.is_a?(Symbol)

          payload[:path]   = extract_path(payload[:path]) if payload.key?(:path)

          exception = payload.delete(:exception)
          if payload[:status].nil? && exception.present?
            exception_class_name = exception.first
            payload[:status]     = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
          end

          # Rounds off the runtimes. For example, :view_runtime, :mongo_runtime, etc.
          payload.keys.each do |key|
            payload[key] = payload[key].to_f.round(2) if key.to_s =~ /(.*)_runtime/
          end

          # Rails 6+ includes allocation count
          payload[:allocations] = event.allocations if event.respond_to?(:allocations)

          payload[:status_message] = ::Rack::Utils::HTTP_STATUS_CODES[payload[:status]] if payload[:status].present?

          # Causes excessive log output with Rails 5 RC1
          payload.delete(:headers)
          # Causes recursion in Rails 6.1.rc1
          payload.delete(:request)
          payload.delete(:response)

          {
            message:  action_message("Completed", event.payload),
            duration: event.duration,
            payload:  payload
          }
        end
      end

      def halted_callback(event)
        controller_logger(event).info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
      end

      def send_file(event)
        controller_logger(event).info(message: "Sent file", payload: {path: event.payload[:path]}, duration: event.duration)
      end

      def redirect_to(event)
        controller_logger(event).info(message: "Redirected to", payload: {location: event.payload[:location]})
      end

      def send_data(event)
        controller_logger(event).info(message:  "Sent data",
                                      payload:  {file_name: event.payload[:filename]},
                                      duration: event.duration)
      end

      def unpermitted_parameters(event)
        controller_logger(event).debug do
          unpermitted_keys = event.payload[:keys]
          "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(', ')}"
        end
      end

      %w[write_fragment read_fragment exist_fragment?
         expire_fragment expire_page write_page].each do |method|
        class_eval <<-METHOD, __FILE__, __LINE__ + 1
          def #{method}(event)
            # enable_fragment_cache_logging as of Rails 5
            return if ::ActionController::Base.respond_to?(:enable_fragment_cache_logging) && !::ActionController::Base.enable_fragment_cache_logging
            controller_logger(event).info do
              key_or_path = event.payload[:key] || event.payload[:path]
              {message: "#{method.to_s.humanize} \#{key_or_path}", duration: event.duration}
            end
          end
        METHOD
      end

      private

      # Returns the logger for the supplied event.
      # Returns ActionController::Base.logger if no controller is present
      def controller_logger(event)
        controller = event.payload[:controller]
        return ::ActionController::Base.logger unless controller

        controller.constantize.logger || ::ActionController::Base.logger
      rescue NameError
        ::ActionController::Base.logger
      end

      def extract_path(path)
        index = path.index("?")
        index ? path[0, index] : path
      end

      def action_message(message, payload)
        if self.class.action_message_format
          self.class.action_message_format.call(message, payload)
        else
          "#{message} ##{payload[:action]}"
        end
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/action_mailer/log_subscriber.rb
================================================
require "active_support/log_subscriber"
require "action_mailer"

module RailsSemanticLogger
  module ActionMailer
    class LogSubscriber < ::ActiveSupport::LogSubscriber
      def deliver(event)
        ex = event.payload[:exception_object]
        message_id = event.payload[:message_id]
        duration = event.duration.round(1)
        if ex
          log_with_formatter event: event, log_duration: true, level: :error do |_fmt|
            {
              message:   "Error delivering mail #{message_id} (#{duration}ms)",
              exception: ex
            }
          end
        else
          message =
            if event.payload[:perform_deliveries]
              "Delivered mail #{message_id} (#{duration}ms)"
            else
              "Skipped delivery of mail #{message_id} as `perform_deliveries` is false"
            end

          log_with_formatter event: event, log_duration: true do |_fmt|
            {message: message}
          end
        end
      end

      # An email was generated.
      def process(event)
        mailer   = event.payload[:mailer]
        action   = event.payload[:action]
        duration = event.duration.round(1)
        log_with_formatter event: event do |_fmt|
          {message: "#{mailer}##{action}: processed outbound mail in #{duration}ms"}
        end
      end

      private

      class EventFormatter
        def initialize(event:, log_duration: false)
          @event = event
          @log_duration = log_duration
        end

        def mailer
          event.payload[:mailer]
        end

        def payload
          {}.tap do |h|
            h[:event_name]         = event.name
            h[:mailer]             = mailer
            h[:action]             = action
            h[:message_id]         = event.payload[:message_id]
            h[:perform_deliveries] = event.payload[:perform_deliveries]
            h[:subject]            = event.payload[:subject]
            h[:to]                 = event.payload[:to]
            h[:from]               = event.payload[:from]
            h[:bcc]                = event.payload[:bcc]
            h[:cc]                 = event.payload[:cc]
            h[:date]               = date
            h[:duration]           = event.duration.round(2) if log_duration?
            h[:args]               = formatted_args
          end
        end

        def date
          if event.payload[:date].respond_to?(:to_time)
            event.payload[:date].to_time.utc
          elsif event.payload[:date].is_a?(String)
            Time.parse(date).utc
          end
        end

        private

        attr_reader :event

        def mailer
          event.payload[:mailer]
        end

        def action
          event.payload[:action]
        end

        def formatted_args
          if defined?(mailer.constantize.log_arguments?) && !mailer.constantize.log_arguments?
            ""
          elsif event.payload[:args].present?
            JSON.pretty_generate(event.payload[:args].map { |arg| format(arg) })
          end
        end

        def format(arg)
          case arg
          when Hash
            arg.transform_values { |value| format(value) }
          when Array
            arg.map { |value| format(value) }
          when GlobalID::Identification
            begin
              arg.to_global_id
            rescue StandardError
              arg
            end
          else
            arg
          end
        end

        def log_duration?
          @log_duration
        end
      end

      def log_with_formatter(level: :info, **kw_args)
        fmt = EventFormatter.new(**kw_args)
        msg = yield fmt
        logger.public_send(level, **msg, payload: fmt.payload)
      end

      def logger
        ::ActionMailer::Base.logger
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/action_view/log_subscriber.rb
================================================
require "active_support/log_subscriber"

module RailsSemanticLogger
  module ActionView
    # Output Semantic logs from Action View.
    class LogSubscriber < ActiveSupport::LogSubscriber
      VIEWS_PATTERN = %r{^app/views/}.freeze

      class << self
        attr_reader :logger
        attr_accessor :rendered_log_level
      end

      def initialize
        @rails_root = nil
        super
      end

      def render_template(event)
        return unless should_log?

        payload = {
          template: from_rails_root(event.payload[:identifier])
        }
        payload[:within]      = from_rails_root(event.payload[:layout]) if event.payload[:layout]
        payload[:allocations] = event.allocations if event.respond_to?(:allocations)

        logger.measure(
          self.class.rendered_log_level,
          "Rendered",
          payload:  payload,
          duration: event.duration
        )
      end

      def render_partial(event)
        return unless should_log?

        payload = {
          partial: from_rails_root(event.payload[:identifier])
        }
        payload[:within]      = from_rails_root(event.payload[:layout]) if event.payload[:layout]
        payload[:cache]       = event.payload[:cache_hit] unless event.payload[:cache_hit].nil?
        payload[:allocations] = event.allocations if event.respond_to?(:allocations)

        logger.measure(
          self.class.rendered_log_level,
          "Rendered",
          payload:  payload,
          duration: event.duration
        )
      end

      def render_collection(event)
        return unless should_log?

        identifier = event.payload[:identifier] || "templates"

        payload = {
          template: from_rails_root(identifier),
          count:    event.payload[:count]
        }
        payload[:cache_hits]  = event.payload[:cache_hits] if event.payload[:cache_hits]
        payload[:allocations] = event.allocations if event.respond_to?(:allocations)

        logger.measure(
          self.class.rendered_log_level,
          "Rendered",
          payload:  payload,
          duration: event.duration
        )
      end

      def start(name, id, payload)
        if ["render_template.action_view", "render_layout.action_view"].include?(name) && should_log?
          qualifier        = " layout" if name == "render_layout.action_view"
          payload          = {template: from_rails_root(payload[:identifier])}
          payload[:within] = from_rails_root(payload[:layout]) if payload[:layout]

          logger.send(self.class.rendered_log_level, message: "Rendering#{qualifier}", payload: payload)
        end

        super
      end

      if (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) || Rails::VERSION::MAJOR > 7
        class Start
          def start(name, _id, payload)
            return unless %w[render_template.action_view render_layout.action_view].include?(name)

            qualifier        = " layout" if name == "render_layout.action_view"
            payload          = {template: from_rails_root(payload[:identifier])}
            payload[:within] = from_rails_root(payload[:layout]) if payload[:layout]

            logger.debug(message: "Rendering#{qualifier}", payload: payload)
          end

          def finish(name, id, payload)
          end

          private

          def from_rails_root(string)
            string = string.sub(rails_root, "")
            string.sub!(VIEWS_PATTERN, "")
            string
          end

          def rails_root
            @root ||= "#{Rails.root}/"
          end

          def logger
            @logger ||= SemanticLogger["ActionView"]
          end
        end

        def self.attach_to(*)
          ActiveSupport::Notifications.unsubscribe("render_template.action_view")
          ActiveSupport::Notifications.unsubscribe("render_layout.action_view")
          ActiveSupport::Notifications.subscribe("render_template.action_view",
                                                 RailsSemanticLogger::ActionView::LogSubscriber::Start.new)
          ActiveSupport::Notifications.subscribe("render_layout.action_view",
                                                 RailsSemanticLogger::ActionView::LogSubscriber::Start.new)

          super
        end
      end

      private

      @logger             = SemanticLogger["ActionView"]
      @rendered_log_level = :debug

      EMPTY = "".freeze

      def should_log?
        logger.send("#{self.class.rendered_log_level}?")
      end

      def from_rails_root(string)
        string = string.sub(rails_root, EMPTY)
        string.sub!(VIEWS_PATTERN, EMPTY)
        string
      end

      def rails_root
        @rails_root ||= "#{Rails.root}/"
      end

      def logger
        self.class.logger
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/active_job/log_subscriber.rb
================================================
require "active_job"

module RailsSemanticLogger
  module ActiveJob
    class LogSubscriber < ::ActiveSupport::LogSubscriber
      def enqueue(event)
        ex = event.payload[:exception_object]

        if ex
          log_with_formatter level: :error, event: event do |fmt|
            {
              message:   "Failed enqueuing #{fmt.job_info} (#{ex.class} (#{ex.message})",
              exception: ex
            }
          end
        elsif event.payload[:aborted]
          log_with_formatter level: :info, event: event do |fmt|
            {message: "Failed enqueuing #{fmt.job_info}, a before_enqueue callback halted the enqueuing execution."}
          end
        else
          log_with_formatter event: event do |fmt|
            {message: "Enqueued #{fmt.job_info}"}
          end
        end
      end

      def enqueue_at(event)
        ex = event.payload[:exception_object]

        if ex
          log_with_formatter level: :error, event: event do |fmt|
            {
              message:   "Failed enqueuing #{fmt.job_info} (#{ex.class} (#{ex.message})",
              exception: ex
            }
          end
        elsif event.payload[:aborted]
          log_with_formatter level: :info, event: event do |fmt|
            {message: "Failed enqueuing #{fmt.job_info}, a before_enqueue callback halted the enqueuing execution."}
          end
        else
          log_with_formatter event: event do |fmt|
            {message: "Enqueued #{fmt.job_info} at #{fmt.scheduled_at}"}
          end
        end
      end

      def perform_start(event)
        log_with_formatter event: event do |fmt|
          {message: "Performing #{fmt.job_info}"}
        end
      end

      def perform(event)
        ex = event.payload[:exception_object]
        if ex
          log_with_formatter event: event, log_duration: true, level: :error do |fmt|
            {
              message:   "Error performing #{fmt.job_info} in #{event.duration.round(2)}ms",
              exception: ex
            }
          end
        else
          log_with_formatter event: event, log_duration: true do |fmt|
            {message: "Performed #{fmt.job_info} in #{event.duration.round(2)}ms"}
          end
        end
      end

      private

      class EventFormatter
        def initialize(event:, log_duration: false)
          @event = event
          @log_duration = log_duration
        end

        def job_info
          "#{job.class.name} (Job ID: #{job.job_id}) to #{queue_name}"
        end

        def payload
          {}.tap do |h|
            h[:event_name]      = event.name
            h[:adapter]         = adapter_name
            h[:queue]           = job.queue_name
            h[:job_class]       = job.class.name
            h[:job_id]          = job.job_id
            h[:provider_job_id] = job.try(:provider_job_id) # Not available in Rails 4.2
            h[:duration]        = event.duration.round(2) if log_duration?
            h[:arguments]       = formatted_args
          end
        end

        def queue_name
          adapter_name + "(#{job.queue_name})"
        end

        def scheduled_at
          Time.at(event.payload[:job].scheduled_at).utc
        end

        private

        attr_reader :event

        def job
          event.payload[:job]
        end

        def adapter_name
          event.payload[:adapter].class.name.demodulize.remove("Adapter")
        end

        def formatted_args
          if defined?(job.class.log_arguments?) && !job.class.log_arguments?
            ""
          else
            JSON.pretty_generate(job.arguments.map { |arg| format(arg) })
          end
        end

        def format(arg)
          case arg
          when String
            arg.encode("UTF-8", invalid: :replace, undef: :replace)
          when Hash
            arg.transform_values { |value| format(value) }
          when Array
            arg.map { |value| format(value) }
          when GlobalID::Identification
            begin
              arg.to_global_id
            rescue StandardError
              arg
            end
          else
            arg
          end
        end

        def log_duration?
          @log_duration
        end
      end

      def log_with_formatter(level: :info, **kw_args)
        fmt = EventFormatter.new(**kw_args)
        msg = yield fmt
        logger.public_send(level, **msg, payload: fmt.payload)
      end

      def logger
        ::ActiveJob::Base.logger
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/active_record/log_subscriber.rb
================================================
module RailsSemanticLogger
  module ActiveRecord
    class LogSubscriber < ActiveSupport::LogSubscriber
      IGNORE_PAYLOAD_NAMES = %w[SCHEMA EXPLAIN].freeze

      class << self
        attr_reader :logger
      end

      # Rails 7.1 stopped using runtime in log subscribers
      if Rails.version.to_f < 7.1
        def self.runtime=(value)
          ::ActiveRecord::RuntimeRegistry.sql_runtime = value
        end

        def self.runtime
          ::ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
        end

        def self.reset_runtime
          rt           = runtime
          self.runtime = 0
          rt
        end
      end

      def sql(event)
        self.class.runtime += event.duration if self.class.respond_to?(:runtime)
        return unless logger.debug?

        payload = event.payload
        name    = payload[:name]
        return if IGNORE_PAYLOAD_NAMES.include?(name)

        log_payload         = {sql: payload[:sql]}
        log_payload[:binds] = bind_values(payload) unless (payload[:binds] || []).empty?
        log_payload[:allocations] = event.allocations if event.respond_to?(:allocations)
        log_payload[:cached] = event.payload[:cached]
        log_payload[:async] = true if event.payload[:async]

        log = {
          message:  name,
          payload:  log_payload,
          duration: event.duration
        }

        # Log the location of the query itself.
        if logger.send(:level_index) >= SemanticLogger.backtrace_level_index
          log[:backtrace] = SemanticLogger::Utils.strip_backtrace(caller)
        end

        logger.debug(log)
      end

      private

      @logger = SemanticLogger["ActiveRecord"]

      # When multiple values are received for a single bound field, it is converted into an array
      def add_bind_value(binds, key, value)
        key = key.downcase.to_sym unless key.nil?

        if rails_filter_params_include?(key)
          value = "[FILTERED]"
        elsif binds.key?(key)
          value = (Array(binds[key]) << value)
        end

        binds[key] = value
      end

      def rails_filter_params_include?(key)
        filter_parameters = Rails.configuration.filter_parameters

        return filter_parameters.first.match? key if filter_parameters.first.is_a? Regexp

        filter_parameters.include? key
      end

      def logger
        self.class.logger
      end

      #
      # Rails 3,4,5 hell trying to get the bind values
      #

      def bind_values_v3(payload)
        binds = {}
        payload[:binds].each do |col, v|
          if col
            add_bind_value(binds, col.name, v)
          else
            binds[nil] = v
          end
        end
        binds
      end

      def bind_values_v4(payload)
        binds = {}
        payload[:binds].each do |col, v|
          attr_name, value = render_bind(col, v)
          add_bind_value(binds, attr_name, value)
        end
        binds
      end

      def bind_values_v5_0_0(payload)
        binds = {}
        payload[:binds].each do |attr|
          attr_name, value = render_bind(attr)
          add_bind_value(binds, attr_name, value)
        end
        binds
      end

      def bind_values_v5_0_3(payload)
        binds         = {}
        casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
        payload[:binds].zip(casted_params).map do |attr, value|
          attr_name, value = render_bind(attr, value)
          add_bind_value(binds, attr_name, value)
        end
        binds
      end

      def bind_values_v5_1_5(payload)
        binds         = {}
        casted_params = type_casted_binds(payload[:type_casted_binds])
        payload[:binds].zip(casted_params).map do |attr, value|
          attr_name, value = render_bind(attr, value)
          add_bind_value(binds, attr_name, value)
        end
        binds
      end

      def bind_values_v6_1(payload)
        binds         = {}
        casted_params = type_casted_binds(payload[:type_casted_binds])
        payload[:binds].each_with_index do |attr, i|
          attr_name, value = render_bind(attr, casted_params[i])
          add_bind_value(binds, attr_name, value)
        end
        binds
      end

      def render_bind_v4_2(column, value)
        if column
          if column.binary?
            # This specifically deals with the PG adapter that casts bytea columns into a Hash.
            value = value[:value] if value.is_a?(Hash)
            value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
          end

          [column.name, value]
        else
          [nil, value]
        end
      end

      def render_bind_v5_0_0(attribute)
        value =
          if attribute.type.binary? && attribute.value
            if attribute.value.is_a?(Hash)
              "<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>"
            else
              "<#{attribute.value.bytesize} bytes of binary data>"
            end
          else
            attribute.value_for_database
          end

        [attribute.name, value]
      end

      def render_bind_v5_0_3(attr, value)
        if attr.is_a?(Array)
          attr = attr.first
        elsif attr.type.binary? && attr.value
          value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
        end

        [attr&.name, value]
      end

      def render_bind_v6_1(attr, value)
        case attr
        when ActiveModel::Attribute
          value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" if attr.type.binary? && attr.value
        when Array
          attr = attr.first
        else
          attr = nil
        end

        [attr&.name || :nil, value]
      end

      def type_casted_binds_v5_0_3(binds, casted_binds)
        casted_binds || ::ActiveRecord::Base.connection.type_casted_binds(binds)
      end

      def type_casted_binds_v5_1_5(casted_binds)
        casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
      end

      if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR.zero? && Rails::VERSION::TINY <= 2 # 5.0.0 - 5.0.2
        alias bind_values bind_values_v5_0_0
        alias render_bind render_bind_v5_0_0
      elsif Rails::VERSION::MAJOR == 5 &&
            ((Rails::VERSION::MINOR.zero? && Rails::VERSION::TINY <= 6) ||
              (Rails::VERSION::MINOR == 1 && Rails::VERSION::TINY <= 4)) # 5.0.3 - 5.0.6 && 5.1.0 - 5.1.4
        alias bind_values bind_values_v5_0_3
        alias render_bind render_bind_v5_0_3
        alias type_casted_binds type_casted_binds_v5_0_3
      elsif (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR > 0) ||
            Rails::VERSION::MAJOR >= 7 # ~> 6.1.0 && >= 7.x.x
        alias bind_values bind_values_v6_1
        alias render_bind render_bind_v6_1
        alias type_casted_binds type_casted_binds_v5_1_5
      elsif Rails::VERSION::MAJOR >= 5 # ~> 5.1.5 && ~> 5.0.7 && 6.x.x
        alias bind_values bind_values_v5_1_5
        alias render_bind render_bind_v5_0_3
        alias type_casted_binds type_casted_binds_v5_1_5
      elsif Rails.version.to_i >= 4 # 4.x
        alias bind_values bind_values_v4
        alias render_bind render_bind_v4_2
      else # 3.x
        alias bind_values bind_values_v3
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/delayed_job/plugin.rb
================================================
module RailsSemanticLogger
  module DelayedJob
    class Plugin < Delayed::Plugin
      callbacks do |lifecycle|
        lifecycle.before(:execute) do |_job|
          ::SemanticLogger.reopen
        end
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/engine.rb
================================================
require "rails"
require "rails_semantic_logger/options"

module RailsSemanticLogger
  class Engine < ::Rails::Engine
    # Make the SemanticLogger config available in the Rails application config
    #
    # Example: Add the MongoDB logging appender in the Rails environment
    #          initializer in file config/environments/development.rb
    #
    #   Rails::Application.configure do
    #     # Add the MongoDB logger appender only once Rails is initialized
    #     config.after_initialize do
    #       appender = SemanticLogger::Appender::Mongo.new(
    #         uri: 'mongodb://127.0.0.1:27017/test'
    #       )
    #       config.semantic_logger.add_appender(appender: appender)
    #     end
    #   end
    config.semantic_logger = ::SemanticLogger

    config.rails_semantic_logger = RailsSemanticLogger::Options.new

    # Initialize SemanticLogger. In a Rails environment it will automatically
    # insert itself above the configured rails logger to add support for its
    # additional features

    # Replace Rails logger initializer
    Rails::Application::Bootstrap.initializers.delete_if { |i| i.name == :initialize_logger }

    initializer :initialize_logger, group: :all do
      config = Rails.application.config

      # Set the default log level based on the Rails config
      SemanticLogger.default_level = config.log_level

      if defined?(Rails::Rack::Logger) && config.rails_semantic_logger.semantic
        config.middleware.swap(Rails::Rack::Logger, RailsSemanticLogger::Rack::Logger, config.log_tags)
      end

      # Existing loggers are ignored because servers like trinidad supply their
      # own file loggers which would result in duplicate logging to the same log file
      Rails.logger = config.logger =
        begin
          if config.rails_semantic_logger.add_file_appender
            path = config.paths["log"].first
            FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(File.dirname(path))

            # Add the log file to the list of appenders
            # Use the colorized formatter if Rails colorized logs are enabled
            ap_options = config.rails_semantic_logger.ap_options
            formatter  = config.rails_semantic_logger.format
            formatter  = {color: {ap: ap_options}} if (formatter == :default) && (config.colorize_logging != false)

            # Set internal logger to log to file only, in case another appender experiences errors during writes
            appender                         = SemanticLogger::Appender::File.new(path, formatter: formatter)
            appender.name                    = "SemanticLogger"
            SemanticLogger::Processor.logger = appender

            # Check for previous file or stdout loggers
            SemanticLogger.appenders.each do |app|
              next unless app.is_a?(SemanticLogger::Appender::File) || app.is_a?(SemanticLogger::Appender::IO)

              app.formatter = formatter
            end
            SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
          end

          SemanticLogger[Rails]
        rescue StandardError => e
          # If not able to log to file, log to standard error with warning level only
          SemanticLogger.default_level = :warn

          SemanticLogger::Processor.logger = SemanticLogger::Appender::IO.new($stderr)
          SemanticLogger.add_appender(io: $stderr)

          logger = SemanticLogger[Rails]
          logger.warn(
            "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " \
            "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.",
            e
          )
          logger
        end

      # Replace Rails loggers
      %i[active_record action_controller action_mailer action_view].each do |name|
        ActiveSupport.on_load(name) { include SemanticLogger::Loggable }
      end
      ActiveSupport.on_load(:action_cable) { self.logger = SemanticLogger["ActionCable"] }
    end

    # Before any initializers run, but after the gems have been loaded
    config.before_initialize do
      if config.respond_to?(:assets) && defined?(Rails::Rack::Logger) && config.rails_semantic_logger.semantic
        config.rails_semantic_logger.quiet_assets = true if config.assets.quiet

        # Otherwise Sprockets can't find the Rails::Rack::Logger middleware
        config.assets.quiet = false
      end

      # Replace the Mongo Loggers
      Mongoid.logger       = SemanticLogger[Mongoid] if defined?(Mongoid)
      Moped.logger         = SemanticLogger[Moped] if defined?(Moped)
      Mongo::Logger.logger = SemanticLogger[Mongo] if defined?(Mongo::Logger)

      # Replace the Resque Logger
      Resque.logger        = SemanticLogger[Resque] if defined?(Resque) && Resque.respond_to?(:logger=)

      # Replace the Sidekiq logger
      if config.rails_semantic_logger.replace_sidekiq_logger && defined?(::Sidekiq)
        ::Sidekiq.configure_client do |config|
          config.logger = ::SemanticLogger[::Sidekiq]
        end

        ::Sidekiq.configure_server do |config|
          config.logger = ::SemanticLogger[::Sidekiq]
          if config.respond_to?(:options)
            config.options[:job_logger] = RailsSemanticLogger::Sidekiq::JobLogger
          else
            config[:job_logger] = RailsSemanticLogger::Sidekiq::JobLogger
          end

          # Add back the default console logger unless already added
          SemanticLogger.add_appender(io: $stdout, formatter: :color) unless SemanticLogger.appenders.console_output?

          # Replace default error handler when present
          existing = RailsSemanticLogger::Sidekiq::Defaults.delete_default_error_handler(config.error_handlers)
          config.error_handlers << RailsSemanticLogger::Sidekiq::Defaults::ERROR_HANDLER if existing
        end

        if defined?(::Sidekiq::Job) && (::Sidekiq::VERSION.to_i != 5)
          ::Sidekiq::Job.singleton_class.prepend(RailsSemanticLogger::Sidekiq::Loggable)
        else
          ::Sidekiq::Worker.singleton_class.prepend(RailsSemanticLogger::Sidekiq::Loggable)
        end
      end

      # Replace the Sidetiq logger
      Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq) && Sidetiq.respond_to?(:logger=)

      # Replace the DelayedJob logger
      if defined?(Delayed::Worker)
        Delayed::Worker.logger = SemanticLogger[Delayed::Worker]
        Delayed::Worker.plugins << RailsSemanticLogger::DelayedJob::Plugin
      end

      # Replace the Bugsnag logger
      Bugsnag.configure(false) { |config| config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)

      # Set the IOStreams PGP logger
      IOStreams::Pgp.logger = SemanticLogger["IOStreams::Pgp"] if defined?(IOStreams)
    end

    # After any initializers run, but after the gems have been loaded
    config.after_initialize do
      config = Rails.application.config

      # Replace the Bugsnag logger
      Bugsnag.configure(false) { |bugsnag_config| bugsnag_config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)

      # Rails Patches
      require("rails_semantic_logger/extensions/action_cable/tagged_logger_proxy") if defined?(::ActionCable)
      require("rails_semantic_logger/extensions/action_controller/live") if defined?(::ActionController::Live)
      if defined?(::ActionDispatch::DebugExceptions)
        require("rails_semantic_logger/extensions/action_dispatch/debug_exceptions")
      end
      if defined?(::ActionView::StreamingTemplateRenderer::Body)
        require("rails_semantic_logger/extensions/action_view/streaming_template_renderer")
      end
      require("rails_semantic_logger/extensions/active_job/logging") if defined?(::ActiveJob)
      require("rails_semantic_logger/extensions/active_model_serializers/logging") if defined?(::ActiveModelSerializers)

      if config.rails_semantic_logger.semantic
        # Active Job
        if defined?(::ActiveJob::Logging::LogSubscriber)
          RailsSemanticLogger.swap_subscriber(
            ::ActiveJob::Logging::LogSubscriber,
            RailsSemanticLogger::ActiveJob::LogSubscriber,
            :active_job
          )
        end

        if defined?(::ActiveJob::LogSubscriber)
          RailsSemanticLogger.swap_subscriber(
            ::ActiveJob::LogSubscriber,
            RailsSemanticLogger::ActiveJob::LogSubscriber,
            :active_job
          )
        end

        # Active Record
        if defined?(::ActiveRecord)
          require "active_record/log_subscriber"

          RailsSemanticLogger.swap_subscriber(
            ::ActiveRecord::LogSubscriber,
            RailsSemanticLogger::ActiveRecord::LogSubscriber,
            :active_record
          )
        end

        # Rack
        RailsSemanticLogger::Rack::Logger.started_request_log_level = :info if config.rails_semantic_logger.started

        # Silence asset logging by applying a filter to the Rails logger itself, not any of the appenders.
        if config.rails_semantic_logger.quiet_assets && config.respond_to?(:assets) && config.assets.prefix
          assets_root                                     = config.relative_url_root.to_s + config.assets.prefix
          assets_regex                                    = %r(\A/{0,2}#{assets_root})
          RailsSemanticLogger::Rack::Logger.logger.filter = ->(log) { log.payload[:path] !~ assets_regex if log.payload }
        end

        # Action View
        if defined?(::ActionView)
          require "action_view/log_subscriber"

          RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info if config.rails_semantic_logger.rendered
          RailsSemanticLogger.swap_subscriber(
            ::ActionView::LogSubscriber,
            RailsSemanticLogger::ActionView::LogSubscriber,
            :action_view
          )
        end

        # Action Controller
        if defined?(::ActionController)
          require "action_controller/log_subscriber"

          RailsSemanticLogger::ActionController::LogSubscriber.action_message_format = config.rails_semantic_logger.action_message_format
          RailsSemanticLogger.swap_subscriber(
            ::ActionController::LogSubscriber,
            RailsSemanticLogger::ActionController::LogSubscriber,
            :action_controller
          )
        end

        # Action Mailer
        if defined?(::ActionMailer)
          require "action_mailer/log_subscriber"

          RailsSemanticLogger.swap_subscriber(
            ::ActionMailer::LogSubscriber,
            RailsSemanticLogger::ActionMailer::LogSubscriber,
            :action_mailer
          )
        end

        if config.rails_semantic_logger.replace_sidekiq_logger && defined?(::Sidekiq)
          require("rails_semantic_logger/extensions/sidekiq/sidekiq")
        end
      end

      #
      # Forking Frameworks
      #

      # Passenger provides the :starting_worker_process event for executing
      # code after it has forked, so we use that and reconnect immediately.
      if defined?(PhusionPassenger)
        PhusionPassenger.on_event(:starting_worker_process) do |forked|
          SemanticLogger.reopen if forked
        end
      end

      # Re-open appenders after Resque has forked a worker
      Resque.after_fork { |_job| ::SemanticLogger.reopen } if defined?(Resque.after_fork)

      # Re-open appenders after Spring has forked a process
      Spring.after_fork { |_job| ::SemanticLogger.reopen } if defined?(Spring.after_fork)

      # Re-open appenders after SolidQueue worker/dispatcher/scheduler has finished booting
      SolidQueue.on_start { ::SemanticLogger.reopen } if defined?(SolidQueue.on_start)
      SolidQueue.on_worker_start { ::SemanticLogger.reopen } if defined?(SolidQueue.on_worker_start)
      SolidQueue.on_dispatcher_start { ::SemanticLogger.reopen } if defined?(SolidQueue.on_dispatcher_start)
      SolidQueue.on_scheduler_start { ::SemanticLogger.reopen } if defined?(SolidQueue.on_scheduler_start)

      console do |_app|
        # Don't use a background thread for logging
        SemanticLogger.sync!
        # Add a stderr logger when running inside a Rails console unless one has already been added.
        if config.rails_semantic_logger.console_logger && !SemanticLogger.appenders.console_output?
          SemanticLogger.add_appender(io: STDERR, formatter: :color)
        end

        # Include method names on log entries in the console
        SemanticLogger.backtrace_level = SemanticLogger.default_level
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb
================================================
require "action_cable/connection/tagged_logger_proxy"

module ActionCable
  module Connection
    class TaggedLoggerProxy
      def tag(logger, &block)
        current_tags = tags - logger.tags
        logger.tagged(*current_tags, &block)
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/action_controller/live.rb
================================================
# Log actual exceptions, not a string representation
require "action_controller"

module ActionController
  module Live
    undef_method :log_error
    def log_error(exception)
      logger.fatal(exception)
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb
================================================
# Log actual exceptions, not a string representation
require "action_dispatch"

module ActionDispatch
  class DebugExceptions
    private

    undef_method :log_error
    if (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) || Rails::VERSION::MAJOR > 7
      def log_error(request, wrapper)
        Rails.application.deprecators.silence do
          return if !log_rescued_responses?(request) && wrapper.rescue_response?

          level = request.get_header("action_dispatch.debug_exception_log_level")
          ActionController::Base.logger.log(level, wrapper.exception)
        end
      end
    else
      def log_error(_request, wrapper)
        ActiveSupport::Deprecation.silence do
          level = wrapper.respond_to?(:rescue_response?) && wrapper.rescue_response? ? :debug : :fatal
          ActionController::Base.logger.log(level, wrapper.exception)
        end
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb
================================================
# Log actual exceptions, not a string representation
require "action_view/renderer/streaming_template_renderer"

module ActionView
  class StreamingTemplateRenderer
    class Body
      private

      undef_method :log_error
      def log_error(exception)
        ActionView::Base.logger.fatal(exception)
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/active_job/logging.rb
================================================
# Patch ActiveJob logger
require "active_job/logging"

module ActiveJob
  module Logging
    include SemanticLogger::Loggable

    private

    undef_method :tag_logger
    def tag_logger(*tags, &block)
      if logger.respond_to?(:tagged)
        logger.tagged(*tags, &block)
      else
        yield
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb
================================================
# Patch ActiveModelSerializers logger
require "active_model_serializers/logging"

module ActiveModelSerializers
  module Logging
    include SemanticLogger::Loggable

    private

    def tag_logger(*tags, &block)
      logger.tagged(*tags, &block)
    end
  end

  class SerializableResource
    include SemanticLogger::Loggable
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb
================================================
if ActiveSupport::VERSION::STRING == "7.1.1"
  require "active_support/log_subscriber"

  module ActiveSupport
    class LogSubscriber
      # @override Rails 7.1
      def silenced?(event)
        native_log_level = @event_levels.fetch(event, ::Logger::Severity::FATAL)
        logger.nil? || SemanticLogger::Levels.index(logger.level) > SemanticLogger::Levels.index(native_log_level)
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/active_support/logger.rb
================================================
require "active_support/logger"

module ActiveSupport
  # More hacks to try and stop Rails from being it's own worst enemy.
  class Logger
    class << self
      undef :logger_outputs_to?

      # Prevent broadcasting since SemanticLogger already supports multiple loggers
      if method_defined?(:broadcast)
        undef :broadcast
        def broadcast(_logger)
          Module.new
        end
      end
    end

    # Prevent Console from trying to merge loggers
    def self.logger_outputs_to?(*_args)
      true
    end

    def self.new(*_args, **_kwargs)
      SemanticLogger[self]
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
================================================
module ActiveSupport
  module TaggedLogging
    # Semantic Logger already does tagged logging
    def self.new(logger)
      logger
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/mongoid/config.rb
================================================
require "mongoid/config"

module Mongoid
  module Config
    private

    # Remove log overrides
    def set_log_levels
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/rack/server.rb
================================================
module RailsSemanticLogger
  module Rack
    module Server
      def daemonize_app
        super
        SemanticLogger.reopen
      end
    end
  end
end

Rack::Server.prepend(RailsSemanticLogger::Rack::Server)


================================================
FILE: lib/rails_semantic_logger/extensions/rackup/server.rb
================================================
module RailsSemanticLogger
  module Rackup
    module Server
      def daemonize_app
        super
        SemanticLogger.reopen
      end
    end
  end
end

Rackup::Server.prepend(RailsSemanticLogger::Rackup::Server)


================================================
FILE: lib/rails_semantic_logger/extensions/rails/server.rb
================================================
# Patch the Rails::Server log_to_stdout so that it logs via SemanticLogger
require "rails"

module Rails
  class Server
    private

    undef_method :log_to_stdout if method_defined?(:log_to_stdout)
    def log_to_stdout
      wrapped_app # touch the app so the logger is set up

      SemanticLogger.add_appender(io: $stdout, formatter: :color) unless SemanticLogger.appenders.console_output?
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb
================================================
# Sidekiq patches
if Sidekiq::VERSION.to_i == 4
  require "sidekiq/logging"
  require "sidekiq/middleware/server/logging"
  require "sidekiq/processor"
elsif Sidekiq::VERSION.to_i == 5
  require "sidekiq/logging"
end

module Sidekiq
  # Sidekiq v4 & v5
  if defined?(::Sidekiq::Logging)
    # Replace Sidekiq logging context
    module Logging
      def self.with_context(msg, &block)
        SemanticLogger.tagged(msg, &block)
      end

      def self.job_hash_context(job_hash)
        h         = {jid: job_hash["jid"]}
        h[:bid]   = job_hash["bid"] if job_hash["bid"]
        h[:queue] = job_hash["queue"] if job_hash["queue"]
        h
      end
    end
  end

  # Sidekiq v4
  if defined?(::Sidekiq::Middleware::Server::Logging)
    # Convert string to machine readable format
    class Processor
      def log_context(job_hash)
        h         = {jid: job_hash["jid"]}
        h[:bid]   = job_hash["bid"] if job_hash["bid"]
        h[:queue] = job_hash["queue"] if job_hash["queue"]
        h
      end
    end

    # Let Semantic Logger handle duration logging
    module Middleware
      module Server
        class Logging
          # rubocop:disable Style/ExplicitBlockArgument
          def call(worker, item, queue)
            SemanticLogger.tagged(queue: queue) do
              if perform_messages_enabled?
                worker.logger.info(
                  "Start #perform",
                  metric:        "sidekiq.queue.latency",
                  metric_amount: job_latency_ms(item)
                )

                worker.logger.measure_info(
                  "Completed #perform",
                  on_exception_level: :error,
                  log_exception:      :full,
                  metric:             "sidekiq.job.perform"
                ) { yield }
              else
                yield
              end
            end
          end

          def perform_messages_enabled?
            RailsSemanticLogger::Sidekiq::JobLogger.perform_messages != false
          end

          def job_latency_ms(job)
            return unless job && job["enqueued_at"]

            enqueued_at = job["enqueued_at"]
            if enqueued_at.is_a?(Float)
              # Sidekiq <= 7: seconds since epoch
              (Time.now.to_f - enqueued_at) * 1000
            else
              # Sidekiq 8+: milliseconds since epoch
              now = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
              now - enqueued_at
            end
          end
        end
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/options.rb
================================================
module RailsSemanticLogger
  # Options for controlling Rails Semantic Logger behavior
  #
  # * Convert Action Controller and Active Record text messages to semantic data
  #
  #     Rails -- Started -- { :ip => "127.0.0.1", :method => "GET", :path => "/dashboards/inquiry_recent_activity" }
  #     UserController -- Completed #index -- { :action => "index", :db_runtime => 54.64, :format => "HTML", :method => "GET", :mongo_runtime => 0.0, :path => "/users", :status => 200, :status_message => "OK", :view_runtime => 709.88 }
  #
  #     config.rails_semantic_logger.semantic = true
  #
  # * Change Rack started message to debug so that it does not appear in production
  #
  #     config.rails_semantic_logger.started = false
  #
  # * Change Processing message to debug so that it does not appear in production
  #
  #     config.rails_semantic_logger.processing = false
  #
  # * Change Action View render log messages to debug so that they do not appear in production
  #
  #     ActionView::Base --   Rendered data/search/_user.html.haml (46.7ms)
  #
  #     config.rails_semantic_logger.rendered = false
  #
  # * Override the Amazing Print options for logging Hash data as text:
  #
  #     Any valid Amazing Print option for rendering data.
  #     The defaults can changed be creating a `~/.aprc` file.
  #     See: https://github.com/amazing-print/amazing_print
  #
  #     Note: The option :multiline is set to false if not supplied.
  #     Note: Has no effect if Amazing Print is not installed.
  #
  #        config.rails_semantic_logger.ap_options = {multiline: false}
  #
  # * Whether to automatically add an environment specific log file appender.
  #     For Example: 'log/development.log'
  #
  #     Note:
  #       When Semantic Logger fails to log to an appender it logs the error to an
  #       internal logger, which by default writes to STDERR.
  #       Example, change the default internal logger to log to stdout:
  #         SemanticLogger::Processor.logger = SemanticLogger::Appender::IO.new($stdout, level: :warn)
  #
  #       config.rails_semantic_logger.add_file_appender = true
  #
  # * Silence asset logging
  #
  #     config.rails_semantic_logger.quiet_assets = false
  #
  # * Disable automatic logging to stderr when running a Rails console.
  #
  #     config.rails_semantic_logger.console_logger = false
  #
  # * Override the output format for the primary Rails log file.
  #
  #     Valid options:
  #     * :default
  #         Plain text output with no color.
  #     * :color
  #         Plain text output with color.
  #     * :json
  #         JSON output format.
  #     * class
  #
  #     * Proc
  #         A block that will be called to format the output.
  #         It is supplied with the `log` entry and should return the formatted data.
  #
  #     Note:
  #     * `:default` is automatically changed to `:color` if `config.colorize_logging` is `true`.
  #
  #     JSON Example, in `application.rb`:
  #        config.rails_semantic_logger.format = :json
  #
  #     Custom Example, create `app/lib/my_formatter.rb`:
  #
  #       # My Custom colorized formatter
  #       class MyFormatter < SemanticLogger::Formatters::Color
  #         # Return the complete log level name in uppercase
  #         def level
  #           "#{color}log.level.upcase#{color_map.clear}"
  #         end
  #       end
  #
  #      # In application.rb:
  #      config.rails_semantic_logger.format = MyFormatter.new
  #
  #
  #      config.rails_semantic_logger.format = :default
  #
  # * Add a filter to the file logger [Regexp|Proc]
  #   RegExp: Only include log messages where the class name matches the supplied
  #           regular expression. All other messages will be ignored.
  #   Proc: Only include log messages where the supplied Proc returns true.
  #         The Proc must return true or false.
  #
  #     config.rails_semantic_logger.filter = nil
  #
  # * named_tags: *DEPRECATED*
  #   Instead, supply a Hash to config.log_tags
  #   config.rails_semantic_logger.named_tags = nil
  #
  # * Change the message format of Action Controller action.
  #   A block that will be called to format the message.
  #   It is supplied with the `message` and `payload` and should return the formatted data.
  #
  #     config.rails_semantic_logger.action_message_format = -> (message, payload) do
  #       "#{message} - #{payload[:controller]}##{payload[:action]}"
  #     end
  #
  # * Do not replace the Sidekiq logger with a Semantic Logger logger.
  #
  #     config.rails_semantic_logger.replace_sidekiq_logger = false
  class Options
    attr_accessor :semantic, :started, :processing, :rendered, :ap_options, :add_file_appender,
                  :quiet_assets, :format, :named_tags, :filter, :console_logger, :action_message_format,
                  :replace_sidekiq_logger

    # Setup default values
    def initialize
      @semantic               = true
      @started                = false
      @processing             = false
      @rendered               = false
      @ap_options             = {multiline: false}
      @add_file_appender      = true
      @quiet_assets           = false
      @format                 = :default
      @named_tags             = nil
      @filter                 = nil
      @console_logger         = true
      @action_message_format  = nil
      @replace_sidekiq_logger = true
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/rack/logger.rb
================================================
require "active_support/core_ext/time/conversions"
require "active_support/core_ext/object/blank"
require "active_support/log_subscriber"
require "action_dispatch/http/request"
require "rack/body_proxy"

module RailsSemanticLogger
  module Rack
    class Logger < ActiveSupport::LogSubscriber
      class << self
        attr_reader :logger
        attr_accessor :started_request_log_level
      end

      def initialize(app, taggers = nil)
        @app     = app
        @taggers = taggers || []
      end

      def call(env)
        request = ActionDispatch::Request.new(env)

        # Check for named tags (Hash)
        if @taggers && !@taggers.empty?
          tags = @taggers.is_a?(Hash) ? compute_named_tags(request) : compute_tags(request)
          logger.tagged(tags) { call_app(request, env) }
        else
          call_app(request, env)
        end
      end

      private

      @logger                    = SemanticLogger["Rack"]
      @started_request_log_level = :debug

      def call_app(request, env)
        instrumenter        = ActiveSupport::Notifications.instrumenter
        if (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) || Rails::VERSION::MAJOR > 7
          handle              = instrumenter.build_handle "request.action_dispatch", request: request
          instrumenter_finish = lambda {
            handle.finish
          }
          handle.start
        else
          instrumenter_state  = instrumenter.start "request.action_dispatch", request: request
          instrumenter_finish = lambda {
            instrumenter.finish_with_state(instrumenter_state, "request.action_dispatch", request: request)
          }
        end

        logger.send(self.class.started_request_log_level) { started_request_message(request) }
        status, headers, body = @app.call(env)
        body                  = ::Rack::BodyProxy.new(body, &instrumenter_finish)
        [status, headers, body]
      rescue Exception
        instrumenter_finish.call
        raise
      end

      def started_request_message(request)
        {
          message: "Started",
          payload: {
            method: request.request_method,
            path:   request.filtered_path,
            ip:     request.remote_ip
          }
        }
      end

      def compute_tags(request)
        @taggers.collect do |tag|
          case tag
          when Proc
            tag.call(request)
          when Symbol
            request.send(tag)
          else
            tag
          end
        end
      end

      # Leave out any named tags with a nil value
      def compute_named_tags(request)
        tagged = {}
        @taggers.each_pair do |tag, value|
          resolved    =
            case value
            when Proc
              value.call(request)
            when Symbol
              request.send(value)
            else
              value
            end
          tagged[tag] = resolved unless resolved.nil?
        end
        tagged
      end

      def logger
        self.class.logger
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/sidekiq/defaults.rb
================================================
module RailsSemanticLogger
  module Sidekiq
    module Defaults
      # Prevent exception logging during standard error handling since the Job Logger below already logs the exception.
      ERROR_HANDLER =
        if ::Sidekiq::VERSION.to_f < 7.1 ||
           (::Sidekiq::VERSION.to_f == 7.1 && ::Sidekiq::VERSION.split(".").last.to_i < 6)
          lambda do |_ex, ctx|
            unless ctx.empty?
              job_hash = ctx[:job] || {}
              klass    = job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
              logger   = klass ? SemanticLogger[klass] : ::Sidekiq.logger
              ctx[:context] ? logger.warn(ctx[:context], ctx) : logger.warn(ctx)
            end
          end
        else
          lambda do |_ex, ctx, _default_configuration|
            unless ctx.empty?
              job_hash = ctx[:job] || {}
              klass    = job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
              logger   = klass ? SemanticLogger[klass] : ::Sidekiq.logger
              ctx[:context] ? logger.warn(ctx[:context], ctx) : logger.warn(ctx)
            end
          end
        end

      # Returns the default logger after removing from the supplied list.
      # Returns [nil] when the default logger was not present.
      def self.delete_default_error_handler(error_handlers)
        return error_handlers.delete(::Sidekiq::Config::ERROR_HANDLER) if defined?(::Sidekiq::Config::ERROR_HANDLER)
        return error_handlers.delete(::Sidekiq::DEFAULT_ERROR_HANDLER) if defined?(::Sidekiq::DEFAULT_ERROR_HANDLER)

        return unless defined?(::Sidekiq::ExceptionHandler)

        existing = error_handlers.find { |handler| handler.is_a?(::Sidekiq::ExceptionHandler::Logger) }
        error_handlers.delete(existing) if existing
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/sidekiq/job_logger.rb
================================================
module RailsSemanticLogger
  module Sidekiq
    class JobLogger
      class << self
        attr_writer :perform_messages

        def perform_messages
          instance_variable_defined?(:@perform_messages) ? @perform_messages : true
        end
      end

      # Sidekiq 6.5 does not take any arguments, whereas v7 is given a logger
      def initialize(*_args)
      end

      def call(item, queue, &block)
        klass  = item["wrapped"] || item["class"]
        logger = klass ? SemanticLogger[klass] : Sidekiq.logger

        SemanticLogger.tagged(queue: queue) do
          if perform_messages_enabled?
          # Latency is the time between when the job was enqueued and when it started executing.
            logger.info(
              "Start #perform",
              metric:        "sidekiq.queue.latency",
              metric_amount: job_latency_ms(item)
            )
          end

          # Measure the duration of running the job
          if perform_messages_enabled?
            logger.measure_info(
              "Completed #perform",
              on_exception_level: :error,
              log_exception:      :full,
              metric:             "sidekiq.job.perform",
              &block
            )
          else
            yield if block_given?
          end
        end
      end

      def prepare(job_hash, &block)
        level = job_hash["log_level"]
        if level
          SemanticLogger.silence(level) do
            SemanticLogger.tagged(job_hash_context(job_hash), &block)
          end
        else
          SemanticLogger.tagged(job_hash_context(job_hash), &block)
        end
      end

      private

      def perform_messages_enabled?
        self.class.perform_messages != false
      end

      def job_hash_context(job_hash)
        h         = {jid: job_hash["jid"]}
        h[:bid]   = job_hash["bid"] if job_hash["bid"]
        h[:tags]  = job_hash["tags"] if job_hash["tags"]
        h[:queue] = job_hash["queue"] if job_hash["queue"]
        h
      end

      def job_latency_ms(job)
        return unless job && job["enqueued_at"]

        (Time.now.to_f - job["enqueued_at"].to_f) * 1000
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/sidekiq/loggable.rb
================================================
module RailsSemanticLogger
  module Sidekiq
    module Loggable
      def included(base)
        super
        base.include(SemanticLogger::Loggable)
      end
    end
  end
end


================================================
FILE: lib/rails_semantic_logger/version.rb
================================================
module RailsSemanticLogger
  VERSION = "4.20.0".freeze
end


================================================
FILE: lib/rails_semantic_logger.rb
================================================
require "semantic_logger"
require "rails_semantic_logger/extensions/rails/server" if defined?(Rails::Server)
require "rails_semantic_logger/engine"

module RailsSemanticLogger
  module ActionController
    autoload :LogSubscriber, "rails_semantic_logger/action_controller/log_subscriber"
  end

  module ActionMailer
    autoload :LogSubscriber, "rails_semantic_logger/action_mailer/log_subscriber"
  end

  module ActionView
    autoload :LogSubscriber, "rails_semantic_logger/action_view/log_subscriber"
  end

  module ActiveJob
    autoload :LogSubscriber, "rails_semantic_logger/active_job/log_subscriber"
  end

  module ActiveRecord
    autoload :LogSubscriber, "rails_semantic_logger/active_record/log_subscriber"
  end

  module Rack
    autoload :Logger, "rails_semantic_logger/rack/logger"
  end

  module DelayedJob
    autoload :Plugin, "rails_semantic_logger/delayed_job/plugin"
  end

  module Sidekiq
    autoload :Defaults, "rails_semantic_logger/sidekiq/defaults"
    autoload :JobLogger, "rails_semantic_logger/sidekiq/job_logger"
    autoload :Loggable, "rails_semantic_logger/sidekiq/loggable"
  end

  autoload :Options, "rails_semantic_logger/options"

  # Swap an existing subscriber with a new one
  def self.swap_subscriber(old_class, new_class, notifier)
    subscribers = ActiveSupport::LogSubscriber.subscribers.select { |s| s.is_a?(old_class) }
    subscribers.each { |subscriber| unattach(subscriber) }

    new_class.attach_to(notifier)
  end

  def self.unattach(subscriber)
    subscriber_patterns(subscriber).each do |pattern|
      listeners_for(ActiveSupport::Notifications.notifier, pattern).each do |sub|
        next unless sub.instance_variable_get(:@delegate) == subscriber

        ActiveSupport::Notifications.unsubscribe(sub)
      end
    end

    ActiveSupport::LogSubscriber.subscribers.delete(subscriber)
  end

  def self.subscriber_patterns(subscriber)
    if subscriber.patterns.respond_to?(:keys)
      subscriber.patterns.keys
    else
      subscriber.patterns
    end
  end

  def self.listeners_for(notifier, pattern)
    if notifier.respond_to?(:all_listeners_for) # Rails >= 7.1
      notifier.all_listeners_for(pattern)
    else
      notifier.listeners_for(pattern)
    end
  end

  private_class_method :listeners_for, :subscriber_patterns, :unattach
end

require("rails_semantic_logger/extensions/mongoid/config") if defined?(Mongoid)
require("rails_semantic_logger/extensions/active_support/logger") if defined?(ActiveSupport::Logger)
require("rails_semantic_logger/extensions/active_support/log_subscriber") if defined?(ActiveSupport::LogSubscriber)

begin
  require "rackup"
rescue LoadError
  # No need to do anything, will fall back to Rack
end
if defined?(Rackup::Server)
  require("rails_semantic_logger/extensions/rackup/server")
elsif defined?(Rack::Server)
  require("rails_semantic_logger/extensions/rack/server")
end


================================================
FILE: rails_semantic_logger.gemspec
================================================
$LOAD_PATH.push File.expand_path("lib", __dir__)

# Maintain your gem's version:
require "rails_semantic_logger/version"

# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
  s.name                  = "rails_semantic_logger"
  s.version               = RailsSemanticLogger::VERSION
  s.platform              = Gem::Platform::RUBY
  s.authors               = ["Reid Morrison"]
  s.homepage              = "https://logger.rocketjob.io"
  s.summary               = "Feature rich logging framework that replaces the Rails logger."
  s.files                 = Dir["lib/**/*", "LICENSE.txt", "Rakefile", "README.md"]
  s.license               = "Apache-2.0"
  s.required_ruby_version = ">= 2.5"
  s.add_dependency "rack"
  s.add_dependency "railties", ">= 5.1"
  s.add_dependency "semantic_logger", "~> 4.16"
  s.metadata = {
    "bug_tracker_uri"       => "https://github.com/reidmorrison/rails_semantic_logger/issues",
    "documentation_uri"     => "https://logger.rocketjob.io",
    "source_code_uri"       => "https://github.com/reidmorrison/rails_semantic_logger/tree/v#{RailsSemanticLogger::VERSION}",
    "rubygems_mfa_required" => "true"
  }
end


================================================
FILE: test/action_controller_test.rb
================================================
require_relative "test_helper"

class ActionControllerTest < Minitest::Test
  describe "RailsSemanticLogger::ActionController::LogSubscriber" do
    let(:subscriber) { RailsSemanticLogger::ActionController::LogSubscriber.new }

    describe "#process_action" do
      it "does not fail if params is not a Hash nor an instance of ActionController::Parameters" do
        event = ActiveSupport::Notifications::Event.new(
          "start_processing.action_controller",
          5.seconds.ago,
          Time.zone.now,
          SecureRandom.uuid,
          {
            payload: "{}"
          }
        )

        messages = semantic_logger_events do
          subscriber.process_action(event)
        end

        assert_equal 1, messages.count, messages
      end
    end
  end
end


================================================
FILE: test/action_mailer_test.rb
================================================
require_relative "test_helper"

class ActionMailerTest < Minitest::Test
  class MyMailer < ActionMailer::Base
    def some_email(opts)
      mail(to: opts[:to], from: opts[:from], subject: opts[:subject], body: "Hello")
    end
  end

  describe "ActionMailer" do
    describe "#deliver" do
      it "sets the ActionMailer logger" do
        assert_kind_of SemanticLogger::Logger, MyMailer.logger
      end

      it "sends the email" do
        MyMailer.some_email(to: "test@test.com", from: "test@test.com", subject: "test").deliver_now
      end

      it "writes log messages" do
        messages = semantic_logger_events do
          MyMailer.some_email(to: "test@test.com", from: "test@test.com", subject: "test").deliver_now
        end
        assert_equal 2, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :info,
          name:             "ActionMailer::Base",
          message_includes: "ActionMailerTest::MyMailer#some_email: processed outbound mail",
          payload_includes: {
            event_name: "process.action_mailer",
            mailer:     "ActionMailerTest::MyMailer",
            action:     :some_email
          }
        )

        assert_semantic_logger_event(
          messages[1],
          level:            :info,
          name:             "ActionMailer::Base",
          message_includes: Rails::VERSION::MAJOR >= 6 ? "Delivered mail" : "Skipped delivery",
          payload_includes: {
            event_name:         "deliver.action_mailer",
            mailer:             "ActionMailerTest::MyMailer",
            perform_deliveries: Rails::VERSION::MAJOR >= 6 ? true : nil,
            subject:            "test",
            to:                 ["test@test.com"],
            from:               ["test@test.com"]
          }
        )
      end
    end

    describe "Logging::LogSubscriber" do
      before do
        skip "Older rails does not support ActiveSupport::Notification" unless defined?(ActiveSupport::Notifications)
      end

      let(:subscriber) { RailsSemanticLogger::ActionMailer::LogSubscriber.new }

      let(:event) do
        ActiveSupport::Notifications::Event.new(event_name, 5.seconds.ago, Time.zone.now, SecureRandom.uuid, payload)
      end

      let(:payload) do
        {
          mailer: "MyMailer",
          action: :some_email
        }
      end

      let(:event_name) { "deliver.action_mailer" }

      let(:mailer) do
        MyMailer.some_email(to: "test@test.com", from: "test@test.com", subject: "test")
      end

      %i[deliver process].each do |method|
        describe "##{method}" do
          specify do
            assert ActionMailer::Base.logger.info
            subscriber.public_send(method, event)
          end
        end
      end

      describe "ActiveJob::Logging::LogSubscriber::EventFormatter" do
        let(:formatter) do
          RailsSemanticLogger::ActionMailer::LogSubscriber::EventFormatter.new(event: event, log_duration: true)
        end

        let(:event_name) { "deliver.action_mailer" }

        describe "#payload" do
          specify do
            assert_equal(formatter.payload[:event_name], "deliver.action_mailer")
            assert_equal(formatter.payload[:mailer], "MyMailer")
            assert_equal(formatter.payload[:action], :some_email)
            assert_kind_of(Float, formatter.payload[:duration])
          end
        end
      end
    end
  end
end


================================================
FILE: test/active_job_test.rb
================================================
require_relative "test_helper"

class ActiveJobTest < Minitest::Test
  if defined?(ActiveJob)
    class MyJob < ActiveJob::Base
      queue_as :my_jobs

      def perform(record)
        "Received: #{record}"
      end
    end

    class SensitiveJob < ActiveJob::Base
      queue_as :my_jobs

      if Rails.version.to_f >= 6.1
        self.log_arguments = false
      else
        def self.log_arguments?
          false
        end
      end

      def perform(record)
        "Received: #{record}"
      end
    end

    class TestModel
      include GlobalID::Identification

      def id
        15
      end
    end
  end

  describe "ActiveJob" do
    before do
      skip "Older rails does not support ActiveJob" unless defined?(ActiveJob)
    end

    describe ".perform_now" do
      it "sets the ActiveJob logger" do
        assert_kind_of SemanticLogger::Logger, MyJob.logger
      end

      it "runs the job" do
        MyJob.perform_now("hello")
      end
    end

    describe "Logging::LogSubscriber" do
      before do
        skip "Older rails does not support ActiveSupport::Notification" unless defined?(ActiveSupport::Notifications)
      end

      let(:subscriber) { RailsSemanticLogger::ActiveJob::LogSubscriber.new }

      let(:event) do
        ActiveSupport::Notifications::Event.new(event_name, 5.seconds.ago, Time.zone.now, SecureRandom.uuid, payload)
      end

      let(:event_name) { "enqueue.active_job" }

      let(:payload) do
        {
          adapter: ActiveJob::QueueAdapters::InlineAdapter.new,
          job:     job
        }
      end

      let(:job) do
        MyJob.new(TestModel.new, 1, "string", foo: "bar")
      end

      %i[enqueue enqueue_at perform_start perform].each do |method|
        describe "##{method}" do
          specify do
            job.stub(:scheduled_at, Time.zone.now.to_i) do
              assert ActiveJob::Base.logger.info
              subscriber.public_send(method, event)
            end
          end
        end
      end

      describe "#perform with exception object" do
        let(:event_name) { "perform.active_job" }

        let(:payload) do
          {
            adapter:          ActiveJob::QueueAdapters::InlineAdapter.new,
            job:              job,
            exception_object: ArgumentError.new("error")
          }
        end

        it "logs messages" do
          messages = semantic_logger_events do
            subscriber.perform(event)
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :error,
            name:             "Rails",
            message_includes: "Error performing ActiveJobTest::MyJob",
            payload_includes: {
              job_class:  "ActiveJobTest::MyJob",
              queue:      "my_jobs",
              event_name: "perform.active_job"
            }
          )
          assert_includes messages[0].payload, :job_id

          exception = messages[0].exception
          assert exception.is_a?(ArgumentError)
          assert_equal "error", exception.message
        end
      end

      describe "#enqueue with exception object" do
        let(:event_name) { "enqueue.active_job" }

        let(:payload) do
          {
            adapter:          ActiveJob::QueueAdapters::InlineAdapter.new,
            job:              job,
            exception_object: ArgumentError.new("error")
          }
        end

        it "logs message" do
          messages = semantic_logger_events do
            subscriber.enqueue(event)
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :error,
            name:             "Rails",
            message_includes: "Failed enqueuing ActiveJobTest::MyJob",
            payload_includes: {
              job_class:  "ActiveJobTest::MyJob",
              queue:      "my_jobs",
              event_name: "enqueue.active_job"
            }
          )
          assert_includes messages[0].payload, :job_id

          exception = messages[0].exception
          assert exception.is_a?(ArgumentError)
          assert_equal "error", exception.message
        end
      end

      describe "#enqueue with throwing :abort" do
        let(:event_name) { "enqueue.active_job" }

        let(:payload) do
          {
            adapter: ActiveJob::QueueAdapters::InlineAdapter.new,
            job:     job,
            aborted: true
          }
        end

        it "logs message" do
          messages = semantic_logger_events do
            subscriber.enqueue(event)
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :info,
            name:             "Rails",
            message_includes: "Failed enqueuing ActiveJobTest::MyJob",
            payload_includes: {
              job_class:  "ActiveJobTest::MyJob",
              queue:      "my_jobs",
              event_name: "enqueue.active_job"
            }
          )
          assert_match(/Failed enqueuing .*, a before_enqueue callback halted the enqueuing execution/, messages[0].message)
          assert_includes messages[0].payload, :job_id
        end
      end

      describe "#enqueue_at with exception object" do
        let(:event_name) { "enqueue.active_job" }

        let(:payload) do
          {
            adapter:          ActiveJob::QueueAdapters::InlineAdapter.new,
            job:              job,
            exception_object: ArgumentError.new("error")
          }
        end

        it "logs message" do
          messages = semantic_logger_events do
            subscriber.enqueue_at(event)
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :error,
            name:             "Rails",
            message_includes: "Failed enqueuing ActiveJobTest::MyJob",
            payload_includes: {
              job_class:  "ActiveJobTest::MyJob",
              queue:      "my_jobs",
              event_name: "enqueue.active_job"
            }
          )
          assert_includes messages[0].payload, :job_id

          exception = messages[0].exception
          assert exception.is_a?(ArgumentError)
          assert_equal "error", exception.message
        end
      end

      describe "#enqueue_at with throwing :abort" do
        let(:event_name) { "enqueue.active_job" }

        let(:payload) do
          {
            adapter: ActiveJob::QueueAdapters::InlineAdapter.new,
            job:     job,
            aborted: true
          }
        end

        it "logs message" do
          messages = semantic_logger_events do
            subscriber.enqueue_at(event)
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :info,
            name:             "Rails",
            message_includes: "Failed enqueuing ActiveJobTest::MyJob",
            payload_includes: {
              job_class:  "ActiveJobTest::MyJob",
              queue:      "my_jobs",
              event_name: "enqueue.active_job"
            }
          )
          assert_match(/Failed enqueuing .*, a before_enqueue callback halted the enqueuing execution/, messages[0].message)
          assert_includes messages[0].payload, :job_id
        end
      end

      describe "ActiveJob::Logging::LogSubscriber::EventFormatter" do
        let(:formatter) do
          RailsSemanticLogger::ActiveJob::LogSubscriber::EventFormatter.new(event: event, log_duration: true)
        end

        let(:event_name) { "perform.active_job" }

        describe "#payload" do
          specify do
            assert_equal(formatter.payload[:event_name], "perform.active_job")
            assert_equal(formatter.payload[:adapter], "Inline")
            assert_equal(formatter.payload[:queue], "my_jobs")
            assert_kind_of(String, formatter.payload[:job_id])
            assert_kind_of(Float, formatter.payload[:duration])
          end

          describe "Show arguments in log" do
            let(:job) do
              MyJob.new(TestModel.new, 1, "string", foo: "bar")
            end

            specify do
              assert_equal(formatter.payload[:job_class], "ActiveJobTest::MyJob")
              arguments = <<~ARGS.chomp
                [
                  "gid://dummy/ActiveJobTest::TestModel/15",
                  1,
                  "string",
                  {
                    "foo": "bar"
                  }
                ]
              ARGS
              assert_equal(formatter.payload[:arguments], arguments)
            end
          end

          describe "Hide arguments from log" do
            let(:job) do
              SensitiveJob.new(TestModel.new, 1, "string", foo: "bar")
            end

            specify do
              assert_equal(formatter.payload[:job_class], "ActiveJobTest::SensitiveJob")
              assert_equal(formatter.payload[:arguments], "")
            end
          end
        end

        describe "#job_info" do
          specify do
            assert_match(/^ActiveJobTest::MyJob \(Job ID: [a-z\-0-9]+\) to Inline\(my_jobs\)$/, formatter.job_info)
          end
        end

        describe "#queue_name" do
          specify do
            assert_equal(formatter.queue_name, "Inline(my_jobs)")
          end
        end
      end
    end
  end
end


================================================
FILE: test/active_record_test.rb
================================================
require_relative "test_helper"

class ActiveRecordTest < Minitest::Test
  describe "ActiveRecord" do
    # Rails 5 has an extra space
    let(:extra_space) { Rails::VERSION::MAJOR >= 6 ? "" : " " }

    describe "logs" do
      it "sql" do
        expected_sql = "SELECT #{extra_space}\"samples\".* FROM \"samples\" ORDER BY \"samples\".\"id\" ASC LIMIT ?"

        messages = semantic_logger_events do
          Sample.first
        end
        assert_equal 1, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:   expected_sql,
            binds: {limit: 1}
          }
        )
        assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
      end

      it "sql with query cache" do
        expected_sql = "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"

        messages = semantic_logger_events do
          Sample.cache { 2.times { Sample.where(name: "foo").first } }
        end
        assert_equal 2, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:   expected_sql,
            binds: {name: "foo", limit: 1}
          }
        )
        assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6

        assert_semantic_logger_event(
          messages[1],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:    expected_sql,
            binds:  {name: "foo", limit: 1},
            cached: true
          }
        )
        assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
      end

      it "single bind value" do
        expected_sql =
          if Rails.version.to_f >= 5.2
            "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
          else
            "SELECT  \"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
          end

        messages = semantic_logger_events do
          Sample.where(name: "Jack").first
        end
        assert_equal 1, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:   expected_sql,
            binds: {name: "Jack", limit: 1}
          }
        )
        assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
      end

      it "filtered bind value" do
        filter_params_setting true, %i[name] do
          expected_sql =
            if Rails.version.to_f >= 5.2
              "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
            else
              "SELECT  \"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
            end

          messages = semantic_logger_events do
            Sample.where(name: "Jack").first
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :debug,
            name:             "ActiveRecord",
            message:          "Sample Load",
            payload_includes: {
              sql:   expected_sql,
              binds: {name: "[FILTERED]", limit: 1}
            }
          )
          assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
        end
      end

      it "filtered bind value when filter_parameters set as regex" do
        filter_params_regex_setting true, %i[name] do
          expected_sql =
            if Rails.version.to_f >= 5.2
              "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
            else
              "SELECT  \"samples\".* FROM \"samples\" WHERE \"samples\".\"name\" = ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"
            end

          messages = semantic_logger_events do
            Sample.where(name: "Jack").first
          end
          assert_equal 1, messages.count, messages

          assert_semantic_logger_event(
            messages[0],
            level:            :debug,
            name:             "ActiveRecord",
            message:          "Sample Load",
            payload_includes: {
              sql:   expected_sql,
              binds: {name: "[FILTERED]", limit: 1}
            }
          )
          assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
        end
      end

      it "multiple bind values" do
        skip "Not applicable to older rails" if Rails.version.to_f <= 5.1

        expected_sql = "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"age\" BETWEEN ? AND ? ORDER BY \"samples\".\"id\" ASC LIMIT ?"

        messages = semantic_logger_events do
          Sample.where(age: 2..21).first
        end
        assert_equal 1, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:   expected_sql,
            binds: {age: [2, 21], limit: 1}
          }
        )
        assert_instance_of Integer, messages[0].payload[:allocations] if Rails.version.to_i >= 6
      end

      it "works with an IN clause" do
        skip "Not applicable to older rails" if Rails.version.to_f <= 5.1

        expected_sql = "SELECT #{extra_space}\"samples\".* FROM \"samples\" WHERE \"samples\".\"age\" IN (?, ?) ORDER BY \"samples\".\"id\" ASC LIMIT ?"

        messages = semantic_logger_events do
          Sample.where(age: [2, 3]).first
        end
        assert_equal 1, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:            :debug,
          name:             "ActiveRecord",
          message:          "Sample Load",
          payload_includes: {
            sql:   expected_sql,
            binds: {age: [2, 3], limit: 1}
          }
        )
      end
    end

    describe "async queries" do
      before do
        skip "Not applicable to older rails" if Rails.version.to_f < 7.1
        ActiveRecord::Base.asynchronous_queries_tracker.start_session
      end

      after do
        ActiveRecord::Base.asynchronous_queries_tracker.finalize_session
      end

      it "marks async queries with async: true" do
        expected_sql = 'SELECT COUNT(*) FROM "samples"'

        messages = semantic_logger_events do
          Sample.count
          Sample.async_count.value
        end
        assert_equal 2, messages.count, messages

        messages.each do |message|
          assert_semantic_logger_event(
            message,
            level:            :debug,
            name:             "ActiveRecord",
            message:          "Sample Count",
            payload_includes: {sql: expected_sql}
          )
        end

        # On Rails prior to 8.0.2, these assertions will mostly pass, but not always.
        # https://github.com/rails/rails/pull/54344
        skip "Older Rails has flakey async instrumentation" if Rails::VERSION::MAJOR < 8
        refute messages[0].payload.key?(:async)
        assert_equal true, messages[1].payload[:async]
      end
    end

    # we could feasibly pull this back to rails 7.1.  This update is related to rails 8.1
    # https://github.com/reidmorrison/rails_semantic_logger/pull/276#issuecomment-3533151110
    describe "runtime=" do
      it "allow reads and writes to the runtime" do
        unless RailsSemanticLogger::ActiveRecord::LogSubscriber.respond_to?(:runtime)
          skip "runtime support ended with Rails v7.1"
        end

        RailsSemanticLogger::ActiveRecord::LogSubscriber.runtime = 5.0

        assert_equal RailsSemanticLogger::ActiveRecord::LogSubscriber.runtime, 5.0
      end

      it "write to the runtime" do
        unless RailsSemanticLogger::ActiveRecord::LogSubscriber.respond_to?(:runtime)
          skip "runtime support ended with Rails v7.1"
        end

        initial_value = RailsSemanticLogger::ActiveRecord::LogSubscriber.runtime
        RailsSemanticLogger::ActiveRecord::LogSubscriber.runtime = initial_value + 5000.0
        assert_equal RailsSemanticLogger::ActiveRecord::LogSubscriber.runtime, initial_value + 5000.0
      end
    end
  end
end


================================================
FILE: test/controllers/articles_controller_test.rb
================================================
require_relative "../test_helper"

class ArticlesControllerTest < ActionDispatch::IntegrationTest
  describe ArticlesController do
    let(:params) { {article: {text: "Text1", title: "Title1"}} }

    describe "#new" do
      it "shows new article" do
        get article_url(:new)

        assert_response :success
      end
    end

    describe "#create" do
      it "has no errors" do
        post articles_url(params: params)

        assert_response :success
      end

      it "successfully logs message" do
        messages = semantic_logger_events do
          post articles_url(params: params)
        end
        assert_equal 5, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          message: "Started",
          name:    "Rack",
          level:   :debug,
          payload: {
            method: "POST",
            path:   "/articles?article%5Btext%5D=Text1&article%5Btitle%5D=Title1",
            ip:     "127.0.0.1"
          }
        )

        assert_semantic_logger_event(
          messages[1],
          message: "Processing #create",
          name:    "ArticlesController",
          level:   :debug
        )

        assert_semantic_logger_event(
          messages[2],
          message: "Rendering",
          name:    "ActionView",
          level:   :debug,
          payload: {
            template: "text template"
          }
        )

        assert_semantic_logger_event(
          messages[3],
          message: "Rendered",
          name:    "ActionView",
          level:   :debug
        )

        assert_semantic_logger_event(
          messages[4],
          message:          "Completed #create",
          name:             "ArticlesController",
          level:            :info,
          payload_includes: {
            controller:     "ArticlesController",
            action:         "create",
            params:         {
              "article" => {
                "text"  => "Text1",
                "title" => "Title1"
              }
            },
            format:         "HTML",
            method:         "POST",
            path:           "/articles",
            status:         200,
            status_message: "OK"
          }
        )
      end

      it "customize action message" do
        old_action_message_format = RailsSemanticLogger::ActionController::LogSubscriber.action_message_format
        RailsSemanticLogger::ActionController::LogSubscriber.action_message_format = -> (message, payload) do
          "#{message} #{payload[:controller]}##{payload[:action]}"
        end

        messages = semantic_logger_events do
          post articles_url(params: params)
        end
        assert_equal 5, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          message: "Started"
        )

        assert_semantic_logger_event(
          messages[1],
          message: "Processing ArticlesController#create"
        )

        assert_semantic_logger_event(
          messages[2],
          message: "Rendering"
        )

        assert_semantic_logger_event(
          messages[3],
          message: "Rendered"
        )

        assert_semantic_logger_event(
          messages[4],
          message: "Completed ArticlesController#create",
        )
      ensure
        RailsSemanticLogger::ActionController::LogSubscriber.action_message_format = old_action_message_format
      end
    end

    describe "#show" do
      it "raises and logs exception" do
        # we're testing ActionDispatch::DebugExceptions in fact
        messages = semantic_logger_events do
          old_show = Rails.application.env_config["action_dispatch.show_exceptions"]
          begin
            Rails.application.env_config["action_dispatch.show_exceptions"] = :all
            get article_url(:show)
          rescue ActiveRecord::RecordNotFound => e
            # expected
          ensure
            Rails.application.env_config["action_dispatch.show_exceptions"] = old_show
          end
        end
        assert_equal 4, messages.count, messages
        assert_kind_of ActiveRecord::RecordNotFound, messages[3].exception
      end

      it "raises and does not log exception when action_dispatch.log_rescued_responses is false" do
        skip "Not applicable to older rails" if Rails.version.to_f < 7.1
        # we're testing ActionDispatch::DebugExceptions here too
        messages = semantic_logger_events do
          old_show = Rails.application.env_config["action_dispatch.show_exceptions"]
          old_log_rescued_responses = Rails.application.env_config["action_dispatch.log_rescued_responses"]

          begin
            Rails.application.env_config["action_dispatch.show_exceptions"] = :all
            Rails.application.env_config["action_dispatch.log_rescued_responses"] = false
            get article_url(:show)
          rescue ActiveRecord::RecordNotFound => e
            # expected
          ensure
            Rails.application.env_config["action_dispatch.show_exceptions"] = old_show
            Rails.application.env_config["action_dispatch.log_rescued_responses"] = old_log_rescued_responses
          end
        end
        assert_equal 3, messages.count, messages
      end
    end
  end
end


================================================
FILE: test/controllers/dashboard_controller_test.rb
================================================
require_relative "../test_helper"

class DashboardControllerTest < ActionDispatch::IntegrationTest
  describe DashboardController do
    describe "#show" do
      it "has no errors" do
        get dashboard_url

        assert_response :success
      end

      it "logs message" do
        messages = semantic_logger_events do
          get dashboard_url
        end
        assert_equal 3, messages.count, messages

        assert_semantic_logger_event(
          messages[0],
          level:   :debug,
          name:    "Rack",
          message: "Started",
          payload: {
            method: "GET",
            path:   "/dashboard",
            ip:     "127.0.0.1"
          }
        )

        assert_semantic_logger_event(
          messages[1],
          level:   :debug,
          name:    "Rails",
          message: "Processing #show",
          payload: nil
        )

        assert_semantic_logger_event(
          messages[2],
          level:            :info,
          name:             "Rails",
          message:          "Completed #show",
          payload_includes: {
            controller:     "DashboardController",
            action:         "show",
            format:         "HTML",
            method:         "GET",
            path:           "/dashboard",
            status:         200,
            status_message: "OK"
          }
        )
      end

      it "does not break rails notifications" do
        PayloadCollector.wrap do
          get dashboard_url
        end

        payload = PayloadCollector.last
        assert_equal payload[:params], {"controller" => "dashboard", "action" => "show"}
      end
    end
  end
end


================================================
FILE: test/controllers/welcome_controller_test.rb
================================================
require_relative "../test_helper"

class WelcomeControllerTest < ActionDispatch::IntegrationTest
  describe WelcomeController do
    describe "#index" do
      it "succeeds" do
        get "/welcome/index"

        assert_response :success
      end
    end
  end
end


================================================
FILE: test/dummy/README.rdoc
================================================
== Welcome to Rails

Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the Model-View-Control pattern.

This pattern splits the view (also called the presentation) into "dumb"
templates that are primarily responsible for inserting pre-built data in between
HTML tags. The model contains the "smart" domain objects (such as Account,
Product, Person, Post) that holds all the business logic and knows how to
persist themselves to a database. The controller handles the incoming requests
(such as Save New Account, Update Product, Show Post) by manipulating the model
and directing data to the view.

In Rails, the model is handled by what's called an object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in
link:files/vendor/rails/activerecord/README.html.

The controller and view are handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.


== Getting Started

1. At the command prompt, create a new Rails application:
       <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)

2. Change directory to <tt>myapp</tt> and start the web server:
       <tt>cd myapp; rails server</tt> (run with --help for options)

3. Go to http://localhost:3000/ and you'll see:
       "Welcome aboard: You're riding Ruby on Rails!"

4. Follow the guidelines to start developing your application. You can find
the following resources handy:

* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
* Ruby on Rails Tutorial Book: http://www.railstutorial.org/


== Debugging Rails

Sometimes your application goes wrong. Fortunately there are a lot of tools that
will help you debug it and get it back on the rails.

First area to check is the application log files. Have "tail -f" commands
running on the server.log and development.log. Rails will automatically display
debugging and runtime information to these files. Debugging info will also be
shown in the browser on requests from 127.0.0.1.

You can also log your own messages directly into the log file from your code
using the Ruby logger class from inside your controllers. Example:

  class WeblogController < ActionController::Base
    def destroy
      @weblog = Weblog.find(params[:id])
      @weblog.destroy
      logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
    end
  end

The result will be a message in your log file along the lines of:

  Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!

More information on how to use the logger is at http://www.ruby-doc.org/core/

Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
several books available online as well:

* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)

These two books will bring you up to speed on the Ruby language and also on
programming in general.


== Debugger

Debugger support is available through the debugger command when you start your
Mongrel or WEBrick server with --debugger. This means that you can break out of
execution at any point in the code, investigate and change the model, and then,
resume execution! You need to install ruby-debug to run the server in debugging
mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:

  class WeblogController < ActionController::Base
    def index
      @posts = Post.all
      debugger
    end
  end

So the controller will accept the action, run the first line, then present you
with a IRB prompt in the server window. Here you can do things like:

  >> @posts.inspect
  => "[#<Post:0x14a6be8
          @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
       #<Post:0x14a6620
          @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
  >> @posts.first.title = "hello from a debugger"
  => "hello from a debugger"

...and even better, you can examine how your runtime objects actually work:

  >> f = @posts.first
  => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
  >> f.
  Display all 152 possibilities? (y or n)

Finally, when you're ready to resume execution, you can enter "cont".


== Console

The console is a Ruby shell, which allows you to interact with your
application's domain model. Here you'll have all parts of the application
configured, just like it is when the application is running. You can inspect
domain models, change values, and save to the database. Starting the script
without arguments will launch it in the development environment.

To start the console, run <tt>rails console</tt> from the application
directory.

Options:

* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
  made to the database.
* Passing an environment name as an argument will load the corresponding
  environment. Example: <tt>rails console production</tt>.

To reload your controllers and models after launching the console run
<tt>reload!</tt>

More information about irb can be found at:
link:http://www.rubycentral.org/pickaxe/irb.html


== dbconsole

You can go to the command line of your database directly through <tt>rails
dbconsole</tt>. You would be connected to the database with the credentials
defined in database.yml. Starting the script without arguments will connect you
to the development database. Passing an argument will connect you to a different
database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
PostgreSQL and SQLite 3.

== Description of Contents

The default directory structure of a generated Ruby on Rails application:

  |-- app
  |   |-- assets
  |       |-- images
  |       |-- javascripts
  |       `-- stylesheets
  |   |-- controllers
  |   |-- helpers
  |   |-- mailers
  |   |-- models
  |   `-- views
  |       `-- layouts
  |-- config
  |   |-- environments
  |   |-- initializers
  |   `-- locales
  |-- db
  |-- doc
  |-- lib
  |   `-- tasks
  |-- log
  |-- public
  |-- script
  |-- test
  |   |-- fixtures
  |   |-- functional
  |   |-- integration
  |   |-- performance
  |   `-- unit
  |-- tmp
  |   |-- cache
  |   |-- pids
  |   |-- sessions
  |   `-- sockets
  `-- vendor
      |-- assets
          `-- stylesheets
      `-- plugins

app
  Holds all the code that's specific to this particular application.

app/assets
  Contains subdirectories for images, stylesheets, and JavaScript files.

app/controllers
  Holds controllers that should be named like weblogs_controller.rb for
  automated URL mapping. All controllers should descend from
  ApplicationController which itself descends from ActionController::Base.

app/models
  Holds models that should be named like post.rb. Models descend from
  ActiveRecord::Base by default.

app/views
  Holds the template files for the view that should be named like
  weblogs/index.html.erb for the WeblogsController#index action. All views use
  eRuby syntax by default.

app/views/layouts
  Holds the template files for layouts to be used with views. This models the
  common header/footer method of wrapping views. In your views, define a layout
  using the <tt>layout :default</tt> and create a file named default.html.erb.
  Inside default.html.erb, call <% yield %> to render the view using this
  layout.

app/helpers
  Holds view helpers that should be named like weblogs_helper.rb. These are
  generated for you automatically when using generators for controllers.
  Helpers can be used to wrap functionality for your views into methods.

config
  Configuration files for the Rails environment, the routing map, the database,
  and other dependencies.

db
  Contains the database schema in schema.rb. db/migrate contains all the
  sequence of Migrations for your schema.

doc
  This directory is where your application documentation will be stored when
  generated using <tt>rake doc:app</tt>

lib
  Application specific libraries. Basically, any kind of custom code that
  doesn't belong under controllers, models, or helpers. This directory is in
  the load path.

public
  The directory available for the web server. Also contains the dispatchers and the
  default HTML files. This should be set as the DOCUMENT_ROOT of your web
  server.

script
  Helper scripts for automation and generation.

test
  Unit and functional tests along with fixtures. When using the rails generate
  command, template test files will be generated for you and placed in this
  directory.

vendor
  External libraries that the application depends on. Also includes the plugins
  subdirectory. If the app has frozen rails, those gems also go here, under
  vendor/rails/. This directory is in the load path.


================================================
FILE: test/dummy/Rakefile
================================================
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path("config/application", __dir__)

Dummy::Application.load_tasks


================================================
FILE: test/dummy/app/assets/javascripts/application.js
================================================
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//# require jquery
//# require jquery_ujs
//# require_tree .


================================================
FILE: test/dummy/app/assets/javascripts/articles.js
================================================
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.


================================================
FILE: test/dummy/app/assets/stylesheets/application.css
================================================
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the top of the
 * compiled file, but it's generally better to create a new file per style scope.
 *
 *= require_self
 *= require_tree .
*/


================================================
FILE: test/dummy/app/assets/stylesheets/articles.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: test/dummy/app/assets/stylesheets/welcome.css
================================================
/*
  Place all the styles related to the matching controller here.
  They will automatically be included in application.css.
*/


================================================
FILE: test/dummy/app/controllers/application_controller.rb
================================================
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end


================================================
FILE: test/dummy/app/controllers/application_metal_controller.rb
================================================
class ApplicationMetalController < ActionController::Metal
  MODULES = [
    ActionController::Instrumentation,
    AbstractController::Rendering,
    ActionController::Rendering,
    ActionController::Renderers::All
    # Helpers::Controller
  ].freeze

  MODULES.each do |mod|
    include mod
  end
end


================================================
FILE: test/dummy/app/controllers/articles_controller.rb
================================================
class ArticlesController < ApplicationController
  def new
  end

  def create
    render plain: params[:article].inspect
  end

  def show
    raise ActiveRecord::RecordNotFound
  end
end


================================================
FILE: test/dummy/app/controllers/dashboard_controller.rb
================================================
class DashboardController < ApplicationMetalController
  def show
  end
end


================================================
FILE: test/dummy/app/controllers/welcome_controller.rb
================================================
class WelcomeController < ApplicationController
  def index
  end
end


================================================
FILE: test/dummy/app/helpers/application_helper.rb
================================================
module ApplicationHelper
end


================================================
FILE: test/dummy/app/helpers/articles_helper.rb
================================================
module ArticlesHelper
end


================================================
FILE: test/dummy/app/helpers/welcome_helper.rb
================================================
module WelcomeHelper
end


================================================
FILE: test/dummy/app/jobs/bad_job.rb
================================================
class BadJob
  include Sidekiq::Worker

  sidekiq_options retry: false

  def perform
    raise ArgumentError, "This is a bad job"
  end
end


================================================
FILE: test/dummy/app/jobs/simple_job.rb
================================================
class SimpleJob
  include Sidekiq::Worker

  def perform
    "SimpleJob is working"
  end
end


================================================
FILE: test/dummy/app/mailers/.gitkeep
================================================


================================================
FILE: test/dummy/app/models/.gitkeep
================================================


================================================
FILE: test/dummy/app/models/sample.rb
================================================
class Sample < ActiveRecord::Base
end


================================================
FILE: test/dummy/app/views/articles/new.html.erb
================================================
<h1>New Article</h1>

<%= form_for :article, url: articles_path do |f| %>
    <p>
      <%= f.label :title %><br>
      <%= f.text_field :title %>
    </p>

    <p>
      <%= f.label :text %><br>
      <%= f.text_area :text %>
    </p>

    <p>
      <%= f.submit %>
    </p>
<% end %>


================================================
FILE: test/dummy/app/views/layouts/application.html.erb
================================================
<!DOCTYPE html>
<html>
<head>
  <title>Dummy</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>


================================================
FILE: test/dummy/app/views/welcome/index.html.erb
================================================
<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>


================================================
FILE: test/dummy/bin/bundle
================================================
#!/usr/bin/env ruby
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
load Gem.bin_path("bundler", "bundle")


================================================
FILE: test/dummy/bin/puma
================================================
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'puma' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("puma", "puma")


================================================
FILE: test/dummy/bin/rails
================================================
#!/usr/bin/env ruby
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"


================================================
FILE: test/dummy/bin/rake
================================================
#!/usr/bin/env ruby
require_relative "../config/boot"
require "rake"
Rake.application.run


================================================
FILE: test/dummy/bin/setup
================================================
#!/usr/bin/env ruby
require "pathname"

# path to your application root.
APP_ROOT = Pathname.new File.expand_path("..", __dir__)

Dir.chdir APP_ROOT do
  # This script is a starting point to setup your application.
  # Add necessary setup steps to this file:

  puts "== Installing dependencies =="
  system "gem install bundler --conservative"
  system "bundle check || bundle install"

  # puts "\n== Copying sample files =="
  # unless File.exist?("config/database.yml")
  #   system "cp config/database.yml.sample config/database.yml"
  # end

  puts "\n== Removing old logs and tempfiles =="
  system "rm -f log/*"
  system "rm -rf tmp/cache"

  puts "\n== Restarting application server =="
  system "touch tmp/restart.txt"
end


================================================
FILE: test/dummy/config/application.rb
================================================
require File.expand_path("boot", __dir__)

require "rails/all"

Bundler.require

module Dummy
  class Application < Rails::Application
    config.load_defaults "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}" if config.respond_to?(:load_defaults)

    # Configure sensitive parameters which will be filtered from the log file.
    config.filter_parameters += [:password]
    config.active_record.sqlite3.represent_boolean_as_integer = true if config.active_record.sqlite3
    config.active_record.async_query_executor = :global_thread_pool if (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) || Rails::VERSION::MAJOR > 7

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de

    # Do not swallow errors in after_commit/after_rollback callbacks.
    # config.active_record.raise_in_transactional_callbacks = true

    config.semantic_logger.default_level = :trace
    # Warning: Set to :error or higher in production to avoid performance issues.
    config.semantic_logger.backtrace_level = :trace

    # Test out Amazing Print
    config.rails_semantic_logger.ap_options = {multiline: false, ruby19_syntax: true}
  end
end


================================================
FILE: test/dummy/config/boot.rb
================================================
require "rubygems"
gemfile = File.expand_path("../../../Gemfile", __dir__)

if File.exist?(gemfile)
  ENV["BUNDLE_GEMFILE"] = gemfile
  require "bundler"
  Bundler.setup
end

$LOAD_PATH.unshift File.expand_path("../../../lib", __dir__)


================================================
FILE: test/dummy/config/database.yml
================================================
# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

production:
  adapter: sqlite3
  database: db/production.sqlite3
  pool: 5
  timeout: 5000


================================================
FILE: test/dummy/config/environment.rb
================================================
# Load the rails application
require File.expand_path("application", __dir__)

# Initialize the rails application
Dummy::Application.initialize!


================================================
FILE: test/dummy/config/environments/development.rb
================================================
Dummy::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes                     = false

  # Do not eager load code on boot.
  config.eager_load                        = false

  # Show full error reports and disable caching.
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation        = :log

  # Raise an error on page load if there are pending migrations.
  # config.active_record.migration_error = :page_load

  # Debug mode disables concatenation and preprocessing of assets.
  # This option may cause significant delays in view rendering with a large
  # number of complex assets.
  config.assets.debug                      = true

  # Asset digests allow you to set far-future HTTP expiration dates on all assets,
  # yet still be able to expire them through the digest params.
  config.assets.digest                     = true

  # Adds additional error checking when serving assets at runtime.
  # Checks for improperly declared sprockets dependencies.
  # Raises helpful error messages.
  config.assets.raise_runtime_errors       = true

  # Raises error for missing translations
  # config.action_view.raise_on_missing_translations = true

  config.rails_semantic_logger.quiet_assets         = true
  config.rails_semantic_logger.ap_options           = {multiline: true}
end


================================================
FILE: test/dummy/config/environments/production.rb
================================================
Dummy::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # Full error reports are disabled and caching is turned on
  config.consider_all_requests_local = false
  config.perform_caching             = true
  config.cache_classes               = true
  config.eager_load                  = true

  # Disable Rails's static asset server (Apache or nginx could already do this)
  config.serve_static_files          = true

  # SSL is handled by the load balancer
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = false

  # See everything in the log (default is :info)
  config.log_level                   = :info

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation can not be found)
  config.i18n.fallbacks              = true

  # Send deprecation notices to registered listeners
  config.active_support.deprecation  = :notify

  # Disable colorized logging
  # config.colorize_logging = false
end


================================================
FILE: test/dummy/config/environments/test.rb
================================================
Dummy::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # The test environment is used exclusively to run your application's
  # test suite. You never need to work with it otherwise. Remember that
  # your test database is "scratch space" for the test suite and is wiped
  # and recreated between test runs. Don't rely on the data there!
  config.cache_classes                              = true

  # Configure static asset server for tests with Cache-Control for performance
  # config.serve_static_assets = true

  # Log error messages when you accidentally call methods on nil
  config.whiny_nils                                 = true
  config.eager_load                                 = false

  # Show full error reports and disable caching
  config.consider_all_requests_local                = true
  config.action_controller.perform_caching          = false

  # Raise exceptions instead of rendering exception templates
  config.action_dispatch.show_exceptions = Rails::VERSION::MAJOR >= 7 ? :none : false

  # Disable request forgery protection in test environment
  config.action_controller.allow_forgery_protection = false

  # Print deprecation notices to the stderr
  config.active_support.deprecation                 = :stderr

  config.active_support.test_order                  = :random
end


================================================
FILE: test/dummy/config/initializers/backtrace_silencers.rb
================================================
# Be sure to restart your server when you modify this file.

# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }

# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!


================================================
FILE: test/dummy/config/initializers/inflections.rb
================================================
# Be sure to restart your server when you modify this file.

# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
#   inflect.plural /^(ox)$/i, '\1en'
#   inflect.singular /^(ox)en/i, '\1'
#   inflect.irregular 'person', 'people'
#   inflect.uncountable %w( fish sheep )
# end
#
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections do |inflect|
#   inflect.acronym 'RESTful'
# end


================================================
FILE: test/dummy/config/initializers/mime_types.rb
================================================
# Be sure to restart your server when you modify this file.

# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone


================================================
FILE: test/dummy/config/initializers/payload_collector.rb
================================================
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  PayloadCollector.append(event.payload)
end


================================================
FILE: test/dummy/config/initializers/secret_token.rb
================================================
# Be sure to restart your server when you modify this file.

# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
Dummy::Application.config.secret_token = "afd0f2e89c2a660f839bfb8e982358b6748c7fcd7c61c98b1edfc164539fae5beafece2906858801a4c7f5bbcd2f2e606db2a766630e1b0b1468f50ad6025630"


================================================
FILE: test/dummy/config/initializers/session_store.rb
================================================
# Be sure to restart your server when you modify this file.

Rails.application.config.session_store :cookie_store, key: "_dummy_session"


================================================
FILE: test/dummy/config/initializers/sidekiq.rb
================================================
# In tests we force Sidekiq into thinking it is running as a server,
# so it creates a stdout logger. Remove it here:
Rails.application.config.after_initialize do
  SemanticLogger.appenders.delete_if { |appender| appender.is_a?(SemanticLogger::Appender::IO) } if Rails.env.test?
end


================================================
FILE: test/dummy/config/initializers/wrap_parameters.rb
================================================
# Be sure to restart your server when you modify this file.

# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.

# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end

# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
#  self.include_root_in_json = true
# end


================================================
FILE: test/dummy/config/locales/en.yml
================================================
# Sample localization file for English. Add more files in this directory for other locales.
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.

en:
  hello: "Hello world"


================================================
FILE: test/dummy/config/routes.rb
================================================
Dummy::Application.routes.draw do
  get "welcome/index"

  resources :articles

  resource :dashboard, controller: :dashboard

  root "welcome#index"
end


================================================
FILE: test/dummy/config/secrets.yml
================================================
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: 72c4f52428cb36cd0afb2cf6e36a8a67fa39f8fd2396f533b85e42441feafdcdcac4f7629f3e1c5b846b1c452ad6e3ecfe368e913b71cd147d4536b35406b2fd

test:
  secret_key_base: 29dc974bc32244b62fd69259cd4f9ff7223a4cfe9fe40ee948dd1e64a99cd6bbef4a5d75f1b106ef50fa750613542e52e21d7fd67695356cd529264f614c1c3d

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>


================================================
FILE: test/dummy/config.ru
================================================
# This file is used by Rack-based servers to start the application.

require File.expand_path("config/environment", __dir__)
run Dummy::Application


================================================
FILE: test/dummy/db/migrate/20170525020551_create_samples.rb
================================================
class CreateSamples < ActiveRecord::Migration
  def change
    create_table :samples do |t|
      t.string :name
      t.integer :age
      t.date :joined

      t.timestamps null: false
    end
  end
end


================================================
FILE: test/dummy/db/schema.rb
================================================
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20_170_525_020_551) do
  create_table "samples", force: :cascade do |t|
    t.string   "name"
    t.integer  "age"
    t.date     "joined"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end


================================================
FILE: test/dummy/lib/assets/.gitkeep
================================================


================================================
FILE: test/dummy/log/.gitkeep
================================================


================================================
FILE: test/dummy/public/404.html
================================================
<!DOCTYPE html>
<html>
<head>
  <title>The page you were looking for doesn't exist (404)</title>
  <style type="text/css">
    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
    div.dialog {
      width: 25em;
      padding: 0 4em;
      margin: 4em auto 0 auto;
      border: 1px solid #ccc;
      border-right-color: #999;
      border-bottom-color: #999;
    }
    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  </style>
</head>

<body>
  <!-- This file lives in public/404.html -->
  <div class="dialog">
    <h1>The page you were looking for doesn't exist.</h1>
    <p>You may have mistyped the address or the page may have moved.</p>
  </div>
</body>
</html>


================================================
FILE: test/dummy/public/422.html
================================================
<!DOCTYPE html>
<html>
<head>
  <title>The change you wanted was rejected (422)</title>
  <style type="text/css">
    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
    div.dialog {
      width: 25em;
      padding: 0 4em;
      margin: 4em auto 0 auto;
      border: 1px solid #ccc;
      border-right-color: #999;
      border-bottom-color: #999;
    }
    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  </style>
</head>

<body>
  <!-- This file lives in public/422.html -->
  <div class="dialog">
    <h1>The change you wanted was rejected.</h1>
    <p>Maybe you tried to change something you didn't have access to.</p>
  </div>
</body>
</html>


================================================
FILE: test/dummy/public/500.html
================================================
<!DOCTYPE html>
<html>
<head>
  <title>We're sorry, but something went wrong (500)</title>
  <style type="text/css">
    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
    div.dialog {
      width: 25em;
      padding: 0 4em;
      margin: 4em auto 0 auto;
      border: 1px solid #ccc;
      border-right-color: #999;
      border-bottom-color: #999;
    }
    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  </style>
</head>

<body>
  <!-- This file lives in public/500.html -->
  <div class="dialog">
    <h1>We're sorry, but something went wrong.</h1>
  </div>
</body>
</html>


================================================
FILE: test/dummy/script/rails
================================================
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.

APP_PATH = File.expand_path("../config/application", __dir__)
require File.expand_path("../config/boot", __dir__)
require "rails/commands"


================================================
FILE: test/dummy/test/fixtures/samples.yml
================================================
# Read about fixtures at
# http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
  name: MyString
  age: 1
  joined: 2017-05-24

two:
  name: MyString
  age: 1
  joined: 2017-05-24


================================================
FILE: test/payload_collector.rb
================================================
class PayloadCollector
  class << self
    def wrap
      @store = true
      yield
    ensure
      @store = false
    end

    def append(payload)
      data.append(payload) if @store
    end

    def last
      data.last
    end

    def flush
      @data = []
    end

    private

    def data
      @data ||= []
    end
  end
end


================================================
FILE: test/rails_test.rb
================================================
require_relative "test_helper"

class RailsTest < Minitest::Test
  describe "Rails" do
    describe ".logger" do
      it "replaces the Rails logger" do
        assert_kind_of SemanticLogger::Logger, Rails.logger
      end

      it "uses the colorized formatter" do
        assert_kind_of SemanticLogger::Formatters::Color, SemanticLogger.appenders.first.formatter
      end

      it "is compatible with Rails logger" do
        assert_nil Rails.logger.formatter
        Rails.logger.formatter = "blah"
        assert_equal "blah", Rails.logger.formatter
      end
    end
  end
end


================================================
FILE: test/sidekiq_test.rb
================================================
require_relative "test_helper"

class SidekiqTest < Minitest::Test
  # Cannot use inline testing since it bypasses the Sidekiq logging calls.
  describe Sidekiq::Worker do
    let(:job) { SimpleJob }
    let(:args) { [] }

    describe "#logger" do
      it "has its own logger with the same name as the job" do
        assert_kind_of SemanticLogger::Logger, SimpleJob.logger
        assert_kind_of SemanticLogger::Logger, job.logger
        assert_equal job.logger.name, job.name
        refute_same Sidekiq.logger, job.logger
      end
    end

    describe "#perform" do
      let(:config) { Sidekiq.default_configuration }
      let(:msg) { Sidekiq.dump_json({"class" => job.to_s, "args" => args, "enqueued_at" => 1.minute.ago}) }
      let(:uow) { Sidekiq::BasicFetch::UnitOfWork.new("queue:default", msg) }
      if Sidekiq::VERSION.to_i == 6 && Sidekiq::VERSION.to_f < 6.5
        let(:processor) do
          mgr          = Minitest::Mock.new
          opts         = Sidekiq.options
          opts[:fetch] = Sidekiq::BasicFetch.new(opts)
          Sidekiq::Processor.new(mgr, opts)
        end
      elsif Sidekiq::VERSION.to_i == 6
        let(:processor) do
          config         = Sidekiq
          config[:fetch] = Sidekiq::BasicFetch.new(config)
          Sidekiq::Processor.new(config) { |*args| }
        end
      elsif Sidekiq::VERSION.to_i < 7
        let(:processor) do
          opts = Sidekiq.options
          mgr  = Minitest::Mock.new
          mgr.expect(:options, opts)
          mgr.expect(:options, opts)
          mgr.expect(:options, opts)
          Sidekiq::Processor.new(mgr)
        end
      else
        let(:processor) { Sidekiq::Processor.new(config.default_capsule) { |*args| } }
      end

      it "a simple job" do
        # SimpleJob.perform_async
        messages = semantic_logger_events do
          processor.send(:process, uow)
        end

        assert_equal 2, messages.count, -> { messages.collect(&:to_h).ai }

        assert_semantic_logger_event(
          messages[0],
          level:      :info,
          name:       "SimpleJob",
          message:    "Start #perform",
          metric:     "sidekiq.queue.latency",
          named_tags: {jid: nil, queue: "default"}
        )
        assert messages[0].metric_amount.is_a?(Float)

        assert_semantic_logger_event(
          messages[1],
          level:      :info,
          name:       "SimpleJob",
          message:    "Completed #perform",
          metric:     "sidekiq.job.perform",
          named_tags: {jid: nil, queue: "default"}
        )
        assert messages[1].duration.is_a?(Float)
      end

      describe "with Bad Job" do
        let(:job) { BadJob }

        it "a job that raises an exception" do
          # BadJob.perform_async
          messages = semantic_logger_events do
            assert_raises ArgumentError do
              processor.send(:process, uow)
            end
          end

          assert_equal 3, messages.count, -> { messages.collect(&:to_h).ai }

          assert_semantic_logger_event(
            messages[0],
            level:      :info,
            name:       "BadJob",
            message:    "Start #perform",
            metric:     "sidekiq.queue.latency",
            named_tags: {jid: nil, queue: "default"},
            exception:  :nil
          )
          assert messages[0].metric_amount.is_a?(Float)

          assert_semantic_logger_event(
            messages[1],
            level:      :error,
            name:       "BadJob",
            message:    "Completed #perform",
            metric:     "sidekiq.job.perform",
            named_tags: {jid: nil, queue: "default"},
            exception:  ArgumentError
          )
          assert messages[1].duration.is_a?(Float)

          assert_semantic_logger_event(
            messages[2],
            level:            :warn,
            name:             "BadJob",
            message:          "Job raised exception",
            payload_includes: {context: "Job raised exception"},
            exception:        :nil
          )
          assert_equal messages[2].payload[:job]["class"], "BadJob"
          assert_equal messages[2].payload[:job]["args"], []
        end
      end
    end
  end
end


================================================
FILE: test/test_helper.rb
================================================
ENV["RAILS_ENV"] ||= "test"
ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"] = "1"
# Load first so Sidekiq thinks it is running as a server instance
require "sidekiq/cli"
if defined?(Sidekiq::DEFAULT_ERROR_HANDLER)
  # Set by Sidekiq CLI at startup
  Sidekiq.options[:error_handlers] << Sidekiq::DEFAULT_ERROR_HANDLER
end
require_relative "dummy/config/environment"

require "rails/test_help"
require "minitest/autorun"
require "minitest/rails"
require "amazing_print"

require_relative "payload_collector"

# Include the complete backtrace?
Minitest.backtrace_filter = Minitest::BacktraceFilter.new if ENV["BACKTRACE"].present?
Rails.backtrace_cleaner.remove_silencers!

# Add Semantic Logger helpers for Minitest
Minitest::Test.include SemanticLogger::Test::Minitest

ActionMailer::Base.delivery_method = :test

def filter_params_setting(value, user_defined_params, &block)
  original_value = Rails.configuration.filter_parameters
  Rails.configuration.filter_parameters = user_defined_params
  block.call
ensure
  Rails.configuration.filter_parameters = original_value
end

def filter_params_regex_setting(value, user_defined_params, &block)
  original_value = Rails.configuration.filter_parameters

  Rails.configuration.filter_parameters += user_defined_params

  filter_params_regex = Rails.configuration.filter_parameters.map do |key|
    "(?i:#{key})"
  end.join("|")

  Rails.configuration.filter_parameters = [/(?-mix:#{filter_params_regex})/]

  block.call
ensure
  Rails.configuration.filter_parameters = original_value
end
Download .txt
gitextract_hgorv55i/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .rubocop.yml
├── Appraisals
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── TESTING.md
├── gemfiles/
│   ├── rails_6.1.gemfile
│   ├── rails_7.0.gemfile
│   ├── rails_7.0b.gemfile
│   ├── rails_7.1.1.gemfile
│   ├── rails_7.1.gemfile
│   ├── rails_7.1b.gemfile
│   ├── rails_7.2.gemfile
│   ├── rails_8.0.gemfile
│   └── rails_8.1.gemfile
├── lib/
│   ├── rails_semantic_logger/
│   │   ├── action_controller/
│   │   │   └── log_subscriber.rb
│   │   ├── action_mailer/
│   │   │   └── log_subscriber.rb
│   │   ├── action_view/
│   │   │   └── log_subscriber.rb
│   │   ├── active_job/
│   │   │   └── log_subscriber.rb
│   │   ├── active_record/
│   │   │   └── log_subscriber.rb
│   │   ├── delayed_job/
│   │   │   └── plugin.rb
│   │   ├── engine.rb
│   │   ├── extensions/
│   │   │   ├── action_cable/
│   │   │   │   └── tagged_logger_proxy.rb
│   │   │   ├── action_controller/
│   │   │   │   └── live.rb
│   │   │   ├── action_dispatch/
│   │   │   │   └── debug_exceptions.rb
│   │   │   ├── action_view/
│   │   │   │   └── streaming_template_renderer.rb
│   │   │   ├── active_job/
│   │   │   │   └── logging.rb
│   │   │   ├── active_model_serializers/
│   │   │   │   └── logging.rb
│   │   │   ├── active_support/
│   │   │   │   ├── log_subscriber.rb
│   │   │   │   ├── logger.rb
│   │   │   │   └── tagged_logging.rb
│   │   │   ├── mongoid/
│   │   │   │   └── config.rb
│   │   │   ├── rack/
│   │   │   │   └── server.rb
│   │   │   ├── rackup/
│   │   │   │   └── server.rb
│   │   │   ├── rails/
│   │   │   │   └── server.rb
│   │   │   └── sidekiq/
│   │   │       └── sidekiq.rb
│   │   ├── options.rb
│   │   ├── rack/
│   │   │   └── logger.rb
│   │   ├── sidekiq/
│   │   │   ├── defaults.rb
│   │   │   ├── job_logger.rb
│   │   │   └── loggable.rb
│   │   └── version.rb
│   └── rails_semantic_logger.rb
├── rails_semantic_logger.gemspec
└── test/
    ├── action_controller_test.rb
    ├── action_mailer_test.rb
    ├── active_job_test.rb
    ├── active_record_test.rb
    ├── controllers/
    │   ├── articles_controller_test.rb
    │   ├── dashboard_controller_test.rb
    │   └── welcome_controller_test.rb
    ├── dummy/
    │   ├── README.rdoc
    │   ├── Rakefile
    │   ├── app/
    │   │   ├── assets/
    │   │   │   ├── javascripts/
    │   │   │   │   ├── application.js
    │   │   │   │   └── articles.js
    │   │   │   └── stylesheets/
    │   │   │       ├── application.css
    │   │   │       ├── articles.css
    │   │   │       └── welcome.css
    │   │   ├── controllers/
    │   │   │   ├── application_controller.rb
    │   │   │   ├── application_metal_controller.rb
    │   │   │   ├── articles_controller.rb
    │   │   │   ├── dashboard_controller.rb
    │   │   │   └── welcome_controller.rb
    │   │   ├── helpers/
    │   │   │   ├── application_helper.rb
    │   │   │   ├── articles_helper.rb
    │   │   │   └── welcome_helper.rb
    │   │   ├── jobs/
    │   │   │   ├── bad_job.rb
    │   │   │   └── simple_job.rb
    │   │   ├── mailers/
    │   │   │   └── .gitkeep
    │   │   ├── models/
    │   │   │   ├── .gitkeep
    │   │   │   └── sample.rb
    │   │   └── views/
    │   │       ├── articles/
    │   │       │   └── new.html.erb
    │   │       ├── layouts/
    │   │       │   └── application.html.erb
    │   │       └── welcome/
    │   │           └── index.html.erb
    │   ├── bin/
    │   │   ├── bundle
    │   │   ├── puma
    │   │   ├── rails
    │   │   ├── rake
    │   │   └── setup
    │   ├── config/
    │   │   ├── application.rb
    │   │   ├── boot.rb
    │   │   ├── database.yml
    │   │   ├── environment.rb
    │   │   ├── environments/
    │   │   │   ├── development.rb
    │   │   │   ├── production.rb
    │   │   │   └── test.rb
    │   │   ├── initializers/
    │   │   │   ├── backtrace_silencers.rb
    │   │   │   ├── inflections.rb
    │   │   │   ├── mime_types.rb
    │   │   │   ├── payload_collector.rb
    │   │   │   ├── secret_token.rb
    │   │   │   ├── session_store.rb
    │   │   │   ├── sidekiq.rb
    │   │   │   └── wrap_parameters.rb
    │   │   ├── locales/
    │   │   │   └── en.yml
    │   │   ├── routes.rb
    │   │   └── secrets.yml
    │   ├── config.ru
    │   ├── db/
    │   │   ├── migrate/
    │   │   │   └── 20170525020551_create_samples.rb
    │   │   └── schema.rb
    │   ├── lib/
    │   │   └── assets/
    │   │       └── .gitkeep
    │   ├── log/
    │   │   └── .gitkeep
    │   ├── public/
    │   │   ├── 404.html
    │   │   ├── 422.html
    │   │   └── 500.html
    │   ├── script/
    │   │   └── rails
    │   └── test/
    │       └── fixtures/
    │           └── samples.yml
    ├── payload_collector.rb
    ├── rails_test.rb
    ├── sidekiq_test.rb
    └── test_helper.rb
Download .txt
SYMBOL INDEX (248 symbols across 52 files)

FILE: lib/rails_semantic_logger.rb
  type RailsSemanticLogger (line 5) | module RailsSemanticLogger
    type ActionController (line 6) | module ActionController
    type ActionMailer (line 10) | module ActionMailer
    type ActionView (line 14) | module ActionView
    type ActiveJob (line 18) | module ActiveJob
    type ActiveRecord (line 22) | module ActiveRecord
    type Rack (line 26) | module Rack
    type DelayedJob (line 30) | module DelayedJob
    type Sidekiq (line 34) | module Sidekiq
    function swap_subscriber (line 43) | def self.swap_subscriber(old_class, new_class, notifier)
    function unattach (line 50) | def self.unattach(subscriber)
    function subscriber_patterns (line 62) | def self.subscriber_patterns(subscriber)
    function listeners_for (line 70) | def self.listeners_for(notifier, pattern)

FILE: lib/rails_semantic_logger/action_controller/log_subscriber.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type ActionController (line 2) | module ActionController
      class LogSubscriber (line 3) | class LogSubscriber < ActiveSupport::LogSubscriber
        method start_processing (line 11) | def start_processing(event)
        method process_action (line 15) | def process_action(event)
        method halted_callback (line 73) | def halted_callback(event)
        method send_file (line 77) | def send_file(event)
        method redirect_to (line 81) | def redirect_to(event)
        method send_data (line 85) | def send_data(event)
        method unpermitted_parameters (line 91) | def unpermitted_parameters(event)
        method controller_logger (line 116) | def controller_logger(event)
        method extract_path (line 125) | def extract_path(path)
        method action_message (line 130) | def action_message(message, payload)

FILE: lib/rails_semantic_logger/action_mailer/log_subscriber.rb
  type RailsSemanticLogger (line 4) | module RailsSemanticLogger
    type ActionMailer (line 5) | module ActionMailer
      class LogSubscriber (line 6) | class LogSubscriber < ::ActiveSupport::LogSubscriber
        method deliver (line 7) | def deliver(event)
        method process (line 33) | def process(event)
        class EventFormatter (line 44) | class EventFormatter
          method initialize (line 45) | def initialize(event:, log_duration: false)
          method mailer (line 50) | def mailer
          method payload (line 54) | def payload
          method date (line 72) | def date
          method mailer (line 84) | def mailer
          method action (line 88) | def action
          method formatted_args (line 92) | def formatted_args
          method format (line 100) | def format(arg)
          method log_duration? (line 117) | def log_duration?
        method log_with_formatter (line 122) | def log_with_formatter(level: :info, **kw_args)
        method logger (line 128) | def logger

FILE: lib/rails_semantic_logger/action_view/log_subscriber.rb
  type RailsSemanticLogger (line 3) | module RailsSemanticLogger
    type ActionView (line 4) | module ActionView
      class LogSubscriber (line 6) | class LogSubscriber < ActiveSupport::LogSubscriber
        method initialize (line 14) | def initialize
        method render_template (line 19) | def render_template(event)
        method render_partial (line 36) | def render_partial(event)
        method render_collection (line 54) | def render_collection(event)
        method start (line 74) | def start(name, id, payload)
        class Start (line 87) | class Start
          method start (line 88) | def start(name, _id, payload)
          method finish (line 98) | def finish(name, id, payload)
          method from_rails_root (line 103) | def from_rails_root(string)
          method rails_root (line 109) | def rails_root
          method logger (line 113) | def logger
        method attach_to (line 118) | def self.attach_to(*)
        method should_log? (line 137) | def should_log?
        method from_rails_root (line 141) | def from_rails_root(string)
        method rails_root (line 147) | def rails_root
        method logger (line 151) | def logger

FILE: lib/rails_semantic_logger/active_job/log_subscriber.rb
  type RailsSemanticLogger (line 3) | module RailsSemanticLogger
    type ActiveJob (line 4) | module ActiveJob
      class LogSubscriber (line 5) | class LogSubscriber < ::ActiveSupport::LogSubscriber
        method enqueue (line 6) | def enqueue(event)
        method enqueue_at (line 27) | def enqueue_at(event)
        method perform_start (line 48) | def perform_start(event)
        method perform (line 54) | def perform(event)
        class EventFormatter (line 72) | class EventFormatter
          method initialize (line 73) | def initialize(event:, log_duration: false)
          method job_info (line 78) | def job_info
          method payload (line 82) | def payload
          method queue_name (line 95) | def queue_name
          method scheduled_at (line 99) | def scheduled_at
          method job (line 107) | def job
          method adapter_name (line 111) | def adapter_name
          method formatted_args (line 115) | def formatted_args
          method format (line 123) | def format(arg)
          method log_duration? (line 142) | def log_duration?
        method log_with_formatter (line 147) | def log_with_formatter(level: :info, **kw_args)
        method logger (line 153) | def logger

FILE: lib/rails_semantic_logger/active_record/log_subscriber.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type ActiveRecord (line 2) | module ActiveRecord
      class LogSubscriber (line 3) | class LogSubscriber < ActiveSupport::LogSubscriber
        method runtime= (line 12) | def self.runtime=(value)
        method runtime (line 16) | def self.runtime
        method reset_runtime (line 20) | def self.reset_runtime
        method sql (line 27) | def sql(event)
        method add_bind_value (line 60) | def add_bind_value(binds, key, value)
        method rails_filter_params_include? (line 72) | def rails_filter_params_include?(key)
        method logger (line 80) | def logger
        method bind_values_v3 (line 88) | def bind_values_v3(payload)
        method bind_values_v4 (line 100) | def bind_values_v4(payload)
        method bind_values_v5_0_0 (line 109) | def bind_values_v5_0_0(payload)
        method bind_values_v5_0_3 (line 118) | def bind_values_v5_0_3(payload)
        method bind_values_v5_1_5 (line 128) | def bind_values_v5_1_5(payload)
        method bind_values_v6_1 (line 138) | def bind_values_v6_1(payload)
        method render_bind_v4_2 (line 148) | def render_bind_v4_2(column, value)
        method render_bind_v5_0_0 (line 162) | def render_bind_v5_0_0(attribute)
        method render_bind_v5_0_3 (line 177) | def render_bind_v5_0_3(attr, value)
        method render_bind_v6_1 (line 187) | def render_bind_v6_1(attr, value)
        method type_casted_binds_v5_0_3 (line 200) | def type_casted_binds_v5_0_3(binds, casted_binds)
        method type_casted_binds_v5_1_5 (line 204) | def type_casted_binds_v5_1_5(casted_binds)

FILE: lib/rails_semantic_logger/delayed_job/plugin.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type DelayedJob (line 2) | module DelayedJob
      class Plugin (line 3) | class Plugin < Delayed::Plugin

FILE: lib/rails_semantic_logger/engine.rb
  type RailsSemanticLogger (line 4) | module RailsSemanticLogger
    class Engine (line 5) | class Engine < ::Rails::Engine

FILE: lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb
  type ActionCable (line 3) | module ActionCable
    type Connection (line 4) | module Connection
      class TaggedLoggerProxy (line 5) | class TaggedLoggerProxy
        method tag (line 6) | def tag(logger, &block)

FILE: lib/rails_semantic_logger/extensions/action_controller/live.rb
  type ActionController (line 4) | module ActionController
    type Live (line 5) | module Live
      function log_error (line 7) | def log_error(exception)

FILE: lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb
  type ActionDispatch (line 4) | module ActionDispatch
    class DebugExceptions (line 5) | class DebugExceptions
      method log_error (line 10) | def log_error(request, wrapper)
      method log_error (line 19) | def log_error(_request, wrapper)

FILE: lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb
  type ActionView (line 4) | module ActionView
    class StreamingTemplateRenderer (line 5) | class StreamingTemplateRenderer
      class Body (line 6) | class Body
        method log_error (line 10) | def log_error(exception)

FILE: lib/rails_semantic_logger/extensions/active_job/logging.rb
  type ActiveJob (line 4) | module ActiveJob
    type Logging (line 5) | module Logging
      function tag_logger (line 11) | def tag_logger(*tags, &block)

FILE: lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb
  type ActiveModelSerializers (line 4) | module ActiveModelSerializers
    type Logging (line 5) | module Logging
      function tag_logger (line 10) | def tag_logger(*tags, &block)
    class SerializableResource (line 15) | class SerializableResource

FILE: lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb
  type ActiveSupport (line 4) | module ActiveSupport
    class LogSubscriber (line 5) | class LogSubscriber
      method silenced? (line 7) | def silenced?(event)

FILE: lib/rails_semantic_logger/extensions/active_support/logger.rb
  type ActiveSupport (line 3) | module ActiveSupport
    class Logger (line 5) | class Logger
      method broadcast (line 12) | def broadcast(_logger)
      method logger_outputs_to? (line 19) | def self.logger_outputs_to?(*_args)
      method new (line 23) | def self.new(*_args, **_kwargs)

FILE: lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
  type ActiveSupport (line 1) | module ActiveSupport
    type TaggedLogging (line 2) | module TaggedLogging
      function new (line 4) | def self.new(logger)

FILE: lib/rails_semantic_logger/extensions/mongoid/config.rb
  type Mongoid (line 3) | module Mongoid
    type Config (line 4) | module Config
      function set_log_levels (line 8) | def set_log_levels

FILE: lib/rails_semantic_logger/extensions/rack/server.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type Rack (line 2) | module Rack
      type Server (line 3) | module Server
        function daemonize_app (line 4) | def daemonize_app

FILE: lib/rails_semantic_logger/extensions/rackup/server.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type Rackup (line 2) | module Rackup
      type Server (line 3) | module Server
        function daemonize_app (line 4) | def daemonize_app

FILE: lib/rails_semantic_logger/extensions/rails/server.rb
  type Rails (line 4) | module Rails
    class Server (line 5) | class Server
      method log_to_stdout (line 9) | def log_to_stdout

FILE: lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb
  type Sidekiq (line 10) | module Sidekiq
    type Logging (line 14) | module Logging
      function with_context (line 15) | def self.with_context(msg, &block)
      function job_hash_context (line 19) | def self.job_hash_context(job_hash)
    class Processor (line 31) | class Processor
      method log_context (line 32) | def log_context(job_hash)
    type Middleware (line 41) | module Middleware
      type Server (line 42) | module Server
        class Logging (line 43) | class Logging
          method call (line 45) | def call(worker, item, queue)
          method perform_messages_enabled? (line 66) | def perform_messages_enabled?
          method job_latency_ms (line 70) | def job_latency_ms(job)

FILE: lib/rails_semantic_logger/options.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    class Options (line 115) | class Options
      method initialize (line 121) | def initialize

FILE: lib/rails_semantic_logger/rack/logger.rb
  type RailsSemanticLogger (line 7) | module RailsSemanticLogger
    type Rack (line 8) | module Rack
      class Logger (line 9) | class Logger < ActiveSupport::LogSubscriber
        method initialize (line 15) | def initialize(app, taggers = nil)
        method call (line 20) | def call(env)
        method call_app (line 37) | def call_app(request, env)
        method started_request_message (line 61) | def started_request_message(request)
        method compute_tags (line 72) | def compute_tags(request)
        method compute_named_tags (line 86) | def compute_named_tags(request)
        method logger (line 103) | def logger

FILE: lib/rails_semantic_logger/sidekiq/defaults.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type Sidekiq (line 2) | module Sidekiq
      type Defaults (line 3) | module Defaults
        function delete_default_error_handler (line 29) | def self.delete_default_error_handler(error_handlers)

FILE: lib/rails_semantic_logger/sidekiq/job_logger.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type Sidekiq (line 2) | module Sidekiq
      class JobLogger (line 3) | class JobLogger
        method perform_messages (line 7) | def perform_messages
        method initialize (line 13) | def initialize(*_args)
        method call (line 16) | def call(item, queue, &block)
        method prepare (line 45) | def prepare(job_hash, &block)
        method perform_messages_enabled? (line 58) | def perform_messages_enabled?
        method job_hash_context (line 62) | def job_hash_context(job_hash)
        method job_latency_ms (line 70) | def job_latency_ms(job)

FILE: lib/rails_semantic_logger/sidekiq/loggable.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger
    type Sidekiq (line 2) | module Sidekiq
      type Loggable (line 3) | module Loggable
        function included (line 4) | def included(base)

FILE: lib/rails_semantic_logger/version.rb
  type RailsSemanticLogger (line 1) | module RailsSemanticLogger

FILE: test/action_controller_test.rb
  class ActionControllerTest (line 3) | class ActionControllerTest < Minitest::Test

FILE: test/action_mailer_test.rb
  class ActionMailerTest (line 3) | class ActionMailerTest < Minitest::Test
    class MyMailer (line 4) | class MyMailer < ActionMailer::Base
      method some_email (line 5) | def some_email(opts)

FILE: test/active_job_test.rb
  class ActiveJobTest (line 3) | class ActiveJobTest < Minitest::Test
    class MyJob (line 5) | class MyJob < ActiveJob::Base
      method perform (line 8) | def perform(record)
    class SensitiveJob (line 13) | class SensitiveJob < ActiveJob::Base
      method log_arguments? (line 19) | def self.log_arguments?
      method perform (line 24) | def perform(record)
    class TestModel (line 29) | class TestModel
      method id (line 32) | def id

FILE: test/active_record_test.rb
  class ActiveRecordTest (line 3) | class ActiveRecordTest < Minitest::Test

FILE: test/controllers/articles_controller_test.rb
  class ArticlesControllerTest (line 3) | class ArticlesControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/dashboard_controller_test.rb
  class DashboardControllerTest (line 3) | class DashboardControllerTest < ActionDispatch::IntegrationTest

FILE: test/controllers/welcome_controller_test.rb
  class WelcomeControllerTest (line 3) | class WelcomeControllerTest < ActionDispatch::IntegrationTest

FILE: test/dummy/app/controllers/application_controller.rb
  class ApplicationController (line 1) | class ApplicationController < ActionController::Base

FILE: test/dummy/app/controllers/application_metal_controller.rb
  class ApplicationMetalController (line 1) | class ApplicationMetalController < ActionController::Metal

FILE: test/dummy/app/controllers/articles_controller.rb
  class ArticlesController (line 1) | class ArticlesController < ApplicationController
    method new (line 2) | def new
    method create (line 5) | def create
    method show (line 9) | def show

FILE: test/dummy/app/controllers/dashboard_controller.rb
  class DashboardController (line 1) | class DashboardController < ApplicationMetalController
    method show (line 2) | def show

FILE: test/dummy/app/controllers/welcome_controller.rb
  class WelcomeController (line 1) | class WelcomeController < ApplicationController
    method index (line 2) | def index

FILE: test/dummy/app/helpers/application_helper.rb
  type ApplicationHelper (line 1) | module ApplicationHelper

FILE: test/dummy/app/helpers/articles_helper.rb
  type ArticlesHelper (line 1) | module ArticlesHelper

FILE: test/dummy/app/helpers/welcome_helper.rb
  type WelcomeHelper (line 1) | module WelcomeHelper

FILE: test/dummy/app/jobs/bad_job.rb
  class BadJob (line 1) | class BadJob
    method perform (line 6) | def perform

FILE: test/dummy/app/jobs/simple_job.rb
  class SimpleJob (line 1) | class SimpleJob
    method perform (line 4) | def perform

FILE: test/dummy/app/models/sample.rb
  class Sample (line 1) | class Sample < ActiveRecord::Base

FILE: test/dummy/config/application.rb
  type Dummy (line 7) | module Dummy
    class Application (line 8) | class Application < Rails::Application

FILE: test/dummy/db/migrate/20170525020551_create_samples.rb
  class CreateSamples (line 1) | class CreateSamples < ActiveRecord::Migration
    method change (line 2) | def change

FILE: test/payload_collector.rb
  class PayloadCollector (line 1) | class PayloadCollector
    method wrap (line 3) | def wrap
    method append (line 10) | def append(payload)
    method last (line 14) | def last
    method flush (line 18) | def flush
    method data (line 24) | def data

FILE: test/rails_test.rb
  class RailsTest (line 3) | class RailsTest < Minitest::Test

FILE: test/sidekiq_test.rb
  class SidekiqTest (line 3) | class SidekiqTest < Minitest::Test

FILE: test/test_helper.rb
  function filter_params_setting (line 27) | def filter_params_setting(value, user_defined_params, &block)
  function filter_params_regex_setting (line 35) | def filter_params_regex_setting(value, user_defined_params, &block)
Condensed preview — 117 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (172K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 68,
    "preview": "# These are supported funding model platforms\n\ngithub: reidmorrison\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1248,
    "preview": "### Environment\n\nProvide at least:\n* Ruby Version.\n* Rails Version.\n* Semantic Logger Version.\n* Rails Semantic Logger V"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 173,
    "preview": "### Issue # (if available)\n\n\n### Description of changes\n\n\nBy submitting this pull request, I confirm that my contributio"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1211,
    "preview": "name: build\n\non:\n  - push\n  - pull_request\n\njobs:\n  test:\n    name: \"Test: Rails ${{ matrix.rails }} on Ruby ${{ matrix."
  },
  {
    "path": ".gitignore",
    "chars": 230,
    "preview": ".bundle/\n*.log\npkg/\ntest/dummy/tmp/\ntest/dummy/db/test.sqlite3-*\ntest/dummy/.sass-cache\n*.gem\n/.idea\ntags\n*.DS_Store\nGem"
  },
  {
    "path": ".rubocop.yml",
    "chars": 2206,
    "preview": "AllCops:\n  Exclude:\n    - \".git/**/*\"\n    - \"docs/**/*\"\n    - \"gemfiles/*\"\n  NewCops: enable\n  TargetRubyVersion: 2.5\n\n#"
  },
  {
    "path": "Appraisals",
    "chars": 899,
    "preview": "appraise \"rails_6.1\" do\n  gem \"rails\", \"~> 6.1.0\"\n  gem \"sidekiq\", \"~> 5.2\"\n  gem \"sqlite3\", \"~> 1.4\"\nend\n\nappraise \"rai"
  },
  {
    "path": "Gemfile",
    "chars": 271,
    "preview": "source \"https://rubygems.org\"\n\ngemspec\n\ngem \"appraisal\"\ngem \"puma\"\n\ngem \"active_model_serializers\"\ngem \"amazing_print\"\ng"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11361,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 7309,
    "preview": "# Rails Semantic Logger\n[![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/ge"
  },
  {
    "path": "Rakefile",
    "chars": 848,
    "preview": "# Setup bundler to avoid having to run bundle exec all the time.\nrequire \"rubygems\"\nrequire \"bundler/setup\"\n\nrequire \"ra"
  },
  {
    "path": "TESTING.md",
    "chars": 565,
    "preview": "## Installation\n\nInstall all needed gems to run the tests:\n\n    appraisal install\n\nThe gems are installed into the globa"
  },
  {
    "path": "gemfiles/rails_6.1.gemfile",
    "chars": 328,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.0.gemfile",
    "chars": 330,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.0b.gemfile",
    "chars": 328,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.1.1.gemfile",
    "chars": 327,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.1.gemfile",
    "chars": 330,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.1b.gemfile",
    "chars": 330,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_7.2.gemfile",
    "chars": 320,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_8.0.gemfile",
    "chars": 320,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "gemfiles/rails_8.1.gemfile",
    "chars": 320,
    "preview": "# This file was generated by Appraisal\n\nsource \"https://rubygems.org\"\n\ngem \"appraisal\"\ngem \"puma\"\ngem \"active_model_seri"
  },
  {
    "path": "lib/rails_semantic_logger/action_controller/log_subscriber.rb",
    "chars": 5235,
    "preview": "module RailsSemanticLogger\n  module ActionController\n    class LogSubscriber < ActiveSupport::LogSubscriber\n      INTERN"
  },
  {
    "path": "lib/rails_semantic_logger/action_mailer/log_subscriber.rb",
    "chars": 3819,
    "preview": "require \"active_support/log_subscriber\"\nrequire \"action_mailer\"\n\nmodule RailsSemanticLogger\n  module ActionMailer\n    cl"
  },
  {
    "path": "lib/rails_semantic_logger/action_view/log_subscriber.rb",
    "chars": 4795,
    "preview": "require \"active_support/log_subscriber\"\n\nmodule RailsSemanticLogger\n  module ActionView\n    # Output Semantic logs from "
  },
  {
    "path": "lib/rails_semantic_logger/active_job/log_subscriber.rb",
    "chars": 4499,
    "preview": "require \"active_job\"\n\nmodule RailsSemanticLogger\n  module ActiveJob\n    class LogSubscriber < ::ActiveSupport::LogSubscr"
  },
  {
    "path": "lib/rails_semantic_logger/active_record/log_subscriber.rb",
    "chars": 7294,
    "preview": "module RailsSemanticLogger\n  module ActiveRecord\n    class LogSubscriber < ActiveSupport::LogSubscriber\n      IGNORE_PAY"
  },
  {
    "path": "lib/rails_semantic_logger/delayed_job/plugin.rb",
    "chars": 232,
    "preview": "module RailsSemanticLogger\n  module DelayedJob\n    class Plugin < Delayed::Plugin\n      callbacks do |lifecycle|\n       "
  },
  {
    "path": "lib/rails_semantic_logger/engine.rb",
    "chars": 12601,
    "preview": "require \"rails\"\nrequire \"rails_semantic_logger/options\"\n\nmodule RailsSemanticLogger\n  class Engine < ::Rails::Engine\n   "
  },
  {
    "path": "lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb",
    "chars": 267,
    "preview": "require \"action_cable/connection/tagged_logger_proxy\"\n\nmodule ActionCable\n  module Connection\n    class TaggedLoggerProx"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/action_controller/live.rb",
    "chars": 225,
    "preview": "# Log actual exceptions, not a string representation\nrequire \"action_controller\"\n\nmodule ActionController\n  module Live\n"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb",
    "chars": 912,
    "preview": "# Log actual exceptions, not a string representation\nrequire \"action_dispatch\"\n\nmodule ActionDispatch\n  class DebugExcep"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb",
    "chars": 333,
    "preview": "# Log actual exceptions, not a string representation\nrequire \"action_view/renderer/streaming_template_renderer\"\n\nmodule "
  },
  {
    "path": "lib/rails_semantic_logger/extensions/active_job/logging.rb",
    "chars": 330,
    "preview": "# Patch ActiveJob logger\nrequire \"active_job/logging\"\n\nmodule ActiveJob\n  module Logging\n    include SemanticLogger::Log"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb",
    "chars": 340,
    "preview": "# Patch ActiveModelSerializers logger\nrequire \"active_model_serializers/logging\"\n\nmodule ActiveModelSerializers\n  module"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb",
    "chars": 414,
    "preview": "if ActiveSupport::VERSION::STRING == \"7.1.1\"\n  require \"active_support/log_subscriber\"\n\n  module ActiveSupport\n    class"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/active_support/logger.rb",
    "chars": 611,
    "preview": "require \"active_support/logger\"\n\nmodule ActiveSupport\n  # More hacks to try and stop Rails from being it's own worst ene"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb",
    "chars": 150,
    "preview": "module ActiveSupport\n  module TaggedLogging\n    # Semantic Logger already does tagged logging\n    def self.new(logger)\n "
  },
  {
    "path": "lib/rails_semantic_logger/extensions/mongoid/config.rb",
    "chars": 138,
    "preview": "require \"mongoid/config\"\n\nmodule Mongoid\n  module Config\n    private\n\n    # Remove log overrides\n    def set_log_levels\n"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/rack/server.rb",
    "chars": 212,
    "preview": "module RailsSemanticLogger\n  module Rack\n    module Server\n      def daemonize_app\n        super\n        SemanticLogger."
  },
  {
    "path": "lib/rails_semantic_logger/extensions/rackup/server.rb",
    "chars": 218,
    "preview": "module RailsSemanticLogger\n  module Rackup\n    module Server\n      def daemonize_app\n        super\n        SemanticLogge"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/rails/server.rb",
    "chars": 413,
    "preview": "# Patch the Rails::Server log_to_stdout so that it logs via SemanticLogger\nrequire \"rails\"\n\nmodule Rails\n  class Server\n"
  },
  {
    "path": "lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb",
    "chars": 2547,
    "preview": "# Sidekiq patches\nif Sidekiq::VERSION.to_i == 4\n  require \"sidekiq/logging\"\n  require \"sidekiq/middleware/server/logging"
  },
  {
    "path": "lib/rails_semantic_logger/options.rb",
    "chars": 5403,
    "preview": "module RailsSemanticLogger\n  # Options for controlling Rails Semantic Logger behavior\n  #\n  # * Convert Action Controlle"
  },
  {
    "path": "lib/rails_semantic_logger/rack/logger.rb",
    "chars": 3065,
    "preview": "require \"active_support/core_ext/time/conversions\"\nrequire \"active_support/core_ext/object/blank\"\nrequire \"active_suppor"
  },
  {
    "path": "lib/rails_semantic_logger/sidekiq/defaults.rb",
    "chars": 1832,
    "preview": "module RailsSemanticLogger\n  module Sidekiq\n    module Defaults\n      # Prevent exception logging during standard error "
  },
  {
    "path": "lib/rails_semantic_logger/sidekiq/job_logger.rb",
    "chars": 2187,
    "preview": "module RailsSemanticLogger\n  module Sidekiq\n    class JobLogger\n      class << self\n        attr_writer :perform_message"
  },
  {
    "path": "lib/rails_semantic_logger/sidekiq/loggable.rb",
    "chars": 178,
    "preview": "module RailsSemanticLogger\n  module Sidekiq\n    module Loggable\n      def included(base)\n        super\n        base.incl"
  },
  {
    "path": "lib/rails_semantic_logger/version.rb",
    "chars": 59,
    "preview": "module RailsSemanticLogger\n  VERSION = \"4.20.0\".freeze\nend\n"
  },
  {
    "path": "lib/rails_semantic_logger.rb",
    "chars": 2892,
    "preview": "require \"semantic_logger\"\nrequire \"rails_semantic_logger/extensions/rails/server\" if defined?(Rails::Server)\nrequire \"ra"
  },
  {
    "path": "rails_semantic_logger.gemspec",
    "chars": 1178,
    "preview": "$LOAD_PATH.push File.expand_path(\"lib\", __dir__)\n\n# Maintain your gem's version:\nrequire \"rails_semantic_logger/version\""
  },
  {
    "path": "test/action_controller_test.rb",
    "chars": 785,
    "preview": "require_relative \"test_helper\"\n\nclass ActionControllerTest < Minitest::Test\n  describe \"RailsSemanticLogger::ActionContr"
  },
  {
    "path": "test/action_mailer_test.rb",
    "chars": 3471,
    "preview": "require_relative \"test_helper\"\n\nclass ActionMailerTest < Minitest::Test\n  class MyMailer < ActionMailer::Base\n    def so"
  },
  {
    "path": "test/active_job_test.rb",
    "chars": 9623,
    "preview": "require_relative \"test_helper\"\n\nclass ActiveJobTest < Minitest::Test\n  if defined?(ActiveJob)\n    class MyJob < ActiveJo"
  },
  {
    "path": "test/active_record_test.rb",
    "chars": 9127,
    "preview": "require_relative \"test_helper\"\n\nclass ActiveRecordTest < Minitest::Test\n  describe \"ActiveRecord\" do\n    # Rails 5 has a"
  },
  {
    "path": "test/controllers/articles_controller_test.rb",
    "chars": 5285,
    "preview": "require_relative \"../test_helper\"\n\nclass ArticlesControllerTest < ActionDispatch::IntegrationTest\n  describe ArticlesCon"
  },
  {
    "path": "test/controllers/dashboard_controller_test.rb",
    "chars": 1678,
    "preview": "require_relative \"../test_helper\"\n\nclass DashboardControllerTest < ActionDispatch::IntegrationTest\n  describe DashboardC"
  },
  {
    "path": "test/controllers/welcome_controller_test.rb",
    "chars": 268,
    "preview": "require_relative \"../test_helper\"\n\nclass WelcomeControllerTest < ActionDispatch::IntegrationTest\n  describe WelcomeContr"
  },
  {
    "path": "test/dummy/README.rdoc",
    "chars": 9208,
    "preview": "== Welcome to Rails\n\nRails is a web-application framework that includes everything needed to create\ndatabase-backed web "
  },
  {
    "path": "test/dummy/Rakefile",
    "chars": 266,
    "preview": "#!/usr/bin/env rake\n# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistran"
  },
  {
    "path": "test/dummy/app/assets/javascripts/application.js",
    "chars": 641,
    "preview": "// This is a manifest file that'll be compiled into application.js, which will include all the files\n// listed below.\n//"
  },
  {
    "path": "test/dummy/app/assets/javascripts/articles.js",
    "chars": 147,
    "preview": "// Place all the behaviors and hooks related to the matching controller here.\n// All this logic will automatically be av"
  },
  {
    "path": "test/dummy/app/assets/stylesheets/application.css",
    "chars": 545,
    "preview": "/*\n * This is a manifest file that'll be compiled into application.css, which will include all the files\n * listed below"
  },
  {
    "path": "test/dummy/app/assets/stylesheets/articles.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "test/dummy/app/assets/stylesheets/welcome.css",
    "chars": 128,
    "preview": "/*\n  Place all the styles related to the matching controller here.\n  They will automatically be included in application."
  },
  {
    "path": "test/dummy/app/controllers/application_controller.rb",
    "chars": 97,
    "preview": "class ApplicationController < ActionController::Base\n  protect_from_forgery with: :exception\nend\n"
  },
  {
    "path": "test/dummy/app/controllers/application_metal_controller.rb",
    "chars": 305,
    "preview": "class ApplicationMetalController < ActionController::Metal\n  MODULES = [\n    ActionController::Instrumentation,\n    Abst"
  },
  {
    "path": "test/dummy/app/controllers/articles_controller.rb",
    "chars": 189,
    "preview": "class ArticlesController < ApplicationController\n  def new\n  end\n\n  def create\n    render plain: params[:article].inspec"
  },
  {
    "path": "test/dummy/app/controllers/dashboard_controller.rb",
    "chars": 76,
    "preview": "class DashboardController < ApplicationMetalController\n  def show\n  end\nend\n"
  },
  {
    "path": "test/dummy/app/controllers/welcome_controller.rb",
    "chars": 70,
    "preview": "class WelcomeController < ApplicationController\n  def index\n  end\nend\n"
  },
  {
    "path": "test/dummy/app/helpers/application_helper.rb",
    "chars": 29,
    "preview": "module ApplicationHelper\nend\n"
  },
  {
    "path": "test/dummy/app/helpers/articles_helper.rb",
    "chars": 26,
    "preview": "module ArticlesHelper\nend\n"
  },
  {
    "path": "test/dummy/app/helpers/welcome_helper.rb",
    "chars": 25,
    "preview": "module WelcomeHelper\nend\n"
  },
  {
    "path": "test/dummy/app/jobs/bad_job.rb",
    "chars": 141,
    "preview": "class BadJob\n  include Sidekiq::Worker\n\n  sidekiq_options retry: false\n\n  def perform\n    raise ArgumentError, \"This is "
  },
  {
    "path": "test/dummy/app/jobs/simple_job.rb",
    "chars": 94,
    "preview": "class SimpleJob\n  include Sidekiq::Worker\n\n  def perform\n    \"SimpleJob is working\"\n  end\nend\n"
  },
  {
    "path": "test/dummy/app/mailers/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/dummy/app/models/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/dummy/app/models/sample.rb",
    "chars": 38,
    "preview": "class Sample < ActiveRecord::Base\nend\n"
  },
  {
    "path": "test/dummy/app/views/articles/new.html.erb",
    "chars": 286,
    "preview": "<h1>New Article</h1>\n\n<%= form_for :article, url: articles_path do |f| %>\n    <p>\n      <%= f.label :title %><br>\n      "
  },
  {
    "path": "test/dummy/app/views/layouts/application.html.erb",
    "chars": 232,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>Dummy</title>\n  <%= stylesheet_link_tag    \"application\", :media => \"all\" %>\n  <%"
  },
  {
    "path": "test/dummy/app/views/welcome/index.html.erb",
    "chars": 74,
    "preview": "<h1>Welcome#index</h1>\n<p>Find me in app/views/welcome/index.html.erb</p>\n"
  },
  {
    "path": "test/dummy/bin/bundle",
    "chars": 125,
    "preview": "#!/usr/bin/env ruby\nENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../Gemfile\", __dir__)\nload Gem.bin_path(\"bundler\", \"bund"
  },
  {
    "path": "test/dummy/bin/puma",
    "chars": 362,
    "preview": "#!/usr/bin/env ruby\n#\n# This file was generated by Bundler.\n#\n# The application 'puma' is installed as part of a gem, an"
  },
  {
    "path": "test/dummy/bin/rails",
    "chars": 141,
    "preview": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path(\"../config/application\", __dir__)\nrequire_relative \"../config/boot\"\nrequ"
  },
  {
    "path": "test/dummy/bin/rake",
    "chars": 90,
    "preview": "#!/usr/bin/env ruby\nrequire_relative \"../config/boot\"\nrequire \"rake\"\nRake.application.run\n"
  },
  {
    "path": "test/dummy/bin/setup",
    "chars": 733,
    "preview": "#!/usr/bin/env ruby\nrequire \"pathname\"\n\n# path to your application root.\nAPP_ROOT = Pathname.new File.expand_path(\"..\", "
  },
  {
    "path": "test/dummy/config/application.rb",
    "chars": 1782,
    "preview": "require File.expand_path(\"boot\", __dir__)\n\nrequire \"rails/all\"\n\nBundler.require\n\nmodule Dummy\n  class Application < Rail"
  },
  {
    "path": "test/dummy/config/boot.rb",
    "chars": 236,
    "preview": "require \"rubygems\"\ngemfile = File.expand_path(\"../../../Gemfile\", __dir__)\n\nif File.exist?(gemfile)\n  ENV[\"BUNDLE_GEMFIL"
  },
  {
    "path": "test/dummy/config/database.yml",
    "chars": 576,
    "preview": "# SQLite version 3.x\n#   gem install sqlite3\n#\n#   Ensure the SQLite 3 gem is defined in your Gemfile\n#   gem 'sqlite3'\n"
  },
  {
    "path": "test/dummy/config/environment.rb",
    "chars": 145,
    "preview": "# Load the rails application\nrequire File.expand_path(\"application\", __dir__)\n\n# Initialize the rails application\nDummy:"
  },
  {
    "path": "test/dummy/config/environments/development.rb",
    "chars": 1737,
    "preview": "Dummy::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n "
  },
  {
    "path": "test/dummy/config/environments/production.rb",
    "chars": 1105,
    "preview": "Dummy::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n  "
  },
  {
    "path": "test/dummy/config/environments/test.rb",
    "chars": 1375,
    "preview": "Dummy::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n  "
  },
  {
    "path": "test/dummy/config/initializers/backtrace_silencers.rb",
    "chars": 404,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
  },
  {
    "path": "test/dummy/config/initializers/inflections.rb",
    "chars": 533,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format\n# (al"
  },
  {
    "path": "test/dummy/config/initializers/mime_types.rb",
    "chars": 205,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Add new mime types for use in respond_to blocks:\n# Mime::"
  },
  {
    "path": "test/dummy/config/initializers/payload_collector.rb",
    "chars": 187,
    "preview": "ActiveSupport::Notifications.subscribe \"process_action.action_controller\" do |*args|\n  event = ActiveSupport::Notificati"
  },
  {
    "path": "test/dummy/config/initializers/secret_token.rb",
    "chars": 496,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key for verifying the integrity of signed coo"
  },
  {
    "path": "test/dummy/config/initializers/session_store.rb",
    "chars": 137,
    "preview": "# Be sure to restart your server when you modify this file.\n\nRails.application.config.session_store :cookie_store, key: "
  },
  {
    "path": "test/dummy/config/initializers/sidekiq.rb",
    "chars": 283,
    "preview": "# In tests we force Sidekiq into thinking it is running as a server,\n# so it creates a stdout logger. Remove it here:\nRa"
  },
  {
    "path": "test/dummy/config/initializers/wrap_parameters.rb",
    "chars": 517,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# This file contains settings for ActionController::ParamsW"
  },
  {
    "path": "test/dummy/config/locales/en.yml",
    "chars": 214,
    "preview": "# Sample localization file for English. Add more files in this directory for other locales.\n# See https://github.com/sve"
  },
  {
    "path": "test/dummy/config/routes.rb",
    "chars": 154,
    "preview": "Dummy::Application.routes.draw do\n  get \"welcome/index\"\n\n  resources :articles\n\n  resource :dashboard, controller: :dash"
  },
  {
    "path": "test/dummy/config/secrets.yml",
    "chars": 964,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key is used for verifying the integrity of si"
  },
  {
    "path": "test/dummy/config.ru",
    "chars": 148,
    "preview": "# This file is used by Rack-based servers to start the application.\n\nrequire File.expand_path(\"config/environment\", __di"
  },
  {
    "path": "test/dummy/db/migrate/20170525020551_create_samples.rb",
    "chars": 205,
    "preview": "class CreateSamples < ActiveRecord::Migration\n  def change\n    create_table :samples do |t|\n      t.string :name\n      t"
  },
  {
    "path": "test/dummy/db/schema.rb",
    "chars": 991,
    "preview": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the mig"
  },
  {
    "path": "test/dummy/lib/assets/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/dummy/log/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/dummy/public/404.html",
    "chars": 728,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>The page you were looking for doesn't exist (404)</title>\n  <style type=\"text/css"
  },
  {
    "path": "test/dummy/public/422.html",
    "chars": 711,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>The change you wanted was rejected (422)</title>\n  <style type=\"text/css\">\n    bo"
  },
  {
    "path": "test/dummy/public/500.html",
    "chars": 643,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>We're sorry, but something went wrong (500)</title>\n  <style type=\"text/css\">\n   "
  },
  {
    "path": "test/dummy/script/rails",
    "chars": 285,
    "preview": "#!/usr/bin/env ruby\n# This command will automatically be run when you run \"rails\" with Rails 3 gems installed from the r"
  },
  {
    "path": "test/dummy/test/fixtures/samples.yml",
    "chars": 197,
    "preview": "# Read about fixtures at\n# http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html\n\none:\n  name: MyString\n  age:"
  },
  {
    "path": "test/payload_collector.rb",
    "chars": 336,
    "preview": "class PayloadCollector\n  class << self\n    def wrap\n      @store = true\n      yield\n    ensure\n      @store = false\n    "
  },
  {
    "path": "test/rails_test.rb",
    "chars": 585,
    "preview": "require_relative \"test_helper\"\n\nclass RailsTest < Minitest::Test\n  describe \"Rails\" do\n    describe \".logger\" do\n      i"
  },
  {
    "path": "test/sidekiq_test.rb",
    "chars": 4246,
    "preview": "require_relative \"test_helper\"\n\nclass SidekiqTest < Minitest::Test\n  # Cannot use inline testing since it bypasses the S"
  },
  {
    "path": "test/test_helper.rb",
    "chars": 1529,
    "preview": "ENV[\"RAILS_ENV\"] ||= \"test\"\nENV[\"DISABLE_DATABASE_ENVIRONMENT_CHECK\"] = \"1\"\n# Load first so Sidekiq thinks it is running"
  }
]

About this extraction

This page contains the full source code of the rocketjob/rails_semantic_logger GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 117 files (154.1 KB), approximately 40.8k tokens, and a symbol index with 248 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!