Statix behaviour (Statix v1.9.0)

View Source

Writer for StatsD-compatible servers.

To get started with Statix, you have to create a module that calls use Statix, like this:

defmodule MyApp.Statix do
  use Statix
end

This will make MyApp.Statix a Statix connection that implements the Statix behaviour. This connection can be started with the MyApp.Statix.connect/1 function (see the connect/1 callback) and a few functions can be called on it to report metrics to the StatsD-compatible server read from the configuration. Usually, connect/1 is called in your application's Application.start/2 callback:

def start(_type, _args) do
  :ok = MyApp.Statix.connect()

  # ...
end

Configuration

Statix can be configured either globally or on a per-connection basis.

The global configuration will affect all Statix connections created with use Statix; it can be specified by configuring the :statix application:

config :statix,
  prefix: "sample",
  host: "stats.tld",
  port: 8181

The per-connection configuration can be specified by configuring each specific connection module under the :statix application:

config :statix, MyApp.Statix,
  port: 8123

Unix domain sockets are also supported for local connections:

config :statix, MyApp.Statix,
  socket_path: "/var/run/statsd.sock"

The following is a list of all the supported options:

  • :prefix - (binary) all metrics sent to the StatsD-compatible server through the configured Statix connection will be prefixed with the value of this option. By default this option is not present.
  • :host - (binary) the host where the StatsD-compatible server is running. Defaults to "127.0.0.1". Ignored if :socket_path is set.
  • :port - (integer) the port (on :host) where the StatsD-compatible server is running. Defaults to 8125. Ignored if :socket_path is set.
  • :socket_path - (binary) path to a Unix domain socket for the StatsD-compatible server. When this option is present, :host and :port are ignored and the connection uses Unix domain sockets instead of UDP. Requires OTP 22+. By default this option is not present.
  • :tags - ([binary]) a list of global tags that will be sent with all metrics. By default this option is not present. See the "Tags" section for more information.
  • :pool_size - (integer) number of ports used to distribute the metric sending. Defaults to 1. See the "Pooling" section for more information.

By default, the configuration is evaluated once, at compile time. If you plan on changing the configuration at runtime, you must specify the :runtime_config option to be true when calling use Statix:

defmodule MyApp.Statix do
  use Statix, runtime_config: true
end

Tags

Tags are a way of adding dimensions to metrics:

MyApp.Statix.gauge("memory", 1, tags: ["region:east"])

In the example above, the memory measurement has been tagged with region:east. Not all StatsD-compatible servers support this feature.

Tags could also be added globally to be included in every metric sent:

config :statix, tags: ["env:#{Mix.env()}"]

Sampling

All the callbacks from the Statix behaviour that accept options support sampling via the :sample_rate option (see also the options/0 type).

MyApp.Statix.increment("page_view", 1, sample_rate: 0.5)

In the example above, the UDP packet will only be sent to the server about half of the time, but the resulting value will be adjusted on the server according to the given sample rate.

Pooling

Statix transmits data using ports.

If a port is busy when you try to send a command to it, the sender may be suspended and some blocking may occur. This becomes more of an issue in highly concurrent environments.

In order to get around that, Statix allows you to start multiple ports, and randomly picks one at the time of transmit.

This option can be configured via the :pool_size option:

config :statix, MyApp.Statix,
  pool_size: 3

Summary

Callbacks

Same as connect([]).

Opens the connection to the StatsD-compatible server.

Same as decrement(key, 1, []).

Same as decrement(key, value, []).

Decrements the StatsD counter identified by key by the given value.

Same as distribution(key, value, []).

Writes value to the distribution identified by key.

Same as gauge(key, value, []).

Writes to the StatsD gauge identified by key.

Same as histogram(key, value, []).

Writes value to the histogram identified by key.

Same as increment(key, 1, []).

Same as increment(key, value, []).

Increments the StatsD counter identified by key by the given value.

Same as measure(key, [], function).

Measures the execution time of the given function and writes that to the StatsD timing identified by key.

Same as send_event(title, text, []).

Sends a DataDog event.

Same as set(key, value, []).

Writes the given value to the StatsD set identified by key.

Same as timing(key, value, []).

Writes the given value to the StatsD timing identified by key.

Types

key()

@type key() :: iodata()

on_send()

@type on_send() :: :ok | {:error, term()}

options()

@type options() :: [sample_rate: float(), tags: [String.t()]]

Callbacks

connect()

@callback connect() :: :ok

Same as connect([]).

connect(options)

@callback connect(options :: keyword()) :: :ok

Opens the connection to the StatsD-compatible server.

The configuration is read from the environment for the :statix application (both globally and per connection).

The given options override the configuration read from the application environment.

decrement(key)

@callback decrement(key()) :: on_send()

Same as decrement(key, 1, []).

decrement(key, value)

@callback decrement(key(), value :: number()) :: on_send()

Same as decrement(key, value, []).

decrement(key, value, options)

@callback decrement(key(), value :: number(), options()) :: on_send()

Decrements the StatsD counter identified by key by the given value.

Works same as increment/3 but subtracts value instead of adding it. For this reason value should be zero or negative.

Examples

iex> MyApp.Statix.decrement("open_connections", 1, [])
:ok

distribution(key, value)

(since 1.9.0)
@callback distribution(key(), value :: String.Chars.t()) :: on_send()

Same as distribution(key, value, []).

distribution(key, value, options)

(since 1.9.0)
@callback distribution(key(), value :: String.Chars.t(), options()) :: on_send()

Writes value to the distribution identified by key.

Distributions are a DataDog-specific (DogStatsD) extension to the StatsD protocol and are not supported by standard StatsD servers. Unlike histograms, values are aggregated server-side by DataDog, providing globally accurate percentiles.

Examples

iex> MyApp.Statix.distribution("request.duration", 123, [])
:ok

gauge(key, value)

@callback gauge(key(), value :: String.Chars.t()) :: on_send()

Same as gauge(key, value, []).

gauge(key, value, options)

@callback gauge(key(), value :: String.Chars.t(), options()) :: on_send()

Writes to the StatsD gauge identified by key.

Examples

iex> MyApp.Statix.gauge("cpu_usage", 0.83, [])
:ok

histogram(key, value)

@callback histogram(key(), value :: String.Chars.t()) :: on_send()

Same as histogram(key, value, []).

histogram(key, value, options)

@callback histogram(key(), value :: String.Chars.t(), options()) :: on_send()

Writes value to the histogram identified by key.

Not all StatsD-compatible servers support histograms. An example of a such server statsite.

Examples

iex> MyApp.Statix.histogram("online_users", 123, [])
:ok

increment(key)

@callback increment(key()) :: on_send()

Same as increment(key, 1, []).

increment(key, value)

@callback increment(key(), value :: number()) :: on_send()

Same as increment(key, value, []).

increment(key, value, options)

@callback increment(key(), value :: number(), options()) :: on_send()

Increments the StatsD counter identified by key by the given value.

value is supposed to be zero or positive and decrement/3 should be used for negative values.

Examples

iex> MyApp.Statix.increment("hits", 1, [])
:ok

measure(key, function)

@callback measure(key(), function :: (-> result)) :: result when result: var

Same as measure(key, [], function).

measure(key, options, function)

@callback measure(key(), options(), function :: (-> result)) :: result when result: var

Measures the execution time of the given function and writes that to the StatsD timing identified by key.

This function returns the value returned by function, making it suitable for easily wrapping existing code.

Examples

iex> MyApp.Statix.measure("integer_to_string", [], fn -> Integer.to_string(123) end)
"123"

send_event(title, text)

(since 1.8.0)
@callback send_event(title :: iodata(), text :: iodata()) :: on_send()

Same as send_event(title, text, []).

send_event(title, text, options)

(since 1.8.0)
@callback send_event(title :: iodata(), text :: iodata(), options()) :: on_send()

Sends a DataDog event.

This uses the DogStatsD event format (_e{title_len,text_len}:title|text), which is a DataDog-specific extension to the StatsD protocol. Standard StatsD servers do not support events.

Examples

iex> MyApp.Statix.send_event("deploy", "v1.2.3", tags: ["env:prod"])
:ok

set(key, value)

@callback set(key(), value :: String.Chars.t()) :: on_send()

Same as set(key, value, []).

set(key, value, options)

@callback set(key(), value :: String.Chars.t(), options()) :: on_send()

Writes the given value to the StatsD set identified by key.

Examples

iex> MyApp.Statix.set("unique_visitors", "user1", [])
:ok

timing(key, value)

@callback timing(key(), value :: String.Chars.t()) :: on_send()

Same as timing(key, value, []).

timing(key, value, options)

@callback timing(key(), value :: String.Chars.t(), options()) :: on_send()

Writes the given value to the StatsD timing identified by key.

value is expected in milliseconds.

Examples

iex> MyApp.Statix.timing("rendering", 12, [])
:ok