sentry-sidekiq-5.18.2/0000755000004100000410000000000014651361625014623 5ustar www-datawww-datasentry-sidekiq-5.18.2/bin/0000755000004100000410000000000014651361625015373 5ustar www-datawww-datasentry-sidekiq-5.18.2/bin/setup0000755000004100000410000000020314651361625016454 0ustar www-datawww-data#!/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 sentry-sidekiq-5.18.2/bin/console0000755000004100000410000000053214651361625016763 0ustar www-datawww-data#!/usr/bin/env ruby require "bundler/setup" require "sentry/ruby" # 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. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) sentry-sidekiq-5.18.2/.gitignore0000644000004100000410000000016114651361625016611 0ustar www-datawww-data/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ # rspec failure tracking .rspec_status sentry-sidekiq-5.18.2/example/0000755000004100000410000000000014651361625016256 5ustar www-datawww-datasentry-sidekiq-5.18.2/example/error_worker.rb0000644000004100000410000000057514651361625021334 0ustar www-datawww-datarequire "sidekiq" require "sentry-sidekiq" Sentry.init do |config| config.breadcrumbs_logger = [:sentry_logger] # replace it with your sentry dsn config.dsn = 'https://2fb45f003d054a7ea47feb45898f7649@o447951.ingest.sentry.io/5434472' end class ErrorWorker include Sidekiq::Worker sidekiq_options retry: 0 def perform 1 / 0 end end ErrorWorker.perform_async sentry-sidekiq-5.18.2/example/Gemfile0000644000004100000410000000023714651361625017553 0ustar www-datawww-datasource "https://rubygems.org" gem "sidekiq" gem "sentry-sidekiq", path: "../" gem "sentry-ruby", path: "../../sentry-ruby" gem "debug", github: "ruby/debug" sentry-sidekiq-5.18.2/example/README.md0000644000004100000410000000032214651361625017532 0ustar www-datawww-data# sentry-sidekiq example ## Usage 1. run `bundle install` 2. change the `dsn` inside `error_worker.rb` 3. run `bundle exec sidekiq -r ./error_worker.rb` 4. you should see the event from your Sentry dashboard sentry-sidekiq-5.18.2/example/config/0000755000004100000410000000000014651361625017523 5ustar www-datawww-datasentry-sidekiq-5.18.2/example/config/sidekiq.yml0000644000004100000410000000011114651361625021670 0ustar www-datawww-data--- :verbose: false :concurrency: 10 :timeout: 25 :queues: - default sentry-sidekiq-5.18.2/lib/0000755000004100000410000000000014651361625015371 5ustar www-datawww-datasentry-sidekiq-5.18.2/lib/sentry/0000755000004100000410000000000014651361625016715 5ustar www-datawww-datasentry-sidekiq-5.18.2/lib/sentry/sidekiq-scheduler/0000755000004100000410000000000014651361625022322 5ustar www-datawww-datasentry-sidekiq-5.18.2/lib/sentry/sidekiq-scheduler/scheduler.rb0000644000004100000410000000602514651361625024630 0ustar www-datawww-data# frozen_string_literal: true # Try to require sidekiq-scheduler to make sure it's loaded before the integration. begin require "sidekiq-scheduler" rescue LoadError return end # If we've loaded sidekiq-scheduler, but the API changed, # and the Scheduler class is not there, fail gracefully. return unless defined?(::SidekiqScheduler::Scheduler) module Sentry module SidekiqScheduler module Scheduler def new_job(name, interval_type, config, schedule, options) # Schedule the job upstream first # SidekiqScheduler does not validate schedules # It will fail with an error if the schedule in the config is invalid. # If this errors out, let it fall through. rufus_job = super klass = config.fetch("class") return rufus_job unless klass # Constantize the job class, and fail gracefully if it could not be found klass_const = begin Object.const_get(klass) rescue NameError return rufus_job end # For cron, every, or interval jobs — grab their schedule. # Rufus::Scheduler::EveryJob stores it's frequency in seconds, # so we convert it to minutes before passing in to the monitor. monitor_config = case interval_type when "cron" # fugit is a second order dependency of sidekiq-scheduler via rufus-scheduler parsed_cron = ::Fugit.parse_cron(schedule) timezone = parsed_cron.timezone # fugit supports having the timezone part of the cron string, # so we need to pull that with some hacky stuff if timezone parsed_cron.instance_variable_set(:@timezone, nil) cron_without_timezone = parsed_cron.to_cron_s Sentry::Cron::MonitorConfig.from_crontab(cron_without_timezone, timezone: timezone.name) else Sentry::Cron::MonitorConfig.from_crontab(schedule) end when "every", "interval" Sentry::Cron::MonitorConfig.from_interval(rufus_job.frequency.to_i / 60, :minute) end # If we couldn't build a monitor config, it's either an error, or # it's a one-time job (interval_type is in, or at), in which case # we should not make a monitof for it automaticaly. return rufus_job if monitor_config.nil? # only patch if not explicitly included in job by user unless klass_const.send(:ancestors).include?(Sentry::Cron::MonitorCheckIns) klass_const.send(:include, Sentry::Cron::MonitorCheckIns) slug = klass_const.send(:sentry_monitor_slug, name: name) klass_const.send(:sentry_monitor_check_ins, slug: slug, monitor_config: monitor_config) ::Sidekiq.logger.info "Injected Sentry Crons monitor checkins into #{klass}" end rufus_job end end end end Sentry.register_patch(:sidekiq_scheduler, Sentry::SidekiqScheduler::Scheduler, ::SidekiqScheduler::Scheduler) sentry-sidekiq-5.18.2/lib/sentry/sidekiq/0000755000004100000410000000000014651361625020346 5ustar www-datawww-datasentry-sidekiq-5.18.2/lib/sentry/sidekiq/configuration.rb0000644000004100000410000000112314651361625023537 0ustar www-datawww-datamodule Sentry class Configuration attr_reader :sidekiq add_post_initialization_callback do @sidekiq = Sentry::Sidekiq::Configuration.new @excluded_exceptions = @excluded_exceptions.concat(Sentry::Sidekiq::IGNORE_DEFAULT) end end module Sidekiq IGNORE_DEFAULT = ["Sidekiq::JobRetry::Skip"] class Configuration # Set this option to true if you want Sentry to only capture the last job # retry if it fails. attr_accessor :report_after_job_retries def initialize @report_after_job_retries = false end end end end sentry-sidekiq-5.18.2/lib/sentry/sidekiq/sentry_context_middleware.rb0000644000004100000410000000436514651361625026170 0ustar www-datawww-data# frozen_string_literal: true require 'sentry/sidekiq/context_filter' module Sentry module Sidekiq class SentryContextServerMiddleware OP_NAME = "queue.sidekiq" SPAN_ORIGIN = "auto.queue.sidekiq" def call(_worker, job, queue) return yield unless Sentry.initialized? context_filter = Sentry::Sidekiq::ContextFilter.new(job) Sentry.clone_hub_to_current_thread scope = Sentry.get_current_scope if (user = job["sentry_user"]) scope.set_user(user) end scope.set_tags(queue: queue, jid: job["jid"]) scope.set_tags(build_tags(job["tags"])) scope.set_contexts(sidekiq: job.merge("queue" => queue)) scope.set_transaction_name(context_filter.transaction_name, source: :task) transaction = start_transaction(scope, job["trace_propagation_headers"]) scope.set_span(transaction) if transaction begin yield rescue finish_transaction(transaction, 500) raise end finish_transaction(transaction, 200) # don't need to use ensure here # if the job failed, we need to keep the scope for error handler. and the scope will be cleared there scope.clear end def build_tags(tags) Array(tags).each_with_object({}) { |name, tags_hash| tags_hash[:"sidekiq.#{name}"] = true } end def start_transaction(scope, env) options = { name: scope.transaction_name, source: scope.transaction_source, op: OP_NAME, origin: SPAN_ORIGIN } transaction = Sentry.continue_trace(env, **options) Sentry.start_transaction(transaction: transaction, **options) end def finish_transaction(transaction, status) return unless transaction transaction.set_http_status(status) transaction.finish end end class SentryContextClientMiddleware def call(_worker_class, job, _queue, _redis_pool) return yield unless Sentry.initialized? user = Sentry.get_current_scope.user job["sentry_user"] = user unless user.empty? job["trace_propagation_headers"] ||= Sentry.get_trace_propagation_headers yield end end end end sentry-sidekiq-5.18.2/lib/sentry/sidekiq/cron/0000755000004100000410000000000014651361625021307 5ustar www-datawww-datasentry-sidekiq-5.18.2/lib/sentry/sidekiq/cron/job.rb0000644000004100000410000000222214651361625022404 0ustar www-datawww-data# frozen_string_literal: true # Try requiring sidekiq-cron to ensure it's loaded before the integration. # If sidekiq-cron is not available, do nothing. begin require "sidekiq-cron" rescue LoadError return end module Sentry module Sidekiq module Cron module Job def save # validation failed, do nothing return false unless super # fail gracefully if can't find class klass_const = begin ::Sidekiq::Cron::Support.constantize(klass.to_s) rescue NameError return true end # only patch if not explicitly included in job by user unless klass_const.send(:ancestors).include?(Sentry::Cron::MonitorCheckIns) klass_const.send(:include, Sentry::Cron::MonitorCheckIns) klass_const.send(:sentry_monitor_check_ins, slug: name, monitor_config: Sentry::Cron::MonitorConfig.from_crontab(cron)) end true end end end end end Sentry.register_patch(:sidekiq_cron, Sentry::Sidekiq::Cron::Job, ::Sidekiq::Cron::Job) sentry-sidekiq-5.18.2/lib/sentry/sidekiq/error_handler.rb0000644000004100000410000000527714651361625023534 0ustar www-datawww-datarequire 'sentry/sidekiq/context_filter' module Sentry module Sidekiq class ErrorHandler WITH_SIDEKIQ_7 = ::Gem::Version.new(::Sidekiq::VERSION) >= ::Gem::Version.new("7.0") # @param ex [Exception] the exception / error that occured # @param context [Hash or Array] Sidekiq error context # @param sidekiq_config [Sidekiq::Config, Hash] Sidekiq configuration, # Defaults to nil. # Sidekiq will pass the config in starting Sidekiq 7.1.5, see # https://github.com/sidekiq/sidekiq/pull/6051 def call(ex, context, sidekiq_config = nil) return unless Sentry.initialized? context_filter = Sentry::Sidekiq::ContextFilter.new(context) scope = Sentry.get_current_scope scope.set_transaction_name(context_filter.transaction_name, source: :task) unless scope.transaction_name # If Sentry is configured to only report an error _after_ all retries have been exhausted, # and if the job is retryable, and have not exceeded the retry_limit, # return early. if Sentry.configuration.sidekiq.report_after_job_retries && retryable?(context) retry_count = context.dig(:job, "retry_count") if retry_count.nil? || retry_count < retry_limit(context, sidekiq_config) - 1 return end end Sentry::Sidekiq.capture_exception( ex, contexts: { sidekiq: context_filter.filtered }, hint: { background: false } ) ensure scope&.clear end private def retryable?(context) retry_option = context.dig(:job, "retry") # when `retry` is not specified, it's default is `true` and it means 25 retries. retry_option == true || (retry_option.is_a?(Integer) && retry_option.positive?) end # @return [Integer] the number of retries allowed for the job # Tries to fetch the retry limit from the job config first, # then falls back to Sidekiq's configuration. def retry_limit(context, sidekiq_config) limit = context.dig(:job, "retry") case limit when Integer limit when TrueClass max_retries = if WITH_SIDEKIQ_7 # Sidekiq 7.1.5+ passes the config to the error handler, so we should use that. # Sidekiq 7.0 -> 7.1.5 provides ::Sidekiq.default_configuration. sidekiq_config.is_a?(::Sidekiq::Config) ? sidekiq_config[:max_retries] : ::Sidekiq.default_configuration[:max_retries] else ::Sidekiq.options[:max_retries] end max_retries || 25 else 0 end end end end end sentry-sidekiq-5.18.2/lib/sentry/sidekiq/version.rb0000644000004100000410000000010014651361625022347 0ustar www-datawww-datamodule Sentry module Sidekiq VERSION = "5.18.2" end end sentry-sidekiq-5.18.2/lib/sentry/sidekiq/context_filter.rb0000644000004100000410000000430414651361625023725 0ustar www-datawww-datamodule Sentry module Sidekiq class ContextFilter ACTIVEJOB_RESERVED_PREFIX_REGEX = /^_aj_/.freeze SIDEKIQ_NAME = "Sidekiq".freeze attr_reader :context def initialize(context) @context = context @has_global_id = defined?(GlobalID) end # Once an ActiveJob is queued, ActiveRecord references get serialized into # some internal reserved keys, such as _aj_globalid. # # The problem is, if this job in turn gets queued back into ActiveJob with # these magic reserved keys, ActiveJob will throw up and error. We want to # capture these and mutate the keys so we can sanely report it. def filtered filtered_context = filter_context(context) if job_entry = filtered_context.delete(:job) job_entry.each do |k, v| filtered_context[k] = v end end # Sidekiq 7.0 started adding `_config` to the context, which is not easily serialisable # And it's presence could be confusing so it's better to remove it until we decided to add it for a reason filtered_context.delete(:_config) filtered_context end def transaction_name class_name = (context["wrapped"] || context["class"] || (context[:job] && (context[:job]["wrapped"] || context[:job]["class"])) ) if class_name "#{SIDEKIQ_NAME}/#{class_name}" elsif context[:event] "#{SIDEKIQ_NAME}/#{context[:event]}" else SIDEKIQ_NAME end end private def filter_context(hash) case hash when Array hash.map { |arg| filter_context(arg) } when Hash Hash[hash.map { |key, value| filter_context_hash(key, value) }] else if has_global_id? && hash.is_a?(GlobalID) hash.to_s else hash end end end def filter_context_hash(key, value) key = key.to_s.sub(ACTIVEJOB_RESERVED_PREFIX_REGEX, "") if key.match(ACTIVEJOB_RESERVED_PREFIX_REGEX) [key, filter_context(value)] end def has_global_id? @has_global_id end end end end sentry-sidekiq-5.18.2/lib/sentry-sidekiq.rb0000644000004100000410000000233614651361625020675 0ustar www-datawww-datarequire "sidekiq" require "sentry-ruby" require "sentry/integrable" require "sentry/sidekiq/version" require "sentry/sidekiq/configuration" require "sentry/sidekiq/error_handler" require "sentry/sidekiq/sentry_context_middleware" module Sentry module Sidekiq extend Sentry::Integrable register_integration name: "sidekiq", version: Sentry::Sidekiq::VERSION if defined?(::Rails::Railtie) class Railtie < ::Rails::Railtie config.after_initialize do next unless Sentry.initialized? && defined?(::Sentry::Rails) Sentry.configuration.rails.skippable_job_adapters << "ActiveJob::QueueAdapters::SidekiqAdapter" end end end end end Sidekiq.configure_server do |config| config.error_handlers << Sentry::Sidekiq::ErrorHandler.new config.server_middleware do |chain| chain.add Sentry::Sidekiq::SentryContextServerMiddleware end config.client_middleware do |chain| chain.add Sentry::Sidekiq::SentryContextClientMiddleware end end Sidekiq.configure_client do |config| config.client_middleware do |chain| chain.add Sentry::Sidekiq::SentryContextClientMiddleware end end # patches require "sentry/sidekiq/cron/job" require "sentry/sidekiq-scheduler/scheduler" sentry-sidekiq-5.18.2/LICENSE.txt0000644000004100000410000000206114651361625016445 0ustar www-datawww-dataThe 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. sentry-sidekiq-5.18.2/.rspec0000644000004100000410000000003714651361625015740 0ustar www-datawww-data--format documentation --color sentry-sidekiq-5.18.2/Rakefile0000644000004100000410000000024714651361625016273 0ustar www-datawww-datarequire "bundler/gem_tasks" require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec).tap do |task| task.rspec_opts = "--order rand" end task default: :spec sentry-sidekiq-5.18.2/Gemfile0000644000004100000410000000156714651361625016127 0ustar www-datawww-datasource "https://rubygems.org" git_source(:github) { |name| "https://github.com/#{name}.git" } # Specify your gem's dependencies in sentry-ruby.gemspec gemspec gem "sentry-ruby", path: "../sentry-ruby" gem "sentry-rails", path: "../sentry-rails" # https://github.com/flavorjones/loofah/pull/267 # loofah changed the required ruby version in a patch so we need to explicitly pin it gem "loofah", "2.20.0" if RUBY_VERSION.to_f < 2.5 # For https://github.com/ruby/psych/issues/655 gem "psych", "5.1.0" sidekiq_version = ENV["SIDEKIQ_VERSION"] sidekiq_version = "7.0" if sidekiq_version.nil? sidekiq_version = Gem::Version.new(sidekiq_version) gem "sidekiq", "~> #{sidekiq_version}" if RUBY_VERSION.to_f >= 2.7 && sidekiq_version >= Gem::Version.new("6.0") gem "sidekiq-cron" gem "sidekiq-scheduler" end gem "rails", "> 5.0.0" eval_gemfile File.expand_path("../Gemfile", __dir__) sentry-sidekiq-5.18.2/sentry-sidekiq.gemspec0000644000004100000410000000237214651361625021147 0ustar www-datawww-datarequire_relative "lib/sentry/sidekiq/version" Gem::Specification.new do |spec| spec.name = "sentry-sidekiq" spec.version = Sentry::Sidekiq::VERSION spec.authors = ["Sentry Team"] spec.description = spec.summary = "A gem that provides Sidekiq integration for the Sentry error logger" spec.email = "accounts@sentry.io" spec.license = 'MIT' spec.platform = Gem::Platform::RUBY spec.required_ruby_version = '>= 2.4' spec.extra_rdoc_files = ["README.md", "LICENSE.txt"] spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n") github_root_uri = 'https://github.com/getsentry/sentry-ruby' spec.homepage = "#{github_root_uri}/tree/#{spec.version}/#{spec.name}" spec.metadata = { "homepage_uri" => spec.homepage, "source_code_uri" => spec.homepage, "changelog_uri" => "#{github_root_uri}/blob/#{spec.version}/CHANGELOG.md", "bug_tracker_uri" => "#{github_root_uri}/issues", "documentation_uri" => "http://www.rubydoc.info/gems/#{spec.name}/#{spec.version}" } spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] spec.add_dependency "sentry-ruby", "~> 5.18.2" spec.add_dependency "sidekiq", ">= 3.0" end sentry-sidekiq-5.18.2/README.md0000644000004100000410000000306714651361625016110 0ustar www-datawww-data


# sentry-sidekiq, the Sidekiq integration for Sentry's Ruby client --- [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq) ![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml/badge.svg) [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) [![Gem](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver) [Documentation](https://docs.sentry.io/platforms/ruby/guides/sidekiq/) | [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-sidekiq" ``` Then you're all set! `sentry-sidekiq` will automatically insert a custom middleware and error handler to capture exceptions from your workers! sentry-sidekiq-5.18.2/CHANGELOG.md0000644000004100000410000000451114651361625016435 0ustar www-datawww-data# Changelog Individual gem's changelog has been deprecated. Please check the [project changelog](https://github.com/getsentry/sentry-ruby/blob/master/CHANGELOG.md). ## 4.4.0 ### Features - Make Sidekiq job context more readable [#1410](https://github.com/getsentry/sentry-ruby/pull/1410) **Before** Sidekiq payload in extra **After** Sidekiq payload in context ## 4.3.0 ### Features - Support performance monitoring on Sidekiq workers [#1311](https://github.com/getsentry/sentry-ruby/pull/1311) ## 4.2.1 - Use ::Rails::Railtie for checking Rails definition [#1284](https://github.com/getsentry/sentry-ruby/pull/1284) - Fixes [#1276](https://github.com/getsentry/sentry-ruby/issues/1276) ## 4.2.0 ### Features - Tag queue name and jid on sidekiq events [#1258](https://github.com/getsentry/sentry-ruby/pull/1258) sidekiq event tagged with queue name and jid ### Refactorings - Add sidekiq adapter to sentry-rails' ignored adapters list [#1257](https://github.com/getsentry/sentry-ruby/pull/1257) ## 4.1.3 - Use sentry-ruby-core as the main SDK dependency [#1245](https://github.com/getsentry/sentry-ruby/pull/1245) ## 4.1.2 - Fix sidekiq middleware [#1175](https://github.com/getsentry/sentry-ruby/pull/1175) - Fixes [#1173](https://github.com/getsentry/sentry-ruby/issues/1173) - Adopt Integrable module [#1177](https://github.com/getsentry/sentry-ruby/pull/1177) ## 4.1.1 - Use stricter dependency declaration [#1159](https://github.com/getsentry/sentry-ruby/pull/1159) ## 4.1.0 - Check SDK initialization before running integrations [#1151](https://github.com/getsentry/sentry-ruby/pull/1151) - Fixes [#1145](https://github.com/getsentry/sentry-ruby/pull/1145) ## 4.0.0 - Only documents update for the official release and no API/feature changes. ## 0.2.0 - Major API changes: [1123](https://github.com/getsentry/sentry-ruby/pull/1123) ## 0.1.3 - Small fixes ## 0.1.2 Fix require reference ## 0.1.1 Release test ## 0.1.0 First version sentry-sidekiq-5.18.2/Makefile0000644000004100000410000000022414651361625016261 0ustar www-datawww-databuild: bundle install gem build sentry-sidekiq.gemspec test: WITH_SENTRY_RAILS=1 bundle exec rspec spec/sentry/rails_spec.rb bundle exec rspec