title | weight | cSpell:ignore |
---|---|---|
Sampling |
80 |
behaviour defmodule healthcheck |
Sampling is a process that restricts the amount of traces that are generated by a system. The Erlang SDK offers several head samplers.
By default, all spans are sampled, and thus, 100% of traces are sampled. If you do not need to manage data volume, you do not need to configure a sampler.
When sampling, the ParentBasedSampler
is most often used for
head sampling. It uses the sampling
decision of the Span's parent, or the fact that there is no parent, to know
which secondary sampler to use.
The sampler can be configured with the environment variables
OTEL_TRACES_SAMPLER
and OTEL_TRACES_SAMPLER_ARG
or using the Application
configuration allows you to configure each of the 5 potential states of a Span's
parent:
root
- No parentremote_parent_sampled
- Parent is from a remote Span that is sampledremote_parent_not_sampled
- Parent is from a remote Span that is not sampledlocal_parent_sampled
- Parent is from a local Span that is sampledlocal_parent_not_sampled
- Parent is from a local Span that is not sampled
Within the ParentBasedSampler
the most common is the
TraceIdRatioBasedSampler
. It deterministically samples a percentage of traces
that you pass in as a parameter.
You can configure the TraceIdRatioBasedSampler
with environment variables:
export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.1"
This tells the SDK to sample spans such that only 10% of Traces get created.
Example in the Application configuration with a root sampler for sampling 10% of Traces and using the parent decision in the other cases:
{{< tabpane text=true >}} {{% tab Erlang %}}
%% config/sys.config.src
{opentelemetry, {sampler, {parent_based, #{root => {trace_id_ratio_based, 0.10},
remote_parent_sampled => always_on,
remote_parent_not_sampled => always_off,
local_parent_sampled => always_on,
local_parent_not_sampled => always_off}}}}
{{% /tab %}} {{% tab Elixir %}}
# config/runtime.exs
config :opentelemetry, sampler: {:parent_based, %{root: {:trace_id_ratio_based, 0.10},
remote_parent_sampled: :always_on,
remote_parent_not_sampled: :always_off,
local_parent_sampled: :always_on,
local_parent_not_sampled: :always_off}}
{{% /tab %}} {{< /tabpane >}}
The other two built-in samplers are the AlwaysOnSampler
and the
AlwaysOffSampler
.
You can configure the ParentBasedSampler
to use either the AlwaysOnSampler
or AlwaysOffSampler
with the environment variable OTEL_TRACES_SAMPLER
:
export OTEL_TRACES_SAMPLER="parentbased_always_on"
And for the AlwaysOffSampler
:
export OTEL_TRACES_SAMPLER="parentbased_always_off"
Here's an example in the Application configuration with a root sampler that always samples and using the parent decision in the other cases:
{{< tabpane text=true >}} {{% tab Erlang %}}
%% config/sys.config.src
{opentelemetry, {sampler, {parent_based, #{root => always_on,
remote_parent_sampled => always_on,
remote_parent_not_sampled => always_off,
local_parent_sampled => always_on,
local_parent_not_sampled => always_off}}}}
{{% /tab %}} {{% tab Elixir %}}
# config/runtime.exs
config :opentelemetry, sampler: {:parent_based, %{root: :always_on,
remote_parent_sampled: :always_on,
remote_parent_not_sampled: :always_off,
local_parent_sampled: :always_on,
local_parent_not_sampled: :always_off}}
{{% /tab %}} {{< /tabpane >}}
Custom samplers can be created by implementing the
otel_sampler
behaviour.
This example sampler:
{{< tabpane text=true >}} {{% tab Erlang %}}
-module(attribute_sampler).
-behavior(otel_sampler).
-export([description/1,
setup/1,
should_sample/7]).
-include("otel_sampler.hrl").
setup(Attributes) when is_map(Attributes) ->
Attributes;
setup(_) ->
#{}.
description(_) ->
<<"AttributeSampler">>.
should_sample(_Ctx, _TraceId, _Links, _SpanName, _SpanKind, Attributes, ConfigAttributes) ->
AttributesSet = sets:from_list(maps:to_list(Attributes)),
ConfigSet = sets:from_list(maps:to_list(ConfigAttributes)),
case sets:is_disjoint(AttributesSet, ConfigSet) of
true -> {?RECORD_AND_SAMPLE, [], []};
_ -> {?DROP, [], []}
end.
{{% /tab %}} {{% tab Elixir %}}
defmodule AttributesSampler do
def setup(attributes) when is_map(attributes) do
attributes
end
def setup(_) do
%{}
end
def description(_) do
"ExampleSampler"
end
def should_sample(_ctx, _trace_id, _links, _span_name, _span_kind, attributes, config_attributes) do
no_match =
Enum.into(attributes, %MapSet{})
|> MapSet.disjoint?(Enum.into(config_attributes, %MapSet{}))
if no_match, do: {:record_and_sample, [], []}, else: {:drop, [], []}
end
end
{{% /tab %}} {{< /tabpane >}}
Will sample Spans that do not have any attributes that match the attributes passed as the sampler's configuration.
Example configuration to not sample any Span with an attribute specifying the
URL requested is /healthcheck
:
{{< tabpane text=true >}} {{% tab Erlang %}}
{opentelemetry, {sampler, {attributes_sampler, #{'http.target' => <<"/healthcheck">>}}}}
{{% /tab %}} {{% tab Elixir %}}
config :opentelemetry, sampler: {AttributesSampler, %{"http.target": "/healthcheck"}}
{{% /tab %}} {{< /tabpane >}}