217 lines
6.7 KiB
Markdown
217 lines
6.7 KiB
Markdown
---
|
|
title: Sampling
|
|
weight: 80
|
|
# For the writing of behaviour, see
|
|
# https://www.erlang.org/doc/reference_manual/modules.html#behaviour-module-attribute
|
|
cSpell:ignore: behaviour defmodule healthcheck
|
|
---
|
|
|
|
<!-- markdownlint-disable no-duplicate-heading -->
|
|
<!-- markdownlint-capture -->
|
|
|
|
[Sampling](/docs/concepts/sampling/) is a process that restricts the amount of
|
|
traces that are generated by a system. The Erlang SDK offers several
|
|
[head samplers](/docs/concepts/sampling#head-sampling).
|
|
|
|
## Default behavior
|
|
|
|
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.
|
|
|
|
## ParentBasedSampler
|
|
|
|
When sampling, the `ParentBasedSampler` is most often used for
|
|
[head sampling](/docs/concepts/sampling/#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 parent
|
|
- `remote_parent_sampled` - Parent is from a remote Span that is sampled
|
|
- `remote_parent_not_sampled` - Parent is from a remote Span that is not sampled
|
|
- `local_parent_sampled` - Parent is from a local Span that is sampled
|
|
- `local_parent_not_sampled` - Parent is from a local Span that is not sampled
|
|
|
|
### TraceIdRatioBasedSampler
|
|
|
|
Within the `ParentBasedSampler` the most common is the
|
|
`TraceIdRatioBasedSampler`. It deterministically samples a percentage of traces
|
|
that you pass in as a parameter.
|
|
|
|
#### Environment Variables
|
|
|
|
You can configure the `TraceIdRatioBasedSampler` with environment variables:
|
|
|
|
```shell
|
|
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.
|
|
|
|
#### Application configuration
|
|
|
|
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 %}}
|
|
|
|
```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 %}}
|
|
|
|
```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 >}}
|
|
|
|
### AlwaysOn and AlwaysOff Sampler
|
|
|
|
The other two built-in samplers are the `AlwaysOnSampler` and the
|
|
`AlwaysOffSampler`.
|
|
|
|
#### Environment Variables
|
|
|
|
You can configure the `ParentBasedSampler` to use either the `AlwaysOnSampler`
|
|
or `AlwaysOffSampler` with the environment variable `OTEL_TRACES_SAMPLER`:
|
|
|
|
```shell
|
|
export OTEL_TRACES_SAMPLER="parentbased_always_on"
|
|
```
|
|
|
|
And for the `AlwaysOffSampler`:
|
|
|
|
```shell
|
|
export OTEL_TRACES_SAMPLER="parentbased_always_off"
|
|
```
|
|
|
|
#### Application configuration
|
|
|
|
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 %}}
|
|
|
|
```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 %}}
|
|
|
|
```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 Sampler
|
|
|
|
Custom samplers can be created by implementing the
|
|
[`otel_sampler` behaviour](https://hexdocs.pm/opentelemetry/1.3.0/otel_sampler.html#callbacks).
|
|
This example sampler:
|
|
|
|
{{< tabpane text=true >}} {{% tab Erlang %}}
|
|
|
|
```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 %}}
|
|
|
|
```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 %}}
|
|
|
|
```erlang
|
|
{opentelemetry, {sampler, {attributes_sampler, #{'http.target' => <<"/healthcheck">>}}}}
|
|
```
|
|
|
|
{{% /tab %}} {{% tab Elixir %}}
|
|
|
|
```elixir
|
|
config :opentelemetry, sampler: {AttributesSampler, %{"http.target": "/healthcheck"}}
|
|
```
|
|
|
|
{{% /tab %}} {{< /tabpane >}}
|