datadog-statsd-schema 0.1.1 → 0.2.0

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.
data/README.md CHANGED
@@ -1,359 +1,410 @@
1
1
  [![RSpec and Rubocop](https://github.com/kigster/datadog-statsd-schema/actions/workflows/ruby.yml/badge.svg)](https://github.com/kigster/datadog-statsd-schema/actions/workflows/ruby.yml)
2
2
 
3
- # Datadog::Statsd::Schema
3
+ # Datadog StatsD Schema
4
4
 
5
- This is a wrapper around [dogstatsd-ruby](https://github.com/DataDog/dogstatsd-ruby) gem that sends custom metrics via StatsD, with additional layer of validation based on a configurable schemas. Schemas can validate allowed metric names, associated tag and tag values. This approach can guide an organization towards a clear declarative approach to metrics and their tags, and then emitting them from within the application with the insurance that any invalid value would raise an exception.
5
+ A Ruby gem that provides comprehensive schema definition, validation, and cost analysis for Datadog StatsD metrics. This library helps teams prevent metric explosion, control costs, and maintain consistent metric naming conventions.
6
6
 
7
- We invite you to explore some of the provided [examples](./examples/README.md) which can be run from project's root, and are described in the linked README.
7
+ ## Features
8
8
 
9
- ## Introduction
9
+ - **Schema Definition**: Define metric schemas with type safety and validation
10
+ - **Tag Management**: Centralized tag definitions with inheritance and validation
11
+ - **Cost Analysis**: Analyze potential custom metric costs before deployment
12
+ - **Metric Validation**: Runtime validation of metrics against defined schemas
13
+ - **CLI Tools**: Command-line interface for schema analysis and validation
14
+ - **Global Configuration**: Centralized configuration for tags and StatsD clients
10
15
 
11
- This is an extension to gem [dogstatsd-ruby](https://github.com/DataDog/dogstatsd-ruby) which enhances the original with a robust schema definition for both the custom metrics being sent, and the tags allowed (or required) to attach to the metric.
16
+ ## Installation
12
17
 
13
- There are several interfaces to `Datadog::Statsd` instance — you can use the class methods of `Datadog::Statsd::Emitter`, and pass the typical statsd methods. But you can also use an instance of this class, which adds a number of features and powerful shortcuts.
18
+ Add this line to your application's Gemfile:
14
19
 
15
- If you do not pass the schema argument to the emitter, it will act as a wrapper around `Datadog::Statsd` instance: it will merge the global and local tags together, it will concatenate metric names together, so it's quite useful on it' on.
20
+ ```ruby
21
+ gem 'datadog-statsd-schema'
22
+ ```
16
23
 
17
- But the real power comes from defining a Schema of metrics and tags, and providing the schema to the Emitter as a constructor argument. In that case every metric send will be validated against the schema.
18
-
19
- ## Metric Types
24
+ And then execute:
20
25
 
21
- > For more information about the metrics, please see the [Datadog Documentation](https://docs.datadoghq.com/metrics/custom_metrics/dogstatsd_metrics_submission/?tab=ruby).
26
+ ```bash
27
+ bundle install
28
+ ```
22
29
 
23
- There are 5 total metric types you can send with Statsd, and it's important to understand the differences:
30
+ Or install it yourself as:
24
31
 
25
- * `COUNT` (eg, `Datadog::Statsd::Emitter.increment('emails.sent', by: 2)`)
26
- * `GAUGE` (eg, `Datadog::Statsd::Emitter.gauge('users.on.site', 100)`)
27
- * `HISTOGRAM` (eg, `Datadog::Statsd::Emitter.histogram('page.load.time', 100)`)
28
- * `DISTRIBUTION` (eg,`Datadog::Statsd::Emitter.distribution('page.load.time', 100)`)
29
- * `SET` (eg, `Datadog::Statsd::Emitter.set('users.unique', '12345')`)
32
+ ```bash
33
+ gem install datadog-statsd-schema
34
+ ```
30
35
 
31
- NOTE: that `HISTOGRAM` converts your metric into FIVE separate metrics (with suffixes .`max`, .`median`, `avg`, .`count`, `p95`), while `DISTRIBUTION` explodes into TEN separate metrics (see the documentation). Do NOT use SET unless you know what you are doing.
36
+ ## Quick Start
32
37
 
33
- You can send metrics via class methods of `Datadog::Statsd::Emitter`, or by instantiating the class.
38
+ ### Basic Schema Definition
34
39
 
35
- ## Sending Metrics
40
+ ```ruby
41
+ require 'datadog/statsd/schema'
42
+
43
+ # Define your metrics schema
44
+ schema = Datadog::Statsd::Schema.new do
45
+ namespace :web do
46
+ tags do
47
+ tag :environment, values: %w[production staging development]
48
+ tag :service, values: %w[api web worker]
49
+ tag :region, values: %w[us-east-1 us-west-2]
50
+ end
36
51
 
37
- ### Class Methods
52
+ metrics do
53
+ counter :requests_total do
54
+ description "Total HTTP requests"
55
+ tags required: [:environment, :service], allowed: [:region]
56
+ end
38
57
 
39
- This is the most straightforward way of using this gem. You can just pass your metric names and tags to the standard operations on Statsd, just like so:
58
+ gauge :memory_usage do
59
+ description "Memory usage in bytes"
60
+ tags required: [:environment], allowed: [:service, :region]
61
+ end
40
62
 
41
- ```ruby
42
- require 'datadog/statsd'
43
- require 'datadog/statsd/schema'
44
-
45
- Datadog::Statsd::Emitter.increment(
46
- 'marathon.started.total',
47
- by: 7,
48
- tags: {
49
- course: "sf-marathon",
50
- length: 26.212,
51
- units: "miles"
52
- },
53
- schema: ....
54
- )
63
+ distribution :request_duration do
64
+ description "Request processing time in milliseconds"
65
+ tags required: [:environment, :service]
66
+ end
67
+ end
68
+ end
69
+ end
55
70
  ```
56
71
 
57
- As you can see, the API is identical to `Datadog::Statsd`. The main difference is that, if you provide a schema argument, the metric `marathon.started.total` must be pre-declared using the schema DSL language. In addition, the metric type ("count") and all of the tags and their possible values must be predeclared in the schema. Schema does support opening up a tag to any number of values, but that is not recommended.
72
+ ### Using the Emitter with Schema Validation
58
73
 
59
- So let's look at a more elaborate use case.
74
+ ```ruby
75
+ # Configure global settings
76
+ Datadog::Statsd::Schema.configure do |config|
77
+ config.statsd = Datadog::Statsd.new('localhost', 8125)
78
+ config.schema = schema
79
+ config.tags = { environment: 'production' }
80
+ end
81
+
82
+ # Create an emitter with validation
83
+ emitter = Datadog::Statsd::Emitter.new(
84
+ schema: schema,
85
+ validation_mode: :strict # :strict, :warn, or :disabled
86
+ )
60
87
 
61
- ### Defining Schema
88
+ # Send metrics with automatic validation
89
+ emitter.increment('web.requests_total', tags: { service: 'api', region: 'us-east-1' })
90
+ emitter.gauge('web.memory_usage', 512_000_000, tags: { service: 'api' })
91
+ emitter.distribution('web.request_duration', 45.2, tags: { service: 'api' })
92
+ ```
62
93
 
63
- Below is an example of configuring the gem by creating a schema using the provided DSL. This can be a single global schema or assigned to a specific Statsd Sender, although you can have any number of Senders of type `Datadog::Statsd::Emitter` that map to a new connection and new defaults.
94
+ ## CLI Usage
64
95
 
65
- ```ruby
66
- require 'etc'
67
- require 'git'
96
+ The gem provides a command-line interface for analyzing schemas and understanding their cost implications.
68
97
 
69
- require 'datadog/statsd'
70
- require 'datadog/statsd/schema'
98
+ ### Installation
71
99
 
72
- # Define the global statsd instance that we'll use to send data through
73
- $statsd = ::Datadog::Statsd.new(
74
- 'localhost', 8125,
75
- delay_serialization: true
76
- )
100
+ After installing the gem, the `dss` (Datadog StatsD Schema) command will be available:
77
101
 
78
- # Configure the schema with global tags and the above-created Statsd instance
79
- Datadog::Statsd::Schema.configure do |config|
80
- # This configures the global tags that will be attached to all methods
81
- config.tags = {
82
- env: "development",
83
- arch: Etc.uname[:machine],
84
- version: Git.open('.').object('HEAD').sha
85
- }
86
-
87
- config.statsd = $statsd
88
- end
102
+ ```bash
103
+ dss --help
104
+ ```
89
105
 
90
- # Now we'll create a Schema using the provided Schema DSL:
91
- schema = Datadog.schema do
92
- # Transformers can be attached to the tags, and applied before the tags are submitted
93
- # or validated.
94
- transformers do
95
- underscore: ->(text) { text.underscore },
96
- downcase: ->(text) { text.downcase }
97
- end
106
+ ### Schema Analysis
98
107
 
99
- namespace :marathon do
100
- tags do
101
- tag :course,
102
- values: ["san francisco", "boston", "new york"],
103
- transform: %i[downcase underscore],
108
+ Create a schema file (e.g., `metrics_schema.rb`):
104
109
 
105
- tag :marathon_type, values: %w[half full]
106
- tag :status, values: %w[finished no-show incomplete]
107
- tag :sponsorship, values: %w[nike cocacola redbull]
110
+ ```ruby
111
+ namespace :web do
112
+ tags do
113
+ tag :environment, values: %w[production staging development]
114
+ tag :service, values: %w[api web worker]
115
+ tag :region, values: %w[us-east-1 us-west-2 eu-west-1]
116
+ end
117
+
118
+ namespace :requests do
119
+ metrics do
120
+ counter :total do
121
+ description "Total HTTP requests"
122
+ tags required: [:environment, :service], allowed: [:region]
108
123
  end
109
124
 
110
- metrics do
111
- # This defines a single metric "marathon.started.total"
112
- namespace :started do
113
- counter :total do
114
- description "Incrementing - the total number of people who were registered for this marathon"
115
- tags required: %i[ course marathon_type ],
116
- allowed: %i[ sponsorship ]
117
- end
118
- end
119
-
120
- # defines two metrics: a counter metric named "marathon.finished.total" and
121
- # a distribution metric "marathon.finished.duration"
122
- namespace :finished do
123
- counter :total, inherit_tags: "marathon.started.total",
124
- description "The number of people who finished a given marathon"
125
- tags required: %i[ status ]
126
- end
127
-
128
- distribution :duration, units: "minutes", inherit_tags: "marathon.finished.count" do
129
- description "The distribution of all finish times registered."
130
- end
131
- end
125
+ distribution :duration do
126
+ description "Request processing time in milliseconds"
127
+ inherit_tags "web.requests.total"
132
128
  end
133
129
  end
134
130
  end
135
131
 
136
- my_sender = Datadog.emitter(
137
- metric: 'marathon',
138
- schema: schema,
139
- validation_mode: :strict,
140
- tags: { marathon_type: :full, course: "san-francisco" }
141
- )
142
-
143
- my_sender.increment('started.total', by: 43579) # register all participants at start
144
- # time passes, first runners start to arrive
145
- my_sender.increment('finished.total') # register one at a time
146
- my_sender.distribution('finished.duration', 33.21, tags: { sponsorship: 'nike' })
147
- ...
148
- my_sender.increment('finished.total')
149
- my_sender.distribution('finished.duration', 35.09, tags: { sponsorship: "redbull" })
132
+ metrics do
133
+ gauge :memory_usage do
134
+ description "Memory usage in bytes"
135
+ tags required: [:environment], allowed: [:service]
136
+ end
137
+ end
138
+ end
150
139
  ```
151
140
 
152
- In this case, the schema will validate that the metrics are named `marathon.finished.total` and `marathon.finished.duration`, and that their tags are appropriately defined.
141
+ Analyze the schema to understand metric costs:
153
142
 
154
- ```ruby
155
- finish_sender = Datadog.emitter(
156
- schema: schema,
157
- validation_mode: :warn,
158
- metric: "marathon.finished",
159
- tags: { marathon_type: :full, course: "san-francisco" }
160
- )
161
- finish.increment("total")
162
- finish.distribution("duration", 34)
143
+ ```bash
144
+ dss analyze --file metrics_schema.rb
163
145
  ```
164
146
 
165
- The above code will transmit the following metric, with the following tags:
166
-
167
- ```ruby
168
- $statsd.increment(
169
- "marathon.finished.total",
170
- tags: { marathon_type: :full, course: "san-francisco" }
171
- )
172
-
173
- $statsd.distribution(
174
- "marathon.finished.duration",
175
- tags: { marathon_type: :full, course: "san-francisco" }
176
- )
147
+ **Output:**
148
+ ```
149
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
150
+ │ Detailed Metric Analysis: │
151
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
152
+
153
+ • gauge('web.memory_usage')
154
+ Expanded names:
155
+ • web.memory_usage.count
156
+ • web.memory_usage.min
157
+ web.memory_usage.max
158
+ • web.memory_usage.sum
159
+ • web.memory_usage.avg
160
+
161
+ Unique tags: 2
162
+ Total tag values: 6
163
+ Possible combinations: 45
164
+
165
+ ──────────────────────────────────────────────────────────────────────────────────────────────
166
+
167
+ • counter('web.requests.total')
168
+
169
+ Unique tags: 3
170
+ Total tag values: 9
171
+ Possible combinations: 27
172
+
173
+ ──────────────────────────────────────────────────────────────────────────────────────────────
174
+
175
+ • distribution('web.requests.duration')
176
+ Expanded names:
177
+ • web.requests.duration.count
178
+ • web.requests.duration.min
179
+ • web.requests.duration.max
180
+ • web.requests.duration.sum
181
+ • web.requests.duration.avg
182
+ • web.requests.duration.p50
183
+ • web.requests.duration.p75
184
+ • web.requests.duration.p90
185
+ • web.requests.duration.p95
186
+ • web.requests.duration.p99
187
+
188
+ Unique tags: 3
189
+ Total tag values: 9
190
+ Possible combinations: 270
191
+
192
+ ──────────────────────────────────────────────────────────────────────────────────────────────
193
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
194
+ │ Schema Analysis Results: │
195
+ │ SUMMARY │
196
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
197
+
198
+ Total unique metrics: 16
199
+ Total possible custom metric combinations: 342
177
200
  ```
178
201
 
179
- ### Validation Mode
202
+ This analysis shows that your schema will generate **342 custom metrics** across **16 unique metric names**. Understanding this before deployment helps prevent unexpected Datadog billing surprises.
180
203
 
181
- There are four validation modes you can pass to an emitter to accompany a schema:
204
+ ## Advanced Features
182
205
 
183
- 1. `:strict` — raise an exception when anything is out of the ordinary is passed
184
- 2. `:warn` — print to stderr and continue
185
- 3. `:drop` — drop this metric
186
- 4. `:off` — no validation, as if schema was not even passed.
206
+ ### Tag Inheritance
187
207
 
188
- ### An Example Tracking Web Performance
208
+ Metrics can inherit tag configurations from other metrics to reduce duplication:
189
209
 
190
210
  ```ruby
191
- Datadog::Statsd::Schema.configure do |config|
192
- config.statsd = $statsd
193
- config.schema = Datadog::Statsd::Schema.new do
194
- namespace "web" do
195
- namespace "request" do
196
- tags do
197
- tag :uri,
198
- values: %r{.*}
199
-
200
- tag :logged_in,
201
- values: %w[logged_in logged_out]
202
-
203
- tag :billing_plan,
204
- values: %w[premium trial free]
205
-
206
- tag :controller,
207
- values: %r{[a-z.]*},
208
- transform: [ :underscore, :downcase ]
209
-
210
- tag :action,
211
- values: %r{[a-z.]*},
212
- transform: [ :underscore, :downcase ]
213
-
214
- tag :method,
215
- values: %i[get post put patch delete head options trace connect],
216
- transform: [ :downcase ]
217
-
218
- tag :status_code,
219
- type: :integer,
220
- validate: ->(code) { (100..599).include?(code) }
221
- end
222
-
223
- metrics do
224
- # This distribution allows tracking of the latency of the request.
225
- distribution :duration do
226
- description "HTTP request processing time in milliseconds"
227
- tags allowed: %w[controller action method status_code region]
228
- required: %w[controller]
229
- end
230
-
231
- # This counter allows tracking the frequency of each controller/action
232
- counter :total, inherit_tags: :duration do
233
- description "Total number of requests received"
234
- end
235
- end
236
- end
237
- end
211
+ namespace :api do
212
+ metrics do
213
+ counter :requests_total do
214
+ tags required: [:environment, :service], allowed: [:region]
215
+ end
216
+
217
+ # Inherits environment, service (required) and region (allowed) from requests_total
218
+ distribution :request_duration do
219
+ inherit_tags "api.requests_total"
220
+ tags required: [:endpoint] # Adds endpoint as additional required tag
238
221
  end
239
222
  end
223
+ end
240
224
  ```
241
225
 
226
+ ### Nested Namespaces
242
227
 
243
- Let's say this monitor only tracks requests from logged in premium users, then you can provide those tags here, and they will be sent together with individual invocations:
228
+ Organize metrics hierarchically with nested namespaces:
244
229
 
245
230
  ```ruby
246
- # We'll use the shorthand version to create this Emitter.
247
- # It's equivalent to *Datadog::Statsd::Emitter.new*
248
- traffic_monitor = Datadog.emitter(
249
- self,
250
- metric: "web.request",
251
- tags: { billing_plan: :premium, logged_in: :logged_in }
252
- )
253
-
254
- my_sender.increment('total', tags: { uri: '/home/settings', method: :get } )
255
- my_sender.distribution('duration', tags: { uri: '/home/settings', method: :get } )
231
+ namespace :application do
232
+ tags do
233
+ tag :environment, values: %w[prod staging dev]
234
+ end
256
235
 
257
- my_sender.increment('total', tags: { uri: '/app/calendar', method: :post} )
258
- my_sender.distribution('duration', tags: { uri: '/app/calendar', method: :post } )
259
- ```
260
-
261
- The above code will send two metrics: `web.request.total` as a counter, tagged with: `{ billing_plan: :premium, logged_in: :logged_in, uri: '/home/settings' }` and the second time for the `uri: '/app/calendar'`.
236
+ namespace :database do
237
+ tags do
238
+ tag :table_name, values: %w[users orders products]
239
+ end
262
240
 
263
- ### Emitter
241
+ metrics do
242
+ counter :queries_total
243
+ distribution :query_duration
244
+ end
245
+ end
264
246
 
265
- You can create instances of this class and use the instance to emit custom metrics. You may want to do this, instead of using the class methods directly, for two reasons:
247
+ namespace :cache do
248
+ tags do
249
+ tag :cache_type, values: %w[redis memcached]
250
+ end
266
251
 
267
- 1. You want to send metrics from several places in the codebase, but have them share the "emitter" tag (which i.e. defines the source, a class, or object)emitting the metric, or any other tags for that matter.
252
+ metrics do
253
+ counter :hits_total
254
+ counter :misses_total
255
+ end
256
+ end
257
+ end
258
+ ```
268
259
 
269
- 2. You want to send metrics with a different sample rate than the defaults.
260
+ ### Validation Modes
270
261
 
271
- In both cases, you can create an instance of this class and use it to emit metrics.
262
+ Control how validation errors are handled:
272
263
 
273
- #### Naming Metrics
264
+ ```ruby
265
+ # Strict mode: Raises exceptions on validation failures
266
+ emitter = Datadog::Statsd::Emitter.new(schema: schema, validation_mode: :strict)
274
267
 
275
- Please remember that naming *IS* important. Good naming is self-documenting, easy to slice the data by, and easy to understand and analyze. Keep the number of unique metric names down, number of tags down, and the number of possible tag values should always be finite. If in doubt, set a tag, instead of creating a new metric.
268
+ # Warn mode: Logs warnings but continues execution
269
+ emitter = Datadog::Statsd::Emitter.new(schema: schema, validation_mode: :warn)
276
270
 
277
- #### Example Tracking email delivery
271
+ # Disabled: No validation (production default)
272
+ emitter = Datadog::Statsd::Emitter.new(schema: schema, validation_mode: :disabled)
273
+ ```
278
274
 
279
- Imagine that we want to track email delivery. But we have many types of emails that we send. Instead of creating new metric for each new email type, use the tag "email_type" to specify what type of email it is.
275
+ ### Global Configuration
280
276
 
281
- Keep metric name list short, eg: "emails.queued", "emails.sent", "emails.delivered" are good metrics as they define a distinctly unique events. However, should you want to differentiate between different types of emails, you could theoretically do the following: (BAD EXAMPLE, DO NOT FOLLOW) — "emails.sent.welcome", "emails.sent.payment". But this example conflates two distinct events into a single metric. Instead, we should use tags to set event properties, such as what type of email that is.
277
+ Set up global defaults for your application:
282
278
 
283
279
  ```ruby
280
+ Datadog::Statsd::Schema.configure do |config|
281
+ config.statsd = Datadog::Statsd.new(
282
+ ENV['DATADOG_AGENT_HOST'] || 'localhost',
283
+ ENV['DATADOG_AGENT_PORT'] || 8125
284
+ )
285
+ config.schema = schema
286
+ config.tags = {
287
+ environment: ENV['RAILS_ENV'],
288
+ service: 'my-application',
289
+ version: ENV['APP_VERSION']
290
+ }
291
+ end
292
+
293
+ # These global tags are automatically added to all metrics
294
+ emitter = Datadog::Statsd::Emitter.new
295
+ emitter.increment('user.signup') # Automatically includes global tags
296
+ ```
284
297
 
285
- emails_emitter = Datadog.emitter(
286
- self,
287
- metric: 'emails'
288
- )
298
+ ## Cost Control and Best Practices
289
299
 
290
- emails_emitter.increment('queued.total')
291
- emails_emitter.increment('delivered.total', by: count)
292
- emails_emitter.gauge('queue.size', EmailQueue.size)
293
- ```
300
+ ### Understanding Metric Expansion
294
301
 
295
- #### What's the Emitter Constructor Arguments?
302
+ Different metric types create different numbers of time series:
296
303
 
297
- The first argument to the `Emitter.new()` or `Datadog.emitter()` (those are equivalent) is an object or a string or a class that's converted to a tag called `emitter`. This is the source class or object that sent the metric. The same mwtric may come from various places in your code, and `emitter` tag allows you to differentiate between them.
304
+ - **Counter/Set**: 1 time series per unique tag combination
305
+ - **Gauge**: 5 time series (count, min, max, sum, avg)
306
+ - **Distribution/Histogram**: 10 time series (count, min, max, sum, avg, p50, p75, p90, p95, p99)
298
307
 
299
- Subsequent arguments are hash arguments.
308
+ ### Tag Value Limits
300
309
 
301
- * `metric` — The (optional) name of the metric to track. If set to, eg. `emails`, then any subsequent method sending metric will prepend `emails.` to it, for example:
310
+ Be mindful of tag cardinality:
302
311
 
303
312
  ```ruby
304
- emitter.increment('sent.total', by: 3)
313
+ # High cardinality - avoid
314
+ tag :user_id, type: :string # Could be millions of values
315
+
316
+ # Better approach - use bucketing
317
+ tag :user_tier, values: %w[free premium enterprise]
318
+ tag :user_cohort, values: %w[new_user returning_user power_user]
305
319
  ```
306
320
 
307
- Will actually increment the metric `emails.sent.total`.
321
+ ### Schema Validation
308
322
 
309
- #### Other Examples
323
+ Always validate your schema before deployment:
310
324
 
311
325
  ```ruby
326
+ # Check for common issues
327
+ errors = schema.validate
328
+ if errors.any?
329
+ puts "Schema validation errors:"
330
+ errors.each { |error| puts " - #{error}" }
331
+ end
332
+ ```
312
333
 
313
- Datadog.emitter(self)
314
- .increment('emails.sent', by: 2)
334
+ ## Integration Examples
315
335
 
316
- Datadog.emitter(ab_test: { 'login_test_2025' => 'control' })
317
- .increment('users.logged_in')
318
- # => tags: { ab_test_name: 'login_test_2025',
319
- # ab_test_group: 'control' }
336
+ ### Rails Integration
320
337
 
321
- Datadog.emitter(SessionsController, metric: 'users')
322
- .gauge('logged_in', 100)
338
+ ```ruby
339
+ # config/initializers/datadog_statsd.rb
340
+ schema = Datadog::Statsd::Schema.load_file(Rails.root.join('config/metrics_schema.rb'))
341
+
342
+ Datadog::Statsd::Schema.configure do |config|
343
+ config.statsd = Datadog::Statsd.new
344
+ config.schema = schema
345
+ config.tags = {
346
+ environment: Rails.env,
347
+ service: 'my-rails-app'
348
+ }
349
+ end
350
+
351
+ # app/controllers/application_controller.rb
352
+ class ApplicationController < ActionController::Base
353
+ before_action :setup_metrics
354
+
355
+ private
356
+
357
+ def setup_metrics
358
+ @metrics = Datadog::Statsd::Emitter.new(
359
+ validation_mode: Rails.env.production? ? :disabled : :warn
360
+ )
361
+ end
362
+ end
363
+ ```
323
364
 
324
- sessions = Datadog.emitter(SessionsController, metric: 'users')
325
- # => tags: { emitter: "sessions_controller" }
326
- sessions.gauge('active', 100)
327
- sessions.distribution('active.total', 114)
365
+ ### Background Job Monitoring
366
+
367
+ ```ruby
368
+ class OrderProcessingJob
369
+ def perform(order_id)
370
+ metrics = Datadog::Statsd::Emitter.new
371
+
372
+ start_time = Time.current
373
+
374
+ begin
375
+ process_order(order_id)
376
+ metrics.increment('jobs.order_processing.success', tags: { queue: 'orders' })
377
+ rescue => error
378
+ metrics.increment('jobs.order_processing.failure',
379
+ tags: { queue: 'orders', error_type: error.class.name })
380
+ raise
381
+ ensure
382
+ duration = Time.current - start_time
383
+ metrics.distribution('jobs.order_processing.duration', duration * 1000,
384
+ tags: { queue: 'orders' })
385
+ end
386
+ end
387
+ end
328
388
  ```
329
389
 
330
- ## Installation
390
+ ## Development
331
391
 
392
+ After checking out the repo, run:
332
393
 
333
394
  ```bash
334
- bundle add datadog-statsd-schema
395
+ bin/setup # Install dependencies
396
+ bundle exec rake spec # Run tests
335
397
  ```
336
398
 
337
- If bundler is not being used to manage dependencies, install the gem by executing:
399
+ To install this gem onto your local machine:
338
400
 
339
401
  ```bash
340
- gem install datadog-statsd-schema
402
+ bundle exec rake install
341
403
  ```
342
404
 
343
- ## Usage
344
-
345
- 1. Define your metrics and tagging schema
346
- 2. Create as many "emitters" as necessary and start sending!
347
-
348
- ## Development
349
-
350
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
351
-
352
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
353
-
354
405
  ## Contributing
355
406
 
356
- Bug reports and pull requests are welcome on GitHub at [https://github.com/kigster/datadog-statsd-schema](https://github.com/kigster/datadog-statsd-schema)
407
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/datadog-statsd-schema.
357
408
 
358
409
  ## License
359
410