sentry-sidekiq-5.18.2/ 0000755 0000041 0000041 00000000000 14651361625 014623 5 ustar www-data www-data sentry-sidekiq-5.18.2/bin/ 0000755 0000041 0000041 00000000000 14651361625 015373 5 ustar www-data www-data sentry-sidekiq-5.18.2/bin/setup 0000755 0000041 0000041 00000000203 14651361625 016454 0 ustar www-data www-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/console 0000755 0000041 0000041 00000000532 14651361625 016763 0 ustar www-data www-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/.gitignore 0000644 0000041 0000041 00000000161 14651361625 016611 0 ustar www-data www-data /.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ # rspec failure tracking .rspec_status sentry-sidekiq-5.18.2/example/ 0000755 0000041 0000041 00000000000 14651361625 016256 5 ustar www-data www-data sentry-sidekiq-5.18.2/example/error_worker.rb 0000644 0000041 0000041 00000000575 14651361625 021334 0 ustar www-data www-data require "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/Gemfile 0000644 0000041 0000041 00000000237 14651361625 017553 0 ustar www-data www-data source "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.md 0000644 0000041 0000041 00000000322 14651361625 017532 0 ustar www-data www-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/ 0000755 0000041 0000041 00000000000 14651361625 017523 5 ustar www-data www-data sentry-sidekiq-5.18.2/example/config/sidekiq.yml 0000644 0000041 0000041 00000000111 14651361625 021670 0 ustar www-data www-data --- :verbose: false :concurrency: 10 :timeout: 25 :queues: - default sentry-sidekiq-5.18.2/lib/ 0000755 0000041 0000041 00000000000 14651361625 015371 5 ustar www-data www-data sentry-sidekiq-5.18.2/lib/sentry/ 0000755 0000041 0000041 00000000000 14651361625 016715 5 ustar www-data www-data sentry-sidekiq-5.18.2/lib/sentry/sidekiq-scheduler/ 0000755 0000041 0000041 00000000000 14651361625 022322 5 ustar www-data www-data sentry-sidekiq-5.18.2/lib/sentry/sidekiq-scheduler/scheduler.rb 0000644 0000041 0000041 00000006025 14651361625 024630 0 ustar www-data www-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/ 0000755 0000041 0000041 00000000000 14651361625 020346 5 ustar www-data www-data sentry-sidekiq-5.18.2/lib/sentry/sidekiq/configuration.rb 0000644 0000041 0000041 00000001123 14651361625 023537 0 ustar www-data www-data module 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.rb 0000644 0000041 0000041 00000004365 14651361625 026170 0 ustar www-data www-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/ 0000755 0000041 0000041 00000000000 14651361625 021307 5 ustar www-data www-data sentry-sidekiq-5.18.2/lib/sentry/sidekiq/cron/job.rb 0000644 0000041 0000041 00000002222 14651361625 022404 0 ustar www-data www-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.rb 0000644 0000041 0000041 00000005277 14651361625 023534 0 ustar www-data www-data require '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.rb 0000644 0000041 0000041 00000000100 14651361625 022347 0 ustar www-data www-data module Sentry module Sidekiq VERSION = "5.18.2" end end sentry-sidekiq-5.18.2/lib/sentry/sidekiq/context_filter.rb 0000644 0000041 0000041 00000004304 14651361625 023725 0 ustar www-data www-data module 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.rb 0000644 0000041 0000041 00000002336 14651361625 020675 0 ustar www-data www-data require "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.txt 0000644 0000041 0000041 00000002061 14651361625 016445 0 ustar www-data www-data 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. sentry-sidekiq-5.18.2/.rspec 0000644 0000041 0000041 00000000037 14651361625 015740 0 ustar www-data www-data --format documentation --color sentry-sidekiq-5.18.2/Rakefile 0000644 0000041 0000041 00000000247 14651361625 016273 0 ustar www-data www-data require "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/Gemfile 0000644 0000041 0000041 00000001567 14651361625 016127 0 ustar www-data www-data source "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.gemspec 0000644 0000041 0000041 00000002372 14651361625 021147 0 ustar www-data www-data require_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.md 0000644 0000041 0000041 00000003067 14651361625 016110 0 ustar www-data www-data
# sentry-sidekiq, the Sidekiq integration for Sentry's Ruby client --- [](https://rubygems.org/gems/sentry-sidekiq)  [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) [](https://rubygems.org/gems/sentry-sidekiq/) [](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.md 0000644 0000041 0000041 00000004511 14651361625 016435 0 ustar www-data www-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**