appsignal 2.10.7-java → 2.11.0.alpha.2-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.semaphore/semaphore.yml +45 -53
- data/CHANGELOG.md +18 -0
- data/build_matrix.yml +13 -6
- data/ext/agent.yml +19 -19
- data/ext/appsignal_extension.c +10 -1
- data/ext/base.rb +15 -4
- data/gemfiles/padrino.gemfile +2 -2
- data/lib/appsignal.rb +21 -1
- data/lib/appsignal/capistrano.rb +2 -0
- data/lib/appsignal/config.rb +6 -2
- data/lib/appsignal/environment.rb +126 -0
- data/lib/appsignal/extension/jruby.rb +10 -0
- data/lib/appsignal/hooks/net_http.rb +2 -0
- data/lib/appsignal/hooks/puma.rb +2 -58
- data/lib/appsignal/hooks/redis.rb +2 -0
- data/lib/appsignal/hooks/sequel.rb +2 -0
- data/lib/appsignal/hooks/sidekiq.rb +2 -99
- data/lib/appsignal/integrations/delayed_job_plugin.rb +16 -3
- data/lib/appsignal/integrations/object.rb +4 -0
- data/lib/appsignal/integrations/resque_active_job.rb +12 -4
- data/lib/appsignal/probes/puma.rb +61 -0
- data/lib/appsignal/probes/sidekiq.rb +102 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +5 -2
- data/lib/appsignal/transaction.rb +22 -7
- data/lib/appsignal/version.rb +1 -1
- data/lib/puma/plugin/appsignal.rb +2 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +2 -1
- data/spec/lib/appsignal/config_spec.rb +6 -1
- data/spec/lib/appsignal/environment_spec.rb +167 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +198 -166
- data/spec/lib/appsignal/hooks/puma_spec.rb +2 -181
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +256 -462
- data/spec/lib/appsignal/integrations/padrino_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +55 -13
- data/spec/lib/appsignal/probes/puma_spec.rb +180 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +201 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -4
- data/spec/lib/appsignal/transaction_spec.rb +30 -13
- data/spec/lib/appsignal_spec.rb +22 -0
- data/spec/lib/puma/appsignal_spec.rb +1 -1
- data/spec/support/helpers/dependency_helper.rb +5 -0
- data/spec/support/helpers/env_helpers.rb +1 -1
- data/spec/support/helpers/environment_metdata_helper.rb +16 -0
- data/spec/support/stubs/sidekiq/api.rb +1 -1
- metadata +19 -8
    
        data/ext/appsignal_extension.c
    CHANGED
    
    | @@ -639,6 +639,14 @@ static VALUE running_in_container() { | |
| 639 639 | 
             
              return appsignal_running_in_container() == 1 ? Qtrue : Qfalse;
         | 
| 640 640 | 
             
            }
         | 
| 641 641 |  | 
| 642 | 
            +
            static VALUE set_environment_metadata(VALUE self, VALUE key, VALUE value) {
         | 
| 643 | 
            +
              appsignal_set_environment_metadata(
         | 
| 644 | 
            +
                  make_appsignal_string(key),
         | 
| 645 | 
            +
                  make_appsignal_string(value)
         | 
| 646 | 
            +
              );
         | 
| 647 | 
            +
              return Qnil;
         | 
| 648 | 
            +
            }
         | 
| 649 | 
            +
             | 
| 642 650 | 
             
            void Init_appsignal_extension(void) {
         | 
| 643 651 | 
             
              Appsignal = rb_define_module("Appsignal");
         | 
| 644 652 | 
             
              Extension = rb_define_class_under(Appsignal, "Extension", rb_cObject);
         | 
| @@ -697,9 +705,10 @@ void Init_appsignal_extension(void) { | |
| 697 705 | 
             
              // Get JSON content of a data
         | 
| 698 706 | 
             
              rb_define_method(Data, "to_s", data_to_s, 0);
         | 
| 699 707 |  | 
| 700 | 
            -
              //  | 
| 708 | 
            +
              // Other helper methods
         | 
| 701 709 | 
             
              rb_define_singleton_method(Extension, "install_allocation_event_hook", install_allocation_event_hook, 0);
         | 
| 702 710 | 
             
              rb_define_singleton_method(Extension, "running_in_container?", running_in_container, 0);
         | 
| 711 | 
            +
              rb_define_singleton_method(Extension, "set_environment_metadata", set_environment_metadata, 2);
         | 
| 703 712 |  | 
| 704 713 | 
             
              // Metrics
         | 
| 705 714 | 
             
              rb_define_singleton_method(Extension, "set_gauge",              set_gauge,              3);
         | 
    
        data/ext/base.rb
    CHANGED
    
    | @@ -32,7 +32,8 @@ def report | |
| 32 32 | 
             
                      "version" => "#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"
         | 
| 33 33 | 
             
                    },
         | 
| 34 34 | 
             
                    "download" => {
         | 
| 35 | 
            -
                      "checksum" => "unverified"
         | 
| 35 | 
            +
                      "checksum" => "unverified",
         | 
| 36 | 
            +
                      "http_proxy" => http_proxy
         | 
| 36 37 | 
             
                    },
         | 
| 37 38 | 
             
                    "build" => {
         | 
| 38 39 | 
             
                      "time" => Time.now.utc,
         | 
| @@ -126,7 +127,11 @@ def download_archive(type) | |
| 126 127 | 
             
                report["download"]["download_url"] = download_url
         | 
| 127 128 |  | 
| 128 129 | 
             
                begin
         | 
| 129 | 
            -
                  return open( | 
| 130 | 
            +
                  return open(
         | 
| 131 | 
            +
                    download_url,
         | 
| 132 | 
            +
                    :ssl_ca_cert => CA_CERT_PATH,
         | 
| 133 | 
            +
                    :proxy => http_proxy
         | 
| 134 | 
            +
                  )
         | 
| 130 135 | 
             
                rescue
         | 
| 131 136 | 
             
                  next
         | 
| 132 137 | 
             
                end
         | 
| @@ -142,14 +147,16 @@ def download_archive(type) | |
| 142 147 | 
             
            end
         | 
| 143 148 |  | 
| 144 149 | 
             
            def verify_archive(archive, type)
         | 
| 145 | 
            -
               | 
| 150 | 
            +
              expected_checksum = ARCH_CONFIG[type]["checksum"]
         | 
| 151 | 
            +
              actual_checksum = Digest::SHA256.hexdigest(archive.read)
         | 
| 152 | 
            +
              if actual_checksum == expected_checksum
         | 
| 146 153 | 
             
                report["download"]["checksum"] = "verified"
         | 
| 147 154 | 
             
                true
         | 
| 148 155 | 
             
              else
         | 
| 149 156 | 
             
                report["download"]["checksum"] = "invalid"
         | 
| 150 157 | 
             
                abort_installation(
         | 
| 151 158 | 
             
                  "Checksum of downloaded archive could not be verified: " \
         | 
| 152 | 
            -
                    "Expected '#{ | 
| 159 | 
            +
                    "Expected '#{expected_checksum}', got '#{actual_checksum}'."
         | 
| 153 160 | 
             
                )
         | 
| 154 161 | 
             
              end
         | 
| 155 162 | 
             
            end
         | 
| @@ -172,3 +179,7 @@ def store_download_version_on_report | |
| 172 179 | 
             
              path = File.expand_path(File.join(File.dirname(__FILE__), "appsignal.version"))
         | 
| 173 180 | 
             
              report["build"]["agent_version"] = File.read(path).strip
         | 
| 174 181 | 
             
            end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
            def http_proxy
         | 
| 184 | 
            +
              Gem.configuration[:http_proxy] || ENV["http_proxy"] || ENV["HTTP_PROXY"]
         | 
| 185 | 
            +
            end
         | 
    
        data/gemfiles/padrino.gemfile
    CHANGED
    
    
    
        data/lib/appsignal.rb
    CHANGED
    
    | @@ -134,11 +134,17 @@ module Appsignal | |
| 134 134 |  | 
| 135 135 | 
             
                      if config[:enable_allocation_tracking] && !Appsignal::System.jruby?
         | 
| 136 136 | 
             
                        Appsignal::Extension.install_allocation_event_hook
         | 
| 137 | 
            +
                        Appsignal::Environment.report_enabled("allocation_tracking")
         | 
| 137 138 | 
             
                      end
         | 
| 138 139 |  | 
| 139 | 
            -
                       | 
| 140 | 
            +
                      if config[:enable_gc_instrumentation]
         | 
| 141 | 
            +
                        GC::Profiler.enable
         | 
| 142 | 
            +
                        Appsignal::Environment.report_enabled("gc_instrumentation")
         | 
| 143 | 
            +
                      end
         | 
| 140 144 |  | 
| 141 145 | 
             
                      Appsignal::Minutely.start if config[:enable_minutely_probes]
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                      collect_environment_metadata
         | 
| 142 148 | 
             
                    else
         | 
| 143 149 | 
             
                      logger.info("Not starting, not active for #{config.env}")
         | 
| 144 150 | 
             
                    end
         | 
| @@ -309,9 +315,23 @@ module Appsignal | |
| 309 315 | 
             
                  logger.warn "Unable to start logger with log path '#{path}'."
         | 
| 310 316 | 
             
                  logger.warn error
         | 
| 311 317 | 
             
                end
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                def collect_environment_metadata
         | 
| 320 | 
            +
                  Appsignal::Environment.report("ruby_version") do
         | 
| 321 | 
            +
                    "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
         | 
| 322 | 
            +
                  end
         | 
| 323 | 
            +
                  Appsignal::Environment.report("ruby_engine") { RUBY_ENGINE }
         | 
| 324 | 
            +
                  if defined?(RUBY_ENGINE_VERSION)
         | 
| 325 | 
            +
                    Appsignal::Environment.report("ruby_engine_version") do
         | 
| 326 | 
            +
                      RUBY_ENGINE_VERSION
         | 
| 327 | 
            +
                    end
         | 
| 328 | 
            +
                  end
         | 
| 329 | 
            +
                  Appsignal::Environment.report_supported_gems
         | 
| 330 | 
            +
                end
         | 
| 312 331 | 
             
              end
         | 
| 313 332 | 
             
            end
         | 
| 314 333 |  | 
| 334 | 
            +
            require "appsignal/environment"
         | 
| 315 335 | 
             
            require "appsignal/system"
         | 
| 316 336 | 
             
            require "appsignal/utils"
         | 
| 317 337 | 
             
            require "appsignal/extension"
         | 
    
        data/lib/appsignal/capistrano.rb
    CHANGED
    
    | @@ -3,6 +3,8 @@ | |
| 3 3 | 
             
            require "appsignal"
         | 
| 4 4 | 
             
            require "capistrano/version"
         | 
| 5 5 |  | 
| 6 | 
            +
            Appsignal::Environment.report_enabled("capistrano")
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
            if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION) >= Gem::Version.new(3)
         | 
| 7 9 | 
             
              # Capistrano 3+
         | 
| 8 10 | 
             
              load File.expand_path("../integrations/capistrano/appsignal.cap", __FILE__)
         | 
    
        data/lib/appsignal/config.rb
    CHANGED
    
    | @@ -18,6 +18,7 @@ module Appsignal | |
| 18 18 | 
             
                  :ignore_namespaces              => [],
         | 
| 19 19 | 
             
                  :filter_parameters              => [],
         | 
| 20 20 | 
             
                  :filter_session_data            => [],
         | 
| 21 | 
            +
                  :send_environment_metadata      => true,
         | 
| 21 22 | 
             
                  :send_params                    => true,
         | 
| 22 23 | 
             
                  :request_headers                => %w[
         | 
| 23 24 | 
             
                    HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
         | 
| @@ -62,6 +63,7 @@ module Appsignal | |
| 62 63 | 
             
                  "APPSIGNAL_IGNORE_NAMESPACES"              => :ignore_namespaces,
         | 
| 63 64 | 
             
                  "APPSIGNAL_FILTER_PARAMETERS"              => :filter_parameters,
         | 
| 64 65 | 
             
                  "APPSIGNAL_FILTER_SESSION_DATA"            => :filter_session_data,
         | 
| 66 | 
            +
                  "APPSIGNAL_SEND_ENVIRONMENT_METADATA"      => :send_environment_metadata,
         | 
| 65 67 | 
             
                  "APPSIGNAL_SEND_PARAMS"                    => :send_params,
         | 
| 66 68 | 
             
                  "APPSIGNAL_HTTP_PROXY"                     => :http_proxy,
         | 
| 67 69 | 
             
                  "APPSIGNAL_ENABLE_ALLOCATION_TRACKING"     => :enable_allocation_tracking,
         | 
| @@ -222,6 +224,7 @@ module Appsignal | |
| 222 224 | 
             
                  ENV["_APPSIGNAL_DNS_SERVERS"]                  = config_hash[:dns_servers].join(",")
         | 
| 223 225 | 
             
                  ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]       = config_hash[:files_world_accessible].to_s
         | 
| 224 226 | 
             
                  ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]       = config_hash[:transaction_debug_mode].to_s
         | 
| 227 | 
            +
                  ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"]    = config_hash[:send_environment_metadata].to_s
         | 
| 225 228 | 
             
                  ENV["_APP_REVISION"]                           = config_hash[:revision].to_s
         | 
| 226 229 | 
             
                end
         | 
| 227 230 |  | 
| @@ -337,8 +340,9 @@ module Appsignal | |
| 337 340 | 
             
                     APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING
         | 
| 338 341 | 
             
                     APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
         | 
| 339 342 | 
             
                     APPSIGNAL_RUNNING_IN_CONTAINER APPSIGNAL_ENABLE_HOST_METRICS
         | 
| 340 | 
            -
                     APPSIGNAL_SEND_PARAMS | 
| 341 | 
            -
                     APPSIGNAL_FILES_WORLD_ACCESSIBLE | 
| 343 | 
            +
                     APPSIGNAL_SEND_ENVIRONMENT_METADATA APPSIGNAL_SEND_PARAMS
         | 
| 344 | 
            +
                     APPSIGNAL_ENABLE_MINUTELY_PROBES APPSIGNAL_FILES_WORLD_ACCESSIBLE
         | 
| 345 | 
            +
                     APPSIGNAL_TRANSACTION_DEBUG_MODE].each do |var|
         | 
| 342 346 | 
             
                    env_var = ENV[var]
         | 
| 343 347 | 
             
                    next unless env_var
         | 
| 344 348 | 
             
                    config[ENV_TO_KEY_MAPPING[var]] = env_var.casecmp("true").zero?
         | 
| @@ -0,0 +1,126 @@ | |
| 1 | 
            +
            module Appsignal
         | 
| 2 | 
            +
              # @api private
         | 
| 3 | 
            +
              class Environment
         | 
| 4 | 
            +
                # Add environment metadata.
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # The key and value of the environment metadata must be a String, even if
         | 
| 7 | 
            +
                # it's actually of another type.
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                # The value of the environment metadata is given as a block that captures
         | 
| 10 | 
            +
                # errors that might be raised while fetching the value. It will not
         | 
| 11 | 
            +
                # re-raise errors, but instead log them using the {Appsignal.logger}. This
         | 
| 12 | 
            +
                # ensures AppSignal will not cause an error in the application when
         | 
| 13 | 
            +
                # collecting this metadata.
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # @example Reporting a key and value
         | 
| 16 | 
            +
                #   Appsignal::Environment.report("ruby_version") { RUBY_VERSION }
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # @example When a value is nil
         | 
| 19 | 
            +
                #   Appsignal::Environment.report("ruby_version") { nil }
         | 
| 20 | 
            +
                #   # Key and value do not get reported. A warning gets logged instead.
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                # @example When an error occurs
         | 
| 23 | 
            +
                #   Appsignal::Environment.report("ruby_version") { raise "uh oh" }
         | 
| 24 | 
            +
                #   # Error does not get reraised. A warning gets logged instead.
         | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                # @param key [String] The name of the key of the environment metadata value.
         | 
| 27 | 
            +
                # @yieldreturn [String] The value of the key of the environment metadata.
         | 
| 28 | 
            +
                # @return [void]
         | 
| 29 | 
            +
                def self.report(key)
         | 
| 30 | 
            +
                  key =
         | 
| 31 | 
            +
                    case key
         | 
| 32 | 
            +
                    when String
         | 
| 33 | 
            +
                      key
         | 
| 34 | 
            +
                    else
         | 
| 35 | 
            +
                      Appsignal.logger.error "Unable to report on environment metadata: " \
         | 
| 36 | 
            +
                        "Unsupported value type for #{key.inspect}"
         | 
| 37 | 
            +
                      return
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  yielded_value =
         | 
| 41 | 
            +
                    begin
         | 
| 42 | 
            +
                      yield
         | 
| 43 | 
            +
                    rescue => e
         | 
| 44 | 
            +
                      Appsignal.logger.error \
         | 
| 45 | 
            +
                        "Unable to report on environment metadata #{key.inspect}:\n" \
         | 
| 46 | 
            +
                          "#{e.class}: #{e}"
         | 
| 47 | 
            +
                      return
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  value =
         | 
| 51 | 
            +
                    case yielded_value
         | 
| 52 | 
            +
                    when TrueClass, FalseClass
         | 
| 53 | 
            +
                      yielded_value.to_s
         | 
| 54 | 
            +
                    when String
         | 
| 55 | 
            +
                      yielded_value
         | 
| 56 | 
            +
                    else
         | 
| 57 | 
            +
                      Appsignal.logger.error "Unable to report on environment metadata " \
         | 
| 58 | 
            +
                        "#{key.inspect}: Unsupported value type for " \
         | 
| 59 | 
            +
                        "#{yielded_value.inspect}"
         | 
| 60 | 
            +
                      return
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  Appsignal::Extension.set_environment_metadata(key, value)
         | 
| 64 | 
            +
                rescue => e
         | 
| 65 | 
            +
                  Appsignal.logger.error "Unable to report on environment metadata:\n" \
         | 
| 66 | 
            +
                    "#{e.class}: #{e}"
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                # @see report_supported_gems
         | 
| 70 | 
            +
                SUPPORTED_GEMS = %w[
         | 
| 71 | 
            +
                  actioncable
         | 
| 72 | 
            +
                  activejob
         | 
| 73 | 
            +
                  capistrano
         | 
| 74 | 
            +
                  celluloid
         | 
| 75 | 
            +
                  data_mapper
         | 
| 76 | 
            +
                  delayed_job
         | 
| 77 | 
            +
                  mongo_ruby_driver
         | 
| 78 | 
            +
                  padrino
         | 
| 79 | 
            +
                  passenger
         | 
| 80 | 
            +
                  puma
         | 
| 81 | 
            +
                  que
         | 
| 82 | 
            +
                  rack
         | 
| 83 | 
            +
                  rails
         | 
| 84 | 
            +
                  rake
         | 
| 85 | 
            +
                  redis
         | 
| 86 | 
            +
                  resque
         | 
| 87 | 
            +
                  sequel
         | 
| 88 | 
            +
                  shoryuken
         | 
| 89 | 
            +
                  sidekiq
         | 
| 90 | 
            +
                  sinatra
         | 
| 91 | 
            +
                  unicorn
         | 
| 92 | 
            +
                  webmachine
         | 
| 93 | 
            +
                ].freeze
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                # Report on the list of AppSignal supported gems
         | 
| 96 | 
            +
                #
         | 
| 97 | 
            +
                # This list is used to report if which AppSignal supported gems are present
         | 
| 98 | 
            +
                # in this app and what version. This data will help AppSignal improve its
         | 
| 99 | 
            +
                # support by knowing what gems and versions of gems it still needs to
         | 
| 100 | 
            +
                # support or can drop support for.
         | 
| 101 | 
            +
                #
         | 
| 102 | 
            +
                # It will ask Bundler to report name and version information from the gems
         | 
| 103 | 
            +
                # that are present in the app bundle.
         | 
| 104 | 
            +
                def self.report_supported_gems
         | 
| 105 | 
            +
                  return unless defined?(Bundler) # Do nothing if Bundler is not present
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  bundle_gem_specs = ::Bundler.rubygems.all_specs
         | 
| 108 | 
            +
                  SUPPORTED_GEMS.each do |gem_name|
         | 
| 109 | 
            +
                    gem_spec = bundle_gem_specs.find { |spec| spec.name == gem_name }
         | 
| 110 | 
            +
                    next unless gem_spec
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    report("ruby_#{gem_name}_version") { gem_spec.version.to_s }
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
                rescue => e
         | 
| 115 | 
            +
                  Appsignal.logger.error "Unable to report supported gems:\n" \
         | 
| 116 | 
            +
                    "#{e.class}: #{e}"
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                def self.report_enabled(feature)
         | 
| 120 | 
            +
                  Appsignal::Environment.report("ruby_#{feature}_enabled") { true }
         | 
| 121 | 
            +
                rescue => e
         | 
| 122 | 
            +
                  Appsignal.logger.error "Unable to report integration enabled:\n" \
         | 
| 123 | 
            +
                    "#{e.class}: #{e}"
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
            end
         | 
| @@ -60,6 +60,9 @@ module Appsignal | |
| 60 60 | 
             
                      [:appsignal_string],
         | 
| 61 61 | 
             
                      :appsignal_string
         | 
| 62 62 | 
             
                    attach_function :appsignal_running_in_container, [], :bool
         | 
| 63 | 
            +
                    attach_function :appsignal_set_environment_metadata,
         | 
| 64 | 
            +
                      [:appsignal_string, :appsignal_string],
         | 
| 65 | 
            +
                      :void
         | 
| 63 66 |  | 
| 64 67 | 
             
                    # Metrics methods
         | 
| 65 68 | 
             
                    attach_function :appsignal_set_gauge,
         | 
| @@ -224,6 +227,13 @@ module Appsignal | |
| 224 227 | 
             
                    appsignal_running_in_container
         | 
| 225 228 | 
             
                  end
         | 
| 226 229 |  | 
| 230 | 
            +
                  def set_environment_metadata(key, value)
         | 
| 231 | 
            +
                    appsignal_set_environment_metadata(
         | 
| 232 | 
            +
                      make_appsignal_string(key),
         | 
| 233 | 
            +
                      make_appsignal_string(value)
         | 
| 234 | 
            +
                    )
         | 
| 235 | 
            +
                  end
         | 
| 236 | 
            +
             | 
| 227 237 | 
             
                  def set_gauge(key, value, tags)
         | 
| 228 238 | 
             
                    appsignal_set_gauge(make_appsignal_string(key), value, tags.pointer)
         | 
| 229 239 | 
             
                  end
         | 
    
        data/lib/appsignal/hooks/puma.rb
    CHANGED
    
    | @@ -24,7 +24,8 @@ module Appsignal | |
| 24 24 | 
             
                      # runs in the Puma main process.
         | 
| 25 25 | 
             
                      # For more information:
         | 
| 26 26 | 
             
                      # https://docs.appsignal.com/ruby/integrations/puma.html
         | 
| 27 | 
            -
                       | 
| 27 | 
            +
                      require "appsignal/probes/puma"
         | 
| 28 | 
            +
                      Appsignal::Minutely.probes.register :puma, ::Appsignal::Probes::PumaProbe
         | 
| 28 29 | 
             
                    end
         | 
| 29 30 |  | 
| 30 31 | 
             
                    return unless defined?(::Puma::Cluster)
         | 
| @@ -39,62 +40,5 @@ module Appsignal | |
| 39 40 | 
             
                    end
         | 
| 40 41 | 
             
                  end
         | 
| 41 42 | 
             
                end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                class PumaProbe
         | 
| 44 | 
            -
                  def initialize
         | 
| 45 | 
            -
                    @hostname = Appsignal.config[:hostname] || Socket.gethostname
         | 
| 46 | 
            -
                  end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                  def call
         | 
| 49 | 
            -
                    puma_stats = fetch_puma_stats
         | 
| 50 | 
            -
                    return unless puma_stats
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                    stats = JSON.parse puma_stats, :symbolize_names => true
         | 
| 53 | 
            -
                    counts = {}
         | 
| 54 | 
            -
                    count_keys = [:backlog, :running, :pool_capacity, :max_threads]
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    if stats[:worker_status] # Multiple workers
         | 
| 57 | 
            -
                      stats[:worker_status].each do |worker|
         | 
| 58 | 
            -
                        stat = worker[:last_status]
         | 
| 59 | 
            -
                        count_keys.each do |key|
         | 
| 60 | 
            -
                          count_if_present counts, key, stat
         | 
| 61 | 
            -
                        end
         | 
| 62 | 
            -
                      end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                      gauge(:workers, stats[:workers], :type => :count)
         | 
| 65 | 
            -
                      gauge(:workers, stats[:booted_workers], :type => :booted)
         | 
| 66 | 
            -
                      gauge(:workers, stats[:old_workers], :type => :old)
         | 
| 67 | 
            -
                    else # Single worker
         | 
| 68 | 
            -
                      count_keys.each do |key|
         | 
| 69 | 
            -
                        count_if_present counts, key, stats
         | 
| 70 | 
            -
                      end
         | 
| 71 | 
            -
                    end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    gauge(:connection_backlog, counts[:backlog]) if counts[:backlog]
         | 
| 74 | 
            -
                    gauge(:pool_capacity, counts[:pool_capacity]) if counts[:pool_capacity]
         | 
| 75 | 
            -
                    gauge(:threads, counts[:running], :type => :running) if counts[:running]
         | 
| 76 | 
            -
                    gauge(:threads, counts[:max_threads], :type => :max) if counts[:max_threads]
         | 
| 77 | 
            -
                  end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                  private
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                  attr_reader :hostname
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  def gauge(field, count, tags = {})
         | 
| 84 | 
            -
                    Appsignal.set_gauge("puma_#{field}", count, tags.merge(:hostname => hostname))
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                  def count_if_present(counts, key, stats)
         | 
| 88 | 
            -
                    stat_value = stats[key]
         | 
| 89 | 
            -
                    return unless stat_value
         | 
| 90 | 
            -
                    counts[key] ||= 0
         | 
| 91 | 
            -
                    counts[key] += stat_value
         | 
| 92 | 
            -
                  end
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                  def fetch_puma_stats
         | 
| 95 | 
            -
                    ::Puma.stats
         | 
| 96 | 
            -
                  rescue NoMethodError # rubocop:disable Lint/HandleExceptions
         | 
| 97 | 
            -
                  end
         | 
| 98 | 
            -
                end
         | 
| 99 43 | 
             
              end
         | 
| 100 44 | 
             
            end
         | 
| @@ -12,7 +12,8 @@ module Appsignal | |
| 12 12 | 
             
                  end
         | 
| 13 13 |  | 
| 14 14 | 
             
                  def install
         | 
| 15 | 
            -
                     | 
| 15 | 
            +
                    require "appsignal/probes/sidekiq"
         | 
| 16 | 
            +
                    Appsignal::Minutely.probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
         | 
| 16 17 |  | 
| 17 18 | 
             
                    ::Sidekiq.configure_server do |config|
         | 
| 18 19 | 
             
                      config.server_middleware do |chain|
         | 
| @@ -22,104 +23,6 @@ module Appsignal | |
| 22 23 | 
             
                  end
         | 
| 23 24 | 
             
                end
         | 
| 24 25 |  | 
| 25 | 
            -
                class SidekiqProbe
         | 
| 26 | 
            -
                  attr_reader :config
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                  def self.dependencies_present?
         | 
| 29 | 
            -
                    Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
         | 
| 30 | 
            -
                  end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                  def initialize(config = {})
         | 
| 33 | 
            -
                    @config = config
         | 
| 34 | 
            -
                    @cache = {}
         | 
| 35 | 
            -
                    config_string = " with config: #{config}" unless config.empty?
         | 
| 36 | 
            -
                    Appsignal.logger.debug("Initializing Sidekiq probe#{config_string}")
         | 
| 37 | 
            -
                    require "sidekiq/api"
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                  def call
         | 
| 41 | 
            -
                    track_redis_info
         | 
| 42 | 
            -
                    track_stats
         | 
| 43 | 
            -
                    track_queues
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  private
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                  attr_reader :cache
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                  def track_redis_info
         | 
| 51 | 
            -
                    return unless ::Sidekiq.respond_to?(:redis_info)
         | 
| 52 | 
            -
                    redis_info = ::Sidekiq.redis_info
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                    gauge "connection_count", redis_info.fetch("connected_clients")
         | 
| 55 | 
            -
                    gauge "memory_usage", redis_info.fetch("used_memory")
         | 
| 56 | 
            -
                    gauge "memory_usage_rss", redis_info.fetch("used_memory_rss")
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  def track_stats
         | 
| 60 | 
            -
                    stats = ::Sidekiq::Stats.new
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                    gauge "worker_count", stats.workers_size
         | 
| 63 | 
            -
                    gauge "process_count", stats.processes_size
         | 
| 64 | 
            -
                    gauge_delta :jobs_processed, "job_count", stats.processed,
         | 
| 65 | 
            -
                      :status => :processed
         | 
| 66 | 
            -
                    gauge_delta :jobs_failed, "job_count", stats.failed, :status => :failed
         | 
| 67 | 
            -
                    gauge "job_count", stats.retry_size, :status => :retry_queue
         | 
| 68 | 
            -
                    gauge_delta :jobs_dead, "job_count", stats.dead_size, :status => :died
         | 
| 69 | 
            -
                    gauge "job_count", stats.scheduled_size, :status => :scheduled
         | 
| 70 | 
            -
                    gauge "job_count", stats.enqueued, :status => :enqueued
         | 
| 71 | 
            -
                  end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                  def track_queues
         | 
| 74 | 
            -
                    ::Sidekiq::Queue.all.each do |queue|
         | 
| 75 | 
            -
                      gauge "queue_length", queue.size, :queue => queue.name
         | 
| 76 | 
            -
                      # Convert latency from seconds to milliseconds
         | 
| 77 | 
            -
                      gauge "queue_latency", queue.latency * 1_000.0, :queue => queue.name
         | 
| 78 | 
            -
                    end
         | 
| 79 | 
            -
                  end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                  # Track a gauge metric with the `sidekiq_` prefix
         | 
| 82 | 
            -
                  def gauge(key, value, tags = {})
         | 
| 83 | 
            -
                    tags[:hostname] = hostname if hostname
         | 
| 84 | 
            -
                    Appsignal.set_gauge "sidekiq_#{key}", value, tags
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                  # Track the delta of two values for a gauge metric
         | 
| 88 | 
            -
                  #
         | 
| 89 | 
            -
                  # First call will store the data for the metric and the second call will
         | 
| 90 | 
            -
                  # set a gauge metric with the difference. This is used for absolute
         | 
| 91 | 
            -
                  # counter values which we want to track as gauges.
         | 
| 92 | 
            -
                  #
         | 
| 93 | 
            -
                  # @example
         | 
| 94 | 
            -
                  #   gauge_delta :my_cache_key, "my_gauge", 10
         | 
| 95 | 
            -
                  #   gauge_delta :my_cache_key, "my_gauge", 15
         | 
| 96 | 
            -
                  #   # Creates a gauge with the value `5`
         | 
| 97 | 
            -
                  # @see #gauge
         | 
| 98 | 
            -
                  def gauge_delta(cache_key, key, value, tags = {})
         | 
| 99 | 
            -
                    previous_value = cache[cache_key]
         | 
| 100 | 
            -
                    cache[cache_key] = value
         | 
| 101 | 
            -
                    return unless previous_value
         | 
| 102 | 
            -
                    new_value = value - previous_value
         | 
| 103 | 
            -
                    gauge key, new_value, tags
         | 
| 104 | 
            -
                  end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                  def hostname
         | 
| 107 | 
            -
                    return @hostname if defined?(@hostname)
         | 
| 108 | 
            -
                    if config.key?(:hostname)
         | 
| 109 | 
            -
                      @hostname = config[:hostname]
         | 
| 110 | 
            -
                      Appsignal.logger.debug "Sidekiq probe: Using hostname config " \
         | 
| 111 | 
            -
                        "option #{@hostname.inspect} as hostname"
         | 
| 112 | 
            -
                      return @hostname
         | 
| 113 | 
            -
                    end
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                    host = nil
         | 
| 116 | 
            -
                    ::Sidekiq.redis { |c| host = c.connection[:host] }
         | 
| 117 | 
            -
                    Appsignal.logger.debug "Sidekiq probe: Using Redis server hostname " \
         | 
| 118 | 
            -
                      "#{host.inspect} as hostname"
         | 
| 119 | 
            -
                    @hostname = host
         | 
| 120 | 
            -
                  end
         | 
| 121 | 
            -
                end
         | 
| 122 | 
            -
             | 
| 123 26 | 
             
                # @api private
         | 
| 124 27 | 
             
                class SidekiqPlugin # rubocop:disable Metrics/ClassLength
         | 
| 125 28 | 
             
                  include Appsignal::Hooks::Helpers
         |