statsd-instrument 2.3.2 → 2.6.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.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/workflows/benchmark.yml +32 -0
- data/.github/workflows/ci.yml +47 -0
- data/.gitignore +1 -0
- data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1027 -0
- data/.rubocop.yml +50 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +288 -2
- data/CONTRIBUTING.md +28 -6
- data/Gemfile +5 -0
- data/README.md +54 -46
- data/Rakefile +4 -2
- data/benchmark/README.md +29 -0
- data/benchmark/datagram-client +41 -0
- data/benchmark/send-metrics-to-dev-null-log +47 -0
- data/benchmark/send-metrics-to-local-udp-receiver +57 -0
- data/lib/statsd/instrument/assertions.rb +179 -30
- data/lib/statsd/instrument/backend.rb +3 -2
- data/lib/statsd/instrument/backends/capture_backend.rb +4 -1
- data/lib/statsd/instrument/backends/logger_backend.rb +3 -3
- data/lib/statsd/instrument/backends/null_backend.rb +2 -0
- data/lib/statsd/instrument/backends/udp_backend.rb +39 -45
- data/lib/statsd/instrument/capture_sink.rb +27 -0
- data/lib/statsd/instrument/client.rb +313 -0
- data/lib/statsd/instrument/datagram.rb +75 -0
- data/lib/statsd/instrument/datagram_builder.rb +101 -0
- data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
- data/lib/statsd/instrument/environment.rb +108 -29
- data/lib/statsd/instrument/helpers.rb +16 -8
- data/lib/statsd/instrument/log_sink.rb +24 -0
- data/lib/statsd/instrument/matchers.rb +14 -11
- data/lib/statsd/instrument/metric.rb +72 -45
- data/lib/statsd/instrument/metric_expectation.rb +32 -18
- data/lib/statsd/instrument/null_sink.rb +13 -0
- data/lib/statsd/instrument/railtie.rb +2 -1
- data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
- data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +42 -0
- data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
- data/lib/statsd/instrument/rubocop/metric_return_value.rb +32 -0
- data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +36 -0
- data/lib/statsd/instrument/rubocop/positional_arguments.rb +99 -0
- data/lib/statsd/instrument/rubocop/splat_arguments.rb +31 -0
- data/lib/statsd/instrument/rubocop.rb +64 -0
- data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
- data/lib/statsd/instrument/strict.rb +235 -0
- data/lib/statsd/instrument/udp_sink.rb +62 -0
- data/lib/statsd/instrument/version.rb +3 -1
- data/lib/statsd/instrument.rb +340 -163
- data/lib/statsd-instrument.rb +2 -0
- data/statsd-instrument.gemspec +13 -10
- data/test/assertions_test.rb +167 -156
- data/test/benchmark/clock_gettime.rb +27 -0
- data/test/benchmark/default_tags.rb +47 -0
- data/test/benchmark/metrics.rb +9 -8
- data/test/benchmark/tags.rb +5 -3
- data/test/capture_backend_test.rb +4 -2
- data/test/capture_sink_test.rb +44 -0
- data/test/client_test.rb +164 -0
- data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
- data/test/datagram_builder_test.rb +120 -0
- data/test/deprecations_test.rb +132 -0
- data/test/dogstatsd_datagram_builder_test.rb +32 -0
- data/test/environment_test.rb +75 -8
- data/test/helpers/rubocop_helper.rb +47 -0
- data/test/helpers_test.rb +2 -1
- data/test/integration_test.rb +31 -7
- data/test/log_sink_test.rb +37 -0
- data/test/logger_backend_test.rb +10 -8
- data/test/matchers_test.rb +42 -28
- data/test/metric_test.rb +18 -22
- data/test/null_sink_test.rb +13 -0
- data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
- data/test/rubocop/metaprogramming_positional_arguments_test.rb +58 -0
- data/test/rubocop/metric_prefix_argument_test.rb +38 -0
- data/test/rubocop/metric_return_value_test.rb +78 -0
- data/test/rubocop/metric_value_keyword_argument_test.rb +39 -0
- data/test/rubocop/positional_arguments_test.rb +110 -0
- data/test/rubocop/splat_arguments_test.rb +27 -0
- data/test/statsd_datagram_builder_test.rb +22 -0
- data/test/statsd_instrumentation_test.rb +109 -100
- data/test/statsd_test.rb +113 -79
- data/test/test_helper.rb +12 -1
- data/test/udp_backend_test.rb +38 -36
- data/test/udp_sink_test.rb +85 -0
- metadata +85 -5
- data/.travis.yml +0 -12
data/.rubocop.yml
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
inherit_from:
|
2
|
+
- https://shopify.github.io/ruby-style-guide/rubocop.yml
|
3
|
+
|
4
|
+
require:
|
5
|
+
- ./lib/statsd/instrument/rubocop.rb
|
6
|
+
|
7
|
+
AllCops:
|
8
|
+
TargetRubyVersion: 2.3
|
9
|
+
UseCache: true
|
10
|
+
CacheRootDirectory: tmp/rubocop
|
11
|
+
Exclude:
|
12
|
+
- statsd-instrument.gemspec
|
13
|
+
|
14
|
+
Naming/FileName:
|
15
|
+
Enabled: true
|
16
|
+
Exclude:
|
17
|
+
- lib/statsd-instrument.rb
|
18
|
+
|
19
|
+
Style/ClassAndModuleChildren:
|
20
|
+
Enabled: false # TODO: enable later
|
21
|
+
|
22
|
+
|
23
|
+
Style/MethodCallWithArgsParentheses:
|
24
|
+
Enabled: false # TODO: enable later
|
25
|
+
|
26
|
+
Lint/UnusedMethodArgument:
|
27
|
+
AllowUnusedKeywordArguments: true
|
28
|
+
|
29
|
+
# Enable our own cops on our own repo
|
30
|
+
|
31
|
+
StatsD/MetricReturnValue:
|
32
|
+
Enabled: true
|
33
|
+
|
34
|
+
StatsD/MetricValueKeywordArgument:
|
35
|
+
Enabled: true
|
36
|
+
|
37
|
+
StatsD/PositionalArguments:
|
38
|
+
Enabled: true
|
39
|
+
|
40
|
+
StatsD/SplatArguments:
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
StatsD/MetaprogrammingPositionalArguments:
|
44
|
+
Enabled: true
|
45
|
+
|
46
|
+
StatsD/MeasureAsDistArgument:
|
47
|
+
Enabled: true
|
48
|
+
|
49
|
+
StatsD/MetricPrefixArgument:
|
50
|
+
Enabled: true
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,296 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
This file documents the changes between releases of this library. When
|
4
|
-
please
|
3
|
+
This file documents the changes between releases of this library. When
|
4
|
+
creating a pull request, please add an entry to the "unreleased changes"
|
5
|
+
section below.
|
5
6
|
|
6
7
|
### Unreleased changes
|
7
8
|
|
9
|
+
_Nothing yet!_
|
10
|
+
|
11
|
+
## Version 2.6.0
|
12
|
+
|
13
|
+
This release contains a new `StatsD::Instrument::Client` class, which is
|
14
|
+
slated to replace the current implementation in the next major release.
|
15
|
+
|
16
|
+
The main reasons for this rewrite are two folds:
|
17
|
+
- Improved performance.
|
18
|
+
- Being able to instantiate multiple clients.
|
19
|
+
|
20
|
+
We have worked hard to make the new client as compatible as possible. However,
|
21
|
+
to accomplish some of our goals we have deprecated some stuff that we think
|
22
|
+
is unlikely to be used. See the rest of the release notes of this version, and
|
23
|
+
version 2.5.0 to see what is deprecated.
|
24
|
+
|
25
|
+
You can test compatibility with the new client by replacing `StatsD` with
|
26
|
+
`StatsD.client`, which points to a client that will be instantiated using
|
27
|
+
the same environment variables that you can already use for this library. You
|
28
|
+
can also use strict mode, and rubocop rules to check whether you are using any
|
29
|
+
deprecated patterns. See below for more info.
|
30
|
+
|
31
|
+
- **⚠️ DEPRECATION**: Using the `prefix: "foo"` argument for `StatsD.metric`
|
32
|
+
calls (and the metaprogramming macros) is deprecated.
|
33
|
+
|
34
|
+
- You can include the prefix in the metric name.
|
35
|
+
- If you want to override the global prefix, set `no_prefix: true` and
|
36
|
+
include the desired prefix in the metric name
|
37
|
+
|
38
|
+
This library ships with a Rubocop rule to detect uses of this keyword
|
39
|
+
argument in your codebase:
|
40
|
+
|
41
|
+
``` sh
|
42
|
+
# Check for the prefix arguments on your StatsD.metric calls
|
43
|
+
rubocop --only StatsD/MetricPrefixArgument \
|
44
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb
|
45
|
+
```
|
46
|
+
|
47
|
+
Strict mode has also been updated to no longer allow this argument.
|
48
|
+
|
49
|
+
- **⚠️ DEPRECATION**: Using the `as_dist: true` argument for `StatsD.measure`
|
50
|
+
and `statsd_measure` methods is deprecated. This argument was only available
|
51
|
+
for internal use, but was exposed in the public API. It is unlikely that you
|
52
|
+
are usijng this argumenr, but you can check to make sure using this Rubocop
|
53
|
+
invocation:
|
54
|
+
|
55
|
+
``` sh
|
56
|
+
# Check for the as_dist arguments on your StatsD.measure calls
|
57
|
+
rubocop --only StatsD/MeasureAsDistArgument \
|
58
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb
|
59
|
+
```
|
60
|
+
|
61
|
+
Strict mode has also been updated to no longer allow this argument.
|
62
|
+
|
63
|
+
- You can now enable strict mode by setting the `STATSD_STRICT_MODE`
|
64
|
+
environment variable. No more need to change your Gemfile! Note that it is
|
65
|
+
still not recommended to enable strict mode in production due to the
|
66
|
+
performance penalty, but is recommended for development and test. E.g. use
|
67
|
+
`STATSD_STRICT_MODE=1 rails test` to run your test suite with strict mode
|
68
|
+
enabled to expose any deprecations in your codebase.
|
69
|
+
|
70
|
+
- Add support for `STATSD_PREFIX` and `STATSD_DEFAULT_TAGS` environment variables
|
71
|
+
to configure the prefix to use for metrics and the comma-separated list of tags
|
72
|
+
to apply to every metric, respectively.
|
73
|
+
|
74
|
+
These environment variables are preferred over using `StatsD.prefix` and
|
75
|
+
`StatsD.default_tags`: it's best practice to configure the StatsD library
|
76
|
+
using environment variables.
|
77
|
+
|
78
|
+
- Several improvements to `StatsD.event` and `StatsD.service_check` (both are
|
79
|
+
Datadog-only). The previous implementation would sometimes construct invalid
|
80
|
+
datagrams based on the input. The method signatures have been made more
|
81
|
+
explicit, and documentation of these methods is now also more clear.
|
82
|
+
|
83
|
+
- Slight behaviour change when using the `assert_statsd_*` assertion methods in
|
84
|
+
combination with `assert_raises`: we now do not allow the block passed to the
|
85
|
+
`assert_statsd_` call to raise an exception. This may cause tests to fail that
|
86
|
+
previousloy were succeeding.
|
87
|
+
|
88
|
+
Consider the following example:
|
89
|
+
|
90
|
+
``` ruby
|
91
|
+
assert_raises(RuntimeError) do
|
92
|
+
assert_statsd_increment('foo') do
|
93
|
+
raise 'something unexpected'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
In versions before 2.3.3, the assert `assert_statsd_*` calls would silently
|
99
|
+
pass when an exception would occur, which would later be handled by
|
100
|
+
`assert_raises`. So the test would pass, even though no `foo` metric would be
|
101
|
+
emitted.
|
102
|
+
|
103
|
+
Version 2.3.3 changed this by failing the test because no metric was being
|
104
|
+
emitted. However, this would hide the the exception from the assertion message,
|
105
|
+
complicating debugging efforts.
|
106
|
+
|
107
|
+
Now, we fail the test because an unexpected exception occured inside the block.
|
108
|
+
This means that the following test will fail:
|
109
|
+
|
110
|
+
``` ruby
|
111
|
+
assert_raises(RuntimeError) do
|
112
|
+
assert_statsd_increment('foo') do
|
113
|
+
StatsD.increment('foo')
|
114
|
+
raise 'something unexpected'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
To fix, you will need to nest the `assert_raises` inside the block passed to
|
120
|
+
`assert_statsd_instrument` so that `assert_statsd_increment` will not see any
|
121
|
+
exceptions:
|
122
|
+
|
123
|
+
``` ruby
|
124
|
+
assert_statsd_increment('foo') do
|
125
|
+
assert_raises(RuntimeError) do
|
126
|
+
StatsD.increment('foo')
|
127
|
+
raise 'something unexpected'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
See #193, #184, and #166 for more information.
|
133
|
+
|
134
|
+
## Verison 2.5.1
|
135
|
+
|
136
|
+
- **Bugfix:** when using metaprogramming methods, changes to `StatsD.prefix` after
|
137
|
+
the metaprogramming method was evaluated would not be respected. This
|
138
|
+
unfortunately is quite common when you set the StatsD prefix inside an
|
139
|
+
initializer. This issue is now addressed: the prefix is evaluated at the
|
140
|
+
mopment the metric is emitted, not when the metaprogramming method is being
|
141
|
+
evaluated. (#202)
|
142
|
+
|
143
|
+
## Version 2.5.0
|
144
|
+
|
145
|
+
- **⚠️ DEPRECATION**: Providing a sample rate and tags to your metrics and method
|
146
|
+
instrumentation macros should be done using keyword arguments rather than
|
147
|
+
positional arguments. Also, previously you could provide `value` as a keyword
|
148
|
+
argument, but it should be provided as the second positional argument.
|
149
|
+
|
150
|
+
``` ruby
|
151
|
+
# DEPRECATED
|
152
|
+
StatsD.increment 'counter', 1, 0.1, ['tag']
|
153
|
+
StatsD.increment 'counter', value: 123, tags: { foo: 'bar' }
|
154
|
+
StatsD.measure('duration', nil, 1.0) { foo }
|
155
|
+
statsd_count_success :method, 'metric-name', 0.1
|
156
|
+
|
157
|
+
# SUPPORTED
|
158
|
+
StatsD.increment 'counter', sample_rate: 0.1, tags: ['tag']
|
159
|
+
StatsD.increment 'counter', 123, tags: { foo: 'bar' }
|
160
|
+
StatsD.measure('duration', sample_rate: 1.0) { foo }
|
161
|
+
statsd_count_success :method, 'metric-name', sample_rate: 0.1
|
162
|
+
```
|
163
|
+
|
164
|
+
The documentation of the methods has been updated to reflect this change.
|
165
|
+
The behavior of the library is not changed for the time being, so you can
|
166
|
+
safely upgrade to this version. However, in a future major release, we will
|
167
|
+
remove support for the positional arguments.
|
168
|
+
|
169
|
+
The library includes some cops to help with finding issues in your existing
|
170
|
+
codebase, and fixing them:
|
171
|
+
|
172
|
+
``` sh
|
173
|
+
# Check for positional arguments on your StatsD.metric calls
|
174
|
+
rubocop --only StatsD/PositionalArguments \
|
175
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/positional_arguments.rb
|
176
|
+
|
177
|
+
# Check for positional arguments on your statsd_instrumentation macros
|
178
|
+
rubocop --only StatsD/MetaprogrammingPositionalArguments \
|
179
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb
|
180
|
+
|
181
|
+
# Check for value as keyword argument
|
182
|
+
rubocop --only StatsD/MetricValueKeywordArgument \
|
183
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb
|
184
|
+
|
185
|
+
```
|
186
|
+
|
187
|
+
- **⚠️ DEPRECATION**: Relying on the return value of the StatsD metric methods
|
188
|
+
(e.g. `StatsD.increment`) is deprecated. StatsD is a fire-and-forget
|
189
|
+
protocol, so your code should not depend on the return value of these methods.
|
190
|
+
|
191
|
+
The documentation of the methods has been updated to reflect this change.
|
192
|
+
The behavior of the library is not changed for the time being, so you can
|
193
|
+
safely upgrade to this version. However, in a future major release, we will
|
194
|
+
start to explicitly return `nil`.
|
195
|
+
|
196
|
+
This gem comes with a Rubocop rule that can help verify that your
|
197
|
+
application is not relying on the return value of the metric methods. To use
|
198
|
+
this cop on your codebase, invoke Rubocop with the following arguments:
|
199
|
+
|
200
|
+
``` sh
|
201
|
+
rubocop --only StatsD/MetricReturnValue \
|
202
|
+
-r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metric_return_value.rb
|
203
|
+
```
|
204
|
+
|
205
|
+
- **Strict mode**: These custom Rubocop rules will give you a quick indication
|
206
|
+
of the issues in your codebase, but are not airtight. This library now also
|
207
|
+
ships with strict mode, a mixin module that already disables this deprecated
|
208
|
+
behavior so it will raise exceptions if you are depending on deprecated
|
209
|
+
behavior. It will also do additional input validation, and make sure the
|
210
|
+
`StatsD` metric methods return `nil`.
|
211
|
+
|
212
|
+
You enable strict mode by requiring `statsd/instrument/strict`:
|
213
|
+
|
214
|
+
``` ruby
|
215
|
+
# In your Gemfile
|
216
|
+
gem 'statd-instrument', require: 'statsd/instrument/strict'
|
217
|
+
|
218
|
+
# Or, in your test helper:
|
219
|
+
require 'statsd/instrument/strict'
|
220
|
+
```
|
221
|
+
|
222
|
+
It is recommended to enable this in CI to find deprecation issues, but not
|
223
|
+
in production because enabling it comes with a performance penalty.
|
224
|
+
|
225
|
+
- **Performance improvements 🎉**: Several internal changes have made the
|
226
|
+
library run singificantly faster. The changes:
|
227
|
+
|
228
|
+
- Improve performance of duration calculations. (#168)
|
229
|
+
- Early exit when no changes are needed to bring tags and metric names to
|
230
|
+
normalized form. (#173)
|
231
|
+
- Refactor method argument handling to reduce object allocations and
|
232
|
+
processing. (#174)
|
233
|
+
|
234
|
+
A benchmark suite was added (#169) and it now runs as part of CI (#170) so we
|
235
|
+
can more easily spot performance regressions before they get merged into the
|
236
|
+
library.
|
237
|
+
|
238
|
+
The result of this work:
|
239
|
+
|
240
|
+
```
|
241
|
+
Comparison:
|
242
|
+
StatsD metrics to local UDP receiver (branch: master, sha: 2f98046): 10344.9 i/s
|
243
|
+
StatsD metrics to local UDP receiver (branch: v2.4.0, sha: 371d22a): 8556.5 i/s - 1.21x (± 0.00) slower
|
244
|
+
```
|
245
|
+
|
246
|
+
The deprecations mentioned above will allows us to provide an even greater
|
247
|
+
performance improvement, so update your code base to not use those
|
248
|
+
deprecations anymore, and keep your eyes open for future releases of the
|
249
|
+
library!
|
250
|
+
|
251
|
+
- _Bugfix:_ avoid deadlock when an error occurs in the integration test suite (#175)
|
252
|
+
|
253
|
+
## Version 2.4.0
|
254
|
+
|
255
|
+
- Add `StatsD.default_tags` to specify tags that should be included in all metrics. (#159)
|
256
|
+
- Improve assertion message when asserting metrics whose tags do not match. (#100)
|
257
|
+
- Enforce the Shopify Ruby style guide. (#164)
|
258
|
+
- Migrate CI to Github actions. (#158)
|
259
|
+
- Make the library frozen string literal-compatible. (#161, #163)
|
260
|
+
- Fix all Ruby warnings. (#162)
|
261
|
+
|
262
|
+
## Version 2.3.5
|
263
|
+
|
264
|
+
- Re-add `StatsD::Instrument.duration`, which was accidentally removed since verison 2.5.3 (#157)
|
265
|
+
|
266
|
+
## Version 2.3.4
|
267
|
+
|
268
|
+
- Improve performance of `Metric#to_s` (#152)
|
269
|
+
- Fix bug in escaping newlines for events with Datadog Backend (#153)
|
270
|
+
|
271
|
+
## Version 2.3.3
|
272
|
+
|
273
|
+
- Capture measure and distribution metrics on exception and early return (#134)
|
274
|
+
|
275
|
+
NOTE: Now that exceptions are measured statistics may behave differently. An exception example:
|
276
|
+
```
|
277
|
+
StatsD.measure('myhttpcall') do
|
278
|
+
my_http_object.invoke
|
279
|
+
end
|
280
|
+
```
|
281
|
+
Version 2.3.2 and below did not track metrics whenever a HTTP Timeout exception was raised.
|
282
|
+
2.3.3 and above will include those metrics which may increase the values included.
|
283
|
+
|
284
|
+
A return example:
|
285
|
+
```
|
286
|
+
StatsD.measure('myexpensivecalculation') do
|
287
|
+
return if expensive_calculation_disabled?
|
288
|
+
expensive_calculation
|
289
|
+
end
|
290
|
+
```
|
291
|
+
If `expensive_calculation_disabled?` is true 50% of the time version 2.3.2 will drop the
|
292
|
+
average metric considerably.
|
293
|
+
|
8
294
|
## Version 2.3.2
|
9
295
|
|
10
296
|
- Add option to override global prefix for metrics (#148)
|
data/CONTRIBUTING.md
CHANGED
@@ -11,27 +11,49 @@ This project is MIT licensed.
|
|
11
11
|
|
12
12
|
Report issues using the [Github issues tracker](https://github.com/Shopify/statsd-instrument/issues/new).
|
13
13
|
|
14
|
-
When reporting issues, please
|
14
|
+
When reporting issues, please include the following information:
|
15
15
|
|
16
16
|
- Your Ruby interpreter version.
|
17
17
|
- The statsd-instrument version. **Note:** only the latest version is supported.
|
18
18
|
- The StatsD backend you are using.
|
19
19
|
|
20
|
-
##
|
20
|
+
## Opening pull requests
|
21
21
|
|
22
22
|
1. Fork the repository, and create a branch.
|
23
23
|
2. Implement the feature or bugfix, and add tests that cover the changed functionality.
|
24
|
-
3. Create a pull request. Make sure that you get
|
24
|
+
3. Create a pull request. Make sure that you get a green CI status on your commit.
|
25
25
|
|
26
26
|
Some notes:
|
27
27
|
|
28
|
-
- Make sure to follow to coding style.
|
28
|
+
- Make sure to follow to coding style. This is enforced by Rubocop
|
29
29
|
- Make sure your changes are properly documented using [yardoc syntax](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md).
|
30
30
|
- Add an entry to the "unreleased changes" section of [CHANGELOG.md](./CHANGELOG.md).
|
31
31
|
- **Do not** update `StatsD::Instrument::VERSION`. This will be done during the release prodecure.
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
### On perfomance & benchmarking
|
34
|
+
|
35
|
+
This gem is used in production at Shopify, and is used to instrument some of
|
36
|
+
our hottest code paths. This means that we are very careful about not
|
37
|
+
introducing performance regressions in this library.
|
38
|
+
|
39
|
+
**Important:** Whenever you make changes to the metric emission code path in
|
40
|
+
this library, you **must** include benchmark results to show the impact of
|
41
|
+
your changes.
|
42
|
+
|
43
|
+
The `benchmark/` folder contains some example benchmark script that you can
|
44
|
+
use, or can serve as a starting point. The [benchmark README](benchmark/README.md)
|
45
|
+
has instructions on how to benchmark your changes.
|
46
|
+
|
47
|
+
### On backwards compatibility
|
48
|
+
|
49
|
+
Shopify's codebases are heavily instrumented using this library. As a result, we cannot
|
50
|
+
accept changes that are backwards incompatible:
|
51
|
+
|
52
|
+
- Changes that will require us to update our codebases.
|
53
|
+
- Changes that will cause metrics emitted by this library to change in form or shape.
|
54
|
+
|
55
|
+
This means that we may not be able to accept fixes for what you consider a bug, because
|
56
|
+
we are depending on the current behavior of the library.
|
35
57
|
|
36
58
|
## Release procedure
|
37
59
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,57 +1,51 @@
|
|
1
1
|
# StatsD client for Ruby apps
|
2
2
|
|
3
|
-
|
3
|
+
This is a ruby client for statsd (http://github.com/etsy/statsd). It provides
|
4
|
+
a lightweight way to track and measure metrics in your application.
|
4
5
|
|
5
|
-
|
6
|
+
We call out to statsd by sending data over a UDP socket. UDP sockets are fast,
|
7
|
+
but unreliable, there is no guarantee that your data will ever arrive at its
|
8
|
+
location. In other words, fire and forget. This is perfect for this use case
|
9
|
+
because it means your code doesn't get bogged down trying to log statistics.
|
10
|
+
We send data to statsd several times per request and haven't noticed a
|
11
|
+
performance hit.
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
For more information about StatsD, see the [README of the Etsy project](http://github.com/etsy/statsd).
|
13
|
+
For more information about StatsD, see the [README of the Etsy
|
14
|
+
project](http://github.com/etsy/statsd).
|
10
15
|
|
11
16
|
## Configuration
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# be logged here.
|
41
|
-
StatsD.logger = defined?(Rails) ? Rails.logger : Logger.new($stderr)
|
42
|
-
|
43
|
-
# An optional prefix to be added to each metric.
|
44
|
-
StatsD.prefix = nil # but can be set to any string
|
45
|
-
|
46
|
-
# Sample 10% of events. By default all events are reported, which may overload your network or server.
|
47
|
-
# You can, and should vary this on a per metric basis, depending on frequency and accuracy requirements
|
48
|
-
StatsD.default_sample_rate = (ENV['STATSD_SAMPLE_RATE'] || 0.1 ).to_f
|
49
|
-
```
|
18
|
+
It's recommended to configure this librray by setting environment variables.
|
19
|
+
The following environment variables are supported:
|
20
|
+
|
21
|
+
- `STATSD_ADDR`: (default `localhost:8125`) The address to send the StatsD UDP
|
22
|
+
datagrams to.
|
23
|
+
- `STATSD_IMPLEMENTATION`: (default: `statsd`). The StatsD implementation you
|
24
|
+
are using. `statsd`, `statsite` and `datadog` are supported. Some features
|
25
|
+
are only available on certain implementations,
|
26
|
+
- `STATSD_ENV`: The environment StatsD will run in. If this is not set
|
27
|
+
explicitly, this will be determined based on other environment variables,
|
28
|
+
like `RAILS_ENV` or `ENV`. The library will behave differently:
|
29
|
+
|
30
|
+
- In the **production** and **staging** environment, thre librray will
|
31
|
+
actually send UDP packets.
|
32
|
+
- In the **test** environment, it will swallow all calls, but allows you to
|
33
|
+
capture them for testing purposes. See below for notes on writing tests.
|
34
|
+
- In **development** and all other environments, it will write all calls to
|
35
|
+
the log (`StatsD.logger`, which by default writes to STDOUT).
|
36
|
+
|
37
|
+
- `STATSD_SAMPLE_RATE`: (default: `1.0`) The default sample rate to use for all
|
38
|
+
metrics. This can be used to reduce the amount of network traffic and CPU
|
39
|
+
overhead the usage of this library generates. This can be overridden in a
|
40
|
+
metric method call.
|
41
|
+
- `STATSD_PREFIX`: The prefix to apply to all metric names. This can be
|
42
|
+
overridden in a metric method call.
|
43
|
+
- `STATSD_DEFAULT_TAGS`: A comma-separated list of tags to apply to all metrics.
|
44
|
+
(Note: tags are not supported by all iomplementations.)
|
50
45
|
|
51
46
|
## StatsD keys
|
52
47
|
|
53
48
|
StatsD keys look like 'admin.logins.api.success'. Dots are used as namespace separators.
|
54
|
-
In Graphite, they will show up as folders.
|
55
49
|
|
56
50
|
## Usage
|
57
51
|
|
@@ -82,7 +76,7 @@ StatsD.increment('GoogleBase.insert')
|
|
82
76
|
StatsD.increment('GoogleBase.insert', 10)
|
83
77
|
# you can also specify a sample rate, so only 1/10 of events
|
84
78
|
# actually get to statsd. Useful for very high volume data
|
85
|
-
StatsD.increment('GoogleBase.insert',
|
79
|
+
StatsD.increment('GoogleBase.insert', sample_rate: 0.1)
|
86
80
|
```
|
87
81
|
|
88
82
|
#### StatsD.gauge
|
@@ -106,6 +100,18 @@ StatsD.set('GoogleBase.customers', "12345", sample_rate: 1.0)
|
|
106
100
|
|
107
101
|
Because you are counting unique values, the results of using a sampling value less than 1.0 can lead to unexpected, hard to interpret results.
|
108
102
|
|
103
|
+
#### StatsD.histogram
|
104
|
+
|
105
|
+
Builds a histogram of numeric values.
|
106
|
+
``` ruby
|
107
|
+
|
108
|
+
StatsD.histogram('Order.value', order.value_in_usd.to_f tags: { source: 'POS' })
|
109
|
+
```
|
110
|
+
|
111
|
+
Because you are counting unique values, the results of using a sampling value less than 1.0 can lead to unexpected, hard to interpret results.
|
112
|
+
|
113
|
+
*Note: This is only supported by the beta datadog implementatation.*
|
114
|
+
|
109
115
|
#### StatsD.distribution
|
110
116
|
|
111
117
|
A modified gauge that submits a distribution of values over a sample period. Arithmetic and statistical calculations (percetiles, average, etc.) on the data set are peformed server side rather than client side like a histogram.
|
@@ -333,7 +339,9 @@ end
|
|
333
339
|
|
334
340
|
### Compatibility
|
335
341
|
|
336
|
-
|
342
|
+
The library is tested against Ruby 2.3 and higher. We are not testing on
|
343
|
+
different Ruby implementations besides MRI, but we expect it to work on other
|
344
|
+
implementations as well.
|
337
345
|
|
338
346
|
### Reliance on DNS
|
339
347
|
|
@@ -350,6 +358,6 @@ This can be particularly problematic in clouds that have a shared DNS infrastruc
|
|
350
358
|
|
351
359
|
This library was developed for shopify.com and is MIT licensed.
|
352
360
|
|
353
|
-
- [API documentation](http://www.rubydoc.info/gems/statsd-instrument
|
361
|
+
- [API documentation](http://www.rubydoc.info/gems/statsd-instrument)
|
354
362
|
- [The changelog](./CHANGELOG.md) covers the changes between releases.
|
355
363
|
- [Contributing notes](./CONTRIBUTING.md) if you are interested in contributing to this library.
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler/gem_tasks'
|
2
4
|
require 'rake/testtask'
|
3
5
|
|
4
6
|
Rake::TestTask.new('test') do |t|
|
5
7
|
t.ruby_opts << '-r rubygems'
|
6
8
|
t.libs << 'lib' << 'test'
|
7
|
-
t.test_files = FileList['test
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
10
|
end
|
9
11
|
|
10
|
-
task :
|
12
|
+
task default: :test
|
data/benchmark/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Benchmark scripts
|
2
|
+
|
3
|
+
This directory contains benchmark scripts that can be used to gauge the
|
4
|
+
performance impact of changes.
|
5
|
+
|
6
|
+
As mentioned in the contributing guidelines, this library is used heavily in
|
7
|
+
production at Shopify in many of our hot code paths. This means that we care a
|
8
|
+
lot about changes not introducing performance regressions. Every pull request
|
9
|
+
that changes the code path to send metrics should include benchmarks
|
10
|
+
demonstrating the performance impact of the changes.
|
11
|
+
|
12
|
+
This directory contains two scripts to help with benchmarking.
|
13
|
+
|
14
|
+
- `send-metrics-to-dev-null-log` exercises the code path to construct metrics.
|
15
|
+
- `send-metrics-to-local-udp-listener` will also exercise the code path to
|
16
|
+
actually send a StatsD packet over UDP.
|
17
|
+
|
18
|
+
To benchmark your changes:
|
19
|
+
|
20
|
+
1. Make sure the benchmark script will actually cover your changes.
|
21
|
+
- If not, please create a new benchmark script that does.
|
22
|
+
- Do not commit this script to the repository (yet), so it will continue to
|
23
|
+
be available if you check out another branch.
|
24
|
+
2. Run these scripts on your pull request branch. The results will be stored in
|
25
|
+
a temporary file.
|
26
|
+
3. Checkout the latest version of `master`.
|
27
|
+
4. Run the benchmark again. The benchmark script will now print a comparison
|
28
|
+
between your branch and master.
|
29
|
+
5. Include the output in your pull request description.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'benchmark/ips'
|
6
|
+
require 'socket'
|
7
|
+
|
8
|
+
# Set up an UDP listener to which we can send StatsD packets
|
9
|
+
legacy_receiver = UDPSocket.new
|
10
|
+
legacy_receiver.bind('localhost', 0)
|
11
|
+
|
12
|
+
ENV['ENV'] = "production"
|
13
|
+
ENV['STATSD_ADDR'] = "#{legacy_receiver.addr[2]}:#{legacy_receiver.addr[1]}"
|
14
|
+
ENV['STATSD_IMPLEMENTATION'] ||= 'datadog'
|
15
|
+
|
16
|
+
require 'statsd-instrument'
|
17
|
+
require 'statsd/instrument/client'
|
18
|
+
|
19
|
+
legacy_client = StatsD
|
20
|
+
|
21
|
+
# Set up an UDP listener to which we can send StatsD packets
|
22
|
+
new_client_receiver = UDPSocket.new
|
23
|
+
new_client_receiver.bind('localhost', 0)
|
24
|
+
|
25
|
+
udp_sink = StatsD::Instrument::UDPSink.new(new_client_receiver.addr[2], new_client_receiver.addr[1])
|
26
|
+
new_client = StatsD::Instrument::Client.new(sink: udp_sink, default_sample_rate: StatsD.default_sample_rate)
|
27
|
+
|
28
|
+
Benchmark.ips do |bench|
|
29
|
+
bench.report("Legacy client (sample rate: #{StatsD.default_sample_rate})") do
|
30
|
+
legacy_client.increment('StatsD.increment')
|
31
|
+
end
|
32
|
+
|
33
|
+
bench.report("New client (sample rate: #{StatsD.default_sample_rate})") do
|
34
|
+
new_client.increment('StatsD.increment')
|
35
|
+
end
|
36
|
+
|
37
|
+
bench.compare!
|
38
|
+
end
|
39
|
+
|
40
|
+
legacy_receiver.close
|
41
|
+
new_client_receiver.close
|