Safe Haskell | None |
---|---|
Language | Haskell2010 |
A module for defining metrics that can be monitored.
Metrics are used to monitor program behavior and performance. All metrics have
- a name, and
- a way to get the metric's current value.
This module provides a way to register metrics in a global "metric store". The store can then be used to get a snapshot of all metrics. The store also serves as a central place to keep track of all the program's metrics, both user and library defined.
Here's an example of creating a single counter, used to count the number of request served by a web server:
import System.Metrics import qualified System.Metrics.Counter as Counter main = do store <- newStore requests <- createCounter "myapp.request_count" store -- Every time we receive a request: Counter.inc requests
This module also provides a way to register a number of predefined
metrics that are useful in most applications. See e.g.
registerGcMetrics
.
- data Store
- newStore :: IO Store
- registerCounter :: Text -> IO Int64 -> Store -> IO ()
- registerGauge :: Text -> IO Int64 -> Store -> IO ()
- registerLabel :: Text -> IO Text -> Store -> IO ()
- registerDistribution :: Text -> IO Stats -> Store -> IO ()
- registerGroup :: HashMap Text (a -> Value) -> IO a -> Store -> IO ()
- createCounter :: Text -> Store -> IO Counter
- createGauge :: Text -> Store -> IO Gauge
- createLabel :: Text -> Store -> IO Label
- createDistribution :: Text -> Store -> IO Distribution
- registerGcMetrics :: Store -> IO ()
- type Sample = HashMap Text Value
- sampleAll :: Store -> IO Sample
- data Value
Naming metrics
Compound metric names should be separated using underscores.
Example: request_count
. Periods in the name imply namespacing.
Example: "myapp.users"
. Some consumers of metrics will use
these namespaces to group metrics in e.g. UIs.
Libraries and frameworks that want to register their own metrics
should prefix them with a namespace, to avoid collision with
user-defined metrics and metrics defined by other libraries. For
example, the Snap web framework could prefix all its metrics with
"snap."
.
It's customary to suffix the metric name with a short string
explaining the metric's type e.g. using "_ms"
to denote
milliseconds.
The metric store
The metric store is a shared store of metrics. It allows several
disjoint components (e.g. libraries) to contribute to the set of
metrics exposed by an application. Libraries that want to provide a
set of metrics should defined a register method, in the style of
registerGcMetrics
, that registers the metrics in the Store
. The
register function should document which metrics are registered and
their types (i.e. counter, gauge, label, or distribution).
Registering metrics
Before metrics can be sampled they need to be registered with the
metric store. The same metric name can only be used once. Passing a
metric name that has already been used to one of the register
function is an error
.
Register a non-negative, monotonically increasing, integer-valued
metric. The provided action to read the value must be thread-safe.
Also see createCounter
.
Register an integer-valued metric. The provided action to read
the value must be thread-safe. Also see createGauge
.
Register a text metric. The provided action to read the value
must be thread-safe. Also see createLabel
.
:: Text | Distribution name |
-> IO Stats | Action to read the current metric value |
-> Store | Metric store |
-> IO () |
Register a distribution metric. The provided action to read the
value must be thread-safe. Also see createDistribution
.
:: HashMap Text (a -> Value) | Metric names and getter functions. |
-> IO a | Action to sample the metric group |
-> Store | Metric store |
-> IO () |
Register an action that will be executed any time one of the metrics computed from the value it returns needs to be sampled.
When one or more of the metrics listed in the first argument needs to be sampled, the action is executed and the provided getter functions will be used to extract the metric(s) from the action's return value.
The registered action might be called from a different thread and therefore needs to be thread-safe.
This function allows you to sample groups of metrics together. This is useful if
- you need a consistent view of several metric or
- sampling the metrics together is more efficient.
For example, sampling GC statistics needs to be done atomically or a GC might strike in the middle of sampling, rendering the values incoherent. Sampling GC statistics is also more efficient if done in "bulk", as the run-time system provides a function to sample all GC statistics at once.
Note that sampling of the metrics is only atomic if the provided
action computes a
atomically (e.g. if a
is a record, the action
needs to compute its fields atomically if the sampling is to be
atomic.)
Example usage:
{-# LANGUAGE OverloadedStrings #-} import qualified Data.HashMap.Strict as M import GHC.Stats import System.Metrics main = do store <- newStore let metrics = [ ("num_gcs", Counter . numGcs) , ("max_bytes_used", Gauge . maxBytesUsed) ] registerGroup (M.fromList metrics) getGCStats store
Convenience functions
These functions combined the creation of a mutable reference (e.g.
a Counter
) with registering that reference in the store in one
convenient function.
Create and register a zero-initialized counter.
Create and register a zero-initialized gauge.
Create and register an empty label.
:: Text | Distribution name |
-> Store | Metric store |
-> IO Distribution |
Create and register an event tracker.
Predefined metrics
This library provides a number of pre-defined metrics that can easily be added to a metrics store by calling their register function.
registerGcMetrics :: Store -> IO () Source
Register a number of metrics related to garbage collector behavior.
To enable GC statistics collection, either run your program with
+RTS -T
or compile it with
-with-rtsopts=-T
The runtime overhead of -T
is very small so it's safe to always
leave it enabled.
Registered counters:
rts.gc.bytes_allocated
- Total number of bytes allocated
rts.gc.num_gcs
- Number of garbage collections performed
rts.gc.num_bytes_usage_samples
- Number of byte usage samples taken
rts.gc.cumulative_bytes_used
- Sum of all byte usage samples, can be
used with
numByteUsageSamples
to calculate averages with arbitrary weighting (if you are sampling this record multiple times). rts.gc.bytes_copied
- Number of bytes copied during GC
rts.gc.mutator_cpu_ms
- CPU time spent running mutator threads, in milliseconds. This does not include any profiling overhead or initialization.
rts.gc.mutator_wall_ms
- Wall clock time spent running mutator threads, in milliseconds. This does not include initialization.
rts.gc.gc_cpu_ms
- CPU time spent running GC, in milliseconds.
rts.gc.gc_wall_ms
- Wall clock time spent running GC, in milliseconds.
rts.gc.cpu_ms
- Total CPU time elapsed since program start, in milliseconds.
rts.gc.wall_ms
- Total wall clock time elapsed since start, in milliseconds.
Registered gauges:
rts.gc.max_bytes_used
- Maximum number of live bytes seen so far
rts.gc.current_bytes_used
- Current number of live bytes
rts.gc.current_bytes_slop
- Current number of bytes lost to slop
rts.gc.max_bytes_slop
- Maximum number of bytes lost to slop at any one time so far
rts.gc.peak_megabytes_allocated
- Maximum number of megabytes allocated
rts.gc.par_tot_bytes_copied
- Number of bytes copied during GC, minus
space held by mutable lists held by the capabilities. Can be used
with
parMaxBytesCopied
to determine how well parallel GC utilized all cores. rts.gc.par_avg_bytes_copied
- Deprecated alias for
par_tot_bytes_copied
. rts.gc.par_max_bytes_copied
- Sum of number of bytes copied each GC by
the most active GC thread each GC. The ratio of
par_tot_bytes_copied
divided bypar_max_bytes_copied
approaches 1 for a maximally sequential run and approaches the number of threads (set by the RTS flag-N
) for a maximally parallel run.
Sampling metrics
The metrics register in the store can be sampled together. Sampling
is not atomic. While each metric will be retrieved atomically,
the sample is not an atomic snapshot of the system as a whole. See
registerGroup
for an explanation of how to sample a subset of all
metrics atomically.