Metrics
Contents
- Step 1: Count something
- Step 2: Measure how long something takes
- Step 3: Break a metric down with dimensions
- Send metrics to a backend
- How metrics behave
A metric is a named number that Semantic Logger emits alongside a log entry, so the same call that records what happened can also feed your dashboards and alerts.
Use metrics to track things like:
- How often an event happens (an error, a sign-up, a cache miss).
- How long something takes (an external API call, a database query).
- Running totals, such as the amount purchased per department over time.
There are two parts to using metrics:
- Emit a metric by adding the
:metricoption to any log ormeasure_call. This is covered in Steps 1 to 3 below. - Subscribe a destination (Statsd, New Relic, SignalFx, and so on) that receives those metrics.
Until a subscriber is registered, the
:metricoption is harmless and the number goes nowhere. See Send metrics to a backend.
Metric subscribers are notified asynchronously on the background log thread, so emitting a metric
never slows the calling thread. A metric rides along with its log entry, so it obeys the same level
and filtering rules: a metric on a :trace call is not emitted while the
level is :info.
Not to be confused with operational stats. The metrics on this page are application metrics that your code emits about what it is doing. To monitor Semantic Logger’s own health instead, such as queue sizes and the number of log entries processed or dropped, use
SemanticLogger.stats.
Step 1: Count something
The simplest metric counts how often something happens. Add :metric with a name to any log call,
and the metric is incremented by 1:
logger.info(message: "Signed up", metric: "users/signup")
Supply :metric_amount to change the amount. To decrement:
logger.info(message: "Item removed", metric: "cart/items", metric_amount: -1)
To add to a running total, such as the dollar amount of purchases per department:
logger.info(message: "Purchase complete", metric: "departments/clothing", metric_amount: 189.42)
Note: Statsd counters are integers, so float amounts are rounded to the nearest integer.
Step 2: Measure how long something takes
A duration metric records elapsed time. The easiest way is to add :metric to a measure_ block
(see Measure how long something takes in the
Guide). The measured duration becomes the metric:
logger.measure_info("Called supplier", metric: "supplier/add_user") do
# Code to call the external service ...
end
When you already have the duration, emit it on a plain log call by supplying both :metric and
:duration (in milliseconds):
logger.info(message: "Called supplier", metric: "supplier/add_user", duration: 100.23)
Step 3: Break a metric down with dimensions
Dimensions are key/value labels attached to a metric, so a backend that supports them (such as
SignalFx) can slice it, for example by user, action, or state. Add them with the :dimensions
option:
# A counter, broken down by user:
logger.info(metric: "filters.count", dimensions: {user: "jbloggs"})
# A gauge with an amount and dimensions:
logger.info(metric: "filters.average", metric_amount: 1.2, dimensions: {user: "jbloggs"})
Not every backend supports dimensions. Statsd and New Relic ignore any metric that carries dimensions; SignalFx is built around them. See each subscriber below.
Send metrics to a backend
A metric goes nowhere until a metric subscriber is registered. Add one with
SemanticLogger.add_appender(metric: ...), usually when your application starts. A subscriber
receives every logged entry that has a :metric, asynchronously on the background thread.
Statsd
Send metrics to Statsd over UDP, which can roll them up and forward them to Graphite, MongoDB, and others:
SemanticLogger.add_appender(metric: :statsd, url: "udp://localhost:8125")
Counters are integers (float amounts are rounded). Does not support dimensions.
New Relic
Forward metrics to New Relic so they can be displayed on custom dashboards:
SemanticLogger.add_appender(metric: :new_relic)
Does not support dimensions.
SignalFx
Forward metrics to SignalFx, which is built around dimensions:
SemanticLogger.add_appender(metric: :signalfx, token: "SIGNALFX_ORG_ACCESS_TOKEN")
application and host are always sent as dimensions. To also forward specific named tags as
dimensions whenever they are present on a log entry, list them:
SemanticLogger.add_appender(
metric: :signalfx,
token: "SIGNALFX_ORG_ACCESS_TOKEN",
dimensions: [:user_id, :state]
)
When a duration metric has no dimensions, SignalFx receives both a gauge and a counter, so you can chart both the timing and the number of occurrences. When dimensions are present, the metric is sent as-is.
Elasticsearch and Splunk
These are ordinary log appenders, not metric subscribers, but a metric is part of
the log entry, so metric, metric_amount, and any dimensions are written into the document
automatically. You can build dashboards on those fields directly, without registering a separate
metric subscriber.
How metrics behave
Asynchronous. Subscribers run on the background logging thread, so emitting a metric never slows down the thread that logged it.
Follows the log level. A metric is emitted only when its log entry is actually logged, so it
obeys the same log level and filtering as any other entry. Use this to your advantage: leave detailed
:trace level metrics in the code where they stay dormant under an :info level, then turn them on
when needed, for example by sending the SIGUSR2 signal to lower
the log level on a running process.