%%%------------------------------------------------------------------------ %% Copyright 2020, 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 Composite TextMap Propagator is a Propagator that performs run %% multiple TextMap Propagators in a specified order. %% %% An example of creating a Composite TextMap Propagator to inject and %% extract Baggage and TraceContext: %% %% ``` %% Propagator = otel_propagator_text_map_composite:create([trace_context, baggage]), %% otel_propagator_text_map:extract(Propagator, Carrier) %% ''' %% @end %%%------------------------------------------------------------------------- -module(otel_propagator_text_map_composite). -behaviour(otel_propagator_text_map). -export([create/1, fields/1, inject/4, extract/5, report_cb/1]). -include_lib("kernel/include/logger.hrl"). %% @doc Create a new Composite TextMap Propagator. %% %% The `Propagators' list is a list of atoms that represent the suffix %% of the module name of the TextMap Propagator to be used. -spec create([otel_propagator:builtin()]) -> otel_propagator:t(). create(Propagators) -> {?MODULE, otel_propagator:builtins_to_modules(Propagators)}. %% @private fields(Propagators) -> lists:flatmap(fun(Propagator) -> otel_propagator_text_map:fields(Propagator) end, Propagators). %% @private -spec inject(Context, Carrier, CarrierSetFun, Injectors) -> Carrier when Context :: otel_ctx:t(), Carrier :: otel_propagator:carrier(), CarrierSetFun :: otel_propagator_text_map:carrier_set(), Injectors :: [otel_propagator_text_map:t()]. inject(Context, Carrier, CarrierSetFun, Injectors) -> run_injectors(Context, Injectors, Carrier, CarrierSetFun). %% @private -spec extract(Context, Carrier, CarrierKeysFun, CarrierGetFun, Extractors) -> Context when Context :: otel_ctx:t(), Carrier :: otel_propagator:carrier(), CarrierKeysFun :: otel_propagator_text_map:carrier_keys(), CarrierGetFun :: otel_propagator_text_map:carrier_get(), Extractors :: [otel_propagator_text_map:t()]. extract(Context, Carrier, CarrierKeysFun, CarrierGetFun, Extractors) -> run_extractors(Context, Extractors, Carrier, CarrierKeysFun, CarrierGetFun). run_extractors(Context, Extractors, Carrier, CarrierKeysFun, CarrierGetFun) when is_list(Extractors) -> lists:foldl(fun(Propagator, ContextAcc) -> try otel_propagator_text_map:extract_to(ContextAcc, Propagator, Carrier, CarrierKeysFun, CarrierGetFun) catch C:E:S -> ?LOG_INFO(#{extractor => Propagator, carrier => Carrier, class => C, exception => E, stacktrace => S}, #{report_cb => fun ?MODULE:report_cb/1}), ContextAcc end end, Context, otel_propagator:builtins_to_modules(Extractors)). run_injectors(Context, Injectors, Carrier, Setter) when is_list(Injectors) -> lists:foldl(fun(Propagator, CarrierAcc) -> try otel_propagator_text_map:inject_from(Context, Propagator, CarrierAcc, Setter) catch C:E:S -> ?LOG_INFO(#{injector => Propagator, carrier => CarrierAcc, class => C, exception => E, stacktrace => S}, #{report_cb => fun ?MODULE:report_cb/1}), CarrierAcc end end, Carrier, otel_propagator:builtins_to_modules(Injectors)). %% @private report_cb(#{extractor := Propagator, carrier := _Carrier, class := Class, exception := Exception, stacktrace := StackTrace}) -> {"text map propagator failed to extract from carrier: propagator=~ts exception=~ts", [Propagator, otel_utils:format_exception(Class, Exception, StackTrace)]}; report_cb(#{injector := Propagator, carrier := _Carrier, class := Class, exception := Exception, stacktrace := StackTrace}) -> {"text map propagator failed to inject to carrier: propagator=~ts exception=~ts", [Propagator, otel_utils:format_exception(Class, Exception, StackTrace)]}.