Minutely probes

Minutely probes are a mechanism to periodically send custom metrics to AppSignal. This is a system that is included in the AppSignal Ruby gem by default. At the start of every minute the minutely probes are triggered one by one to collect metrics and then snoozed until the next minute.

By default the AppSignal Ruby gem enables probes for libraries that are detected for your app.

Note: In AppSignal Ruby gem 3.7.0 and lower, use the Appsignal::Minutely.probes module to register probes, rather than the new Appsignal::Probes API.

Usage

The minutely probes allow the AppSignal Ruby gem to collect custom metrics by default for integrations and app-specific metrics by creating your own probe.

Multiple instances

Once activated, the minutely probes system runs on every instance of an app. This means that if a probe report metrics without some kind of differentiating tag, global metrics may be overwritten by instance-level metrics. For example, there's a probe that tracks how large the local background job queue is for an app. The queue database runs locally on the instance and queue sizes may vary wildly. Each instance of an app reports different metric values for the same metric and tags, overwriting the metric value every minute with those of the last reporting instance.

To remedy this, we suggest tagging your metrics with the hostname or something else unique for each instance. For example, the Sidekiq probe tags metrics with the Redis hostname by default.

Alternatively you can disable minutely probes for all but one instance, on which the minutely probes process is run. We suggest using the APPSIGNAL_ENABLE_MINUTELY_PROBES environment variable to only enable it on the instance of your choosing.

Configuration

The minutely probes are configured using the enable_minutely_probes config option.

Creating probes

If you want to track more custom metrics from your app than our the default probes that ship with our integrations, you can add your own probe(s).

An AppSignal minutely probe can be either of three things. Which of the three types to use for your class depends on the use case.

Lambda probe

The simplest probe type to register. If you have no dependencies for your probe this is the preferred method.

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register(:my_probe, lambda do Appsignal.set_gauge("database_size", 10) end)

Class probe

This feature requires AppSignal for Ruby version 2.9.0 or higher.

A class probe is a lazy initialized probe. It will only be started if the minutely probes are started. It will be initialized at the start of the minutely probes thread and remain initialized for as long as your app is running.

This method is useful when you do not have enable_minutely_probes enabled for every environment and don't want it to be initialized by default.

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def initialize # This is only called when the minutely probe gets initialized require "background_job_library" @connection = BackgroundJobLibrary.connection end def call stats = @connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end end # Registering a Class probe Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe )

Initialized class probe

This feature requires AppSignal for Ruby version 2.9.0 or higher.

This method is most useful for overriding default probes. The AppSignal Ruby gem ships some probes for integrations by default. These default probes register probes as a class so they won't be initialized when overridden. When the probe default config does not fit your use case you can override a default probe with your own config.

Note that we do not register a class as a probe, but an instance of the class using .new and pass along a config object, e.g. BackgroundJobLibraryProbe.new(<config>).

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot require "background_job_library" # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def initialize(config) @connection = BackgroundJobLibrary.connection(config) end def call stats = @connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end end # Registering an initialized Class probe Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe.new(:database => "redis://localhost:6379") )

Registering probes

This feature requires AppSignal for Ruby version 2.9.6 or higher.

Probes can be registered with the register method on the Appsignal::Probes module. This method accepts two arguments.

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register(:my_probe, lambda do Appsignal.set_gauge("database_size", 10) end)

Rails apps

We recommend registering your probes in a Rails initializer, like: config/initializers/my_probe.rb.

Dependency requirements

This feature requires AppSignal for Ruby version 2.9.6 or higher.

Not always should a probe be added to the list of probes by default. Some dependency may be required for the probe to work properly. This dependency check is used in probes shipped in the gem, but can also be used in your own probes.

By adding a class method called dependencies_present?, a check can be performed ahead of starting the probe whether not it should be started. This works on both class probes and initialized class probes. For the latter scenario there should be no call to said dependency in the initialize method of the probe as it's already initialized.

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot require "background_job_library" # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def self.dependencies_present? # Only start the probe if the BackgroundJobLibrary version is higher or # equal to 1.0.0. Gem::Version.new(BackgroundJobLibrary::Version) >= Gem::Version.new("1.0.0") end def initialize(config = {}) @config = config end def call stats = connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end private def connection @connection ||= BackgroundJobLibrary.connection(@config) end end # Registering a Class probe with a `dependencies_present?` check Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe ) # Also works for initialized probes Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe.new(:url => "schema://my_connection_url:9090") )

Overriding default probes

AppSignal ships with default probes for certain integrations. If for any reason this probe does not function properly or requires some additional configuration for your use case, you can override the default probe by initializing the probe class with your own config.

Example overriding the Sidekiq probe.

Ruby
# config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register( :sidekiq, # Use the same key as the default Sidekiq probe to override it Appsignal::Hooks::SidekiqProbe.new(:hostname => ENV["REDIS_URL"]) )

(Note that you'll need to set the REDIS_URL environment variable yourself.)

Overriding probes will log a debug message in the appsignal.log file which can help to detect if a probe is correctly overridden.

Unregister probes

This feature requires AppSignal for Ruby version 3.7.1 or higher.

To unregister previously registered probes, including the default probes, use the Appsignal::Probes.unregister method. Call the unregister method with the name of the probe to unregister it.

Ruby
Appsignal::Probes.unregister( :probe_name # Use the same key as used in `Probes.register` to unregister it )