Skip to content

Commit

Permalink
Add RecordException to Elixir's Span module
Browse files Browse the repository at this point in the history
Reference for [`RecordException`](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#record-exception)

`RecordException` has been implemented only on Elixir side as it has a
more uniform way to deal with exceptions as a value.

The attribute `exception.escaped` is left up to the user to supply
through the `attributes` parameter in `record_exception/4`.
  • Loading branch information
gugahoa committed Nov 2, 2020
1 parent ee1fc15 commit 93aa6f0
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
22 changes: 22 additions & 0 deletions apps/opentelemetry_api/lib/open_telemetry/span.ex
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ defmodule OpenTelemetry.Span do
@spec add_events(OpenTelemetry.span_ctx(), [OpenTelemetry.event()]) :: boolean()
defdelegate add_events(span_ctx, events), to: :otel_span

@doc """
Record an exception as an event, following the semantics convetions for exceptions.
If trace is not provided, the stacktrace is retrieved from `Process.info/2`
"""
@spec record_exception(OpenTelemetry.span_ctx(), Exception.t()) :: boolean()
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 = [
{"exception.type", exception_type},
{"exception.message", Exception.message(exception)},
{"exception.stacktrace", Exception.format_stacktrace(trace)}
]

add_event(span_ctx, "exception", exception_attributes ++ attributes)
end

def record_exception(_, _, _, _), do: false

@doc """
Sets the Status of the currently active Span.
Expand Down
2 changes: 1 addition & 1 deletion apps/opentelemetry_api/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule OpenTelemetry.MixProject do
app: app,
version: version(Keyword.fetch!(desc, :vsn)),
description: to_string(Keyword.fetch!(desc, :description)),
elixir: "~> 1.8",
elixir: "~> 1.11",
start_permanent: Mix.env() == :prod,
# We should never have dependencies
deps: deps(Keyword.fetch!(config, :deps)),
Expand Down
37 changes: 37 additions & 0 deletions test/otel_tests.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ defmodule OtelTests do
require Record
@fields Record.extract(:span, from_lib: "opentelemetry/include/otel_span.hrl")
Record.defrecordp(:span, @fields)
@event_fields Record.extract(:event, from_lib: "opentelemetry_api/include/opentelemetry.hrl")
Record.defrecordp(:event, @event_fields)

test "use Tracer to set attributes" do
:otel_batch_processor.set_exporter(:otel_exporter_pid, self())
Expand Down Expand Up @@ -34,4 +36,39 @@ defmodule OtelTests do
{"attr-2", "value-2"}])}
end

test "Span.record_exception/4 should return false if passed an invalid exception" do
Tracer.with_span "span-3" do
refute OpenTelemetry.Span.record_exception(Tracer.current_span_ctx(), :not_an_exception)
end
end

test "Span.record_exception/4 should add an exception event to the span" do
:otel_batch_processor.set_exporter(:otel_exporter_pid, self())
s = Tracer.start_span("span-4")

try do
raise RuntimeError, "my error message"
rescue
ex ->
assert Span.record_exception(s, ex, __STACKTRACE__)
assert Span.end_span(s)

stacktrace = Exception.format_stacktrace(__STACKTRACE__)

assert_receive {:span,
span(
name: "span-4",
events: [
event(
name: "exception",
attributes: [
{"exception.type", "Elixir.RuntimeError"},
{"exception.message", "my error message"},
{"exception.stacktrace", ^stacktrace}
]
)
]
)}
end
end
end

0 comments on commit 93aa6f0

Please sign in to comment.