Skip to content
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ open_telemetry_decorator-*.tar

# Intellij nonsense
.idea/
*.iml
*.iml
.history/
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.14.4
erlang 25.3.1
elixir 1.15.7-otp-25
erlang 25.3.2.7
13 changes: 12 additions & 1 deletion lib/open_telemetry_decorator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,16 @@ defmodule OpenTelemetryDecorator do
"""
def with_span(span_name, opts \\ [], body, context) do
include = Keyword.get(opts, :include, [])
kind = get_kind(opts)
decorator_attributes = Keyword.get(opts, :attributes, [])

Validator.validate_args(span_name, include)

quote location: :keep do
require OpenTelemetry.Tracer, as: Tracer
require OpenTelemetry.Span, as: Span

Tracer.with_span unquote(span_name) do
Tracer.with_span unquote(span_name), %{kind: unquote(kind)} do
span_context = Tracer.current_span_ctx()

input_params =
Expand All @@ -68,6 +71,7 @@ defmodule OpenTelemetryDecorator do

# Called functions can mess up Tracer's current span context, so ensure we at least write to ours
Attributes.set(span_context, attrs)
Attributes.set(span_context, unquote(decorator_attributes))

result
rescue
Expand All @@ -83,4 +87,11 @@ defmodule OpenTelemetryDecorator do
target = "#{inspect(context.module)}.#{context.name}/#{context.arity} @decorate telemetry"
reraise %ArgumentError{message: "#{target} #{e.message}"}, __STACKTRACE__
end

def get_kind(opts) do
case Keyword.get(opts, :kind, :internal) do
kind when kind in [:internal, :server, :client, :producer, :consumer] -> kind
_ -> :internal
end
end
end
2 changes: 1 addition & 1 deletion test/open_telemetry_decorator/attributes_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule OpenTelemetryDecorator.AttributesTest do
use ExUnit.Case, async: true
use ExUnit.Case, async: false
use OtelHelper

alias OpenTelemetryDecorator.Attributes
Expand Down
92 changes: 91 additions & 1 deletion test/open_telemetry_decorator_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule OpenTelemetryDecoratorTest do
use ExUnit.Case, async: true
use ExUnit.Case, async: false
use OtelHelper

doctest OpenTelemetryDecorator
Expand Down Expand Up @@ -63,6 +63,21 @@ defmodule OpenTelemetryDecoratorTest do

@decorate with_span("Example.with_error")
def with_error, do: OpenTelemetryDecorator.Attributes.set(:error, "ruh roh!")

@decorate with_span("Example.with_attributes", attributes: [foo: "bar", baz: "qux"])
def with_attributes, do: :ok

@decorate with_span("Example.with_attrs_and_include",
attributes: [foo: "bar", baz: "qux"],
include: [:opts]
)
def with_attrs_and_include(opts), do: {:ok, opts}

@decorate with_span("Example.with_attrs_and_conflicts",
attributes: [foo: "bar"],
include: [:foo]
)
def with_attrs_and_conflicts(foo), do: {:ok, foo}
end

test "does not modify inputs or function result" do
Expand Down Expand Up @@ -239,5 +254,80 @@ defmodule OpenTelemetryDecoratorTest do
expected = %{"error" => "ruh roh!"}
assert get_span_attributes(attrs) == expected
end

test "can set the span.kind on the span" do
defmodule SpanKinds do
use OpenTelemetryDecorator

@decorate with_span("SpanKinds.producer", kind: :producer)
def producer do
:ok
end

@decorate with_span("SpanKinds.consumer", kind: :consumer)
def consumer do
:ok
end

@decorate with_span("SpanKinds.internal", kind: :internal)
def internal do
:ok
end

@decorate with_span("SpanKinds.client", kind: :client)
def client do
:ok
end

@decorate with_span("SpanKinds.server", kind: :server)
def server do
:ok
end

@decorate with_span("SpanKinds.invalid", kind: :invalid)
def invalid do
:ok
end
end

SpanKinds.producer()
assert_receive {:span, span(name: "SpanKinds.producer", kind: :producer)}

SpanKinds.consumer()
assert_receive {:span, span(name: "SpanKinds.consumer", kind: :consumer)}

SpanKinds.client()
assert_receive {:span, span(name: "SpanKinds.client", kind: :client)}

SpanKinds.server()
assert_receive {:span, span(name: "SpanKinds.server", kind: :server)}

SpanKinds.internal()
assert_receive {:span, span(name: "SpanKinds.internal", kind: :internal)}

# using an invalid span.kind will default to :internal
SpanKinds.invalid()
assert_receive {:span, span(name: "SpanKinds.invalid", kind: :internal)}
end

test "can set attributes on the span" do
Example.with_attributes()
assert_receive {:span, span(name: "Example.with_attributes", attributes: attrs)}
assert %{"app.baz" => "qux", "app.foo" => "bar"} == get_span_attributes(attrs)
end

test "can set attributes and input params on the span" do
Example.with_attrs_and_include(:include_me)
assert_receive {:span, span(name: "Example.with_attrs_and_include", attributes: attrs)}

assert %{"app.baz" => "qux", "app.foo" => "bar", "app.opts" => ":include_me"} ==
get_span_attributes(attrs)
end

test "can set attributes and input params on the span, where attributes win with conflicting names" do
Example.with_attrs_and_conflicts("not_bar")
assert_receive {:span, span(name: "Example.with_attrs_and_conflicts", attributes: attrs)}
assert %{"app.foo" => "bar"} == get_span_attributes(attrs)
end
end
end
2 changes: 2 additions & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Application.stop(:opentelemetry)
Application.unload(:opentelemetry)
ExUnit.start()