From 7c01f87b925cec12bbf82a78c532052fc0016460 Mon Sep 17 00:00:00 2001 From: Alberto Sartori Date: Sun, 5 Nov 2023 16:15:03 +0100 Subject: [PATCH] improvements --- .../lib/open_telemetry/span.ex | 19 ++++---- apps/opentelemetry_api/src/otel_span.erl | 43 +++++++++++++------ test/otel_tests.exs | 6 +-- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/apps/opentelemetry_api/lib/open_telemetry/span.ex b/apps/opentelemetry_api/lib/open_telemetry/span.ex index 75adda9f..b0fe2536 100644 --- a/apps/opentelemetry_api/lib/open_telemetry/span.ex +++ b/apps/opentelemetry_api/lib/open_telemetry/span.ex @@ -136,16 +136,15 @@ defmodule OpenTelemetry.Span do def record_exception(span_ctx, exception, trace \\ nil, attributes \\ []) def record_exception(span_ctx, exception, trace, attributes) when is_exception?(exception) do - exception_type = to_string(exception.__struct__) - - exception_attributes = [ - {OpenTelemetry.SemanticConventions.Trace.exception_type(), exception_type}, - {OpenTelemetry.SemanticConventions.Trace.exception_message(), Exception.message(exception)}, - {OpenTelemetry.SemanticConventions.Trace.exception_stacktrace(), - Exception.format_stacktrace(trace)} - ] - - add_event(span_ctx, "exception", exception_attributes ++ attributes) + trace = + if trace do + trace + else + {:current_stacktrace, t} = Process.info(self(), :current_stacktrace) + Enum.drop(t, 3) + end + + :otel_span.record_exception(span_ctx, :error, exception, trace, attributes) end def record_exception(_, _, _, _), do: false diff --git a/apps/opentelemetry_api/src/otel_span.erl b/apps/opentelemetry_api/src/otel_span.erl index af2aaf8c..f73d939c 100644 --- a/apps/opentelemetry_api/src/otel_span.erl +++ b/apps/opentelemetry_api/src/otel_span.erl @@ -221,12 +221,7 @@ add_events(_, _) -> record_exception(SpanCtx, Class, Term, Stacktrace, Attributes) when is_list(Attributes) -> record_exception(SpanCtx, Class, Term, Stacktrace, maps:from_list(Attributes)); record_exception(SpanCtx, Class, Term, Stacktrace, Attributes) when is_map(Attributes) -> - ExceptionType = exception_type(Class, Term), - {ok, StacktraceString} = otel_utils:format_binary_string("~0tP", [Stacktrace, 10], [{chars_limit, 50}]), - ExceptionAttributes = #{?EXCEPTION_TYPE => ExceptionType, - ?EXCEPTION_STACKTRACE => StacktraceString}, - ExceptionAttributes1 = add_elixir_message(ExceptionAttributes, Term), - add_event(SpanCtx, 'exception', maps:merge(ExceptionAttributes1, Attributes)); + do_record_exception(SpanCtx, Class, Term, undefined, Stacktrace, Attributes); record_exception(_, _, _, _, _) -> false. @@ -240,15 +235,33 @@ record_exception(_, _, _, _, _) -> record_exception(SpanCtx, Class, Term, Message, Stacktrace, Attributes) when is_list(Attributes) -> record_exception(SpanCtx, Class, Term, Message, Stacktrace, maps:from_list(Attributes)); record_exception(SpanCtx, Class, Term, Message, Stacktrace, Attributes) when is_map(Attributes) -> - ExceptionType = exception_type(Class, Term), - {ok, StacktraceString} = otel_utils:format_binary_string("~0tP", [Stacktrace, 10], [{chars_limit, 50}]), - ExceptionAttributes = #{?EXCEPTION_TYPE => ExceptionType, - ?EXCEPTION_STACKTRACE => StacktraceString, - ?EXCEPTION_MESSAGE => Message}, - add_event(SpanCtx, 'exception', maps:merge(ExceptionAttributes, Attributes)); + do_record_exception(SpanCtx, Class, Term, Message, Stacktrace, Attributes); record_exception(_, _, _, _, _, _) -> false. +do_record_exception(SpanCtx, Class, Term, Message, Stacktrace, Attributes) -> + ExceptionFromElixir = exception_from_elixir(Stacktrace), + Term1 = normalize_exception(Class, Term, Stacktrace, ExceptionFromElixir), + ExceptionType = exception_type(Class, Term1), + StacktraceString = format_stacktrace(Stacktrace, ExceptionFromElixir), + ExceptionAttributes = #{?EXCEPTION_TYPE => ExceptionType, + ?EXCEPTION_STACKTRACE => StacktraceString}, + ExceptionAttributes1 = add_message(ExceptionAttributes, Message, Term1), + add_event(SpanCtx, exception, maps:merge(ExceptionAttributes1, Attributes)). +exception_from_elixir([{Module, _, _, _} | _]) -> + ModuleStr = atom_to_list(Module), + string:find(ModuleStr, "Elixir.") =:= ModuleStr; +exception_from_elixir(_) -> + false. +format_stacktrace(Stacktrace, false) -> + {ok, StacktraceString} = otel_utils:format_binary_string("~0tP", [Stacktrace, 10], [{chars_limit, 50}]), + StacktraceString; +format_stacktrace(Stacktrace, true) -> + 'Elixir.Exception':format_stacktrace(Stacktrace). +normalize_exception(Class, Term, Stacktrace, true) -> + 'Elixir.Exception':normalize(Class, Term, Stacktrace); +normalize_exception(_Class, Term, _ExceptionStacktrace, false) -> + Term. exception_type(error, #{'__exception__' := true, '__struct__' := ElixirErrorStruct} = Term) -> case atom_to_binary(ElixirErrorStruct) of <<"Elixir.", ExceptionType/binary>> -> ExceptionType; @@ -260,7 +273,9 @@ exception_type_erl(Class, Term) -> {ok, ExceptionType} = otel_utils:format_binary_string("~0tP:~0tP", [Class, 10, Term, 10], [{chars_limit, 50}]), ExceptionType. -add_elixir_message(Attributes, #{'__exception__' := true} = Exception) -> +add_message(Attributes, Message, _Exception) when Message /= undefined -> + maps:put(?EXCEPTION_MESSAGE, Message, Attributes); +add_message(Attributes, undefined, #{'__exception__' := true} = Exception) -> try Message = 'Elixir.Exception':message(Exception), maps:put(?EXCEPTION_MESSAGE, Message, Attributes) @@ -268,7 +283,7 @@ add_elixir_message(Attributes, #{'__exception__' := true} = Exception) -> _Class:_Exception -> Attributes end; -add_elixir_message(Attributes, _) -> +add_message(Attributes, _, _) -> Attributes. -spec set_status(SpanCtx, StatusOrCode) -> boolean() when diff --git a/test/otel_tests.exs b/test/otel_tests.exs index 1fd37e83..231eb75b 100644 --- a/test/otel_tests.exs +++ b/test/otel_tests.exs @@ -247,7 +247,7 @@ defmodule OtelTests do attributes = :otel_attributes.new( [ - {:"exception.type", "Elixir.RuntimeError"}, + {:"exception.type", "RuntimeError"}, {:"exception.message", "my error message"}, {:"exception.stacktrace", stacktrace} ], @@ -265,7 +265,7 @@ defmodule OtelTests do :infinity, 0, [ - {:event, _, "exception", ^attributes} + {:event, _, :exception, ^attributes} ] } )} @@ -358,7 +358,7 @@ defmodule OtelTests do event assert %{ - "exception.type": "error:badarg", + "exception.type": "ArgumentError", "exception.stacktrace": _ } = received_attirbutes end