Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move the rest of application env vars to configuration map #328

Merged
merged 1 commit into from
Dec 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 93 additions & 79 deletions apps/opentelemetry/src/otel_configuration.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,45 @@
%% using a map instead of a record because there can be more values
-type t() :: #{log_level := atom(),
register_loaded_applications := boolean(),
id_generator := module(),
deny_list := [atom()],
resource_detectors => [module()],
resource_detector_timeout => integer(),
text_map_propagators := [atom()],
traces_exporter := {atom(), term()},
processors := list(),
sampler := {atom(), term()},
sweeper := #{interval => integer() | infinity,
strategy => atom() | fun(),
span_ttl => integer() | infinity,
storage_size => integer() | infinity},
attribute_count_limit := integer(),
attribute_value_length_limit := integer() | infinity,
event_count_limit := integer(),
link_count_limit := integer(),
attribute_per_event_limit := integer(),
attribute_per_link_limit := integer()}.

-spec new() -> t().
new() ->
#{log_level => info,
register_loaded_applications => true,
id_generator => otel_id_generator,
deny_list => [],
resource_detectors => [otel_resource_env_var,
otel_resource_app_env],
resource_detector_timeout => 5000,
text_map_propagators => [trace_context, baggage],
traces_exporter => {opentelemetry_exporter, #{}},
processors => [{otel_batch_processor, #{scheduled_delay_ms => 5000,
exporting_timeout_ms => 30000,
max_queue_size => 2048,
exporter => {opentelemetry_exporter, #{}}}}],
sampler => {parent_based, #{root => always_on}},
sweeper => #{interval => timer:minutes(10),
strategy => drop,
span_ttl => timer:minutes(30),
storage_size => infinity},
attribute_count_limit => 128,
attribute_value_length_limit => infinity,
event_count_limit => 128,
Expand All @@ -65,7 +84,8 @@ merge_with_os(AppEnv) ->
end, ConfigMap, [fun span_limits/2,
fun general/2,
fun sampler/2,
fun processors/2]).
fun processors/2,
fun sweeper/2]).

-spec span_limits(list(), t()) -> t().
span_limits(AppEnv, ConfigMap) ->
Expand All @@ -75,6 +95,16 @@ span_limits(AppEnv, ConfigMap) ->
general(AppEnv, ConfigMap) ->
merge_list_with_environment(config_mappings(general_sdk), AppEnv, ConfigMap).

-spec sweeper(list(), t()) -> t().
sweeper(AppEnv, ConfigMap=#{sweeper := DefaultSweeperConfig}) ->
AppEnvSweeper = proplists:get_value(sweeper, AppEnv, #{}),

%% convert sweeper config to a list to utilize the merge_list_with_environment function
SweeperConfig = merge_list_with_environment(config_mappings(sweeper),
maps:to_list(AppEnvSweeper),
DefaultSweeperConfig),
ConfigMap#{sweeper => SweeperConfig}.

-spec processors(list(), t()) -> t().
processors(AppEnv, ConfigMap) ->
%% builtin processors have OS environment configuration per type of processor
Expand All @@ -83,7 +113,7 @@ processors(AppEnv, ConfigMap) ->
Processors = proplists:get_value(processors, AppEnv, maps:get(processors, ConfigMap)),

ProcessorsConfig = lists:map(fun({Name, Opts}) ->
{Name, merge_with_environment(config_mappings(Name), Opts)}
{Name, merge_with_os_environment(config_mappings(Name), Opts)}
end, Processors),

ConfigMap#{processors := ProcessorsConfig}.
Expand All @@ -92,106 +122,74 @@ processors(AppEnv, ConfigMap) ->
%% sub-configuration of the sampler config, and isn't a list.
-spec sampler(list(), t()) -> t().
sampler(AppEnv, ConfigMap) ->
OSVar = "OTEL_TRACES_SAMPLER",
Key = sampler,
Transform = sampler,
case os:getenv("OTEL_TRACES_SAMPLER") of
false ->
case proplists:get_value(sampler, AppEnv) of
case proplists:get_value(Key, AppEnv) of
undefined ->
ConfigMap;
Sampler ->
try transform(sampler, Sampler) of
TransformedSampler ->
ConfigMap#{sampler := TransformedSampler}
catch
Kind:Reason:StackTrace ->
?LOG_INFO(#{source => transform,
kind => Kind,
reason => Reason,
os_var => "OTEL_TRACES_SAMPLER",
key => sampler,
transform => sampler,
value => Sampler,
stacktrace => StackTrace},
#{report_cb => fun ?MODULE:report_cb/1}),
ConfigMap
end
update_config_map(OSVar, Key, Transform, Sampler, ConfigMap)
end;
OSEnvSampler->
SamplerTuple = {OSEnvSampler, os:getenv("OTEL_TRACES_SAMPLER_ARG")},
try transform(sampler, SamplerTuple) of
TransformedSampler ->
ConfigMap#{sampler := TransformedSampler}
catch
Kind:Reason:StackTrace ->
?LOG_INFO(#{source => transform,
kind => Kind,
reason => Reason,
os_var => "OTEL_TRACES_SAMPLER",
key => sampler,
transform => sampler,
value => SamplerTuple,
stacktrace => StackTrace},
#{report_cb => fun ?MODULE:report_cb/1}),
ConfigMap
end
update_config_map(OSVar, Key, Transform, SamplerTuple, ConfigMap)
end.

-spec merge_list_with_environment([{OSVar, Key, Transform}], list(), map()) -> map()
%% requires `ConfigMap' contains every key and its default
%% will replace the defaults with the value from either the OS environment or application
%% environment, with the OS environment taking precedence.
-spec merge_list_with_environment([{OSVar, Key, Transform}], AppEnv, ConfigMap) -> ConfigMap
when OSVar :: string(),
Key :: atom(),
Transform :: atom().
Transform :: atom(),
AppEnv :: [{atom(), term()}],
ConfigMap :: map().
merge_list_with_environment(ConfigMappings, AppEnv, ConfigMap) ->
lists:foldl(fun({OSVar, Key, Transform}, Acc) ->
case os:getenv(OSVar) of
false ->
%% not in the OS environment so check application environment
case lists:keyfind(Key, 1, AppEnv) of
false ->
%% not in the application env so leave default
Acc;
{_, Value} ->
%% transform even the value from the
%% application environment to ensure it
%% is of the right type/format
try transform(Transform, Value) of
TransformedValue ->
Acc#{Key := TransformedValue}
catch
Kind:Reason:StackTrace ->
?LOG_INFO(#{source => transform,
kind => Kind,
reason => Reason,
os_var => OSVar,
key => Key,
transform => Transform,
value => Value,
stacktrace => StackTrace},
#{report_cb => fun ?MODULE:report_cb/1}),
Acc
end
update_config_map(OSVar, Key, Transform, Value, Acc)
end;
OSVal ->
try transform(Transform, OSVal) of
TransformedValue ->
Acc#{Key := TransformedValue}
catch
Kind:Reason:StackTrace ->
?LOG_INFO(#{source => transform,
kind => Kind,
reason => Reason,
os_var => OSVar,
key => Key,
transform => Transform,
value => OSVal,
stacktrace => StackTrace},
#{report_cb => fun ?MODULE:report_cb/1}),
Acc
end
update_config_map(OSVar, Key, Transform, OSVal, Acc)
end
end, ConfigMap, ConfigMappings).

-spec merge_with_environment([{OSVar, Key, Transform}], map()) -> map()
update_config_map(OSVar, Key, Transform, Value, ConfigMap) ->
try transform(Transform, Value) of
TransformedValue ->
ConfigMap#{Key := TransformedValue}
catch
Kind:Reason:StackTrace ->
?LOG_INFO(#{source => transform,
kind => Kind,
reason => Reason,
os_var => OSVar,
key => Key,
transform => Transform,
value => Value,
stacktrace => StackTrace},
#{report_cb => fun ?MODULE:report_cb/1}),
ConfigMap
end.

-spec merge_with_os_environment([{OSVar, Key, Transform}], map()) -> map()
when OSVar :: string(),
Key :: atom(),
Transform :: atom().
merge_with_environment(ConfigMappings, Opts) ->
merge_with_os_environment(ConfigMappings, Opts) ->
lists:foldl(fun({OSVar, Key, Transform}, Acc) ->
case os:getenv(OSVar) of
false ->
Expand Down Expand Up @@ -234,17 +232,21 @@ report_cb(#{source := transform,
config_mappings(general_sdk) ->
[{"OTEL_LOG_LEVEL", log_level, existing_atom},
{"OTEL_REGISTER_LOADED_APPLICATIONS", register_loaded_applications, boolean},
{"OTEL_ID_GENERATOR", id_generator, existing_atom},
{"OTEL_DENY_LIST", deny_list, list},
{"OTEL_PROPAGATORS", text_map_propagators, propagators},
{"OTEL_TRACES_EXPORTER", traces_exporter, exporter},
{"OTEL_METRICS_EXPORTER", metrics_exporter, exporter}];
{"OTEL_METRICS_EXPORTER", metrics_exporter, exporter},
{"OTEL_RESOURCE_DETECTORS", resource_detectors, kvlist_value},
{"OTEL_RESOURCE_DETECTOR_TIMEOUT", resource_detector_timeout, integer}];
config_mappings(otel_batch_processor) ->
[{"OTEL_BSP_SCHEDULE_DELAY_MILLIS", scheduled_delay_ms, integer}, %% 5000,
{"OTEL_BSP_EXPORT_TIMEOUT_MILLIS", exporting_timeout_ms, integer}, %% 30000,
{"OTEL_BSP_MAX_QUEUE_SIZE", max_queue_size, integer}, %% 2048,
[{"OTEL_BSP_SCHEDULE_DELAY_MILLIS", scheduled_delay_ms, integer},
{"OTEL_BSP_EXPORT_TIMEOUT_MILLIS", exporting_timeout_ms, integer},
{"OTEL_BSP_MAX_QUEUE_SIZE", max_queue_size, integer},
%% a second usage of OTEL_TRACES_EXPORTER to set the exporter used by batch processor
{"OTEL_TRACES_EXPORTER", exporter, exporter} %% "otlp",
{"OTEL_TRACES_EXPORTER", exporter, exporter}
%% the following are not supported yet
%% {"OTEL_BSP_MAX_EXPORT_BATCH_SIZE", max_export_batch_size, 512}
%% {"OTEL_BSP_MAX_EXPORT_BATCH_SIZE", max_export_batch_size, integer}
];
config_mappings(span_limits) ->
[{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", attribute_count_limit, integer},
Expand All @@ -253,8 +255,14 @@ config_mappings(span_limits) ->
{"OTEL_SPAN_LINK_COUNT_LIMIT", link_count_limit, integer},
{"OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", attribute_per_event_limit, integer},
{"OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, integer}%% ,
%% {"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", attribute_value_length_limit, 128, integer},
%% {"OTEL_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, 128, integer}
%% {"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", attribute_value_length_limit, integer},
%% {"OTEL_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, integer}
];
config_mappings(sweeper) ->
[{"OTEL_SPAN_SWEEPER_INTERVAL", interval, integer_infinity},
{"OTEL_SPAN_SWEEPER_STRATEGY", strategy, atom_or_fun},
{"OTEL_SPAN_SWEEPER_SPAN_TTL", span_ttl, integer_infinity},
{"OTEL_SPAN_SWEEPER_STORAGE_SIZE", storage_size, integer_infinity}
];
config_mappings(_) ->
[].
Expand Down Expand Up @@ -289,6 +297,12 @@ transform(existing_atom, Value) when is_atom(Value) ->
Value;
transform(existing_atom, Value) when is_list(Value) ->
list_to_existing_atom(Value);
transform(atom_or_fun, Value) when is_list(Value) ->
list_to_existing_atom(Value);
transform(atom_or_fun, Value) when is_atom(Value) ->
Value;
transform(atom_or_fun, Value) when is_function(Value) ->
Value;
transform(boolean, Value) when is_boolean(Value) ->
Value;
transform(boolean, "true") ->
Expand Down
13 changes: 7 additions & 6 deletions apps/opentelemetry/src/otel_resource_detector.erl
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@
detectors :: [detector()],
detector_timeout :: integer()}).

start_link(Opts) ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
-spec start_link(Config) -> {ok, pid()} | ignore | {error, term()} when
Config :: #{resource_detectors := [module()],
resource_detector_timeout := integer()}.
start_link(Config) ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [Config], []).

get_resource() ->
get_resource(6000).
Expand All @@ -66,12 +69,10 @@ get_resource(Timeout) ->
otel_resource:create([])
end.

init([_Opts]) ->
init([#{resource_detectors := Detectors,
resource_detector_timeout := DetectorTimeout}]) ->
process_flag(trap_exit, true),

Detectors = application:get_env(opentelemetry, resource_detectors, []),
DetectorTimeout = application:get_env(opentelemetry, resource_detectors_timeout, 5000),

{ok, collecting, #data{resource=otel_resource:create([]),
detectors=Detectors,
detector_timeout=DetectorTimeout},
Expand Down
10 changes: 5 additions & 5 deletions apps/opentelemetry/src/otel_span_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@

-define(SERVER, ?MODULE).

start_link(Opts) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, [Opts]).
start_link(Config) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, [Config]).

start_child(ChildSpec) ->
supervisor:start_child(?SERVER, ChildSpec).

init([_Opts]) ->
init([Config]) ->
SupFlags = #{strategy => one_for_one,
intensity => 1,
period => 5},

SweeperOpts = application:get_env(opentelemetry, sweeper, #{}),
SweeperConfig = maps:get(sweeper, Config),
Sweeper = #{id => otel_span_sweeper,
start => {otel_span_sweeper, start_link, [SweeperOpts]},
start => {otel_span_sweeper, start_link, [SweeperConfig]},
restart => permanent,
shutdown => 5000,
type => worker,
Expand Down
15 changes: 7 additions & 8 deletions apps/opentelemetry/src/otel_span_sweeper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@
storage_size() ->
{ets:info(?SPAN_TAB, size), ets:info(?SPAN_TAB, memory) * erlang:system_info({wordsize, external})}.

start_link(Opts) ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [Opts], []).

init([SweeperConfig]) ->
Interval = maps:get(interval, SweeperConfig, timer:minutes(10)),
Strategy = maps:get(strategy, SweeperConfig, drop),
TTL = maps:get(span_ttl, SweeperConfig, timer:minutes(30)),
StorageSize = maps:get(storage_size, SweeperConfig, infinity),
start_link(Config) ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [Config], []).

init([#{interval := Interval,
strategy := Strategy,
span_ttl := TTL,
storage_size := StorageSize}]) ->
{ok, ready, #data{interval=Interval,
strategy=Strategy,
ttl=maybe_convert_time_unit(TTL),
Expand Down
17 changes: 8 additions & 9 deletions apps/opentelemetry/src/otel_tracer_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,17 @@
telemetry_library :: telemetry_library()
}).

start_link(Opts) ->
gen_server:start_link({local, otel_tracer_provider}, ?MODULE, Opts, []).

init(Opts) ->
-spec start_link(otel_configuration:t()) -> {ok, pid()} | ignore | {error, term()}.
start_link(Config) ->
gen_server:start_link({local, otel_tracer_provider}, ?MODULE, Config, []).

init(#{id_generator := IdGeneratorModule,
sampler := SamplerSpec,
processors := Processors,
deny_list := DenyList}) ->
Resource = otel_resource_detector:get_resource(),

IdGeneratorModule = application:get_env(opentelemetry, id_generator, otel_id_generator),

SamplerSpec = maps:get(sampler, Opts),
Sampler = otel_sampler:new(SamplerSpec),
Processors = maps:get(processors, Opts),
DenyList = application:get_env(opentelemetry, deny_list, []),

{ok, LibraryVsn} = application:get_key(opentelemetry, vsn),
LibraryName = <<"opentelemetry">>,
Expand Down
Loading