--- 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 --- [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 >}}