ekg-core-0.1.1.6: Tracking of system metrics

Safe Haskell | None
Language | Haskell2010

System.Metrics

Contents

- Naming metrics
- The metric store
- Registering metrics
  - Convenience functions
  - Predefined metrics
- Sampling metrics

Description

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`.

Synopsis

- 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
  - = Counter !Int64
  - | Gauge !Int64
  - | Label !Text
  - | Distribution !Stats

# 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).

data Store Source #

A mutable metric store.

newStore :: IO Store Source #

Create a new, empty metric store.

# 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`.

registerCounter Source #

Arguments

:: Text | Counter name
-> IO Int64 | Action to read the current metric value
-> Store | Metric store
-> IO () |

Register a non-negative, monotonically increasing, integer-valued metric. The provided action to read the value must be thread-safe. Also see `createCounter`.

registerGauge Source #

Arguments

:: Text | Gauge name
-> IO Int64 | Action to read the current metric value
-> Store | Metric store
-> IO () |

Register an integer-valued metric. The provided action to read the value must be thread-safe. Also see `createGauge`.

registerLabel Source #

Arguments

:: Text | Label name
-> IO Text | Action to read the current metric value
-> Store | Metric store
-> IO () |

Register a text metric. The provided action to read the value must be thread-safe. Also see `createLabel`.

registerDistribution Source #

Arguments

:: 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`.

registerGroup Source #

Arguments

:: 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 `Value`) with registering that reference in the store in one convenient function.

createCounter Source #

Arguments

:: Text | Counter name
-> Store | Metric store
-> IO Counter |

Create and register a zero-initialized counter.

createGauge Source #

Arguments

:: Text | Gauge name
-> Store | Metric store
-> IO Gauge |

Create and register a zero-initialized gauge.

createLabel Source #

Arguments

:: Text | Label name
-> Store | Metric store
-> IO Label |

Create and register an empty label.

createDistribution Source #

Arguments

:: 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.init_cpu_ms`
  CPU time used by the init phase, in milliseconds. GHC 8.6+ only.
`rts.gc.init_wall_ms`
  Wall clock time spent running the init phase, in milliseconds. GHC 8.6+ only.
`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 by `par_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.

type Sample = HashMap Text Value Source #

A sample of some metrics.

sampleAll :: Store -> IO Sample Source #

Sample all metrics. Sampling is not atomic in the sense that some metrics might have been mutated before they're sampled but after some other metrics have already been sampled.

data Value Source #

The value of a sampled metric.

Constructors

Counter !Int64 |
Gauge !Int64 |
Label !Text |
Distribution !Stats |

Instances

Eq Value Source # |
Instance details Defined in System.Metrics Methods (==) :: Value -> Value -> Bool Source # (/=) :: Value -> Value -> Bool Source #
Show Value Source # |
Instance details Defined in System.Metrics Methods showsPrec :: Int -> Value -> ShowS Source # show :: Value -> String Source # showList :: [Value] -> ShowS Source #