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