feat(emqx_opentelemetry): use one global exporter config for all otel signals

This commit is contained in:
Serge Tupchii 2023-11-28 15:16:47 +02:00
parent 2a3f6b749c
commit c8e69357cc
7 changed files with 95 additions and 104 deletions

View File

@ -24,7 +24,7 @@
start(_StartType, _StartArgs) -> start(_StartType, _StartArgs) ->
emqx_otel_config:add_handler(), emqx_otel_config:add_handler(),
ok = emqx_otel_config:add_otel_log_handler(), ok = emqx_otel_config:add_otel_log_handler(),
ok = emqx_otel_trace:ensure_traces(emqx:get_config([opentelemetry, traces])), ok = emqx_otel_trace:ensure_traces(emqx:get_config([opentelemetry])),
emqx_otel_sup:start_link(). emqx_otel_sup:start_link().
stop(_State) -> stop(_State) ->

View File

@ -85,30 +85,40 @@ otel_exporter(ExporterConf) ->
%% Internal functions %% Internal functions
ensure_otel_metrics(#{metrics := MetricsConf}, #{metrics := MetricsConf}) -> ensure_otel_metrics(
#{metrics := MetricsConf, exporter := Exporter},
#{metrics := MetricsConf, exporter := Exporter}
) ->
ok; ok;
ensure_otel_metrics(#{metrics := #{enable := true} = MetricsConf}, _Old) -> ensure_otel_metrics(#{metrics := #{enable := true}} = Conf, _Old) ->
_ = emqx_otel_metrics:stop_otel(), _ = emqx_otel_metrics:stop_otel(),
emqx_otel_metrics:start_otel(MetricsConf); emqx_otel_metrics:start_otel(Conf);
ensure_otel_metrics(#{metrics := #{enable := false}}, _Old) -> ensure_otel_metrics(#{metrics := #{enable := false}}, _Old) ->
emqx_otel_metrics:stop_otel(); emqx_otel_metrics:stop_otel();
ensure_otel_metrics(_, _) -> ensure_otel_metrics(_, _) ->
ok. ok.
ensure_otel_logs(#{logs := LogsConf}, #{logs := LogsConf}) -> ensure_otel_logs(
#{logs := LogsConf, exporter := Exporter},
#{logs := LogsConf, exporter := Exporter}
) ->
ok; ok;
ensure_otel_logs(#{logs := #{enable := true} = LogsConf}, _OldConf) -> ensure_otel_logs(#{logs := #{enable := true}} = Conf, _OldConf) ->
ok = remove_handler_if_present(?OTEL_LOG_HANDLER_ID), ok = remove_handler_if_present(?OTEL_LOG_HANDLER_ID),
HandlerConf = tr_handler_conf(LogsConf), HandlerConf = tr_handler_conf(Conf),
%% NOTE: should primary logger level be updated if it's higher than otel log level? %% NOTE: should primary logger level be updated if it's higher than otel log level?
logger:add_handler(?OTEL_LOG_HANDLER_ID, ?OTEL_LOG_HANDLER, HandlerConf); logger:add_handler(?OTEL_LOG_HANDLER_ID, ?OTEL_LOG_HANDLER, HandlerConf);
ensure_otel_logs(#{logs := #{enable := false}}, _OldConf) -> ensure_otel_logs(#{logs := #{enable := false}}, _OldConf) ->
remove_handler_if_present(?OTEL_LOG_HANDLER_ID). remove_handler_if_present(?OTEL_LOG_HANDLER_ID).
ensure_otel_traces(#{traces := TracesConf}, #{traces := TracesConf}) -> ensure_otel_traces(
#{traces := TracesConf, exporter := Exporter},
#{traces := TracesConf, exporter := Exporter}
) ->
ok; ok;
ensure_otel_traces(#{traces := #{enable := true} = TracesConf}, _OldConf) -> ensure_otel_traces(#{traces := #{enable := true}} = Conf, _OldConf) ->
emqx_otel_trace:start(TracesConf); _ = emqx_otel_trace:stop(),
emqx_otel_trace:start(Conf);
ensure_otel_traces(#{traces := #{enable := false}}, _OldConf) -> ensure_otel_traces(#{traces := #{enable := false}}, _OldConf) ->
emqx_otel_trace:stop(). emqx_otel_trace:stop().
@ -120,14 +130,13 @@ remove_handler_if_present(HandlerId) ->
ok ok
end. end.
tr_handler_conf(Conf) -> tr_handler_conf(#{logs := LogsConf, exporter := ExporterConf}) ->
#{ #{
level := Level, level := Level,
max_queue_size := MaxQueueSize, max_queue_size := MaxQueueSize,
exporting_timeout := ExportingTimeout, exporting_timeout := ExportingTimeout,
scheduled_delay := ScheduledDelay, scheduled_delay := ScheduledDelay
exporter := ExporterConf } = LogsConf,
} = Conf,
#{ #{
level => Level, level => Level,
config => #{ config => #{

View File

@ -65,7 +65,7 @@ handle_info(_Msg, State) ->
terminate(_Reason, _State) -> terminate(_Reason, _State) ->
ok. ok.
setup(Conf = #{enable := true}) -> setup(Conf = #{metrics := #{enable := true}}) ->
ensure_apps(Conf), ensure_apps(Conf),
create_metric_views(); create_metric_views();
setup(_Conf) -> setup(_Conf) ->
@ -73,7 +73,10 @@ setup(_Conf) ->
ok. ok.
ensure_apps(Conf) -> ensure_apps(Conf) ->
#{exporter := #{interval := ExporterInterval} = Exporter} = Conf, #{
exporter := Exporter,
metrics := #{interval := ExporterInterval}
} = Conf,
_ = opentelemetry_experimental:stop_default_metrics(), _ = opentelemetry_experimental:stop_default_metrics(),
ok = application:set_env( ok = application:set_env(

View File

@ -30,15 +30,27 @@
upgrade_legacy_metrics(RawConf) -> upgrade_legacy_metrics(RawConf) ->
case RawConf of case RawConf of
#{<<"opentelemetry">> := Otel} -> #{<<"opentelemetry">> := Otel} ->
LegacyMetricsFields = [<<"enable">>, <<"exporter">>], Otel1 =
Otel1 = maps:without(LegacyMetricsFields, Otel), case maps:take(<<"enable">>, Otel) of
Metrics = maps:with(LegacyMetricsFields, Otel), {MetricsEnable, OtelConf} ->
case Metrics =:= #{} of emqx_utils_maps:deep_put(
true -> [<<"metrics">>, <<"enable">>], OtelConf, MetricsEnable
RawConf; );
false -> error ->
RawConf#{<<"opentelemetry">> => Otel1#{<<"metrics">> => Metrics}} Otel
end; end,
Otel2 =
case Otel1 of
#{<<"exporter">> := #{<<"interval">> := Interval} = Exporter} ->
emqx_utils_maps:deep_put(
[<<"metrics">>, <<"interval">>],
Otel1#{<<"exporter">> => maps:remove(<<"interval">>, Exporter)},
Interval
);
_ ->
Otel1
end,
RawConf#{<<"opentelemetry">> => Otel2};
_ -> _ ->
RawConf RawConf
end. end.
@ -69,6 +81,13 @@ fields("opentelemetry") ->
#{ #{
desc => ?DESC(otel_traces) desc => ?DESC(otel_traces)
} }
)},
{exporter,
?HOCON(
?R_REF("otel_exporter"),
#{
desc => ?DESC(otel_exporter)
}
)} )}
]; ];
fields("otel_metrics") -> fields("otel_metrics") ->
@ -82,10 +101,15 @@ fields("otel_metrics") ->
desc => ?DESC(enable) desc => ?DESC(enable)
} }
)}, )},
{exporter, {interval,
?HOCON( ?HOCON(
?R_REF("otel_metrics_exporter"), emqx_schema:timeout_duration_ms(),
#{desc => ?DESC(exporter)} #{
aliases => [scheduled_delay],
default => <<"10s">>,
desc => ?DESC(scheduled_delay),
importance => ?IMPORTANCE_HIDDEN
}
)} )}
]; ];
fields("otel_logs") -> fields("otel_logs") ->
@ -134,14 +158,6 @@ fields("otel_logs") ->
desc => ?DESC(scheduled_delay), desc => ?DESC(scheduled_delay),
importance => ?IMPORTANCE_HIDDEN importance => ?IMPORTANCE_HIDDEN
} }
)},
{exporter,
?HOCON(
?R_REF("otel_logs_exporter"),
#{
desc => ?DESC(exporter),
importance => ?IMPORTANCE_HIGH
}
)} )}
]; ];
fields("otel_traces") -> fields("otel_traces") ->
@ -182,14 +198,6 @@ fields("otel_traces") ->
importance => ?IMPORTANCE_HIDDEN importance => ?IMPORTANCE_HIDDEN
} }
)}, )},
{exporter,
?HOCON(
?R_REF("otel_traces_exporter"),
#{
desc => ?DESC(exporter),
importance => ?IMPORTANCE_HIGH
}
)},
{filter, {filter,
?HOCON( ?HOCON(
?R_REF("trace_filter"), ?R_REF("trace_filter"),
@ -199,42 +207,7 @@ fields("otel_traces") ->
} }
)} )}
]; ];
fields("otel_metrics_exporter") -> fields("otel_exporter") ->
exporter_fields(metrics);
fields("otel_logs_exporter") ->
exporter_fields(logs);
fields("ssl_opts") ->
Schema = emqx_schema:client_ssl_opts_schema(#{}),
lists:keydelete("enable", 1, Schema);
fields("otel_traces_exporter") ->
exporter_fields(traces);
fields("trace_filter") ->
%% More filters can be implemented in future, e.g. topic, clientid
[
{trace_all,
?HOCON(
boolean(),
#{
default => false,
desc => ?DESC(trace_all),
importance => ?IMPORTANCE_MEDIUM
}
)}
].
desc("opentelemetry") -> ?DESC(opentelemetry);
desc("exporter") -> ?DESC(exporter);
desc("otel_logs_exporter") -> ?DESC(exporter);
desc("otel_metrics_exporter") -> ?DESC(exporter);
desc("otel_traces_exporter") -> ?DESC(exporter);
desc("otel_logs") -> ?DESC(otel_logs);
desc("otel_metrics") -> ?DESC(otel_metrics);
desc("otel_traces") -> ?DESC(otel_traces);
desc("ssl_opts") -> ?DESC(exporter_ssl);
desc("trace_filter") -> ?DESC(trace_filter);
desc(_) -> undefined.
exporter_fields(OtelSignal) ->
[ [
{endpoint, {endpoint,
?HOCON( ?HOCON(
@ -263,21 +236,29 @@ exporter_fields(OtelSignal) ->
importance => ?IMPORTANCE_LOW importance => ?IMPORTANCE_LOW
} }
)} )}
] ++ exporter_extra_fields(OtelSignal). ];
fields("ssl_opts") ->
%% Let's keep it in exporter config for metrics, as it is different from Schema = emqx_schema:client_ssl_opts_schema(#{}),
%% scheduled_delay_ms opt used for otel traces and logs lists:keydelete("enable", 1, Schema);
exporter_extra_fields(metrics) -> fields("trace_filter") ->
%% More filters can be implemented in future, e.g. topic, clientid
[ [
{interval, {trace_all,
?HOCON( ?HOCON(
emqx_schema:timeout_duration_ms(), boolean(),
#{ #{
default => <<"10s">>, default => false,
required => true, desc => ?DESC(trace_all),
desc => ?DESC(scheduled_delay) importance => ?IMPORTANCE_MEDIUM
} }
)} )}
]; ].
exporter_extra_fields(_OtelSignal) ->
[]. desc("opentelemetry") -> ?DESC(opentelemetry);
desc("otel_exporter") -> ?DESC(otel_exporter);
desc("otel_logs") -> ?DESC(otel_logs);
desc("otel_metrics") -> ?DESC(otel_metrics);
desc("otel_traces") -> ?DESC(otel_traces);
desc("ssl_opts") -> ?DESC(exporter_ssl);
desc("trace_filter") -> ?DESC(trace_filter);
desc(_) -> undefined.

View File

@ -41,8 +41,8 @@ init([]) ->
period => 512 period => 512
}, },
Children = Children =
case emqx_conf:get([opentelemetry, metrics]) of case emqx_conf:get([opentelemetry]) of
#{enable := false} -> []; #{metrics := #{enable := false}} -> [];
#{enable := true} = Conf -> [worker_spec(emqx_otel_metrics, Conf)] #{metrics := #{enable := true}} = Conf -> [worker_spec(emqx_otel_metrics, Conf)]
end, end,
{ok, {SupFlags, Children}}. {ok, {SupFlags, Children}}.

View File

@ -55,26 +55,24 @@ toggle_registered(false = _Enable) ->
ok. ok.
-spec ensure_traces(map()) -> ok | {error, term()}. -spec ensure_traces(map()) -> ok | {error, term()}.
ensure_traces(#{enable := true} = Conf) -> ensure_traces(#{traces := #{enable := true}} = Conf) ->
start(Conf); start(Conf);
ensure_traces(_Conf) -> ensure_traces(_Conf) ->
ok. ok.
-spec start(map()) -> ok | {error, term()}. -spec start(map()) -> ok | {error, term()}.
start(Conf) -> start(#{traces := TracesConf, exporter := ExporterConf}) ->
_ = safe_stop_default_tracer(),
#{ #{
exporter := Exporter,
max_queue_size := MaxQueueSize, max_queue_size := MaxQueueSize,
exporting_timeout := ExportingTimeout, exporting_timeout := ExportingTimeout,
scheduled_delay := ScheduledDelay, scheduled_delay := ScheduledDelay,
filter := #{trace_all := TraceAll} filter := #{trace_all := TraceAll}
} = Conf, } = TracesConf,
OtelEnv = [ OtelEnv = [
{bsp_scheduled_delay_ms, ScheduledDelay}, {bsp_scheduled_delay_ms, ScheduledDelay},
{bsp_exporting_timeout_ms, ExportingTimeout}, {bsp_exporting_timeout_ms, ExportingTimeout},
{bsp_max_queue_size, MaxQueueSize}, {bsp_max_queue_size, MaxQueueSize},
{traces_exporter, emqx_otel_config:otel_exporter(Exporter)} {traces_exporter, emqx_otel_config:otel_exporter(ExporterConf)}
], ],
set_trace_all(TraceAll), set_trace_all(TraceAll),
ok = application:set_env([{opentelemetry, OtelEnv}]), ok = application:set_env([{opentelemetry, OtelEnv}]),

View File

@ -17,8 +17,8 @@ otel_traces.label: "Open Telemetry Traces"
enable.desc: "Enable or disable Open Telemetry signal." enable.desc: "Enable or disable Open Telemetry signal."
enable.label: "Enable." enable.label: "Enable."
exporter.desc: "Open Telemetry Exporter" otel_exporter.desc: "Open Telemetry Exporter"
exporter.label: "Exporter" otel_exporter.label: "Exporter"
max_queue_size.desc: max_queue_size.desc:
"""The maximum queue size. After the size is reached Open Telemetry signals are dropped.""" """The maximum queue size. After the size is reached Open Telemetry signals are dropped."""