From 8aacfff5e32c535171e88e6a4e17fc7e1096834a Mon Sep 17 00:00:00 2001 From: dvic Date: Wed, 4 Aug 2021 21:00:40 +0200 Subject: [PATCH 01/13] Refactor otel_sampler to use callbacks for setup, should_sample, and decription --- apps/opentelemetry/src/always_off.erl | 49 ++++ apps/opentelemetry/src/always_on.erl | 49 ++++ apps/opentelemetry/src/otel_configuration.erl | 8 +- apps/opentelemetry/src/otel_sampler.erl | 216 +++++------------- apps/opentelemetry/src/otel_span_utils.erl | 7 +- apps/opentelemetry/src/otel_tracer.hrl | 3 +- apps/opentelemetry/src/otel_tracer_server.erl | 12 +- apps/opentelemetry/src/parent_based.erl | 96 ++++++++ .../src/trace_id_ratio_based.erl | 77 +++++++ .../test/opentelemetry_SUITE.erl | 2 +- .../test/otel_configuration_SUITE.erl | 10 +- .../test/otel_samplers_SUITE.erl | 75 +++--- apps/opentelemetry/test/static_sampler.erl | 15 +- 13 files changed, 395 insertions(+), 224 deletions(-) create mode 100644 apps/opentelemetry/src/always_off.erl create mode 100644 apps/opentelemetry/src/always_on.erl create mode 100644 apps/opentelemetry/src/parent_based.erl create mode 100644 apps/opentelemetry/src/trace_id_ratio_based.erl diff --git a/apps/opentelemetry/src/always_off.erl b/apps/opentelemetry/src/always_off.erl new file mode 100644 index 00000000..7420ce55 --- /dev/null +++ b/apps/opentelemetry/src/always_off.erl @@ -0,0 +1,49 @@ +%%%------------------------------------------------------------------------ +%% Copyright 2019, OpenTelemetry Authors +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% @doc +%% A sampler is a function run on each started span that returns whether to +%% record and propagate, only record or not record the span. +%% @end +%%%------------------------------------------------------------------------- +-module(always_off). + +-behavior(otel_sampler). + +-export([description/1, setup/1, should_sample/7]). + +-export_type([opts/0]). + +-include_lib("opentelemetry_api/include/opentelemetry.hrl"). +-include("otel_sampler.hrl"). + +-type opts() :: #{attributes => opentelemetry:attributes()}. + +setup(#{attributes := Attributes}) -> Attributes; +setup(_) -> []. + +description(_) -> <<"AlwaysOffSampler">>. + +should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, Attributes) -> + {?RECORD_AND_SAMPLE, Attributes, tracestate(Ctx)}. + +tracestate(Ctx) -> + tracestate_(otel_tracer:current_span_ctx(Ctx)). + +tracestate_(#span_ctx{tracestate = undefined}) -> + []; +tracestate_(#span_ctx{tracestate = TraceState}) -> + TraceState; +tracestate_(undefined) -> + []. diff --git a/apps/opentelemetry/src/always_on.erl b/apps/opentelemetry/src/always_on.erl new file mode 100644 index 00000000..1394fcd2 --- /dev/null +++ b/apps/opentelemetry/src/always_on.erl @@ -0,0 +1,49 @@ +%%%------------------------------------------------------------------------ +%% Copyright 2019, OpenTelemetry Authors +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% @doc +%% A sampler is a function run on each started span that returns whether to +%% record and propagate, only record or not record the span. +%% @end +%%%------------------------------------------------------------------------- +-module(always_on). + +-behavior(otel_sampler). + +-export([description/1, setup/1, should_sample/7]). + +-export_type([opts/0]). + +-include_lib("opentelemetry_api/include/opentelemetry.hrl"). +-include("otel_sampler.hrl"). + +-type opts() :: #{attributes => opentelemetry:attributes()}. + +setup(#{attributes := Attributes}) -> Attributes; +setup(_) -> []. + +description(_) -> <<"AlwaysOnSampler">>. + +should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, DecisionAttributes) -> + {?RECORD_AND_SAMPLE, DecisionAttributes, tracestate(Ctx)}. + +tracestate(Ctx) -> + tracestate_(otel_tracer:current_span_ctx(Ctx)). + +tracestate_(#span_ctx{tracestate = undefined}) -> + []; +tracestate_(#span_ctx{tracestate = TraceState}) -> + TraceState; +tracestate_(undefined) -> + []. diff --git a/apps/opentelemetry/src/otel_configuration.erl b/apps/opentelemetry/src/otel_configuration.erl index 39c71225..dd929ac4 100644 --- a/apps/opentelemetry/src/otel_configuration.erl +++ b/apps/opentelemetry/src/otel_configuration.erl @@ -151,14 +151,14 @@ transform(sampler, {"always_on", _}) -> transform(sampler, {"always_off", _}) -> {always_off, #{}}; transform(sampler, {"traceidratio", false}) -> - {trace_id_ratio_based, 1.0}; + {trace_id_ratio_based, #{probability => 1.0}}; transform(sampler, {"traceidratio", Probability}) -> - {trace_id_ratio_based, probability_string_to_float(Probability)}; + {trace_id_ratio_based, #{probability => probability_string_to_float(Probability)}}; transform(sampler, {"parentbased_traceidratio", false}) -> - {parentbased_traceidratio, 1.0}; + {parent_based, #{root => {trace_id_ratio_based, #{probability => 1.0}}}}; transform(sampler, {"parentbased_traceidratio", Probability}) -> {parent_based, - #{root => {trace_id_ratio_based, probability_string_to_float(Probability)}}}; + #{root => {trace_id_ratio_based, #{probability => probability_string_to_float(Probability)}}}}; transform(sampler, Value) -> Value; diff --git a/apps/opentelemetry/src/otel_sampler.erl b/apps/opentelemetry/src/otel_sampler.erl index 3e4e649b..a3788110 100644 --- a/apps/opentelemetry/src/otel_sampler.erl +++ b/apps/opentelemetry/src/otel_sampler.erl @@ -19,171 +19,61 @@ %%%------------------------------------------------------------------------- -module(otel_sampler). --export([new/3, - setup/1, - get_description/1, - always_on/7, - always_off/7, - parent_based/7, - trace_id_ratio_based/7]). +-export([description/1, new/1, should_sample/7]). + +-export_type([ + description/0, + instance/0, + sampler_config/0, + sampler_opts/0, + sampling_decision/0, + sampling_result/0, + t/0 +]). + +-callback setup(sampler_opts()) -> sampler_config(). + +-callback description(sampler_config()) -> description(). + +-callback should_sample( + otel_ctx:t(), + opentelemetry:trace_id(), + opentelemetry:links(), + opentelemetry:span_name(), + opentelemetry:span_kind(), + opentelemetry:attributes(), + sampler_config() +) -> sampling_result(). --include_lib("kernel/include/logger.hrl"). --include_lib("opentelemetry_api/include/opentelemetry.hrl"). -include("otel_sampler.hrl"). --include("otel_span.hrl"). --callback setup(sampler_opts()) -> t(). - --type sampling_decision() :: ?DROP | ?RECORD_ONLY | ?RECORD_AND_SAMPLE. --type sampling_result() :: {sampling_decision(), opentelemetry:attributes(), opentelemetry:tracestate()}. +-opaque instance() :: {t(), description(), sampler_opts()}. -type description() :: unicode:unicode_binary(). --type sampler_fun() :: fun((otel_ctx:t(), - opentelemetry:trace_id(), - opentelemetry:links(), - opentelemetry:span_name(), - opentelemetry:span_kind(), - opentelemetry:attributes(), - term()) -> sampling_result()). --type sampler() :: {sampler_fun(), description(), sampler_opts()}. +-type sampler_config() :: term(). -type sampler_opts() :: term(). --opaque t() :: sampler(). --export_type([sampler_fun/0, - description/0, - sampling_result/0, - sampling_decision/0, - sampler_opts/0, - t/0]). - --define(MAX_VALUE, 9223372036854775807). %% 2^63 - 1 - --spec new(sampler_fun(), description(), sampler_opts()) -> t(). -new(DecisionFunction, Description, SamplerOpts) -> - {DecisionFunction, Description, SamplerOpts}. - --spec setup(atom() | {atom() | module(), sampler_opts()}) -> t(). -setup({Sampler, Opts}) -> - setup(Sampler, Opts); -setup(Sampler) when is_atom(Sampler) -> - setup(Sampler, #{}). - -setup(always_on, Opts) -> - {fun ?MODULE:always_on/7, description(always_on, Opts), []}; -setup(always_off, Opts) -> - {fun ?MODULE:always_off/7, description(always_off, Opts), []}; -setup(parent_based, Opts) -> - {Config, Description} = parent_based_config(Opts), - {fun ?MODULE:parent_based/7, Description, Config}; -setup(trace_id_ratio_based, Probability) -> - IdUpperBound = case Probability of - P when P =:= 0.0 -> - 0; - P when P =:= 1.0 -> - ?MAX_VALUE; - P when P >= 0.0 andalso P =< 1.0 -> - P * ?MAX_VALUE - end, - {fun ?MODULE:trace_id_ratio_based/7, description(trace_id_ratio_based, Probability), IdUpperBound}; -setup(Sampler, Opts) -> - Sampler:setup(Opts). - -always_on(Ctx, _TraceId, _Links, _SpanName, _Kind, _Attributes, _Opts) -> - {?RECORD_AND_SAMPLE, [], tracestate(Ctx)}. - -always_off(Ctx, _TraceId, _Links, _SpanName, _Kind, _Attributes, _Opts) -> - {?DROP, [], tracestate(Ctx)}. - --spec get_description(sampler()) -> description(). -get_description({_Fun, Description, _Opts}) -> - Description. - -parent_based_config(Opts=#{root := {RootSampler, RootOpts}}) - when is_atom(RootSampler)-> - {RemoteParentSampled, RemoteParentSampledOpts} - = maps:get(remote_parent_sampled, Opts, {always_on, #{}}), - {RemoteParentNotSampled, RemoteParentNotSampledOpts} - = maps:get(remote_parent_not_sampled, Opts, {always_off, #{}}), - {LocalParentSampled, LocalParentSampledOpts} - = maps:get(local_parent_sampled, Opts, {always_on, #{}}), - {LocalParentNotSampled, LocalParentNotSampledOpts} - = maps:get(local_parent_not_sampled, Opts, {always_off, #{}}), - - ParentBasedConfig = #{root => setup(RootSampler, RootOpts), - remote_parent_sampled => - setup(RemoteParentSampled, RemoteParentSampledOpts), - remote_parent_not_sampled => - setup(RemoteParentNotSampled, RemoteParentNotSampledOpts), - local_parent_sampled => - setup(LocalParentSampled, LocalParentSampledOpts), - local_parent_not_sampled => - setup(LocalParentNotSampled, LocalParentNotSampledOpts)}, - {ParentBasedConfig, description(parent_based, ParentBasedConfig)}; -parent_based_config(Opts) -> - ?LOG_INFO("no root opt found for sampler parent_based. always_on will be used for root spans"), - parent_based_config(Opts#{root => {always_on, #{}}}). - -parent_based(Ctx, TraceId, Links, SpanName, Kind, Attributes, Opts) -> - ParentSpanCtx = otel_tracer:current_span_ctx(Ctx), - {Sampler, _Description, SamplerOpts} = parent_based_sampler(ParentSpanCtx, Opts), - Sampler(Ctx, TraceId, Links, SpanName, Kind, Attributes, SamplerOpts). - -%% remote parent sampled -parent_based_sampler(#span_ctx{trace_flags=TraceFlags, - is_remote=true}, #{remote_parent_sampled := SamplerAndOpts}) - when ?IS_SAMPLED(TraceFlags) -> - SamplerAndOpts; -%% remote parent not sampled -parent_based_sampler(#span_ctx{is_remote=true}, #{remote_parent_not_sampled := SamplerAndOpts}) -> - SamplerAndOpts; -%% local parent sampled -parent_based_sampler(#span_ctx{trace_flags=TraceFlags, - is_remote=false}, #{local_parent_sampled := SamplerAndOpts}) - when ?IS_SAMPLED(TraceFlags) -> - SamplerAndOpts; -%% local parent not sampled -parent_based_sampler(#span_ctx{is_remote=false}, #{local_parent_not_sampled := SamplerAndOpts}) -> - SamplerAndOpts; -%% root -parent_based_sampler(_SpanCtx, #{root := SamplerAndOpts}) -> - SamplerAndOpts. - - -trace_id_ratio_based(Ctx, undefined, _, _, _, _, _IdUpperBound) -> - {?DROP, [], tracestate(Ctx)}; -trace_id_ratio_based(Ctx, 0, _, _, _, _, _IdUpperBound) -> - {?DROP, [], tracestate(Ctx)}; -trace_id_ratio_based(Ctx, TraceId, _, _, _, _, IdUpperBound) -> - Lower64Bits = TraceId band ?MAX_VALUE, - case erlang:abs(Lower64Bits) < IdUpperBound of - true -> - {?RECORD_AND_SAMPLE, [], tracestate(Ctx)}; - false -> - {?DROP, [], tracestate(Ctx)} - end. - -tracestate(Ctx) -> - tracestate_(otel_tracer:current_span_ctx(Ctx)). - -tracestate_(#span_ctx{tracestate=undefined}) -> - []; -tracestate_(#span_ctx{tracestate=TraceState}) -> - TraceState; -tracestate_(undefined) -> - []. - -description(always_on, _) -> - <<"AlwaysOnSampler">>; -description(always_off, _) -> - <<"AlwaysOffSampler">>; -description(trace_id_ratio_based, Probability) -> - unicode:characters_to_binary(io_lib:format("TraceIdRatioBased{~.6f}", [Probability])); -description(parent_based, #{root := RootSampler, - remote_parent_sampled := RemoteParentSampler, - remote_parent_not_sampled := RemoteParentNotSampler, - local_parent_sampled := LocalParentSampler, - local_parent_not_sampled := LocalParentNotSampler}) -> - <<"ParentBased{root:", (get_description(RootSampler))/binary, - ",remoteParentSampled:", (get_description(RemoteParentSampler))/binary, - ",remoteParentNotSampled:", (get_description(RemoteParentNotSampler))/binary, - ",localParentSampled:", (get_description(LocalParentSampler))/binary, - ",localParentNotSampled:", (get_description(LocalParentNotSampler))/binary, - "}">>. +-type sampler_spec() :: {t(), sampler_opts()}. +-type sampling_decision() :: ?DROP | ?RECORD_ONLY | ?RECORD_AND_SAMPLE. +-type sampling_result() :: { + sampling_decision(), opentelemetry:attributes(), opentelemetry:tracestate() +}. +-type t() :: module(). + +-spec new(sampler_spec()) -> instance(). +new({Sampler, Opts}) -> + Config = Sampler:setup(Opts), + {Sampler, Sampler:description(Config), Config}. + +-spec should_sample( + instance(), + otel_ctx:t(), + opentelemetry:trace_id(), + opentelemetry:links(), + opentelemetry:span_name(), + opentelemetry:span_kind(), + opentelemetry:attributes() +) -> sampling_result(). +should_sample({Sampler, _, Config}, Ctx, TraceId, Links, SpanName, Kind, Attributes) -> + Sampler:should_sample(Ctx, TraceId, Links, SpanName, Kind, Attributes, Config). + +-spec description(instance()) -> description(). +description({_, Description, _}) -> Description. diff --git a/apps/opentelemetry/src/otel_span_utils.erl b/apps/opentelemetry/src/otel_span_utils.erl index 5ed9deed..51d970c6 100644 --- a/apps/opentelemetry/src/otel_span_utils.erl +++ b/apps/opentelemetry/src/otel_span_utils.erl @@ -101,9 +101,10 @@ end_span(Span) -> %% -sample(Ctx, {Sampler, _Description, Opts}, TraceId, Links, SpanName, Kind, Attributes) -> - {Decision, NewAttributes, TraceState} = Sampler(Ctx, TraceId, Links, SpanName, - Kind, Attributes, Opts), +sample(Ctx, Sampler, TraceId, Links, SpanName, Kind, Attributes) -> + {Decision, NewAttributes, TraceState} = otel_sampler:should_sample( + Sampler, Ctx, TraceId, Links, SpanName, Kind, Attributes + ), case Decision of ?DROP -> {0, false, NewAttributes, TraceState}; diff --git a/apps/opentelemetry/src/otel_tracer.hrl b/apps/opentelemetry/src/otel_tracer.hrl index b252b85c..63f8735d 100644 --- a/apps/opentelemetry/src/otel_tracer.hrl +++ b/apps/opentelemetry/src/otel_tracer.hrl @@ -8,10 +8,9 @@ module :: module(), on_start_processors :: fun((otel_ctx:t(), opentelemetry:span()) -> opentelemetry:span()), on_end_processors :: fun((opentelemetry:span()) -> boolean() | {error, term()}), - sampler :: otel_sampler:t(), + sampler :: otel_sampler:instance(), instrumentation_library :: otel_tracer_server:instrumentation_library() | undefined, telemetry_library :: otel_tracer_server:telemetry_library() | undefined, resource :: otel_resource:t() | undefined }). -type tracer() :: #tracer{}. - diff --git a/apps/opentelemetry/src/otel_tracer_server.erl b/apps/opentelemetry/src/otel_tracer_server.erl index 7c4dc248..e466fda8 100644 --- a/apps/opentelemetry/src/otel_tracer_server.erl +++ b/apps/opentelemetry/src/otel_tracer_server.erl @@ -40,7 +40,7 @@ %% tracers created by this provider shared_tracer :: tracer(), processors :: [module()], - sampler :: otel_sampler:t(), + sampler :: otel_sampler:instance(), resource :: otel_resource:t(), %% list of tracer names to return noop tracers for @@ -54,8 +54,10 @@ init(Opts) -> Resource = otel_resource_detector:get_resource(), - SamplerAndOpts = proplists:get_value(sampler, Opts, {parent_based, #{root => always_on}}), - SamplerFun = otel_sampler:setup(SamplerAndOpts), + SamplerSpec = proplists:get_value( + sampler, Opts, {parent_based, #{root => {always_on, #{}}}} + ), + Sampler = otel_sampler:new(SamplerSpec), Processors = proplists:get_value(processors, Opts, []), DenyList = proplists:get_value(deny_list, Opts, []), @@ -67,7 +69,7 @@ init(Opts) -> version=list_to_binary(LibraryVsn)}, Tracer = #tracer{module=otel_tracer_default, - sampler=SamplerFun, + sampler=Sampler, on_start_processors=on_start(Processors), on_end_processors=on_end(Processors), resource=Resource, @@ -76,7 +78,7 @@ init(Opts) -> {ok, #state{shared_tracer=Tracer, resource=Resource, - sampler=SamplerFun, + sampler=Sampler, telemetry_library=TelemetryLibrary, deny_list=DenyList, processors=Processors}}. diff --git a/apps/opentelemetry/src/parent_based.erl b/apps/opentelemetry/src/parent_based.erl new file mode 100644 index 00000000..2d855fc5 --- /dev/null +++ b/apps/opentelemetry/src/parent_based.erl @@ -0,0 +1,96 @@ +%%%------------------------------------------------------------------------ +%% Copyright 2019, OpenTelemetry Authors +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% @doc +%% A sampler is a function run on each started span that returns whether to +%% record and propagate, only record or not record the span. +%% @end +%%%------------------------------------------------------------------------- +-module(parent_based). + +-behavior(otel_sampler). + +-export([description/1, setup/1, should_sample/7]). + +-export_type([opts/0]). + +-include_lib("kernel/include/logger.hrl"). +-include_lib("opentelemetry_api/include/opentelemetry.hrl"). + +-type opts() :: #{ + remote_parent_sampled => otel_sampler:sampler_spec(), + remote_parent_not_sampled => otel_sampler:sampler_spec(), + local_parent_sampled => otel_sampler:sampler_spec(), + local_parent_not_sampled => otel_sampler:sampler_spec() +}. + +setup(Opts = #{root := RootSpec}) -> + RemoteParentSampledSampler = sampler_for_spec(remote_parent_sampled, Opts, always_on), + RemoteParentNotSampledSampler = sampler_for_spec(remote_parent_not_sampled, Opts, always_off), + LocalParentSampledSampler = sampler_for_spec(local_parent_sampled, Opts, always_on), + LocalParentNotSampledSampler = sampler_for_spec(local_parent_not_sampled, Opts, always_off), + RootSampler = otel_sampler:new(RootSpec), + #{ + root => RootSampler, + remote_parent_sampled => RemoteParentSampledSampler, + remote_parent_not_sampled => RemoteParentNotSampledSampler, + local_parent_sampled => LocalParentSampledSampler, + local_parent_not_sampled => LocalParentNotSampledSampler + }; +setup(Opts) -> + ?LOG_INFO("No sampler spec found for parent_based 'root' option. The sampler 'always_on' will be used for root spans"), + setup(Opts#{root => {always_on, #{}}}). + +sampler_for_spec(Key, Opts, DefaultModule) -> + Spec = maps:get(Key, Opts, {DefaultModule, #{}}), + otel_sampler:new(Spec). + +description(#{ + root := RootSampler, + remote_parent_sampled := RemoteParentSampler, + remote_parent_not_sampled := RemoteParentNotSampler, + local_parent_sampled := LocalParentSampler, + local_parent_not_sampled := LocalParentNotSampler +}) -> + <<"ParentBased{root:", (otel_sampler:description(RootSampler))/binary, ",remoteParentSampled:", + (otel_sampler:description(RemoteParentSampler))/binary, ",remoteParentNotSampled:", + (otel_sampler:description(RemoteParentNotSampler))/binary, ",localParentSampled:", + (otel_sampler:description(LocalParentSampler))/binary, ",localParentNotSampled:", + (otel_sampler:description(LocalParentNotSampler))/binary, "}">>. + +should_sample(Ctx, TraceId, Links, SpanName, SpanKind, Attributes, Config) -> + ParentSpanCtx = otel_tracer:current_span_ctx(Ctx), + SamplerKey = parent_based_sampler(ParentSpanCtx), + {Sampler, _Description, SamplerOpts} = maps:get(SamplerKey, Config), + Sampler:should_sample(Ctx, TraceId, Links, SpanName, SpanKind, Attributes, SamplerOpts). + +%% remote parent sampled +parent_based_sampler(#span_ctx{trace_flags = TraceFlags, is_remote = true}) when + ?IS_SAMPLED(TraceFlags) +-> + remote_parent_sampled; +%% remote parent not sampled +parent_based_sampler(#span_ctx{is_remote = true}) -> + remote_parent_not_sampled; +%% local parent sampled +parent_based_sampler(#span_ctx{trace_flags = TraceFlags, is_remote = false}) when + ?IS_SAMPLED(TraceFlags) +-> + local_parent_sampled; +%% local parent not sampled +parent_based_sampler(#span_ctx{is_remote = false}) -> + local_parent_not_sampled; +%% root +parent_based_sampler(_SpanCtx) -> + root. diff --git a/apps/opentelemetry/src/trace_id_ratio_based.erl b/apps/opentelemetry/src/trace_id_ratio_based.erl new file mode 100644 index 00000000..1ebc616f --- /dev/null +++ b/apps/opentelemetry/src/trace_id_ratio_based.erl @@ -0,0 +1,77 @@ +%%%------------------------------------------------------------------------ +%% Copyright 2019, OpenTelemetry Authors +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% @doc +%% A sampler is a function run on each started span that returns whether to +%% record and propagate, only record or not record the span. +%% @end +%%%------------------------------------------------------------------------- +-module(trace_id_ratio_based). + +-behavior(otel_sampler). + +-export([description/1, setup/1, should_sample/7]). + +-export_type([opts/0]). + +-include_lib("opentelemetry_api/include/opentelemetry.hrl"). +-include("otel_sampler.hrl"). + +-type opts() :: #{attributes => opentelemetry:attributes(), probability := float()}. + +%% 2^63 - 1 +-define(MAX_VALUE, 9223372036854775807). + +setup(Opts = #{probability := Probability}) -> + IdUpperBound = + case Probability of + P when P =:= 0.0 -> + 0; + P when P =:= 1.0 -> + ?MAX_VALUE; + P when P >= 0.0 andalso P =< 1.0 -> + P * ?MAX_VALUE + end, + Attributes = maps:get(attributes, Opts, []), + #{attributes => Attributes, probability => Probability, id_upper_bound => IdUpperBound}. + +description(#{probability := Probability}) -> + unicode:characters_to_binary(io_lib:format("TraceIdRatioBased{~.6f}", [Probability])). + +should_sample(Ctx, TraceId, _Links, _SpanName, _SpanKind, _Attributes, #{ + attributes := DecisionAttributes, id_upper_bound := IdUpperBound +}) -> + Decision = decide(TraceId, IdUpperBound), + {Decision, DecisionAttributes, tracestate(Ctx)}. + +decide(undefined, _IdUpperBound) -> + ?DROP; +decide(0, _IdUpperBound) -> + ?DROP; +decide(TraceId, IdUpperBound) -> + Lower64Bits = TraceId band ?MAX_VALUE, + case erlang:abs(Lower64Bits) < IdUpperBound of + true -> ?RECORD_AND_SAMPLE; + false -> ?DROP + end. + +tracestate(Ctx) -> + tracestate_(otel_tracer:current_span_ctx(Ctx)). + +tracestate_(#span_ctx{tracestate = undefined}) -> + []; +tracestate_(#span_ctx{tracestate = TraceState}) -> + TraceState; +tracestate_(undefined) -> + []. diff --git a/apps/opentelemetry/test/opentelemetry_SUITE.erl b/apps/opentelemetry/test/opentelemetry_SUITE.erl index fb6b783d..39866384 100644 --- a/apps/opentelemetry/test/opentelemetry_SUITE.erl +++ b/apps/opentelemetry/test/opentelemetry_SUITE.erl @@ -462,7 +462,7 @@ record_but_not_sample(Config) -> "as a valid recorded span but is not sent to the exporter."), Tid = ?config(tid, Config), - Sampler = otel_sampler:setup({static_sampler, #{<<"span-record-and-sample">> => ?RECORD_AND_SAMPLE, + Sampler = otel_sampler:new({static_sampler, #{<<"span-record-and-sample">> => ?RECORD_AND_SAMPLE, <<"span-record">> => ?RECORD_ONLY}}), Tracer = opentelemetry:get_tracer(), diff --git a/apps/opentelemetry/test/otel_configuration_SUITE.erl b/apps/opentelemetry/test/otel_configuration_SUITE.erl index 64332933..251f372e 100644 --- a/apps/opentelemetry/test/otel_configuration_SUITE.erl +++ b/apps/opentelemetry/test/otel_configuration_SUITE.erl @@ -123,31 +123,31 @@ sampler(_Config) -> ok. sampler_parent_based(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.5}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 0.5}}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, 0.5}}, + ?assertMatch({sampler, {trace_id_ratio_based, #{probability := 0.5}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id_default(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, 1.0}}, + ?assertMatch({sampler, {trace_id_ratio_based, #{probability := 1.0}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_one(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 1.0}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 1.0}}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_zero(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.0}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 0.0}}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index 7fa3296f..c669f54c 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -28,13 +28,19 @@ end_per_testcase(_, _Config) -> get_description(_Config) -> Probability = 0.5, - Sampler = otel_sampler:setup({trace_id_ratio_based, Probability}), + Sampler = otel_sampler:new({trace_id_ratio_based, #{probability => Probability}}), - ?assertEqual(<<"TraceIdRatioBased{0.500000}">>, otel_sampler:get_description(Sampler)), + ?assertEqual(<<"TraceIdRatioBased{0.500000}">>, otel_sampler:description(Sampler)), - ParentBasedSampler = otel_sampler:setup({parent_based, #{root => {trace_id_ratio_based, Probability}}}), - ?assertEqual(<<"ParentBased{root:TraceIdRatioBased{0.500000},remoteParentSampled:AlwaysOnSampler,remoteParentNotSampled:AlwaysOffSampler,localParentSampled:AlwaysOnSampler,localParentNotSampled:AlwaysOffSampler}">>, - otel_sampler:get_description(ParentBasedSampler)), + ParentBasedSampler = otel_sampler:new( + {parent_based, #{ + root => {trace_id_ratio_based, #{probability => Probability}} + }} + ), + ?assertEqual( + <<"ParentBased{root:TraceIdRatioBased{0.500000},remoteParentSampled:AlwaysOnSampler,remoteParentNotSampled:AlwaysOffSampler,localParentSampled:AlwaysOnSampler,localParentNotSampled:AlwaysOffSampler}">>, + otel_sampler:description(ParentBasedSampler) + ), ok. @@ -47,33 +53,33 @@ trace_id_ratio_based(_Config) -> Ctx = otel_ctx:new(), %% sampler that runs on all spans - {Sampler, _, Opts} = otel_sampler:setup({trace_id_ratio_based, Probability}), + {Sampler, _, Opts} = otel_sampler:new({trace_id_ratio_based, #{probability => Probability}}), %% checks the trace id is under the upper bound ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, undefined), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), DoSample, [], SpanName, undefined, [], Opts)), %% checks the trace id is is over the upper bound ?assertMatch({?DROP, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, undefined), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), DoNotSample, [], SpanName, undefined, [], Opts)), %% ignores the parent span context trace flags ?assertMatch({?DROP, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, + Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, is_remote=true}), DoNotSample, [], SpanName, undefined, [], Opts)), %% ignores the parent span context trace flags ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, + Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, is_remote=false}), DoSample, [], SpanName, undefined, [], Opts)), %% trace id is under the upper bound ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, + Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, is_remote=true}), DoSample, [], SpanName, undefined, [], Opts)), @@ -87,51 +93,52 @@ parent_based(_Config) -> Ctx = otel_ctx:new(), - {Sampler, _, Opts} = otel_sampler:setup({parent_based, - #{root => {trace_id_ratio_based, Probability}}}), + {Sampler, _, Opts} = otel_sampler:new( + {parent_based, #{root => {trace_id_ratio_based, #{probability => Probability}}}} + ), %% with no parent it will run the probability sampler ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, undefined), - DoSample, [], SpanName, undefined, [], Opts)), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), + DoSample, [], SpanName, undefined, [], Opts)), ?assertMatch({?DROP, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, undefined), - DoNotSample, [], SpanName, undefined, [], Opts)), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), + DoNotSample, [], SpanName, undefined, [], Opts)), %% with parent it will use the parents value ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts)), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, + is_remote=true}), + DoNotSample, [], SpanName, undefined, [], Opts)), ?assertMatch({?DROP, [], []}, - Sampler(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts)), + Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, + is_remote=true}), + DoNotSample, [], SpanName, undefined, [], Opts)), %% with no root sampler in setup opts the default sampler always_on is used - {DefaultParentOrElse, _, Opts1} = otel_sampler:setup({parent_based, #{}}), + {DefaultParentOrElse, _, Opts1} = otel_sampler:new({parent_based, #{}}), ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse(otel_tracer:set_current_span(Ctx, undefined), - DoSample, [], SpanName, undefined, [], Opts1)), + DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, undefined), + DoSample, [], SpanName, undefined, [], Opts1)), ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse(otel_tracer:set_current_span(Ctx, undefined), - DoNotSample, [], SpanName, undefined, [], Opts1)), + DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, undefined), + DoNotSample, [], SpanName, undefined, [], Opts1)), ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1}), - DoNotSample, [], SpanName, undefined, [], Opts1)), + DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1}), + DoNotSample, [], SpanName, undefined, [], Opts1)), ?assertMatch({?DROP, [], []}, - DefaultParentOrElse(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, + DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts1)), + DoNotSample, [], SpanName, undefined, [], Opts1)), ok. custom_sampler_module(_Config) -> SpanName = <<"span-name">>, - {Sampler, _, Opts} = otel_sampler:setup({static_sampler, #{SpanName => ?DROP}}), + {Sampler, _, Opts} = otel_sampler:new({static_sampler, #{SpanName => ?DROP}}), ?assertMatch({?DROP, [], []}, - Sampler(otel_ctx:new(), opentelemetry:generate_trace_id(), [], + Sampler:should_sample(otel_ctx:new(), opentelemetry:generate_trace_id(), [], SpanName, undefined, [], Opts)), ok. diff --git a/apps/opentelemetry/test/static_sampler.erl b/apps/opentelemetry/test/static_sampler.erl index 19bb292d..368a2310 100644 --- a/apps/opentelemetry/test/static_sampler.erl +++ b/apps/opentelemetry/test/static_sampler.erl @@ -1,13 +1,14 @@ -module(static_sampler). --export([setup/1]). +-behavior(otel_sampler). + +-export([description/1, setup/1, should_sample/7]). -include("otel_sampler.hrl"). %% sampler returns the value from the Opts map based on the SpanName or `NOT_RECORD' -setup(Opts) -> - otel_sampler:new( - fun(_, _, _, SpanName, _, _, Opts1) -> {maps:get(SpanName, Opts1, ?DROP), [], []} end, - <<"StaticSampler">>, - Opts - ). +setup(Opts) -> Opts. + +description(_) -> <<"StaticSampler">>. + +should_sample(_, _, _, SpanName, _, _, Config) -> {maps:get(SpanName, Config, ?DROP), [], []}. From 24fb117ad4118e5e0289c26faa3ffa93cf3c719e Mon Sep 17 00:00:00 2001 From: dvic Date: Wed, 4 Aug 2021 21:20:52 +0200 Subject: [PATCH 02/13] Fix always_off sampler --- apps/opentelemetry/src/always_off.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opentelemetry/src/always_off.erl b/apps/opentelemetry/src/always_off.erl index 7420ce55..142bce7e 100644 --- a/apps/opentelemetry/src/always_off.erl +++ b/apps/opentelemetry/src/always_off.erl @@ -36,7 +36,7 @@ setup(_) -> []. description(_) -> <<"AlwaysOffSampler">>. should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, Attributes) -> - {?RECORD_AND_SAMPLE, Attributes, tracestate(Ctx)}. + {?DROP, Attributes, tracestate(Ctx)}. tracestate(Ctx) -> tracestate_(otel_tracer:current_span_ctx(Ctx)). From 30257ce8c9a5a7ffd7786f1462c6e7f1903c358d Mon Sep 17 00:00:00 2001 From: dvic Date: Wed, 4 Aug 2021 21:34:46 +0200 Subject: [PATCH 03/13] Add tests for passing attributes to built-in samplers --- apps/opentelemetry/src/always_off.erl | 4 +- .../test/otel_samplers_SUITE.erl | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/apps/opentelemetry/src/always_off.erl b/apps/opentelemetry/src/always_off.erl index 142bce7e..1ed52a95 100644 --- a/apps/opentelemetry/src/always_off.erl +++ b/apps/opentelemetry/src/always_off.erl @@ -35,8 +35,8 @@ setup(_) -> []. description(_) -> <<"AlwaysOffSampler">>. -should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, Attributes) -> - {?DROP, Attributes, tracestate(Ctx)}. +should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, DecisionAttributes) -> + {?DROP, DecisionAttributes, tracestate(Ctx)}. tracestate(Ctx) -> tracestate_(otel_tracer:current_span_ctx(Ctx)). diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index c669f54c..8d70bf6a 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -142,3 +142,61 @@ custom_sampler_module(_Config) -> Sampler:should_sample(otel_ctx:new(), opentelemetry:generate_trace_id(), [], SpanName, undefined, [], Opts)), ok. + +pass_attributes(_Config) -> + SpanName = <<"span-name">>, + Probability = 0.5, + + % always_on + {AlwaysOnSampler, _, AlwaysOnSamplerOpts} = otel_sampler:new( + {always_on, #{attributes => [{<<"foo">>, <<"bar">>}]}} + ), + ?assertMatch( + {_, [{<<"foo">>, <<"bar">>}], []}, + AlwaysOnSampler:should_sample( + otel_ctx:new(), + opentelemetry:generate_trace_id(), + [], + SpanName, + undefined, + [], + AlwaysOnSamplerOpts + ) + ), + + % always_off + {AlwaysOffSampler, _, AlwaysOffSamplerOpts} = otel_sampler:new( + {always_off, #{attributes => [{<<"foo">>, <<"bar">>}]}} + ), + ?assertMatch( + {_, [{<<"foo">>, <<"bar">>}], []}, + AlwaysOffSampler:should_sample( + otel_ctx:new(), + opentelemetry:generate_trace_id(), + [], + SpanName, + undefined, + [], + AlwaysOffSamplerOpts + ) + ), + + % trace_id_ratio_based + {TraceIdRatioBased, _, TraceIdRatioBasedOpts} = otel_sampler:new( + {trace_id_ratio_based, #{ + probability => Probability, attributes => [{<<"foo">>, <<"bar">>}] + }} + ), + ?assertMatch( + {_, [{<<"foo">>, <<"bar">>}], []}, + TraceIdRatioBased:should_sample( + otel_ctx:new(), + opentelemetry:generate_trace_id(), + [], + SpanName, + undefined, + [], + TraceIdRatioBasedOpts + ) + ), + ok. From c332b9252235010e6a31aaa085fea29679c6edb9 Mon Sep 17 00:00:00 2001 From: dvic Date: Wed, 4 Aug 2021 21:38:20 +0200 Subject: [PATCH 04/13] Add test for otel_samplers:should_sample --- apps/opentelemetry/test/otel_samplers_SUITE.erl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index 8d70bf6a..7541d5c6 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -200,3 +200,19 @@ pass_attributes(_Config) -> ) ), ok. + +should_sample(_Config) -> + Sampler = otel_sampler:new({always_on, #{}}), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + otel_samplers:should_sample( + Sampler, + otel_ctx:new(), + opentelemetry:generate_trace_id(), + [], + <<"span-name">>, + undefined, + [] + ) + ), + ok. From acfd32ef8c1332ea4910f5e775c907829441cabf Mon Sep 17 00:00:00 2001 From: dvic Date: Thu, 5 Aug 2021 19:42:14 +0200 Subject: [PATCH 05/13] Add 'pass_attributes' test to all() --- apps/opentelemetry/test/otel_samplers_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index 7541d5c6..c9ebdc85 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -9,7 +9,7 @@ -include("otel_sampler.hrl"). all() -> - [trace_id_ratio_based, parent_based, get_description, custom_sampler_module]. + [trace_id_ratio_based, parent_based, get_description, custom_sampler_module, pass_attributes]. init_per_suite(Config) -> application:load(opentelemetry), From 5efd97328c3634a7257ff56df1a1785c4a68ebe9 Mon Sep 17 00:00:00 2001 From: dvic Date: Fri, 6 Aug 2021 17:01:07 +0200 Subject: [PATCH 06/13] Fix parent-based sampler picking the wrong sampler, see #264 --- apps/opentelemetry/src/parent_based.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opentelemetry/src/parent_based.erl b/apps/opentelemetry/src/parent_based.erl index 2d855fc5..4d80812a 100644 --- a/apps/opentelemetry/src/parent_based.erl +++ b/apps/opentelemetry/src/parent_based.erl @@ -84,12 +84,12 @@ parent_based_sampler(#span_ctx{trace_flags = TraceFlags, is_remote = true}) when parent_based_sampler(#span_ctx{is_remote = true}) -> remote_parent_not_sampled; %% local parent sampled -parent_based_sampler(#span_ctx{trace_flags = TraceFlags, is_remote = false}) when +parent_based_sampler(#span_ctx{trace_flags = TraceFlags}) when ?IS_SAMPLED(TraceFlags) -> local_parent_sampled; %% local parent not sampled -parent_based_sampler(#span_ctx{is_remote = false}) -> +parent_based_sampler(#span_ctx{}) -> local_parent_not_sampled; %% root parent_based_sampler(_SpanCtx) -> From 2bb52628475b12848c05b5ab70bff8fdfcbab40f Mon Sep 17 00:00:00 2001 From: dvic Date: Fri, 6 Aug 2021 20:39:12 +0200 Subject: [PATCH 07/13] Revert support for attributes in built-in samplers --- apps/opentelemetry/src/always_off.erl | 11 +- apps/opentelemetry/src/always_on.erl | 11 +- apps/opentelemetry/src/otel_configuration.erl | 8 +- apps/opentelemetry/src/parent_based.erl | 3 +- .../src/trace_id_ratio_based.erl | 16 +- .../test/otel_configuration_SUITE.erl | 10 +- .../test/otel_samplers_SUITE.erl | 266 ++++++++++++------ 7 files changed, 198 insertions(+), 127 deletions(-) diff --git a/apps/opentelemetry/src/always_off.erl b/apps/opentelemetry/src/always_off.erl index 1ed52a95..33be3ae0 100644 --- a/apps/opentelemetry/src/always_off.erl +++ b/apps/opentelemetry/src/always_off.erl @@ -23,20 +23,15 @@ -export([description/1, setup/1, should_sample/7]). --export_type([opts/0]). - -include_lib("opentelemetry_api/include/opentelemetry.hrl"). -include("otel_sampler.hrl"). --type opts() :: #{attributes => opentelemetry:attributes()}. - -setup(#{attributes := Attributes}) -> Attributes; -setup(_) -> []. +setup(_Opts) -> []. description(_) -> <<"AlwaysOffSampler">>. -should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, DecisionAttributes) -> - {?DROP, DecisionAttributes, tracestate(Ctx)}. +should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, _Opts) -> + {?DROP, [], tracestate(Ctx)}. tracestate(Ctx) -> tracestate_(otel_tracer:current_span_ctx(Ctx)). diff --git a/apps/opentelemetry/src/always_on.erl b/apps/opentelemetry/src/always_on.erl index 1394fcd2..d4a3f0c5 100644 --- a/apps/opentelemetry/src/always_on.erl +++ b/apps/opentelemetry/src/always_on.erl @@ -23,20 +23,15 @@ -export([description/1, setup/1, should_sample/7]). --export_type([opts/0]). - -include_lib("opentelemetry_api/include/opentelemetry.hrl"). -include("otel_sampler.hrl"). --type opts() :: #{attributes => opentelemetry:attributes()}. - -setup(#{attributes := Attributes}) -> Attributes; -setup(_) -> []. +setup(_Opts) -> []. description(_) -> <<"AlwaysOnSampler">>. -should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, DecisionAttributes) -> - {?RECORD_AND_SAMPLE, DecisionAttributes, tracestate(Ctx)}. +should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, _Opts) -> + {?RECORD_AND_SAMPLE, [], tracestate(Ctx)}. tracestate(Ctx) -> tracestate_(otel_tracer:current_span_ctx(Ctx)). diff --git a/apps/opentelemetry/src/otel_configuration.erl b/apps/opentelemetry/src/otel_configuration.erl index dd929ac4..45d43c78 100644 --- a/apps/opentelemetry/src/otel_configuration.erl +++ b/apps/opentelemetry/src/otel_configuration.erl @@ -151,14 +151,14 @@ transform(sampler, {"always_on", _}) -> transform(sampler, {"always_off", _}) -> {always_off, #{}}; transform(sampler, {"traceidratio", false}) -> - {trace_id_ratio_based, #{probability => 1.0}}; + {trace_id_ratio_based, 1.0}; transform(sampler, {"traceidratio", Probability}) -> - {trace_id_ratio_based, #{probability => probability_string_to_float(Probability)}}; + {trace_id_ratio_based, probability_string_to_float(Probability)}; transform(sampler, {"parentbased_traceidratio", false}) -> - {parent_based, #{root => {trace_id_ratio_based, #{probability => 1.0}}}}; + {parent_based, #{root => {trace_id_ratio_based, 1.0}}}; transform(sampler, {"parentbased_traceidratio", Probability}) -> {parent_based, - #{root => {trace_id_ratio_based, #{probability => probability_string_to_float(Probability)}}}}; + #{root => {trace_id_ratio_based, probability_string_to_float(Probability)}}}; transform(sampler, Value) -> Value; diff --git a/apps/opentelemetry/src/parent_based.erl b/apps/opentelemetry/src/parent_based.erl index 4d80812a..20ca15ac 100644 --- a/apps/opentelemetry/src/parent_based.erl +++ b/apps/opentelemetry/src/parent_based.erl @@ -32,7 +32,8 @@ remote_parent_sampled => otel_sampler:sampler_spec(), remote_parent_not_sampled => otel_sampler:sampler_spec(), local_parent_sampled => otel_sampler:sampler_spec(), - local_parent_not_sampled => otel_sampler:sampler_spec() + local_parent_not_sampled => otel_sampler:sampler_spec(), + root => otel_sampler:sampler_spec() }. setup(Opts = #{root := RootSpec}) -> diff --git a/apps/opentelemetry/src/trace_id_ratio_based.erl b/apps/opentelemetry/src/trace_id_ratio_based.erl index 1ebc616f..4fc0289d 100644 --- a/apps/opentelemetry/src/trace_id_ratio_based.erl +++ b/apps/opentelemetry/src/trace_id_ratio_based.erl @@ -23,17 +23,19 @@ -export([description/1, setup/1, should_sample/7]). --export_type([opts/0]). +-export_type([config/0, probability/0]). -include_lib("opentelemetry_api/include/opentelemetry.hrl"). -include("otel_sampler.hrl"). --type opts() :: #{attributes => opentelemetry:attributes(), probability := float()}. +-type probability() :: float(). +-opaque config() :: #{probability := probability(), id_upper_bound := integer()}. %% 2^63 - 1 -define(MAX_VALUE, 9223372036854775807). -setup(Opts = #{probability := Probability}) -> +-spec setup(probability()) -> config(). +setup(Probability) -> IdUpperBound = case Probability of P when P =:= 0.0 -> @@ -43,17 +45,15 @@ setup(Opts = #{probability := Probability}) -> P when P >= 0.0 andalso P =< 1.0 -> P * ?MAX_VALUE end, - Attributes = maps:get(attributes, Opts, []), - #{attributes => Attributes, probability => Probability, id_upper_bound => IdUpperBound}. + #{probability => Probability, id_upper_bound => IdUpperBound}. description(#{probability := Probability}) -> unicode:characters_to_binary(io_lib:format("TraceIdRatioBased{~.6f}", [Probability])). should_sample(Ctx, TraceId, _Links, _SpanName, _SpanKind, _Attributes, #{ - attributes := DecisionAttributes, id_upper_bound := IdUpperBound + id_upper_bound := IdUpperBound }) -> - Decision = decide(TraceId, IdUpperBound), - {Decision, DecisionAttributes, tracestate(Ctx)}. + {decide(TraceId, IdUpperBound), [], tracestate(Ctx)}. decide(undefined, _IdUpperBound) -> ?DROP; diff --git a/apps/opentelemetry/test/otel_configuration_SUITE.erl b/apps/opentelemetry/test/otel_configuration_SUITE.erl index 251f372e..64332933 100644 --- a/apps/opentelemetry/test/otel_configuration_SUITE.erl +++ b/apps/opentelemetry/test/otel_configuration_SUITE.erl @@ -123,31 +123,31 @@ sampler(_Config) -> ok. sampler_parent_based(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 0.5}}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.5}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, #{probability := 0.5}}}, + ?assertMatch({sampler, {trace_id_ratio_based, 0.5}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id_default(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, #{probability := 1.0}}}, + ?assertMatch({sampler, {trace_id_ratio_based, 1.0}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_one(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 1.0}}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 1.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_zero(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, #{probability := 0.0}}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index c9ebdc85..4fca37a4 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -9,7 +9,7 @@ -include("otel_sampler.hrl"). all() -> - [trace_id_ratio_based, parent_based, get_description, custom_sampler_module, pass_attributes]. + [trace_id_ratio_based, parent_based, get_description, custom_sampler_module]. init_per_suite(Config) -> application:load(opentelemetry), @@ -28,13 +28,13 @@ end_per_testcase(_, _Config) -> get_description(_Config) -> Probability = 0.5, - Sampler = otel_sampler:new({trace_id_ratio_based, #{probability => Probability}}), + Sampler = otel_sampler:new({trace_id_ratio_based, Probability}), ?assertEqual(<<"TraceIdRatioBased{0.500000}">>, otel_sampler:description(Sampler)), ParentBasedSampler = otel_sampler:new( {parent_based, #{ - root => {trace_id_ratio_based, #{probability => Probability}} + root => {trace_id_ratio_based, Probability} }} ), ?assertEqual( @@ -48,40 +48,91 @@ trace_id_ratio_based(_Config) -> SpanName = <<"span-prob-sampled">>, Probability = 0.5, DoSample = 120647249294066572380176333851662846319, - DoNotSample = 53020601517903903921384168845238205400, + DoNotSample = 53020601517903903921384168845238205400, Ctx = otel_ctx:new(), %% sampler that runs on all spans - {Sampler, _, Opts} = otel_sampler:new({trace_id_ratio_based, #{probability => Probability}}), + {Sampler, _, Opts} = otel_sampler:new({trace_id_ratio_based, Probability}), %% checks the trace id is under the upper bound - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% checks the trace id is is over the upper bound - ?assertMatch({?DROP, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoNotSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?DROP, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% ignores the parent span context trace flags - ?assertMatch({?DROP, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?DROP, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 1, + is_remote = true + }), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% ignores the parent span context trace flags - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, - is_remote=false}), - DoSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 0, + is_remote = false + }), + DoSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% trace id is under the upper bound - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, - is_remote=true}), - DoSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 0, + is_remote = true + }), + DoSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), ok. @@ -89,114 +140,143 @@ parent_based(_Config) -> SpanName = <<"span-prob-sampled">>, Probability = 0.5, DoSample = 120647249294066572380176333851662846319, - DoNotSample = 53020601517903903921384168845238205400, + DoNotSample = 53020601517903903921384168845238205400, Ctx = otel_ctx:new(), {Sampler, _, Opts} = otel_sampler:new( - {parent_based, #{root => {trace_id_ratio_based, #{probability => Probability}}}} + {parent_based, #{root => {trace_id_ratio_based, Probability}}} ), %% with no parent it will run the probability sampler - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoSample, [], SpanName, undefined, [], Opts)), - ?assertMatch({?DROP, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoNotSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), + ?assertMatch( + {?DROP, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% with parent it will use the parents value - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts)), - ?assertMatch({?DROP, [], []}, - Sampler:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts)), + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 1, + is_remote = true + }), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), + ?assertMatch( + {?DROP, [], []}, + Sampler:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 0, + is_remote = true + }), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts + ) + ), %% with no root sampler in setup opts the default sampler always_on is used {DefaultParentOrElse, _, Opts1} = otel_sampler:new({parent_based, #{}}), - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoSample, [], SpanName, undefined, [], Opts1)), - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, undefined), - DoNotSample, [], SpanName, undefined, [], Opts1)), - - ?assertMatch({?RECORD_AND_SAMPLE, [], []}, - DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=1}), - DoNotSample, [], SpanName, undefined, [], Opts1)), - ?assertMatch({?DROP, [], []}, - DefaultParentOrElse:should_sample(otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags=0, - is_remote=true}), - DoNotSample, [], SpanName, undefined, [], Opts1)), - - ok. - -custom_sampler_module(_Config) -> - SpanName = <<"span-name">>, - {Sampler, _, Opts} = otel_sampler:new({static_sampler, #{SpanName => ?DROP}}), - ?assertMatch({?DROP, [], []}, - Sampler:should_sample(otel_ctx:new(), opentelemetry:generate_trace_id(), [], - SpanName, undefined, [], Opts)), - ok. - -pass_attributes(_Config) -> - SpanName = <<"span-name">>, - Probability = 0.5, - - % always_on - {AlwaysOnSampler, _, AlwaysOnSamplerOpts} = otel_sampler:new( - {always_on, #{attributes => [{<<"foo">>, <<"bar">>}]}} + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + DefaultParentOrElse:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoSample, + [], + SpanName, + undefined, + [], + Opts1 + ) ), ?assertMatch( - {_, [{<<"foo">>, <<"bar">>}], []}, - AlwaysOnSampler:should_sample( - otel_ctx:new(), - opentelemetry:generate_trace_id(), + {?RECORD_AND_SAMPLE, [], []}, + DefaultParentOrElse:should_sample( + otel_tracer:set_current_span(Ctx, undefined), + DoNotSample, [], SpanName, undefined, [], - AlwaysOnSamplerOpts + Opts1 ) ), - % always_off - {AlwaysOffSampler, _, AlwaysOffSamplerOpts} = otel_sampler:new( - {always_off, #{attributes => [{<<"foo">>, <<"bar">>}]}} + ?assertMatch( + {?RECORD_AND_SAMPLE, [], []}, + DefaultParentOrElse:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{trace_flags = 1}), + DoNotSample, + [], + SpanName, + undefined, + [], + Opts1 + ) ), ?assertMatch( - {_, [{<<"foo">>, <<"bar">>}], []}, - AlwaysOffSampler:should_sample( - otel_ctx:new(), - opentelemetry:generate_trace_id(), + {?DROP, [], []}, + DefaultParentOrElse:should_sample( + otel_tracer:set_current_span(Ctx, #span_ctx{ + trace_flags = 0, + is_remote = true + }), + DoNotSample, [], SpanName, undefined, [], - AlwaysOffSamplerOpts + Opts1 ) ), - % trace_id_ratio_based - {TraceIdRatioBased, _, TraceIdRatioBasedOpts} = otel_sampler:new( - {trace_id_ratio_based, #{ - probability => Probability, attributes => [{<<"foo">>, <<"bar">>}] - }} - ), + ok. + +custom_sampler_module(_Config) -> + SpanName = <<"span-name">>, + {Sampler, _, Opts} = otel_sampler:new({static_sampler, #{SpanName => ?DROP}}), ?assertMatch( - {_, [{<<"foo">>, <<"bar">>}], []}, - TraceIdRatioBased:should_sample( + {?DROP, [], []}, + Sampler:should_sample( otel_ctx:new(), opentelemetry:generate_trace_id(), [], SpanName, undefined, [], - TraceIdRatioBasedOpts + Opts ) ), ok. From 5401b3ad268c648b0e45c796518a3c7e5cddaf40 Mon Sep 17 00:00:00 2001 From: dvic Date: Fri, 6 Aug 2021 20:44:56 +0200 Subject: [PATCH 08/13] Revert introducing otel_sampler:instance() --- apps/opentelemetry/src/otel_sampler.erl | 12 +++++------- apps/opentelemetry/src/otel_tracer.hrl | 14 +++++++------- apps/opentelemetry/src/otel_tracer_server.erl | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/apps/opentelemetry/src/otel_sampler.erl b/apps/opentelemetry/src/otel_sampler.erl index a3788110..6d007f72 100644 --- a/apps/opentelemetry/src/otel_sampler.erl +++ b/apps/opentelemetry/src/otel_sampler.erl @@ -23,7 +23,6 @@ -export_type([ description/0, - instance/0, sampler_config/0, sampler_opts/0, sampling_decision/0, @@ -47,24 +46,23 @@ -include("otel_sampler.hrl"). --opaque instance() :: {t(), description(), sampler_opts()}. -type description() :: unicode:unicode_binary(). -type sampler_config() :: term(). -type sampler_opts() :: term(). --type sampler_spec() :: {t(), sampler_opts()}. +-type sampler_spec() :: {module(), sampler_opts()}. -type sampling_decision() :: ?DROP | ?RECORD_ONLY | ?RECORD_AND_SAMPLE. -type sampling_result() :: { sampling_decision(), opentelemetry:attributes(), opentelemetry:tracestate() }. --type t() :: module(). +-opaque t() :: {module(), description(), sampler_opts()}. --spec new(sampler_spec()) -> instance(). +-spec new(sampler_spec()) -> t(). new({Sampler, Opts}) -> Config = Sampler:setup(Opts), {Sampler, Sampler:description(Config), Config}. -spec should_sample( - instance(), + t(), otel_ctx:t(), opentelemetry:trace_id(), opentelemetry:links(), @@ -75,5 +73,5 @@ new({Sampler, Opts}) -> should_sample({Sampler, _, Config}, Ctx, TraceId, Links, SpanName, Kind, Attributes) -> Sampler:should_sample(Ctx, TraceId, Links, SpanName, Kind, Attributes, Config). --spec description(instance()) -> description(). +-spec description(t()) -> description(). description({_, Description, _}) -> Description. diff --git a/apps/opentelemetry/src/otel_tracer.hrl b/apps/opentelemetry/src/otel_tracer.hrl index 63f8735d..7e00392b 100644 --- a/apps/opentelemetry/src/otel_tracer.hrl +++ b/apps/opentelemetry/src/otel_tracer.hrl @@ -5,12 +5,12 @@ %% See OpenTelemetry Tracer spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-tracing.md#tracer-creation -record(tracer, { - module :: module(), - on_start_processors :: fun((otel_ctx:t(), opentelemetry:span()) -> opentelemetry:span()), - on_end_processors :: fun((opentelemetry:span()) -> boolean() | {error, term()}), - sampler :: otel_sampler:instance(), - instrumentation_library :: otel_tracer_server:instrumentation_library() | undefined, - telemetry_library :: otel_tracer_server:telemetry_library() | undefined, - resource :: otel_resource:t() | undefined + module :: module(), + on_start_processors :: fun((otel_ctx:t(), opentelemetry:span()) -> opentelemetry:span()), + on_end_processors :: fun((opentelemetry:span()) -> boolean() | {error, term()}), + sampler :: otel_sampler:t(), + instrumentation_library :: otel_tracer_server:instrumentation_library() | undefined, + telemetry_library :: otel_tracer_server:telemetry_library() | undefined, + resource :: otel_resource:t() | undefined }). -type tracer() :: #tracer{}. diff --git a/apps/opentelemetry/src/otel_tracer_server.erl b/apps/opentelemetry/src/otel_tracer_server.erl index e466fda8..70ecd749 100644 --- a/apps/opentelemetry/src/otel_tracer_server.erl +++ b/apps/opentelemetry/src/otel_tracer_server.erl @@ -40,7 +40,7 @@ %% tracers created by this provider shared_tracer :: tracer(), processors :: [module()], - sampler :: otel_sampler:instance(), + sampler :: otel_sampler:t(), resource :: otel_resource:t(), %% list of tracer names to return noop tracers for From 0081136aeb590e42a25507cceca74668d2eea81f Mon Sep 17 00:00:00 2001 From: dvic Date: Sun, 8 Aug 2021 00:09:38 +0200 Subject: [PATCH 09/13] Prefix all built-in sampler modules with otel_sampler_ --- apps/opentelemetry/src/opentelemetry.app.src | 2 +- apps/opentelemetry/src/otel_configuration.erl | 24 +++++++++---------- ...ys_off.erl => otel_sampler_always_off.erl} | 2 +- ...ways_on.erl => otel_sampler_always_on.erl} | 2 +- ...ased.erl => otel_sampler_parent_based.erl} | 14 +++++------ ... => otel_sampler_trace_id_ratio_based.erl} | 2 +- apps/opentelemetry/src/otel_tracer_server.erl | 2 +- .../test/otel_configuration_SUITE.erl | 14 +++++------ .../test/otel_samplers_SUITE.erl | 14 +++++------ 9 files changed, 38 insertions(+), 38 deletions(-) rename apps/opentelemetry/src/{always_off.erl => otel_sampler_always_off.erl} (97%) rename apps/opentelemetry/src/{always_on.erl => otel_sampler_always_on.erl} (97%) rename apps/opentelemetry/src/{parent_based.erl => otel_sampler_parent_based.erl} (90%) rename apps/opentelemetry/src/{trace_id_ratio_based.erl => otel_sampler_trace_id_ratio_based.erl} (98%) diff --git a/apps/opentelemetry/src/opentelemetry.app.src b/apps/opentelemetry/src/opentelemetry.app.src index ff16c097..21f3544e 100644 --- a/apps/opentelemetry/src/opentelemetry.app.src +++ b/apps/opentelemetry/src/opentelemetry.app.src @@ -8,7 +8,7 @@ stdlib, opentelemetry_api ]}, - {env, [{sampler, {parent_based, #{root => {always_on, #{}}}}}, % default sampler + {env, [{sampler, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}}, % default sampler {text_map_propagators, [fun otel_baggage:get_text_map_propagators/0, fun otel_tracer_default:w3c_propagators/0]}, diff --git a/apps/opentelemetry/src/otel_configuration.erl b/apps/opentelemetry/src/otel_configuration.erl index 45d43c78..7bd8821b 100644 --- a/apps/opentelemetry/src/otel_configuration.erl +++ b/apps/opentelemetry/src/otel_configuration.erl @@ -45,7 +45,7 @@ processors(AppEnvOpts) -> %% sampler configuration is unique since it has the _ARG that is a sort of %% sub-configuration of the sampler config, and isn't a list. sampler(AppEnvOpts) -> - Sampler = proplists:get_value(sampler, AppEnvOpts, {parent_based, #{root => {always_on, #{}}}}), + Sampler = proplists:get_value(sampler, AppEnvOpts, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}), Sampler1 = case os:getenv("OTEL_TRACES_SAMPLER") of false -> @@ -143,22 +143,22 @@ transform(url, Value) -> uri_string:parse(Value); %% convert sampler string to usable configuration term transform(sampler, {"parentbased_always_on", _}) -> - {parent_based, #{root => {always_on, #{}}}}; + {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}; transform(sampler, {"parentbased_always_off", _}) -> - {parent_based, #{root => {always_off, #{}}}}; -transform(sampler, {"always_on", _}) -> - {always_on, #{}}; -transform(sampler, {"always_off", _}) -> - {always_off, #{}}; + {otel_sampler_parent_based, #{root => {otel_sampler_always_off, #{}}}}; +transform(sampler, {"otel_sampler_always_on", _}) -> + {otel_sampler_always_on, #{}}; +transform(sampler, {"otel_sampler_always_off", _}) -> + {otel_sampler_always_off, #{}}; transform(sampler, {"traceidratio", false}) -> - {trace_id_ratio_based, 1.0}; + {otel_sampler_trace_id_ratio_based, 1.0}; transform(sampler, {"traceidratio", Probability}) -> - {trace_id_ratio_based, probability_string_to_float(Probability)}; + {otel_sampler_trace_id_ratio_based, probability_string_to_float(Probability)}; transform(sampler, {"parentbased_traceidratio", false}) -> - {parent_based, #{root => {trace_id_ratio_based, 1.0}}}; + {otel_sampler_parent_based, #{root => {otel_sampler_trace_id_ratio_based, 1.0}}}; transform(sampler, {"parentbased_traceidratio", Probability}) -> - {parent_based, - #{root => {trace_id_ratio_based, probability_string_to_float(Probability)}}}; + {otel_sampler_parent_based, + #{root => {otel_sampler_trace_id_ratio_based, probability_string_to_float(Probability)}}}; transform(sampler, Value) -> Value; diff --git a/apps/opentelemetry/src/always_off.erl b/apps/opentelemetry/src/otel_sampler_always_off.erl similarity index 97% rename from apps/opentelemetry/src/always_off.erl rename to apps/opentelemetry/src/otel_sampler_always_off.erl index 33be3ae0..182f1737 100644 --- a/apps/opentelemetry/src/always_off.erl +++ b/apps/opentelemetry/src/otel_sampler_always_off.erl @@ -17,7 +17,7 @@ %% record and propagate, only record or not record the span. %% @end %%%------------------------------------------------------------------------- --module(always_off). +-module(otel_sampler_always_off). -behavior(otel_sampler). diff --git a/apps/opentelemetry/src/always_on.erl b/apps/opentelemetry/src/otel_sampler_always_on.erl similarity index 97% rename from apps/opentelemetry/src/always_on.erl rename to apps/opentelemetry/src/otel_sampler_always_on.erl index d4a3f0c5..ff030d4a 100644 --- a/apps/opentelemetry/src/always_on.erl +++ b/apps/opentelemetry/src/otel_sampler_always_on.erl @@ -17,7 +17,7 @@ %% record and propagate, only record or not record the span. %% @end %%%------------------------------------------------------------------------- --module(always_on). +-module(otel_sampler_always_on). -behavior(otel_sampler). diff --git a/apps/opentelemetry/src/parent_based.erl b/apps/opentelemetry/src/otel_sampler_parent_based.erl similarity index 90% rename from apps/opentelemetry/src/parent_based.erl rename to apps/opentelemetry/src/otel_sampler_parent_based.erl index 20ca15ac..cf0975b6 100644 --- a/apps/opentelemetry/src/parent_based.erl +++ b/apps/opentelemetry/src/otel_sampler_parent_based.erl @@ -17,7 +17,7 @@ %% record and propagate, only record or not record the span. %% @end %%%------------------------------------------------------------------------- --module(parent_based). +-module(otel_sampler_parent_based). -behavior(otel_sampler). @@ -37,10 +37,10 @@ }. setup(Opts = #{root := RootSpec}) -> - RemoteParentSampledSampler = sampler_for_spec(remote_parent_sampled, Opts, always_on), - RemoteParentNotSampledSampler = sampler_for_spec(remote_parent_not_sampled, Opts, always_off), - LocalParentSampledSampler = sampler_for_spec(local_parent_sampled, Opts, always_on), - LocalParentNotSampledSampler = sampler_for_spec(local_parent_not_sampled, Opts, always_off), + RemoteParentSampledSampler = sampler_for_spec(remote_parent_sampled, Opts, otel_sampler_always_on), + RemoteParentNotSampledSampler = sampler_for_spec(remote_parent_not_sampled, Opts, otel_sampler_always_off), + LocalParentSampledSampler = sampler_for_spec(local_parent_sampled, Opts, otel_sampler_always_on), + LocalParentNotSampledSampler = sampler_for_spec(local_parent_not_sampled, Opts, otel_sampler_always_off), RootSampler = otel_sampler:new(RootSpec), #{ root => RootSampler, @@ -50,8 +50,8 @@ setup(Opts = #{root := RootSpec}) -> local_parent_not_sampled => LocalParentNotSampledSampler }; setup(Opts) -> - ?LOG_INFO("No sampler spec found for parent_based 'root' option. The sampler 'always_on' will be used for root spans"), - setup(Opts#{root => {always_on, #{}}}). + ?LOG_INFO("No sampler spec found for otel_sampler_parent_based 'root' option. The sampler 'otel_sampler_always_on' will be used for root spans"), + setup(Opts#{root => {otel_sampler_always_on, #{}}}). sampler_for_spec(Key, Opts, DefaultModule) -> Spec = maps:get(Key, Opts, {DefaultModule, #{}}), diff --git a/apps/opentelemetry/src/trace_id_ratio_based.erl b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl similarity index 98% rename from apps/opentelemetry/src/trace_id_ratio_based.erl rename to apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl index 4fc0289d..bf18cabe 100644 --- a/apps/opentelemetry/src/trace_id_ratio_based.erl +++ b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl @@ -17,7 +17,7 @@ %% record and propagate, only record or not record the span. %% @end %%%------------------------------------------------------------------------- --module(trace_id_ratio_based). +-module(otel_sampler_trace_id_ratio_based). -behavior(otel_sampler). diff --git a/apps/opentelemetry/src/otel_tracer_server.erl b/apps/opentelemetry/src/otel_tracer_server.erl index 70ecd749..e4216831 100644 --- a/apps/opentelemetry/src/otel_tracer_server.erl +++ b/apps/opentelemetry/src/otel_tracer_server.erl @@ -55,7 +55,7 @@ init(Opts) -> Resource = otel_resource_detector:get_resource(), SamplerSpec = proplists:get_value( - sampler, Opts, {parent_based, #{root => {always_on, #{}}}} + sampler, Opts, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}} ), Sampler = otel_sampler:new(SamplerSpec), Processors = proplists:get_value(processors, Opts, []), diff --git a/apps/opentelemetry/test/otel_configuration_SUITE.erl b/apps/opentelemetry/test/otel_configuration_SUITE.erl index 64332933..0de4c496 100644 --- a/apps/opentelemetry/test/otel_configuration_SUITE.erl +++ b/apps/opentelemetry/test/otel_configuration_SUITE.erl @@ -109,7 +109,7 @@ empty_os_environment(_Config) -> ?assertIsSubset([{log_level,info}, {propagators,[fun otel_tracer_default:w3c_propagators/0, fun otel_baggage:get_text_map_propagators/0]}, - {sampler,{parent_based,#{root => {always_on,#{}}}}}], + {sampler,{otel_sampler_parent_based,#{root => {otel_sampler_always_on,#{}}}}}], otel_configuration:merge_with_os([])), ?assertIsSubset([{log_level, error}], otel_configuration:merge_with_os([{log_level, error}])), @@ -117,37 +117,37 @@ empty_os_environment(_Config) -> ok. sampler(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {always_off, #{}}}}}, + ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_always_off, #{}}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.5}}}}, + ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 0.5}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, 0.5}}, + ?assertMatch({sampler, {otel_sampler_trace_id_ratio_based, 0.5}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id_default(_Config) -> - ?assertMatch({sampler, {trace_id_ratio_based, 1.0}}, + ?assertMatch({sampler, {otel_sampler_trace_id_ratio_based, 1.0}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_one(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 1.0}}}}, + ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 1.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_zero(_Config) -> - ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.0}}}}, + ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 0.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index 4fca37a4..a9ad6420 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -28,13 +28,13 @@ end_per_testcase(_, _Config) -> get_description(_Config) -> Probability = 0.5, - Sampler = otel_sampler:new({trace_id_ratio_based, Probability}), + Sampler = otel_sampler:new({otel_sampler_trace_id_ratio_based, Probability}), ?assertEqual(<<"TraceIdRatioBased{0.500000}">>, otel_sampler:description(Sampler)), ParentBasedSampler = otel_sampler:new( - {parent_based, #{ - root => {trace_id_ratio_based, Probability} + {otel_sampler_parent_based, #{ + root => {otel_sampler_trace_id_ratio_based, Probability} }} ), ?assertEqual( @@ -53,7 +53,7 @@ trace_id_ratio_based(_Config) -> Ctx = otel_ctx:new(), %% sampler that runs on all spans - {Sampler, _, Opts} = otel_sampler:new({trace_id_ratio_based, Probability}), + {Sampler, _, Opts} = otel_sampler:new({otel_sampler_trace_id_ratio_based, Probability}), %% checks the trace id is under the upper bound ?assertMatch( @@ -145,7 +145,7 @@ parent_based(_Config) -> Ctx = otel_ctx:new(), {Sampler, _, Opts} = otel_sampler:new( - {parent_based, #{root => {trace_id_ratio_based, Probability}}} + {otel_sampler_parent_based, #{root => {otel_sampler_trace_id_ratio_based, Probability}}} ), %% with no parent it will run the probability sampler @@ -207,7 +207,7 @@ parent_based(_Config) -> ), %% with no root sampler in setup opts the default sampler always_on is used - {DefaultParentOrElse, _, Opts1} = otel_sampler:new({parent_based, #{}}), + {DefaultParentOrElse, _, Opts1} = otel_sampler:new({otel_sampler_parent_based, #{}}), ?assertMatch( {?RECORD_AND_SAMPLE, [], []}, @@ -282,7 +282,7 @@ custom_sampler_module(_Config) -> ok. should_sample(_Config) -> - Sampler = otel_sampler:new({always_on, #{}}), + Sampler = otel_sampler:new({otel_sampler_always_on, #{}}), ?assertMatch( {?RECORD_AND_SAMPLE, [], []}, otel_samplers:should_sample( From c2909357f0382485d6d7c1e687cd48e5f1682a89 Mon Sep 17 00:00:00 2001 From: dvic Date: Sun, 8 Aug 2021 00:21:47 +0200 Subject: [PATCH 10/13] Add documentation for the built-in samplers --- apps/opentelemetry/src/otel_sampler_always_off.erl | 3 +-- apps/opentelemetry/src/otel_sampler_always_on.erl | 3 +-- apps/opentelemetry/src/otel_sampler_parent_based.erl | 10 ++++++++-- .../src/otel_sampler_trace_id_ratio_based.erl | 5 +++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/opentelemetry/src/otel_sampler_always_off.erl b/apps/opentelemetry/src/otel_sampler_always_off.erl index 182f1737..ef9d6b6f 100644 --- a/apps/opentelemetry/src/otel_sampler_always_off.erl +++ b/apps/opentelemetry/src/otel_sampler_always_off.erl @@ -13,8 +13,7 @@ %% limitations under the License. %% %% @doc -%% A sampler is a function run on each started span that returns whether to -%% record and propagate, only record or not record the span. +%% This sampler always decides to neither record nor sample each span. %% @end %%%------------------------------------------------------------------------- -module(otel_sampler_always_off). diff --git a/apps/opentelemetry/src/otel_sampler_always_on.erl b/apps/opentelemetry/src/otel_sampler_always_on.erl index ff030d4a..2321a459 100644 --- a/apps/opentelemetry/src/otel_sampler_always_on.erl +++ b/apps/opentelemetry/src/otel_sampler_always_on.erl @@ -13,8 +13,7 @@ %% limitations under the License. %% %% @doc -%% A sampler is a function run on each started span that returns whether to -%% record and propagate, only record or not record the span. +%% This sampler always decides to record and sample each span. %% @end %%%------------------------------------------------------------------------- -module(otel_sampler_always_on). diff --git a/apps/opentelemetry/src/otel_sampler_parent_based.erl b/apps/opentelemetry/src/otel_sampler_parent_based.erl index cf0975b6..489c85e5 100644 --- a/apps/opentelemetry/src/otel_sampler_parent_based.erl +++ b/apps/opentelemetry/src/otel_sampler_parent_based.erl @@ -13,8 +13,14 @@ %% limitations under the License. %% %% @doc -%% A sampler is a function run on each started span that returns whether to -%% record and propagate, only record or not record the span. +%% This sampler makes the decision based on the parent, with the following possibilities: +%% 1) a remote parent that is sampled (by default otel_sampler_always_on); +%% 2) a remote parent that is not sampled (by default otel_sampler_always_off); +%% 3) a local parent that is sampled (by default otel_sampler_always_on); +%% 4) a local parent that isnot sampled (by default otel_sampler_always_on); +%% 5) no parent (by default otel_sampler_always_on). +%% +%% For each of these cases a different sampler can be configured. %% @end %%%------------------------------------------------------------------------- -module(otel_sampler_parent_based). diff --git a/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl index bf18cabe..3995fb52 100644 --- a/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl +++ b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl @@ -13,8 +13,9 @@ %% limitations under the License. %% %% @doc -%% A sampler is a function run on each started span that returns whether to -%% record and propagate, only record or not record the span. +%% This sampler samples a configured percentage of spans, where the sampling +%% decision is deterministic with respect to the span trace id, i.e., it always +%% makes the same decision for the same trace id. %% @end %%%------------------------------------------------------------------------- -module(otel_sampler_trace_id_ratio_based). From 78e65d0a66bd0f9982bf6f6a91bbf11b9508f7bd Mon Sep 17 00:00:00 2001 From: dvic Date: Mon, 9 Aug 2021 23:30:56 +0200 Subject: [PATCH 11/13] Do not use otel_sampler_ prefix in sampler spec for built-in samplers --- apps/opentelemetry/src/opentelemetry.app.src | 2 +- apps/opentelemetry/src/otel_configuration.erl | 23 +++++++++--------- apps/opentelemetry/src/otel_sampler.erl | 21 +++++++++++++++- .../src/otel_sampler_parent_based.erl | 24 +++++++++---------- apps/opentelemetry/src/otel_tracer_server.erl | 2 +- .../test/otel_configuration_SUITE.erl | 14 +++++------ .../test/otel_samplers_SUITE.erl | 14 +++++------ 7 files changed, 59 insertions(+), 41 deletions(-) diff --git a/apps/opentelemetry/src/opentelemetry.app.src b/apps/opentelemetry/src/opentelemetry.app.src index 21f3544e..576b7a6d 100644 --- a/apps/opentelemetry/src/opentelemetry.app.src +++ b/apps/opentelemetry/src/opentelemetry.app.src @@ -8,7 +8,7 @@ stdlib, opentelemetry_api ]}, - {env, [{sampler, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}}, % default sampler + {env, [{sampler, {parent_based, #{root => always_on}}}, % default sampler {text_map_propagators, [fun otel_baggage:get_text_map_propagators/0, fun otel_tracer_default:w3c_propagators/0]}, diff --git a/apps/opentelemetry/src/otel_configuration.erl b/apps/opentelemetry/src/otel_configuration.erl index 7bd8821b..41373836 100644 --- a/apps/opentelemetry/src/otel_configuration.erl +++ b/apps/opentelemetry/src/otel_configuration.erl @@ -45,7 +45,7 @@ processors(AppEnvOpts) -> %% sampler configuration is unique since it has the _ARG that is a sort of %% sub-configuration of the sampler config, and isn't a list. sampler(AppEnvOpts) -> - Sampler = proplists:get_value(sampler, AppEnvOpts, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}), + Sampler = proplists:get_value(sampler, AppEnvOpts, {parent_based, #{root => always_on}}), Sampler1 = case os:getenv("OTEL_TRACES_SAMPLER") of false -> @@ -143,22 +143,21 @@ transform(url, Value) -> uri_string:parse(Value); %% convert sampler string to usable configuration term transform(sampler, {"parentbased_always_on", _}) -> - {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}}; + {parent_based, #{root => always_on}}; transform(sampler, {"parentbased_always_off", _}) -> - {otel_sampler_parent_based, #{root => {otel_sampler_always_off, #{}}}}; -transform(sampler, {"otel_sampler_always_on", _}) -> - {otel_sampler_always_on, #{}}; -transform(sampler, {"otel_sampler_always_off", _}) -> - {otel_sampler_always_off, #{}}; + {parent_based, #{root => always_off}}; +transform(sampler, {"always_on", _}) -> + always_on; +transform(sampler, {"always_off", _}) -> + always_off; transform(sampler, {"traceidratio", false}) -> - {otel_sampler_trace_id_ratio_based, 1.0}; + {trace_id_ratio_based, 1.0}; transform(sampler, {"traceidratio", Probability}) -> - {otel_sampler_trace_id_ratio_based, probability_string_to_float(Probability)}; + {trace_id_ratio_based, probability_string_to_float(Probability)}; transform(sampler, {"parentbased_traceidratio", false}) -> - {otel_sampler_parent_based, #{root => {otel_sampler_trace_id_ratio_based, 1.0}}}; + {parent_based, #{root => {trace_id_ratio_based, 1.0}}}; transform(sampler, {"parentbased_traceidratio", Probability}) -> - {otel_sampler_parent_based, - #{root => {otel_sampler_trace_id_ratio_based, probability_string_to_float(Probability)}}}; + {parent_based, #{root => {trace_id_ratio_based, probability_string_to_float(Probability)}}}; transform(sampler, Value) -> Value; diff --git a/apps/opentelemetry/src/otel_sampler.erl b/apps/opentelemetry/src/otel_sampler.erl index 6d007f72..de1b935e 100644 --- a/apps/opentelemetry/src/otel_sampler.erl +++ b/apps/opentelemetry/src/otel_sampler.erl @@ -49,7 +49,18 @@ -type description() :: unicode:unicode_binary(). -type sampler_config() :: term(). -type sampler_opts() :: term(). --type sampler_spec() :: {module(), sampler_opts()}. +-type builtin_sampler() :: + always_on + | always_off + | {trace_id_ratio_based, float()} + | {parent_based, #{ + remote_parent_sampled => sampler_spec(), + remote_parent_not_sampled => sampler_spec(), + local_parent_sampled => sampler_spec(), + local_parent_not_sampled => sampler_spec(), + root => sampler_spec() + }}. +-type sampler_spec() :: builtin_sampler() | {module(), sampler_opts()}. -type sampling_decision() :: ?DROP | ?RECORD_ONLY | ?RECORD_AND_SAMPLE. -type sampling_result() :: { sampling_decision(), opentelemetry:attributes(), opentelemetry:tracestate() @@ -57,6 +68,14 @@ -opaque t() :: {module(), description(), sampler_opts()}. -spec new(sampler_spec()) -> t(). +new(always_on) -> + new({otel_sampler_always_on, #{}}); +new(always_off) -> + new({otel_sampler_always_off, #{}}); +new({trace_id_ratio_based, Opts}) -> + new({otel_sampler_trace_id_ratio_based, Opts}); +new({parent_based, Opts}) -> + new({otel_sampler_parent_based, Opts}); new({Sampler, Opts}) -> Config = Sampler:setup(Opts), {Sampler, Sampler:description(Config), Config}. diff --git a/apps/opentelemetry/src/otel_sampler_parent_based.erl b/apps/opentelemetry/src/otel_sampler_parent_based.erl index 489c85e5..0b43e8f8 100644 --- a/apps/opentelemetry/src/otel_sampler_parent_based.erl +++ b/apps/opentelemetry/src/otel_sampler_parent_based.erl @@ -14,11 +14,11 @@ %% %% @doc %% This sampler makes the decision based on the parent, with the following possibilities: -%% 1) a remote parent that is sampled (by default otel_sampler_always_on); -%% 2) a remote parent that is not sampled (by default otel_sampler_always_off); -%% 3) a local parent that is sampled (by default otel_sampler_always_on); -%% 4) a local parent that isnot sampled (by default otel_sampler_always_on); -%% 5) no parent (by default otel_sampler_always_on). +%% 1) a remote parent that is sampled (by default always_on); +%% 2) a remote parent that is not sampled (by default always_off); +%% 3) a local parent that is sampled (by default always_on); +%% 4) a local parent that isnot sampled (by default always_on); +%% 5) no parent (by default always_on). %% %% For each of these cases a different sampler can be configured. %% @end @@ -43,10 +43,10 @@ }. setup(Opts = #{root := RootSpec}) -> - RemoteParentSampledSampler = sampler_for_spec(remote_parent_sampled, Opts, otel_sampler_always_on), - RemoteParentNotSampledSampler = sampler_for_spec(remote_parent_not_sampled, Opts, otel_sampler_always_off), - LocalParentSampledSampler = sampler_for_spec(local_parent_sampled, Opts, otel_sampler_always_on), - LocalParentNotSampledSampler = sampler_for_spec(local_parent_not_sampled, Opts, otel_sampler_always_off), + RemoteParentSampledSampler = sampler_for_spec(remote_parent_sampled, Opts, always_on), + RemoteParentNotSampledSampler = sampler_for_spec(remote_parent_not_sampled, Opts, always_off), + LocalParentSampledSampler = sampler_for_spec(local_parent_sampled, Opts, always_on), + LocalParentNotSampledSampler = sampler_for_spec(local_parent_not_sampled, Opts, always_off), RootSampler = otel_sampler:new(RootSpec), #{ root => RootSampler, @@ -56,11 +56,11 @@ setup(Opts = #{root := RootSpec}) -> local_parent_not_sampled => LocalParentNotSampledSampler }; setup(Opts) -> - ?LOG_INFO("No sampler spec found for otel_sampler_parent_based 'root' option. The sampler 'otel_sampler_always_on' will be used for root spans"), - setup(Opts#{root => {otel_sampler_always_on, #{}}}). + ?LOG_INFO("No sampler spec found for parent_based 'root' option. The 'always_on' sampler will be used for root spans."), + setup(Opts#{root => always_on}). sampler_for_spec(Key, Opts, DefaultModule) -> - Spec = maps:get(Key, Opts, {DefaultModule, #{}}), + Spec = maps:get(Key, Opts, DefaultModule), otel_sampler:new(Spec). description(#{ diff --git a/apps/opentelemetry/src/otel_tracer_server.erl b/apps/opentelemetry/src/otel_tracer_server.erl index e4216831..e1b36674 100644 --- a/apps/opentelemetry/src/otel_tracer_server.erl +++ b/apps/opentelemetry/src/otel_tracer_server.erl @@ -55,7 +55,7 @@ init(Opts) -> Resource = otel_resource_detector:get_resource(), SamplerSpec = proplists:get_value( - sampler, Opts, {otel_sampler_parent_based, #{root => {otel_sampler_always_on, #{}}}} + sampler, Opts, {parent_based, #{root => always_on}} ), Sampler = otel_sampler:new(SamplerSpec), Processors = proplists:get_value(processors, Opts, []), diff --git a/apps/opentelemetry/test/otel_configuration_SUITE.erl b/apps/opentelemetry/test/otel_configuration_SUITE.erl index 0de4c496..62f9a02e 100644 --- a/apps/opentelemetry/test/otel_configuration_SUITE.erl +++ b/apps/opentelemetry/test/otel_configuration_SUITE.erl @@ -109,7 +109,7 @@ empty_os_environment(_Config) -> ?assertIsSubset([{log_level,info}, {propagators,[fun otel_tracer_default:w3c_propagators/0, fun otel_baggage:get_text_map_propagators/0]}, - {sampler,{otel_sampler_parent_based,#{root => {otel_sampler_always_on,#{}}}}}], + {sampler,{parent_based,#{root => always_on}}}], otel_configuration:merge_with_os([])), ?assertIsSubset([{log_level, error}], otel_configuration:merge_with_os([{log_level, error}])), @@ -117,37 +117,37 @@ empty_os_environment(_Config) -> ok. sampler(_Config) -> - ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_always_off, #{}}}}}, + ?assertMatch({sampler, {parent_based, #{root := always_off}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based(_Config) -> - ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 0.5}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.5}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id(_Config) -> - ?assertMatch({sampler, {otel_sampler_trace_id_ratio_based, 0.5}}, + ?assertMatch({sampler, {trace_id_ratio_based, 0.5}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_trace_id_default(_Config) -> - ?assertMatch({sampler, {otel_sampler_trace_id_ratio_based, 1.0}}, + ?assertMatch({sampler, {trace_id_ratio_based, 1.0}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_one(_Config) -> - ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 1.0}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 1.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. sampler_parent_based_zero(_Config) -> - ?assertMatch({sampler, {otel_sampler_parent_based, #{root := {otel_sampler_trace_id_ratio_based, 0.0}}}}, + ?assertMatch({sampler, {parent_based, #{root := {trace_id_ratio_based, 0.0}}}}, lists:keyfind(sampler, 1, otel_configuration:merge_with_os([]))), ok. diff --git a/apps/opentelemetry/test/otel_samplers_SUITE.erl b/apps/opentelemetry/test/otel_samplers_SUITE.erl index a9ad6420..454bf3ff 100644 --- a/apps/opentelemetry/test/otel_samplers_SUITE.erl +++ b/apps/opentelemetry/test/otel_samplers_SUITE.erl @@ -28,13 +28,13 @@ end_per_testcase(_, _Config) -> get_description(_Config) -> Probability = 0.5, - Sampler = otel_sampler:new({otel_sampler_trace_id_ratio_based, Probability}), + Sampler = otel_sampler:new({trace_id_ratio_based, Probability}), ?assertEqual(<<"TraceIdRatioBased{0.500000}">>, otel_sampler:description(Sampler)), ParentBasedSampler = otel_sampler:new( - {otel_sampler_parent_based, #{ - root => {otel_sampler_trace_id_ratio_based, Probability} + {parent_based, #{ + root => {trace_id_ratio_based, Probability} }} ), ?assertEqual( @@ -53,7 +53,7 @@ trace_id_ratio_based(_Config) -> Ctx = otel_ctx:new(), %% sampler that runs on all spans - {Sampler, _, Opts} = otel_sampler:new({otel_sampler_trace_id_ratio_based, Probability}), + {Sampler, _, Opts} = otel_sampler:new({trace_id_ratio_based, Probability}), %% checks the trace id is under the upper bound ?assertMatch( @@ -145,7 +145,7 @@ parent_based(_Config) -> Ctx = otel_ctx:new(), {Sampler, _, Opts} = otel_sampler:new( - {otel_sampler_parent_based, #{root => {otel_sampler_trace_id_ratio_based, Probability}}} + {parent_based, #{root => {trace_id_ratio_based, Probability}}} ), %% with no parent it will run the probability sampler @@ -207,7 +207,7 @@ parent_based(_Config) -> ), %% with no root sampler in setup opts the default sampler always_on is used - {DefaultParentOrElse, _, Opts1} = otel_sampler:new({otel_sampler_parent_based, #{}}), + {DefaultParentOrElse, _, Opts1} = otel_sampler:new({parent_based, #{}}), ?assertMatch( {?RECORD_AND_SAMPLE, [], []}, @@ -282,7 +282,7 @@ custom_sampler_module(_Config) -> ok. should_sample(_Config) -> - Sampler = otel_sampler:new({otel_sampler_always_on, #{}}), + Sampler = otel_sampler:new(always_on), ?assertMatch( {?RECORD_AND_SAMPLE, [], []}, otel_samplers:should_sample( From ad882b78df70d96f8e86a5587d086c2f00540a28 Mon Sep 17 00:00:00 2001 From: dvic Date: Thu, 12 Aug 2021 20:12:07 +0200 Subject: [PATCH 12/13] Fix Elixir test for refactored otel_sampler:new function --- test/otel_tests.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/otel_tests.exs b/test/otel_tests.exs index 29b4ae75..d697b07a 100644 --- a/test/otel_tests.exs +++ b/test/otel_tests.exs @@ -35,7 +35,7 @@ defmodule OtelTests do :otel_batch_processor.set_exporter(:otel_exporter_pid, self()) OpenTelemetry.register_tracer(:test_tracer, "0.1.0") - sampler = :otel_sampler.setup(:always_off) + sampler = :otel_sampler.new(:always_off) Tracer.with_span "span-1", %{sampler: sampler} do Tracer.with_span "span-2" do From cd4ae4d7762ca9dcce2cb432d93abefcd7bdfaf8 Mon Sep 17 00:00:00 2001 From: dvic Date: Thu, 19 Aug 2021 09:33:06 +0200 Subject: [PATCH 13/13] Use otel_span:tracestate in built-in samplers --- apps/opentelemetry/src/otel_sampler_always_off.erl | 13 ++----------- apps/opentelemetry/src/otel_sampler_always_on.erl | 13 ++----------- .../src/otel_sampler_trace_id_ratio_based.erl | 13 ++----------- apps/opentelemetry_api/src/otel_span.erl | 8 ++++++-- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/apps/opentelemetry/src/otel_sampler_always_off.erl b/apps/opentelemetry/src/otel_sampler_always_off.erl index ef9d6b6f..5f6d6ec9 100644 --- a/apps/opentelemetry/src/otel_sampler_always_off.erl +++ b/apps/opentelemetry/src/otel_sampler_always_off.erl @@ -30,14 +30,5 @@ setup(_Opts) -> []. description(_) -> <<"AlwaysOffSampler">>. should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, _Opts) -> - {?DROP, [], tracestate(Ctx)}. - -tracestate(Ctx) -> - tracestate_(otel_tracer:current_span_ctx(Ctx)). - -tracestate_(#span_ctx{tracestate = undefined}) -> - []; -tracestate_(#span_ctx{tracestate = TraceState}) -> - TraceState; -tracestate_(undefined) -> - []. + SpanCtx = otel_tracer:current_span_ctx(Ctx), + {?DROP, [], otel_span:tracestate(SpanCtx)}. diff --git a/apps/opentelemetry/src/otel_sampler_always_on.erl b/apps/opentelemetry/src/otel_sampler_always_on.erl index 2321a459..b7e4497b 100644 --- a/apps/opentelemetry/src/otel_sampler_always_on.erl +++ b/apps/opentelemetry/src/otel_sampler_always_on.erl @@ -30,14 +30,5 @@ setup(_Opts) -> []. description(_) -> <<"AlwaysOnSampler">>. should_sample(Ctx, _TraceId, _Links, _SpanName, _SpanKind, _Attributes, _Opts) -> - {?RECORD_AND_SAMPLE, [], tracestate(Ctx)}. - -tracestate(Ctx) -> - tracestate_(otel_tracer:current_span_ctx(Ctx)). - -tracestate_(#span_ctx{tracestate = undefined}) -> - []; -tracestate_(#span_ctx{tracestate = TraceState}) -> - TraceState; -tracestate_(undefined) -> - []. + SpanCtx = otel_tracer:current_span_ctx(Ctx), + {?RECORD_AND_SAMPLE, [], otel_span:tracestate(SpanCtx)}. diff --git a/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl index 3995fb52..a9e31410 100644 --- a/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl +++ b/apps/opentelemetry/src/otel_sampler_trace_id_ratio_based.erl @@ -54,7 +54,8 @@ description(#{probability := Probability}) -> should_sample(Ctx, TraceId, _Links, _SpanName, _SpanKind, _Attributes, #{ id_upper_bound := IdUpperBound }) -> - {decide(TraceId, IdUpperBound), [], tracestate(Ctx)}. + SpanCtx = otel_tracer:current_span_ctx(Ctx), + {decide(TraceId, IdUpperBound), [], otel_span:tracestate(SpanCtx)}. decide(undefined, _IdUpperBound) -> ?DROP; @@ -66,13 +67,3 @@ decide(TraceId, IdUpperBound) -> true -> ?RECORD_AND_SAMPLE; false -> ?DROP end. - -tracestate(Ctx) -> - tracestate_(otel_tracer:current_span_ctx(Ctx)). - -tracestate_(#span_ctx{tracestate = undefined}) -> - []; -tracestate_(#span_ctx{tracestate = TraceState}) -> - TraceState; -tracestate_(undefined) -> - []. diff --git a/apps/opentelemetry_api/src/otel_span.erl b/apps/opentelemetry_api/src/otel_span.erl index 19c523a3..468e1ba6 100644 --- a/apps/opentelemetry_api/src/otel_span.erl +++ b/apps/opentelemetry_api/src/otel_span.erl @@ -69,9 +69,13 @@ trace_id(#span_ctx{trace_id=TraceId }) -> span_id(#span_ctx{span_id=SpanId }) -> SpanId. --spec tracestate(opentelemetry:span_ctx()) -> opentelemetry:tracestate(). +-spec tracestate(opentelemetry:span_ctx() | undefined) -> opentelemetry:tracestate(). +tracestate(#span_ctx{tracestate=undefined}) -> + []; tracestate(#span_ctx{tracestate=Tracestate}) -> - Tracestate. + Tracestate; +tracestate(_) -> + []. -spec set_attribute(SpanCtx, Key, Value) -> boolean() when Key :: opentelemetry:attribute_key(),