Class: Wurk::Metrics::Statsd
- Inherits:
-
Object
- Object
- Wurk::Metrics::Statsd
- Includes:
- Wurk::Middleware::ServerMiddleware
- Defined in:
- lib/wurk/metrics/statsd.rb
Overview
Pro parity (§9): emits per-job timing + counters to a statsd / dogstatsd client. The client itself is plumbed in by the host app via:
Wurk.configure_server do |config|
config.dogstatsd = -> { Datadog::Statsd.new('metrics.example.com', 8125) }
config.server_middleware { |chain| chain.add Wurk::Metrics::Statsd }
end
The ‘dogstatsd` accessor is a callable — invoked once per process, memoized — so the client is built lazily AFTER fork. Sharing a UDP socket across forks is fine, but `Datadog::Statsd` keeps thread-locals that must be initialized inside the child.
Per-job tuning via ‘Statsd.options = ->(klass, job, queue) { sample_rate: }`. Default options: tags `[“worker:<klass>”, “queue:<q>”]`, sample_rate 1.0. The `dd_rate` job option, when present, overrides sample_rate.
Metric naming follows Sidekiq Pro 8+: every metric prefixed ‘sidekiq.` (the prefix is hardcoded, not configurable — third-party dashboards built for Sidekiq Pro work unchanged).
‘Statsd.increment(metric, tags:)` is the class-level fast path used by other Wurk components (Buffered client, Expiry middleware, super_fetch recovery, Batch lifecycle). No-op when no client is configured so callers never have to guard.
Spec: docs/target/sidekiq-pro.md §9.
Constant Summary collapse
- METRIC_PREFIX =
'sidekiq.'- DEFAULT_SAMPLE_RATE =
1.0
Class Attribute Summary collapse
-
.options ⇒ Object
Returns the value of attribute options.
Attributes included from Wurk::Middleware::ServerMiddleware
Class Method Summary collapse
-
.client ⇒ Object
Resolves the live client: invokes the configured ‘dogstatsd` proc exactly once per process and memoizes.
-
.distribution(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
Distribution send.
- .gauge(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
-
.increment(metric, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
Counter shortcut used across the codebase.
-
.reset! ⇒ Object
Test/lifecycle hook.
Instance Method Summary collapse
-
#call(_worker, job, queue) ⇒ Object
rubocop:disable Metrics/AbcSize.
Methods included from Wurk::Middleware::ServerMiddleware
Class Attribute Details
.options ⇒ Object
Returns the value of attribute options.
39 40 41 |
# File 'lib/wurk/metrics/statsd.rb', line 39 def @options end |
Class Method Details
.client ⇒ Object
Resolves the live client: invokes the configured ‘dogstatsd` proc exactly once per process and memoizes. Returns nil when no proc is configured, so callers get a clean no-op without raising.
94 95 96 97 98 99 100 101 |
# File 'lib/wurk/metrics/statsd.rb', line 94 def client return @client if defined?(@client) && !@client.nil? builder = Wurk.configuration.respond_to?(:dogstatsd) ? Wurk.configuration.dogstatsd : nil return nil if builder.nil? @client = builder.respond_to?(:call) ? builder.call : builder end |
.distribution(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
Distribution send. Some statsd clients lack ‘distribution` (vanilla statsd-ruby, for example) — fall back to `histogram` so the metric still lands somewhere. `dogstatsd-ruby` always has `distribution`.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/wurk/metrics/statsd.rb', line 73 def distribution(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) client = self.client return nil unless client opts = sample_rate_kw(sample_rate) opts[:tags] = if name = "#{METRIC_PREFIX}#{metric}" if client.respond_to?(:distribution) client.distribution(name, value, **opts) elsif client.respond_to?(:histogram) client.histogram(name, value, **opts) end nil rescue StandardError => e handle_error(e) nil end |
.gauge(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/wurk/metrics/statsd.rb', line 57 def gauge(metric, value, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) client = self.client return nil unless client opts = sample_rate_kw(sample_rate) opts[:tags] = if client.gauge("#{METRIC_PREFIX}#{metric}", value, **opts) nil rescue StandardError => e handle_error(e) nil end |
.increment(metric, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) ⇒ Object
Counter shortcut used across the codebase. Tags are forwarded as given — caller’s job to namespace them (‘“class:Foo”`, `“queue:bar”`). No-op when no client is wired up.
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/wurk/metrics/statsd.rb', line 44 def increment(metric, tags: nil, sample_rate: DEFAULT_SAMPLE_RATE) client = self.client return nil unless client opts = sample_rate_kw(sample_rate) opts[:tags] = if client.increment("#{METRIC_PREFIX}#{metric}", **opts) nil rescue StandardError => e handle_error(e) nil end |
.reset! ⇒ Object
Test/lifecycle hook. Reset between specs and after fork so the parent’s socket doesn’t bleed into children.
105 106 107 |
# File 'lib/wurk/metrics/statsd.rb', line 105 def reset! @client = nil end |
Instance Method Details
#call(_worker, job, queue) ⇒ Object
rubocop:disable Metrics/AbcSize
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/wurk/metrics/statsd.rb', line 120 def call(_worker, job, queue) # rubocop:disable Metrics/AbcSize client = safe_client return yield if client.nil? klass = job['class'] opts = (klass, job, queue) = opts[:tags] rate = opts.fetch(:sample_rate, DEFAULT_SAMPLE_RATE) emit(:increment, 'jobs.count', tags: , sample_rate: rate) started = monotonic_ms success = false begin yield success = true ensure duration = monotonic_ms - started # Metrics are best-effort: an emit failure mid-finalize must not # corrupt the job result the caller already produced. begin finalize(success, duration, tags: , sample_rate: rate) rescue StandardError => e self.class.send(:handle_error, e) end end end |