[
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\n\non:\n  pull_request:\n  push:\n    branches:\n      - '**'\n    tags-ignore:\n      - 'v*'\n\njobs:\n  rubocop:\n    # Skip running tests for local pull requests (use push event instead), run only for foreign ones\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login != github.event.pull_request.base.repo.owner.login\n    name: RuboCop\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: \"3.4\"\n          bundler-cache: true\n      - name: Lint Ruby code with RuboCop\n        run: |\n          bundle exec rubocop\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Build and release gem\n\non:\n  push:\n    tags:\n      - v*\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      id-token: write\n      packages: write\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0 # Fetch current tag as annotated. See https://github.com/actions/checkout/issues/290\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: \"3.4\"\n      - name: \"Extract data from tag: version, message, body\"\n        id: tag\n        run: |\n          git fetch --tags --force # Really fetch annotated tag. See https://github.com/actions/checkout/issues/290#issuecomment-680260080\n          echo ::set-output name=version::${GITHUB_REF#refs/tags/v}\n          echo ::set-output name=subject::$(git for-each-ref $GITHUB_REF --format='%(contents:subject)')\n          BODY=\"$(git for-each-ref $GITHUB_REF --format='%(contents:body)')\"\n          # Extract changelog entries between this and previous version headers\n          escaped_version=$(echo ${GITHUB_REF#refs/tags/v} | sed -e 's/[]\\/$*.^[]/\\\\&/g')\n          changelog=$(awk \"BEGIN{inrelease=0} /## ${escaped_version}/{inrelease=1;next} /## [0-9]+\\.[0-9]+\\.[0-9]+/{inrelease=0;exit} {if (inrelease) print}\" CHANGELOG.md)\n          # Multiline body for release. See https://github.community/t/set-output-truncates-multiline-strings/16852/5\n          BODY=\"${BODY}\"$'\\n'\"${changelog}\"\n          BODY=\"${BODY//'%'/'%25'}\"\n          BODY=\"${BODY//$'\\n'/'%0A'}\"\n          BODY=\"${BODY//$'\\r'/'%0D'}\"\n          echo \"::set-output name=body::$BODY\"\n          # Add pre-release option if tag name has any suffix after vMAJOR.MINOR.PATCH\n          if [[ ${GITHUB_REF#refs/tags/} =~ ^v[0-9]+\\.[0-9]+\\.[0-9]+.+ ]]; then\n            echo ::set-output name=prerelease::true\n          fi\n      - name: Build gem\n        run: gem build\n      - name: Calculate checksums\n        run: sha256sum yabeda-rails-${{ steps.tag.outputs.version }}.gem > SHA256SUM\n      - name: Check version\n        run: ls -l yabeda-rails-${{ steps.tag.outputs.version }}.gem\n      - name: Create Release\n        id: create_release\n        uses: actions/create-release@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ github.ref }}\n          release_name: ${{ steps.tag.outputs.subject }}\n          body: ${{ steps.tag.outputs.body }}\n          draft: false\n          prerelease: ${{ steps.tag.outputs.prerelease }}\n      - name: Upload built gem as release asset\n        uses: actions/upload-release-asset@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: yabeda-rails-${{ steps.tag.outputs.version }}.gem\n          asset_name: yabeda-rails-${{ steps.tag.outputs.version }}.gem\n          asset_content_type: application/x-tar\n      - name: Upload checksums as release asset\n        uses: actions/upload-release-asset@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: SHA256SUM\n          asset_name: SHA256SUM\n          asset_content_type: text/plain\n      - name: Publish to GitHub packages\n        env:\n          GEM_HOST_API_KEY: Bearer ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          gem push yabeda-rails-${{ steps.tag.outputs.version }}.gem --host https://rubygems.pkg.github.com/${{ github.repository_owner }}\n      - name: Configure RubyGems Credentials\n        uses: rubygems/configure-rubygems-credentials@main\n      - name: Publish to RubyGems\n        run: |\n          gem push yabeda-rails-${{ steps.tag.outputs.version }}.gem\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Tests\n\non:\n  pull_request:\n  push:\n    branches:\n      - '**'\n    tags-ignore:\n      - 'v*'\n\njobs:\n  test:\n    name: 'Rails ${{ matrix.rails }} × Ruby ${{ matrix.ruby }}'\n    # Skip running tests for local pull requests (use push event instead), run only for foreign ones\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login != github.event.pull_request.base.repo.owner.login\n    runs-on: ubuntu-latest\n    continue-on-error: ${{ matrix.optional || false }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - ruby: \"head\"\n            rails: \"HEAD\"\n            optional: true\n          - ruby: \"4.0\"\n            rails: \"8.1\"\n          - ruby: \"3.4\"\n            rails: \"8.1\"\n          - ruby:  \"3.4\"\n            rails: \"8.0\"\n          - ruby:  \"3.3\"\n            rails: \"7.2\"\n          - ruby:  \"3.2\"\n            rails: \"7.1\"\n          - ruby:  \"3.1\"\n            rails: \"7.0\"\n          - ruby:  \"3.0\"\n            rails: \"6.1\"\n          - ruby:  \"2.7\"\n            rails: \"6.0\"\n    env:\n      CI: true\n      RAILS_VERSION: ${{ matrix.rails }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: ${{ matrix.ruby }}\n          bundler-cache: true\n      - name: Run RSpec\n        run: bundle exec rspec\n"
  },
  {
    "path": ".gitignore",
    "content": "/.bundle/\n/.yardoc\n/_yardoc/\n/coverage/\n/doc/\n/pkg/\n/spec/reports/\n/tmp/\nGemfile.lock\n\n# rspec failure tracking\n.rspec_status\n"
  },
  {
    "path": ".rspec",
    "content": "--format documentation\n--color\n--require spec_helper\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "---\nrequire:\n- rubocop-rspec\n\nAllCops:\n  TargetRubyVersion: 2.5\n\nMetrics/BlockLength:\n  Exclude:\n  - \"Gemfile\"\n  - \"spec/**/*\"\n\nStyle/StringLiterals:\n  EnforcedStyle: double_quotes\n\n# Allow to use let!\nRSpec/LetSetup:\n  Enabled: false\n\nRSpec/MultipleExpectations:\n  Enabled: false\n\nBundler/OrderedGems:\n  Enabled: false\n\nStyle/TrailingCommaInArguments:\n  Description: 'Checks for trailing comma in argument lists.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-params-comma'\n  Enabled: true\n  EnforcedStyleForMultiline: consistent_comma\n\nStyle/TrailingCommaInArrayLiteral:\n  Description: 'Checks for trailing comma in array literals.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'\n  Enabled: true\n  EnforcedStyleForMultiline: consistent_comma\n\nStyle/TrailingCommaInHashLiteral:\n  Description: 'Checks for trailing comma in hash literals.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'\n  Enabled: true\n  EnforcedStyleForMultiline: consistent_comma\n\nBundler/DuplicatedGem:\n  Enabled: false\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).\n\n## 0.11.0 - 2025-12-03\n\n### Added\n\n- Ability to use procs and regexps in `ignore_actions` configuration. [@lewispb][] in [#34](https://github.com/yabeda-rb/yabeda-rails/pull/34), [@Envek][]\n\n## 0.10.0 - 2025-09-09\n\n### Added\n\n- Add Passenger server to auto register list [@mabrikan][] in [#28](https://github.com/yabeda-rb/yabeda-rails/pull/28)\n- Allow defining default_tags only for rails group [@magec][] in [#30](https://github.com/yabeda-rb/yabeda-rails/pull/30)\n- Ability to customize the bucket sizing for histograms [@skateman][] in [#32](https://github.com/yabeda-rb/yabeda-rails/pull/32)\n- Ability to ignore certain controller#actions [@zzip][] in [#33](https://github.com/yabeda-rb/yabeda-rails/pull/33)\n\n## 0.9.0 - 2023-08-03\n\n### Added\n\n- Ability to switch controller name case in `controller` tag between `:snake` and `:camel` case. [@lewispb][] in [#26](https://github.com/yabeda-rb/yabeda-rails/pull/26)\n\n## Changed\n\n- Minimal Ruby version increased to 2.5. [@Envek][]\n\n## 0.8.1 - 2022-06-06\n\n### Fixed\n\n- Fill status codes for responses with unhandled exceptions. [@dks17][] in [#24](https://github.com/yabeda-rb/yabeda-rails/pull/24)\n\n## 0.8.0 - 2022-05-30\n\n### Added\n\n- Add ability to expose custom Apdex target value for later use in graphs/alerts. [@Envek][] in [#18](https://github.com/yabeda-rb/yabeda-rails/pull/18)\n\n### Changed\n\n- Reduce number of dependencies by depending only on railties instead of the whole Ruby on Rails. [@lautis][] in [#23](https://github.com/yabeda-rb/yabeda-rails/pull/23).\n\n## 0.7.2 - 2021-03-15\n\n### Fixed\n\n- Fix undesirable overwrite of metric tags when global `default_tag` is declared with one of tag names that are being used by yabeda-rails, like `controller`. [@liaden] in [#19](https://github.com/yabeda-rb/yabeda-rails/pull/19)\n\n## 0.7.1 - 2020-10-02\n\n### Changed\n\n - Explicitly require previously removed railtie to fix case when it doesn't get required in `yabeda` gem (if `yabeda` is required before `rails`). See [yabeda-rb/yabeda#15](https://github.com/yabeda-rb/yabeda/issues/15). @Envek\n\n## 0.7.0 - 2020-08-21\n\n### Removed\n\n - Railtie to configure Yabeda – it is moved into Yabeda itself. Increase required Yabeda version to keep behavior for users who require only `yabeda-rails` in their Gemfiles. @Envek\n\n## 0.6.0 - 2020-08-06\n\n### Added\n\n - Ability to add default/custom tags to metrics from controllers. @raivil in [#13](https://github.com/yabeda-rb/yabeda-rails/pull/13)\n\n## 0.5.0 - 2020-03-27\n\n### Added\n\n - Support for Unicorn application server. @vast in [#9](https://github.com/yabeda-rb/yabeda-rails/pull/9)\n\n## 0.4.0 - 2020-01-28\n\n### Changed\n\n - Configure Yabeda after application initialization as since 0.4.0 Yabeda requires to call configuration logic explicitly. @Envek\n\n## 0.2.0 - 2020-01-14\n\n### Changed\n\n - Added `tags` option to metric declarations for compatibility with yabeda and yabeda-prometheus 0.2. @Envek\n\n## 0.1.2 - 2019-01-19\n\n### Added\n\n - Support for Puma application server. @daffydowden\n\n## 0.1.1 - 2018-10-17\n\n### Changed\n\n - Renamed evil-metrics-rails gem to yabeda-rails. @Envek\n\n## 0.1.0 - 2018-10-03\n\n - Initial release of evil-metrics-rails gem. @Envek\n\n   Basic metrics for request durations by controller, action, status, format, and method. ActiveRecord and ActionView timings.\n\n[@Envek]: https://github.com/Envek \"Andrey Novikov\"\n[@liaden]: https://github.com/liaden \"Joel Johnson\"\n[@lautis]: https://github.com/lautis \"Ville Lautanala\"\n[@dks17]: https://github.com/dks17 \"Konstantin\"\n[@lewispb]: https://github.com/lewispb \"Lewis Buckley\"\n[@mabrikan]: https://github.com/mabrikan \"Musaed Albrikan\"\n[@magec]: https://github.com/magec \"Jose Fernández\"\n[@skateman]: https://github.com/skateman \"Halász Dávid\"\n[@zzip]: https://github.com/zzip \"Dale Hofkens\"\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngit_source(:github) { |repo_name| \"https://github.com/#{repo_name}\" }\n\n# Specify your gem's dependencies in yabeda-rails.gemspec\ngemspec\n\nrails_version = ENV.fetch(\"RAILS_VERSION\", \"~> 8.0\")\ncase rails_version\nwhen \"HEAD\"\n  git \"https://github.com/rails/rails.git\" do\n    gem \"rails\"\n    gem \"activesupport\"\n    gem \"railties\"\n  end\nelse\n  rails_version = \"~> #{rails_version}.0\" if rails_version.match?(/^\\d+\\.\\d+$/)\n  gem \"rails\", rails_version\n  gem \"activesupport\", rails_version\n  gem \"railties\", rails_version\nend\n\ngroup :development, :test do\n  gem \"yabeda\", \"~> 0.11\" # Test helpers\n  gem \"rspec-rails\"\n\n  gem \"debug\"\n\n  gem \"rubocop\", \"~> 1.8\"\n  gem \"rubocop-rspec\"\nend\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Andrey Novikov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ![Yabeda::Rails](./yabeda-rails-logo.png)\n\nBuilt-in metrics for out-of-the box [Rails] applications monitoring.\n\nIf your monitoring system already collects Rails metrics (e.g. NewRelic) then most probably you don't need this gem.\n\nSample Grafana dashboard ID: [11668](https://grafana.com/grafana/dashboards/11668)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'yabeda-rails'\n# Then add monitoring system adapter, e.g.:\n# gem 'yabeda-prometheus'\n```\n\nAnd then execute:\n\n    $ bundle\n\n### Registering metrics on server process start\n\nCurrently, yabeda-rails automatically registers rails metrics when a server is started via `rails server`, `puma -C config/puma.rb` or `unicorn -c`. However, other application servers or launching via `rackup` aren't supported at the moment.\n\nA possible workaround is to detect server process and manually activate yabeda-rails in an initializer:\n\n```ruby\n# config/initializers/yabeda.rb\n\nif your_app_server_process? # Your logic here\n  Yabeda::Rails.install!\nend\n```\n\nYou always can add support for your app server to [lib/yabeda/rails/railtie.rb](lib/yabeda/rails/railtie.rb). Pull Requests are always welcome!\n\n\n## Metrics\n\n - Total web requests received: `rails_requests_total`\n - Web request duration: `rails_request_duration` (in seconds)\n - Views rendering duration: `rails_view_runtime` (in seconds)\n - DB request duration: `rails_db_runtime` (in seconds)\n\n\n## Hooks\n\n - `on_controller_action`: Allows to collect\n\n    ```ruby\n    Yabeda::Rails.on_controller_action do |event, labels|\n      next unless event.payload[:ext_service_runtime]\n      time_in_seconds = event.payload[:ext_service_runtime] / 1000.0\n      rails_ext_service_runtime.measure(labels, time_in_seconds)\n    end\n    ```\n\n## Custom tags\n\nYou can add additional tags to the existing metrics by adding custom payload to your controller.\n\n```ruby\n# This block is optional but some adapters (like Prometheus) requires that all tags should be declared in advance\nYabeda.configure do\n  default_tag :importance, nil\nend\n\nclass ApplicationController < ActionController::Base\n  def append_info_to_payload(payload)\n    super\n    payload[:importance] = extract_importance(params)\n  end\nend\n```\n`append_info_to_payload` is a method from [ActionController::Instrumentation](https://api.rubyonrails.org/classes/ActionController/Instrumentation.html#method-i-append_info_to_payload)\n\n## Configuration\n\nConfiguration is handled by [anyway_config] gem. With it you can load settings from environment variables (upcased and prefixed with `YABEDA_RAILS_`), YAML files, and other sources. See [anyway_config] docs for details.\n\n| Config key             | Type    | Default | Description                                                                                                                                           |\n| ---------------------- | ------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `apdex_target`         | integer | nil     | Tolerable time for Apdex in seconds, exposed as gauge if set.                                                                                         |\n| `controller_name_case` | symbol  | :snake  | Defines whether controller name is reported in camel case (:camel) or snake case (:snake).                                                            |\n| `ignore_actions`       | array or proc | []      | array of controller#action strings or a proc that receives the controller#action string and returns true if the action should be ignored. Controller should be in camel case, example `['HealthCheck::HealthCheckController#index']` or `->(controller_action) { controller_action.start_with?(\"HealthCheck\") }` |\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n### Releasing\n\n 1. Bump version number in `lib/yabeda/rails/version.rb`\n\n    In case of pre-releases keep in mind [rubygems/rubygems#3086](https://github.com/rubygems/rubygems/issues/3086) and check version with command like `Gem::Version.new(Yabeda::Rails::VERSION).to_s`\n\n 2. Fill `CHANGELOG.md` with missing changes, add header with version and date.\n\n 3. Make a commit:\n\n    ```sh\n    git add lib/yabeda/rails/version.rb CHANGELOG.md\n    version=$(ruby -r ./lib/yabeda/rails/version.rb -e \"puts Gem::Version.new(Yabeda::Rails::VERSION)\")\n    git commit --message=\"${version}: \" --edit\n    ```\n\n 4. Create annotated tag:\n\n    ```sh\n    git tag v${version} --annotate --message=\"${version}: \" --edit --sign\n    ```\n\n 5. Fill version name into subject line and (optionally) some description (list of changes will be taken from changelog and appended automatically)\n\n 6. Push it:\n\n    ```sh\n    git push --follow-tags\n    ```\n\n 7. You're done!\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/yabeda-rb/yabeda-rails.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n[Rails]: https://rubyonrails.org \"Ruby on Rails MVC web-application framework optimized for programmer happiness\"\n"
  },
  {
    "path": "Rakefile",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/gem_tasks\"\nrequire \"rspec/core/rake_task\"\n\nRSpec::Core::RakeTask.new(:spec)\n\ntask default: :spec\n"
  },
  {
    "path": "bin/console",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire \"yabeda/rails\"\n\n# You can add fixtures and/or initialization code here to make experimenting\n# with your gem easier. You can also use a different console, if you like.\n\nrequire \"pry\"\nPry.start\n"
  },
  {
    "path": "bin/setup",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\nset -vx\n\nbundle install\n\n# Do any other automated setup that you need to do here\n"
  },
  {
    "path": "lib/yabeda/rails/config.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"anyway\"\n\nmodule Yabeda\n  module Rails\n    # yabeda-rails configuration\n    class Config < ::Anyway::Config\n      config_name :yabeda_rails\n\n      attr_config :apdex_target\n      attr_config :buckets\n      attr_config controller_name_case: :snake\n      attr_config ignore_actions: []\n    end\n  end\nend\n"
  },
  {
    "path": "lib/yabeda/rails/event.rb",
    "content": "# frozen_string_literal: true\n\nmodule Yabeda\n  module Rails\n    # ActiveSupport Event with added logic for Yabeda tags formatting\n    class Event < ActiveSupport::Notifications::Event\n      def labels\n        @labels ||= begin\n          labels = {\n            controller: controller,\n            action: action,\n            status: status,\n            format: format,\n            method: method,\n          }\n          labels.merge(payload.slice(*(Yabeda.default_tags.keys + Yabeda.rails.default_tags.keys) - labels.keys))\n        end\n      end\n\n      def duration\n        ms2s super\n      end\n\n      def view_runtime\n        ms2s payload[:view_runtime]\n      end\n\n      def db_runtime\n        ms2s payload[:db_runtime]\n      end\n\n      def controller_action\n        \"#{payload[:controller]}##{payload[:action]}\"\n      end\n\n      private\n\n      def controller\n        case Yabeda::Rails.config.controller_name_case\n        when :camel\n          payload[:controller]\n        else\n          payload[:params][\"controller\"]\n        end\n      end\n\n      def action\n        payload[:action]\n      end\n\n      def status\n        if payload[:status].nil? && payload[:exception].present?\n          ActionDispatch::ExceptionWrapper.status_code_for_exception(payload[:exception].first)\n        else\n          payload[:status]\n        end\n      end\n\n      def format\n        payload[:format]\n      end\n\n      def method\n        payload[:method].downcase\n      end\n\n      def ms2s(milliseconds)\n        (milliseconds.to_f / 1000).round(3)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/yabeda/rails/railtie.rb",
    "content": "# frozen_string_literal: true\n\n# Explicitly require yabeda's railtie in case if its require was skipped there.\n# See https://github.com/yabeda-rb/yabeda/issues/15\nrequire \"yabeda/railtie\"\n\nmodule Yabeda\n  module Rails\n    class Railtie < ::Rails::Railtie # :nodoc:\n      def rails_server?\n        ::Rails.const_defined?(:Server)\n      end\n\n      def puma_server?\n        ::Rails.const_defined?(\"Puma::CLI\")\n      end\n\n      def unicorn_server?\n        ::Rails.const_defined?(\"Unicorn::Launcher\")\n      end\n\n      def passenger_server?\n        ::Rails.const_defined?(\"PhusionPassenger\")\n      end\n\n      initializer \"yabeda-rails.metrics\" do\n        ::Yabeda::Rails.install! if rails_server? || puma_server? || unicorn_server? || passenger_server?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/yabeda/rails/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Yabeda\n  module Rails\n    VERSION = \"0.11.0\"\n  end\nend\n"
  },
  {
    "path": "lib/yabeda/rails.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"yabeda\"\nrequire \"active_support\"\nrequire \"rails/railtie\"\nrequire \"yabeda/rails/railtie\"\nrequire \"yabeda/rails/config\"\nrequire \"yabeda/rails/event\"\n\nmodule Yabeda\n  # Minimal set of Rails-specific metrics for using with Yabeda\n  module Rails\n    LONG_RUNNING_REQUEST_BUCKETS = [\n      0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, # standard\n      30, 60, 120, 300, 600, # Sometimes requests may be really long-running\n    ].freeze\n\n    class << self\n      def controller_handlers\n        @controller_handlers ||= []\n      end\n\n      def on_controller_action(&block)\n        controller_handlers << block\n      end\n\n      # Declare metrics and install event handlers for collecting themya\n      # rubocop: disable Metrics/MethodLength, Metrics/BlockLength, Metrics/AbcSize\n      def install!\n        Yabeda.configure do\n          config = ::Yabeda::Rails.config\n          buckets = config.buckets || LONG_RUNNING_REQUEST_BUCKETS\n\n          group :rails\n\n          counter   :requests_total,   comment: \"A counter of the total number of HTTP requests rails processed.\",\n                                       tags: %i[controller action status format method]\n\n          histogram :request_duration, tags: %i[controller action status format method],\n                                       unit: :seconds,\n                                       buckets: buckets,\n                                       comment: \"A histogram of the response latency.\"\n\n          histogram :view_runtime, unit: :seconds, buckets: buckets,\n                                   comment: \"A histogram of the view rendering time.\",\n                                   tags: %i[controller action status format method]\n\n          histogram :db_runtime, unit: :seconds, buckets: buckets,\n                                 comment: \"A histogram of the activerecord execution time.\",\n                                 tags: %i[controller action status format method]\n\n          if config.apdex_target\n            gauge :apdex_target, unit: :seconds,\n                                 comment: \"Tolerable time for Apdex (T value: maximum duration of satisfactory request)\"\n            collect { rails_apdex_target.set({}, config.apdex_target) }\n          end\n\n          ActiveSupport::Notifications.subscribe \"process_action.action_controller\" do |*args|\n            event = Yabeda::Rails::Event.new(*args)\n\n            # rubocop: disable Style/CaseEquality\n            next if Array(config.ignore_actions).any? { |action| action === event.controller_action }\n            # rubocop: enable Style/CaseEquality\n\n            rails_requests_total.increment(event.labels)\n            rails_request_duration.measure(event.labels, event.duration)\n            rails_view_runtime.measure(event.labels, event.view_runtime)\n            rails_db_runtime.measure(event.labels, event.db_runtime)\n\n            Yabeda::Rails.controller_handlers.each do |handler|\n              handler.call(event, event.labels)\n            end\n          end\n        end\n      end\n      # rubocop: enable Metrics/MethodLength, Metrics/BlockLength, Metrics/AbcSize\n\n      def config\n        @config ||= Config.new\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# frozen_string_literal: true\n\nENV[\"RAILS_ENV\"] = \"test\"\n\nrequire \"bundler/setup\"\nrequire \"logger\"\nrequire \"debug\"\nrequire \"yabeda/rails\"\nrequire \"yabeda/rspec\"\n\nrequire_relative \"support/rails_app\"\n\nrequire \"rspec/rails\"\n\nRSpec.configure do |config|\n  # Enable flags like --only-failures and --next-failure\n  config.example_status_persistence_file_path = \".rspec_status\"\n\n  # Disable RSpec exposing methods globally on `Module` and `main`\n  config.disable_monkey_patching!\n\n  config.expect_with :rspec do |c|\n    c.syntax = :expect\n  end\n\n  Kernel.srand config.seed\n  config.order = :random\n\n  config.before(:suite) do\n    Yabeda::Rails.install!\n  end\nend\n"
  },
  {
    "path": "spec/support/rails_app.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"rails\"\nrequire \"action_controller/railtie\"\nrequire \"active_support/railtie\"\n\nclass TestApplication < Rails::Application\n  config.logger = Logger.new($stdout)\n  config.log_level = :fatal\n  config.consider_all_requests_local = true\n  config.eager_load = true\n\n  routes.append do\n    get \"/hello/world\" => \"hello#world\"\n    get \"/hello/long\" => \"hello#long\"\n    get \"/hello/internal_server_error\" => \"hello#internal_server_error\"\n  end\nend\n\nclass HelloController < ActionController::API\n  def append_info_to_payload(payload)\n    super\n    payload[:custom_tag_from_rails] = \"hello-world-from-rails\"\n    payload[:custom_tag] = \"hello-world\"\n  end\n\n  def world\n    render json: { hello: :world }\n  end\n\n  def long\n    sleep(0.01)\n    render json: { good: :morning }\n  end\n\n  def internal_server_error\n    raise StandardError\n  end\nend\n\nTestApplication.initialize!\n"
  },
  {
    "path": "spec/yabeda/rails_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"action_controller/test_case\"\n\nRSpec.describe Yabeda::Rails, type: :integration do\n  include ActionDispatch::Integration::Runner\n  include ActionDispatch::IntegrationTest::Behavior\n\n  def app\n    TestApplication\n  end\n\n  it \"increments counters for every request\" do\n    expect { get \"/hello/world\" }.to \\\n      increment_yabeda_counter(Yabeda.rails.requests_total)\n      .with_tags(controller: \"hello\", action: \"world\", status: 200, method: \"get\", format: :html)\n      .by(1)\n  end\n\n  it \"measure action runtime for every request\" do\n    expect { get \"/hello/long\" }.to \\\n      measure_yabeda_histogram(Yabeda.rails.request_duration)\n      .with_tags(controller: \"hello\", action: \"long\", status: 200, method: \"get\", format: :html)\n      .with(be_between(0.005, 0.05))\n  end\n\n  it \"returns internal_server_error status code\" do\n    expect { get \"/hello/internal_server_error\" }.to \\\n      increment_yabeda_counter(Yabeda.rails.requests_total)\n      .with_tags(controller: \"hello\", action: \"internal_server_error\", status: 500, method: \"get\", format: :html)\n  end\n\n  context \"with changed controller name case config tp camel case\" do\n    around do |example|\n      original_case = described_class.config.controller_name_case\n      described_class.config.controller_name_case = :camel\n      example.call\n    ensure\n      described_class.config.controller_name_case = original_case\n    end\n\n    it \"reports controller tag in camel case\" do\n      expect { get \"/hello/world\" }.to \\\n        increment_yabeda_counter(Yabeda.rails.requests_total)\n        .with_tags(controller: \"HelloController\", action: \"world\", status: 200, method: \"get\", format: :html)\n        .by(1)\n    end\n  end\n\n  context \"with default_tags set\" do\n    before do\n      Yabeda.default_tag :custom_tag, nil\n    end\n\n    it \"increments counters for every request\" do\n      expect { get \"/hello/world\" }.to \\\n        increment_yabeda_counter(Yabeda.rails.requests_total)\n        .with_tags(custom_tag: \"hello-world\")\n        .by(1)\n    end\n  end\n\n  context \"with ':rails' default_tags set\" do\n    before do\n      Yabeda.default_tag :custom_tag_from_rails, nil, group: :rails\n    end\n\n    it \"increments counters for every request\" do\n      expect { get \"/hello/world\" }.to \\\n        increment_yabeda_counter(Yabeda.rails.requests_total)\n        .with_tags(custom_tag_from_rails: \"hello-world-from-rails\")\n        .by(1)\n    end\n  end\n\n  context \"with ignore_actions\" do\n    around do |example|\n      original_ignore_actions = described_class.config.ignore_actions\n      described_class.config.ignore_actions = [\"HelloController#world\", \"HelloController#long\"]\n      example.call\n    ensure\n      described_class.config.ignore_actions = original_ignore_actions\n    end\n\n    it \"ignores actions matching the proc\" do\n      expect { get \"/hello/world\" }.not_to \\\n        increment_yabeda_counter(Yabeda.rails.requests_total)\n    end\n  end\n\n  context \"with ignore_actions as a proc\" do\n    around do |example|\n      original_ignore_actions = described_class.config.ignore_actions\n      described_class.config.ignore_actions = lambda { |controller_action|\n        controller_action.start_with?(\"HelloController#\")\n      }\n      example.call\n    ensure\n      described_class.config.ignore_actions = original_ignore_actions\n    end\n\n    it \"ignores actions matching the proc\" do\n      expect { get \"/hello/world\" }.not_to \\\n        increment_yabeda_counter(Yabeda.rails.requests_total)\n    end\n  end\nend\n"
  },
  {
    "path": "yabeda-rails.gemspec",
    "content": "# frozen_string_literal: true\n\nlib = File.expand_path(\"lib\", __dir__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire \"yabeda/rails/version\"\n\nGem::Specification.new do |spec|\n  spec.name          = \"yabeda-rails\"\n  spec.version       = Yabeda::Rails::VERSION\n  spec.authors       = [\"Andrey Novikov\"]\n  spec.email         = [\"envek@envek.name\"]\n\n  spec.summary       = \"Extensible metrics for monitoring Ruby on Rails application\"\n  spec.description   = \"Easy collecting your Rails apps metrics\"\n  spec.homepage      = \"https://github.com/yabeda-rb/yabeda-rails\"\n  spec.license       = \"MIT\"\n\n  spec.metadata = {\n    \"changelog_uri\" => \"https://github.com/yabeda-rb/yabeda-rails/blob/master/CHANGELOG.md\",\n    \"rubygems_mfa_required\" => \"true\",\n  }\n\n  spec.files = `git ls-files -z`.split(\"\\x0\").reject do |f|\n    f.match(%r{^(test|spec|features)/})\n  end\n  spec.bindir        = \"exe\"\n  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }\n  spec.require_paths = [\"lib\"]\n\n  spec.required_ruby_version = \">= 2.5\"\n\n  spec.add_dependency \"activesupport\"\n  spec.add_dependency \"anyway_config\", \">= 1.3\", \"< 3\"\n  spec.add_dependency \"railties\"\n  spec.add_dependency \"yabeda\", \"~> 0.8\"\n\n  spec.add_development_dependency \"bundler\", \">= 2.0\"\n  spec.add_development_dependency \"rake\", \"~> 13.0\"\n  spec.add_development_dependency \"rspec\", \"~> 3.0\"\nend\n"
  }
]