-
-
Notifications
You must be signed in to change notification settings - Fork 532
feat(yabeda): Add sentry-yabeda adapter gem #2925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c41fc31
2ad73c0
f890d48
8261a62
670e40a
73fd417
c51d7ad
07bbe18
855c165
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| name: sentry-yabeda Test | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| workflow_call: | ||
| outputs: | ||
| matrix-result: | ||
| description: "Matrix job result" | ||
| value: ${{ jobs.test.outputs.matrix-result }} | ||
| inputs: | ||
| versions: | ||
| required: true | ||
| type: string | ||
| # Cancel in progress workflows on pull_requests. | ||
| # https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value | ||
| concurrency: | ||
| group: sentry-yabeda-test-${{ github.head_ref || github.run_id }} | ||
| cancel-in-progress: true | ||
| jobs: | ||
| test: | ||
| defaults: | ||
| run: | ||
| working-directory: sentry-yabeda | ||
| name: Ruby ${{ matrix.ruby_version }}, options - ${{ toJson(matrix.options) }} | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| env: | ||
| RUBYOPT: ${{ matrix.options.rubyopt }} | ||
| BUNDLE_GEMFILE: ${{ github.workspace }}/sentry-yabeda/Gemfile | ||
| BUNDLE_WITHOUT: rubocop | ||
| JRUBY_OPTS: "--debug" # for more accurate test coverage | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| ruby_version: ${{ fromJson(inputs.versions) }} | ||
| include: | ||
| - ruby_version: "3.2" | ||
| options: | ||
| rubyopt: "--enable-frozen-string-literal --debug=frozen-string-literal" | ||
| exclude: | ||
| - ruby_version: 'jruby' | ||
| - ruby_version: 'jruby-head' | ||
| steps: | ||
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
|
|
||
| - name: Set up Ruby ${{ matrix.ruby_version }} | ||
| uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1 | ||
| with: | ||
| ruby-version: ${{ matrix.ruby_version }} | ||
| bundler-cache: true | ||
|
|
||
| - name: Run specs | ||
| run: bundle exec rake | ||
|
|
||
| - name: Upload Coverage | ||
| uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5 | ||
| with: | ||
| token: ${{ secrets.CODECOV_TOKEN }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| source "https://rubygems.org" | ||
| git_source(:github) { |name| "https://github.com/#{name}.git" } | ||
|
|
||
| eval_gemfile "../Gemfile.dev" | ||
|
|
||
| # Specify your gem's dependencies in sentry-yabeda.gemspec | ||
| gemspec | ||
|
|
||
| gem "sentry-ruby", path: "../sentry-ruby" | ||
|
|
||
| gem "timecop" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| The MIT License (MIT) | ||
|
|
||
| Copyright (c) 2020 Sentry | ||
|
|
||
| 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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <p align="center"> | ||
| <a href="https://sentry.io" target="_blank" align="center"> | ||
| <img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280"> | ||
| </a> | ||
| <br> | ||
| </p> | ||
|
|
||
| # sentry-yabeda, the Yabeda integration for Sentry's Ruby client | ||
|
|
||
| --- | ||
|
|
||
| [](https://rubygems.org/gems/sentry-yabeda) | ||
|  | ||
| [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | ||
| [](https://rubygems.org/gems/sentry-yabeda/) | ||
|
|
||
|
|
||
| [Documentation](https://docs.sentry.io/platforms/ruby/) | [Bug Tracker](https://github.com/getsentry/sentry-ruby/issues) | [Forum](https://forum.sentry.io/) | IRC: irc.freenode.net, #sentry | ||
|
|
||
| The official Ruby-language client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API. | ||
|
|
||
|
|
||
| ## Getting Started | ||
|
|
||
| ### Install | ||
|
|
||
| ```ruby | ||
| gem "sentry-ruby" | ||
| gem "sentry-yabeda" | ||
| ``` | ||
|
|
||
| Then initialize Sentry with metrics enabled: | ||
|
|
||
| ```ruby | ||
| Sentry.init do |config| | ||
| config.dsn = ENV["SENTRY_DSN"] | ||
| config.enable_metrics = true | ||
| end | ||
| ``` | ||
|
|
||
| That's it! All Yabeda metrics will automatically flow to Sentry. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "bundler/gem_tasks" | ||
| require_relative "../lib/sentry/test/rake_tasks" | ||
|
|
||
| Sentry::Test::RakeTasks.define_spec_tasks( | ||
| spec_pattern: "spec/sentry/**/*_spec.rb", | ||
| spec_rspec_opts: "--order rand --format progress" | ||
| ) | ||
|
|
||
| task default: :spec |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "yabeda" | ||
| require "sentry-ruby" | ||
| require "sentry/integrable" | ||
| require "sentry/yabeda/version" | ||
| require "sentry/yabeda/adapter" | ||
| require "sentry/yabeda/collector" | ||
| require "sentry/yabeda/configuration" | ||
|
|
||
| module Sentry | ||
| module Yabeda | ||
| extend Sentry::Integrable | ||
|
|
||
| register_integration name: "yabeda", version: Sentry::Yabeda::VERSION | ||
|
|
||
| class << self | ||
| attr_accessor :collector | ||
| end | ||
| end | ||
| end | ||
|
|
||
| ::Yabeda.register_adapter(:sentry, Sentry::Yabeda::Adapter.new) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "yabeda/base_adapter" | ||
|
|
||
| module Sentry | ||
| module Yabeda | ||
| class Adapter < ::Yabeda::BaseAdapter | ||
| # Sentry does not require pre-registration of metrics | ||
| def register_counter!(_metric); end | ||
| def register_gauge!(_metric); end | ||
| def register_histogram!(_metric); end | ||
| def register_summary!(_metric); end | ||
|
|
||
| def perform_counter_increment!(counter, tags, increment) | ||
| return unless enabled? | ||
|
|
||
| Sentry.metrics.count( | ||
| metric_name(counter), | ||
| value: increment, | ||
| attributes: attributes_for(tags) | ||
| ) | ||
| end | ||
|
|
||
| def perform_gauge_set!(gauge, tags, value) | ||
| return unless enabled? | ||
|
|
||
| Sentry.metrics.gauge( | ||
| metric_name(gauge), | ||
| value, | ||
| unit: unit_for(gauge), | ||
| attributes: attributes_for(tags) | ||
| ) | ||
| end | ||
|
|
||
| def perform_histogram_measure!(histogram, tags, value) | ||
| return unless enabled? | ||
|
|
||
| Sentry.metrics.distribution( | ||
| metric_name(histogram), | ||
| value, | ||
| unit: unit_for(histogram), | ||
| attributes: attributes_for(tags) | ||
| ) | ||
| end | ||
|
|
||
| def perform_summary_observe!(summary, tags, value) | ||
| return unless enabled? | ||
|
|
||
| Sentry.metrics.distribution( | ||
| metric_name(summary), | ||
| value, | ||
| unit: unit_for(summary), | ||
| attributes: attributes_for(tags) | ||
| ) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def enabled? | ||
| Sentry.initialized? && Sentry.configuration.enable_metrics | ||
| end | ||
|
|
||
| def attributes_for(tags) | ||
| tags.empty? ? nil : tags | ||
| end | ||
|
|
||
| def metric_name(metric) | ||
| [metric.group, metric.name].compact.join(".") | ||
| end | ||
|
|
||
| # TODO: Normalize Yabeda unit symbols (e.g. :milliseconds) to Sentry's | ||
| # canonical singular strings (e.g. "millisecond") once units are visible | ||
| # in the Sentry product. See https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes/#units | ||
| def unit_for(metric) | ||
| metric.unit&.to_s | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "sentry/threaded_periodic_worker" | ||
|
|
||
| module Sentry | ||
| module Yabeda | ||
| # Periodically calls Yabeda.collect! to trigger gauge collection blocks | ||
| # registered by plugins like yabeda-puma-plugin, yabeda-gc, and | ||
| # yabeda-gvl_metrics. | ||
| # | ||
| # In a pull-based system (Prometheus), the scrape request triggers | ||
| # collection. In a push-based system (Sentry), we need this periodic | ||
| # worker to drive the collect → gauge.set → adapter.perform_gauge_set! | ||
| # pipeline. | ||
| class Collector < Sentry::ThreadedPeriodicWorker | ||
| DEFAULT_INTERVAL = 15 # seconds | ||
|
|
||
| def initialize(configuration, interval: DEFAULT_INTERVAL) | ||
| super(configuration.sdk_logger, interval) | ||
| ensure_thread | ||
| end | ||
|
|
||
| def run | ||
| ::Yabeda.collect! | ||
| rescue => e | ||
| log_warn("[Sentry::Yabeda::Collector] collection failed: #{e.message}") | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Sentry | ||
| class Configuration | ||
| after(:configured) do | ||
| if enable_metrics | ||
| Sentry::Yabeda.collector&.kill | ||
| Sentry::Yabeda.collector = Sentry::Yabeda::Collector.new(self) | ||
| end | ||
| end | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Collector thread leaks when re-initializing with metrics disabledMedium Severity The Additional Locations (1)Reviewed by Cursor Bugbot for commit 855c165. Configure here. |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Sentry | ||
| module Yabeda | ||
| VERSION = "6.5.0" | ||
| end | ||
| end |


Uh oh!
There was an error while loading. Please reload this page.