diff --git a/apps/opentelemetry/test/opentelemetry_SUITE.erl b/apps/opentelemetry/test/opentelemetry_SUITE.erl index 688f939a..36f0c06f 100644 --- a/apps/opentelemetry/test/opentelemetry_SUITE.erl +++ b/apps/opentelemetry/test/opentelemetry_SUITE.erl @@ -233,7 +233,7 @@ propagation(Config) -> ?assertEqual(undefined, ?current_span_ctx), %% clear our baggage from the context to test extraction - otel_ctx:remove(otel_baggage:ctx_key()), + otel_baggage:clear(), ?assertEqual(#{}, otel_baggage:get_all()), %% make header keys uppercase to validate the extractor is case insensitive diff --git a/apps/opentelemetry_api/lib/open_telemetry/baggage.ex b/apps/opentelemetry_api/lib/open_telemetry/baggage.ex new file mode 100644 index 00000000..8f3bf072 --- /dev/null +++ b/apps/opentelemetry_api/lib/open_telemetry/baggage.ex @@ -0,0 +1,13 @@ +defmodule OpenTelemetry.Baggage do + @moduledoc """ + Baggage is used to annotate telemetry, adding context and information to + metrics, traces, and logs. It is represented by a set of name/value pairs + describing user-defined properties. + """ + + defdelegate set(keyvalues), to: :otel_baggage + defdelegate set(key, values), to: :otel_baggage + defdelegate get_all(), to: :otel_baggage + defdelegate clear(), to: :otel_baggage + defdelegate get_text_map_propagators(), to: :otel_baggage +end diff --git a/apps/opentelemetry_api/lib/open_telemetry/ctx.ex b/apps/opentelemetry_api/lib/open_telemetry/ctx.ex new file mode 100644 index 00000000..635b8a3c --- /dev/null +++ b/apps/opentelemetry_api/lib/open_telemetry/ctx.ex @@ -0,0 +1,18 @@ +defmodule OpenTelemetry.Ctx do + @moduledoc """ + Ctx is responsible for propagating values within a process that are associated + with a particular Trace or set of Baggage. `OpenTelemetry.Tracer` and + `OpenTelemetry.Baggage` handle updating the Context. + """ + + defdelegate new(), to: :otel_ctx + defdelegate attach(ctx), to: :otel_ctx + defdelegate detach(token), to: :otel_ctx + defdelegate set_value(key, value), to: :otel_ctx + defdelegate set_value(ctx, key, value), to: :otel_ctx + defdelegate get_value(key, default), to: :otel_ctx + defdelegate get_value(ctx, key, default), to: :otel_ctx + defdelegate clear(), to: :otel_ctx + defdelegate remove(key), to: :otel_ctx + defdelegate get_current(), to: :otel_ctx +end diff --git a/apps/opentelemetry_api/src/otel_baggage.erl b/apps/opentelemetry_api/src/otel_baggage.erl index caba643d..d39d7dde 100644 --- a/apps/opentelemetry_api/src/otel_baggage.erl +++ b/apps/opentelemetry_api/src/otel_baggage.erl @@ -12,14 +12,17 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% @doc +%% @doc Baggage is used to annotate telemetry, adding context and +%% information to metrics, traces, and logs. It is represented by a set +%% of name/value pairs describing user-defined properties. %% @end %%%------------------------------------------------------------------------- -module(otel_baggage). --export([ctx_key/0, +-export([set/1, set/2, get_all/0, + clear/0, get_text_map_propagators/0]). -type key() :: string(). @@ -34,8 +37,12 @@ -define(BAGGAGE_KEY, '$__otel_baggage_ctx_key'). -define(BAGGAGE_HEADER, <<"baggage">>). -ctx_key() -> - ?BAGGAGE_KEY. +-spec set(#{key() => value()} | [{key(), value()}]) -> ok. +set(KeyValues) when is_list(KeyValues) -> + set(maps:from_list(KeyValues)); +set(KeyValues) when is_map(KeyValues) -> + Baggage = otel_ctx:get_value(?BAGGAGE_KEY, #{}), + otel_ctx:set_value(?BAGGAGE_KEY, maps:merge(Baggage, KeyValues)). -spec set(key(), value()) -> ok. set(Key, Value) -> @@ -46,6 +53,10 @@ set(Key, Value) -> get_all() -> otel_ctx:get_value(?BAGGAGE_KEY, #{}). +-spec clear() -> ok. +clear() -> + otel_ctx:set_value(?BAGGAGE_KEY, #{}). + -spec get_text_map_propagators() -> {otel_propagator:text_map_extractor(), otel_propagator:text_map_injector()}. get_text_map_propagators() -> ToText = fun(Baggage) when is_map(Baggage) -> diff --git a/apps/opentelemetry_api/src/otel_ctx.erl b/apps/opentelemetry_api/src/otel_ctx.erl index 8b949139..5089691f 100644 --- a/apps/opentelemetry_api/src/otel_ctx.erl +++ b/apps/opentelemetry_api/src/otel_ctx.erl @@ -12,7 +12,10 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% @doc +%% @doc Ctx is responsible for propagating values within a process that +%% are associated with a particular Trace or set of Baggage. +%% `OpenTelemetry.Tracer` and `OpenTelemetry.Baggage` handle updating +%% the Context. %% @end %%%------------------------------------------------------------------------- -module(otel_ctx). diff --git a/apps/opentelemetry_api/test/open_telemetry_test.exs b/apps/opentelemetry_api/test/open_telemetry_test.exs index f3eb1763..31d81a17 100644 --- a/apps/opentelemetry_api/test/open_telemetry_test.exs +++ b/apps/opentelemetry_api/test/open_telemetry_test.exs @@ -3,6 +3,8 @@ defmodule OpenTelemetryTest do require OpenTelemetry.Tracer, as: Tracer require OpenTelemetry.Span, as: Span + require OpenTelemetry.Baggage, as: Baggage + require OpenTelemetry.Ctx, as: Ctx require Record @fields Record.extract(:span_ctx, from_lib: "opentelemetry_api/include/opentelemetry.hrl") @@ -63,4 +65,42 @@ defmodule OpenTelemetryTest do assert [] = Span.tracestate(span) end end + + test "baggage api from elixir" do + Baggage.set(%{"a" => "b"}) + assert %{"a" => "b"} = Baggage.get_all() + + Baggage.set(%{"a" => "c"}) + assert %{"a" => "c"} = Baggage.get_all() + + Baggage.clear() + assert 0 = :erlang.map_size(Baggage.get_all()) + end + + test "context api from elixir" do + ctx = Ctx.new() + ctx = Ctx.set_value(ctx, :somekey, :somevalue) + assert :somevalue = Ctx.get_value(ctx, :somekey, "default") + + # attach the context and get value from implicit attached context + Ctx.attach(ctx) + assert :somevalue = Ctx.get_value(:somekey, "default") + end + + test "baggage across contexts" do + ctx = Ctx.get_current() + + Baggage.set(%{"a" => "b"}) + assert %{"a" => "b"} = Baggage.get_all() + + # attach the empty context + # gets a token for the context + token = Ctx.attach(ctx) + assert 0 = :erlang.map_size(Baggage.get_all()) + + # return to the context in the pdict before the attach + Ctx.detach(token) + assert %{"a" => "b"} = Baggage.get_all() + end + end