statsd-instrument: a Ruby StatsD client with a metaprogramming half
A StatsD client for Ruby apps. Provides metaprogramming methods to inject StatsD instrumentation into your code.
At a glance
- What is it?
- statsd-instrument is a Ruby client for StatsD that sends metrics over a UDP socket and configures itself entirely from environment variables, with an environment-dependent behaviour that sends packets in production, swallows them in test and logs them in development. It also has an experimental aggregation mode that is tied to specific Datadog Agent versions.
- Who is it for?
- statsd-instrument suits a Ruby service that wants cheap, fire and forget metrics without running an agent inside the request path, and the environment variable configuration means a deployment can turn sending on or off without a code change.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 30 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Fire and forget over a UDP socket
The transport choice is stated up front and defended, which is the right way to explain it. The client calls out to StatsD by sending data over a UDP socket, and UDP sockets are fast but unreliable, with no guarantee that the data ever arrives. The project calls this fire and forget, and argues it is right for this use case because your code does not get bogged down trying to log statistics. It also reports that it sends data to StatsD several times per request without having noticed a performance hit, which is the kind of claim worth testing in your own application before you rely on it.
The consequence is straightforward: a metric that is lost is lost, and the client offers no retry, no acknowledgement and no queue. That is the right trade for counters and timings where a dropped sample is noise, and the wrong trade for anything you intend to bill on. The library sits alongside a companion concept in the same project, the metaprogramming side, which instruments your own methods rather than requiring you to write calls by hand.
STATSD_ENV decides what happens to your metrics
One environment variable changes the behaviour of the whole client, and it is the setting to understand first. If it is not set explicitly, the environment is worked out from other variables such as RAILS_ENV or ENV, and then the client behaves differently in each case. In production and staging it actually sends UDP packets. In the test environment it swallows all calls, but allows you to capture them for testing purposes. In development and every other environment it writes all calls to the log, through a logger that by default writes to STDOUT.
That last behaviour is the one that catches people out during a first deployment. A misconfigured environment does not error and does not send, it writes your metric names to a log file, and an application with a chatty logger can fill a disk with metric lines instead of reporting them. It is also a sensible default for development, since it lets you see what you are about to send before you send it. The test behaviour is the more useful half for most teams, because capturing the calls lets you assert on them, so the test environment is a supported workflow rather than a stub.
The knobs that control network traffic
Most of the configuration is about how much traffic the client generates. The address of the StatsD server is set by one variable, defaulting to localhost:8125, and the implementation is another, defaulting to datadog, with plain statsd also supported. The documentation warns that some features are only available on certain implementations, and tags are called out specifically as not being supported by all of them, which is why the default tags variable carries that caveat.
A default sample rate of 1.0 applies to all metrics and can be overridden per call, so a high frequency counter can be sampled down without touching the others. A prefix can be applied to all metric names, also overridable per call, which is how one application reports under several names.
The transport settings are the interesting ones. The buffer capacity, 5000 by default, is the number of events that may sit in the buffer before the emitting thread starts to block, and the documentation is careful about what raising it does and does not buy: it helps with a spike of events, but if the application emits faster than the buffer can be drained, a bigger buffer will not help. Setting it to zero disables batching entirely and sends each event in its own UDP packet, which the documentation calls much slower. A flush interval variable still exists but is marked deprecated, with a value of zero being equivalent to a zero buffer capacity. The maximum packet size defaults to 1472 bytes, and the advice is to leave it alone unless the network genuinely handles larger packets.
Batch statistics that report on the reporter
There is a diagnostic mode built into the client. When the batch statistics interval is set to a non-zero value, the batched UDP sink tracks what it has been doing and emits statistics on that interval to the default sink for your environment. The tracked values are the number of batches sent of any size, the number of times the batched sender had to send a line synchronously because the buffer was full, the average buffer length measured at the start of each batch, the average per-batch byte size of the packet sent to the underlying sink, and the average number of StatsD lines per batch.
Those five numbers are enough to tell you which of the two failure modes you are in. A high count of synchronous sends means the buffer is filling faster than it drains, so a larger capacity will not fix it. A low average batch length with a healthy send count means the batching is not buying you anything, usually because events arrive too slowly to fill a batch before the flush. The default is off, and the naming of the metrics under the statsd_instrument.batched_udp_sink namespace means they are easy to alert on once you have turned them on.
Experimental aggregation, and the version trap
The aggregation feature aggregates multiple metric events into a single sample, which reduces the number of network requests and can cut the overhead of high frequency reporting. Counters that would have gone out as three packets are sent as one:
my.counter:3|cinstead of
my.counter:1|c
my.counter:1|c
my.counter:1|cHistograms are aggregated the same way, with the values joined by colons in a single packet:
my.histogram:1:2:3|hThe feature is off by default and is turned on with one environment variable, with the flush interval set by a second, which defaults to two seconds when it is not specified. The warning attached to it is explicit: it is an experimental feature, it should be used with caution in production environments, and it is only compatible with Datadog Agent versions of 6.25.0 and above but below 7.0.0, or versions of 7.25.0 and above. That last constraint is the one to check before you plan around it, because a plain StatsD server will not understand the aggregated form at all.
Metric names are normalised without telling you
StatsD keys look like admin.logins.api.success, with dots as namespace separators. The library then normalises metric names and prefixes, replacing the colon, the pipe, the at sign and ASCII whitespace, which covers spaces, tabs and line breaks, with the character _, one per replaced character. Newlines in set values are replaced with the character _ as well, and in array and hash tags the newlines are removed along with the pipe and comma characters, while other whitespace inside tag values is preserved.
The last line of that section is the one to keep in mind: the normalisation is silent. Nothing raises, nothing is logged, and a name that contains a character the protocol cannot carry is quietly rewritten. For the common case that is a convenience, since it removes a class of malformed packets. But it also means that two different source strings can normalise to the same key, and if your metric names are generated from user data, two distinct values can end up counted as one series. That is a real risk in an application that builds metric names dynamically, and it is worth checking for by listing the names your code produces before you rely on the aggregates.
The metaprogramming half and how the gem is maintained
The library offers two ways in. You can use the basic methods to submit stats over StatsD, or you can use the metaprogramming methods to instrument your methods with basic stats, meaning call counts, successes, failures and timings. The basic methods are ordinary calls, and the measure method either takes a key and a millisecond value or wraps a block of code: ``` ruby # You can pass a key and a ms value StatsD.measure('GoogleBase.insert', 2.55)
# or more commonly pass a block that calls your code StatsD.measure('GoogleBase.insert') do GoogleBase.insert(product) end
The counter method takes an optional amount, defaulting to one increment:ruby # increments default to +1 StatsD.increment('GoogleBase.insert') # you can also specify how much to increment the key by StatsD.increment('GoogleBase.insert', 10) ``` On the maintenance side, the repository is a well dressed gem: a gemspec, a Gemfile, a Rakefile, a Makefile whose check target runs an update, a lint pass and the test suite in sequence, rubocop configuration, yard options for the documentation, a benchmark directory, and a release configuration file for the shipit tooling. The changelog is in the repository and the project publishes no GitHub releases, so the gem version is the thing to track. The licence is MIT, the last push was on 2026-09-23, and the documentation is published under the shopify.github.io address.
Editorial conclusion
statsd-instrument suits a Ruby service that wants cheap, fire and forget metrics without running an agent inside the request path, and the environment variable configuration means a deployment can turn sending on or off without a code change. It is the wrong choice if you need delivery guarantees, since the transport is UDP and packets are simply discarded if they do not arrive, and it is the wrong choice if you want the experimental aggregation mode, because the project warns it should be used with caution in production and states it only works with particular Datadog Agent versions. Before you switch it on, set the environment variable that matches your deployment and confirm your StatsD implementation supports the features you plan to use, since the client supports two implementations and some features exist on only one of them. If you rely on the batch statistics, note that they are off by default and are emitted to the sink for your environment. The licence is MIT and the last push was on 2026-09-23.
Frequently asked questions
How do I configure statsd-instrument?
The project recommends configuring it through environment variables. The address of the StatsD server defaults to localhost:8125, the implementation defaults to datadog with plain statsd also supported, and the environment variable that decides behaviour is STATSD_ENV, which is inferred from variables such as RAILS_ENV when it is not set explicitly.
What happens to metrics in the test and development environments?
In the test environment the client swallows all calls but allows them to be captured for testing purposes. In development and any other environment it writes all calls to the log through a logger that writes to STDOUT by default, while production and staging actually send UDP packets.
How do I enable the experimental metric aggregation?
Set STATSD_ENABLE_AGGREGATION to true, and set STATSD_AGGREGATION_INTERVAL to the flush interval in seconds, which defaults to two. The project states the feature is experimental, should be used with caution in production, and is only compatible with Datadog Agent versions from 6.25.0 up to but not including 7.0.0, or 7.25.0 and above.
What does STATSD_BUFFER_CAPACITY do?
It is the maximum number of events that may be buffered before the emitting threads start to block, and it defaults to 5000. Raising it helps with a spike of events but not when the application emits faster than the buffer can be sent, and setting it to zero disables batching so events go out in individual UDP packets, which is much slower.
Are metric names sanitised?
Yes, and silently. Colons, pipes, at signs and ASCII whitespace are replaced with the character _, one per replaced character, and newlines are handled slightly differently in set values than in array and hash tags. The normalisation raises nothing and logs nothing, so two different names can end up as the same key.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shopify-statsd-instrument)Was this useful?