From 64abb0899fb2e4be64f2ab218f2f6b1f1f43248f Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Mon, 6 Nov 2023 17:01:37 -0500 Subject: [PATCH 1/7] update tool-versions --- .tool-versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.tool-versions b/.tool-versions index 60f0fd0..fa9578d 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -elixir 1.14.4 -erlang 25.3.1 \ No newline at end of file +elixir 1.15.7-otp-25 +erlang 25.3.1 From c96839fc09dc7ecf8fc7f371b509cbb1ba6c5eac Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Mon, 6 Nov 2023 17:02:20 -0500 Subject: [PATCH 2/7] add .history/ to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6ff06dc..39ec585 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ open_telemetry_decorator-*.tar # Intellij nonsense .idea/ -*.iml \ No newline at end of file +*.iml +.history/ From 66f3455ce46c06b12095a1ed9d7086150b46163b Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Mon, 6 Nov 2023 17:20:39 -0500 Subject: [PATCH 3/7] Make tests synchronous Creating/Destroying the otel_exporter_pid for each test was not cooperating with all the tests running simultaneously. Almost certainly due to the race condition in OtelHlper.otel_pid_reporter altering the global state to configure where the spans were being sent Co-authored-by: Gray --- test/open_telemetry_decorator_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/open_telemetry_decorator_test.exs b/test/open_telemetry_decorator_test.exs index 1a5ef08..0a4d853 100644 --- a/test/open_telemetry_decorator_test.exs +++ b/test/open_telemetry_decorator_test.exs @@ -1,5 +1,5 @@ defmodule OpenTelemetryDecoratorTest do - use ExUnit.Case, async: true + use ExUnit.Case, async: false use OtelHelper doctest OpenTelemetryDecorator From b0a39cf426506a3e91a19b4901abf013077d932e Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Mon, 6 Nov 2023 17:29:57 -0500 Subject: [PATCH 4/7] Allow user to specify the span.kind in the with_span decorator --- lib/open_telemetry_decorator.ex | 10 ++++- test/open_telemetry_decorator_test.exs | 55 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/open_telemetry_decorator.ex b/lib/open_telemetry_decorator.ex index e48ac51..12da208 100644 --- a/lib/open_telemetry_decorator.ex +++ b/lib/open_telemetry_decorator.ex @@ -40,13 +40,14 @@ defmodule OpenTelemetryDecorator do """ def with_span(span_name, opts \\ [], body, context) do include = Keyword.get(opts, :include, []) + kind = get_kind(opts) 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 = @@ -83,4 +84,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 diff --git a/test/open_telemetry_decorator_test.exs b/test/open_telemetry_decorator_test.exs index 0a4d853..119fcdb 100644 --- a/test/open_telemetry_decorator_test.exs +++ b/test/open_telemetry_decorator_test.exs @@ -239,5 +239,60 @@ 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 end end From ab0ad10f8ba50f6ebcf1822d046a566ecd037583 Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Tue, 7 Nov 2023 12:49:50 -0500 Subject: [PATCH 5/7] Stop opentelemetry from starting in test Did this because the first test was always failing Co-authored-by: Gray --- test/open_telemetry_decorator/attributes_test.exs | 2 +- test/test_helper.exs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/open_telemetry_decorator/attributes_test.exs b/test/open_telemetry_decorator/attributes_test.exs index d3eb269..e6c2ba9 100644 --- a/test/open_telemetry_decorator/attributes_test.exs +++ b/test/open_telemetry_decorator/attributes_test.exs @@ -1,5 +1,5 @@ defmodule OpenTelemetryDecorator.AttributesTest do - use ExUnit.Case, async: true + use ExUnit.Case, async: false use OtelHelper alias OpenTelemetryDecorator.Attributes diff --git a/test/test_helper.exs b/test/test_helper.exs index 869559e..6b8ecd6 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1 +1,3 @@ +Application.stop(:opentelemetry) +Application.unload(:opentelemetry) ExUnit.start() From b57dbc9276666b4491c356319f064b141dfcf89b Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Tue, 7 Nov 2023 12:50:41 -0500 Subject: [PATCH 6/7] Added the ability to set span attributes in the decorator --- lib/open_telemetry_decorator.ex | 3 +++ test/open_telemetry_decorator_test.exs | 35 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/open_telemetry_decorator.ex b/lib/open_telemetry_decorator.ex index 12da208..2eae002 100644 --- a/lib/open_telemetry_decorator.ex +++ b/lib/open_telemetry_decorator.ex @@ -41,6 +41,8 @@ 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 @@ -69,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 diff --git a/test/open_telemetry_decorator_test.exs b/test/open_telemetry_decorator_test.exs index 119fcdb..fafe662 100644 --- a/test/open_telemetry_decorator_test.exs +++ b/test/open_telemetry_decorator_test.exs @@ -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 @@ -294,5 +309,25 @@ defmodule OpenTelemetryDecoratorTest do 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 From 08dadfa4716a5cdaa40da0ead8f835ebea6ffbaa Mon Sep 17 00:00:00 2001 From: Jeff Deville Date: Sun, 10 Dec 2023 13:47:38 -0500 Subject: [PATCH 7/7] Fix credo --- .tool-versions | 2 +- test/open_telemetry_decorator_test.exs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.tool-versions b/.tool-versions index fa9578d..6efbcf8 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ elixir 1.15.7-otp-25 -erlang 25.3.1 +erlang 25.3.2.7 diff --git a/test/open_telemetry_decorator_test.exs b/test/open_telemetry_decorator_test.exs index fafe662..02e95f6 100644 --- a/test/open_telemetry_decorator_test.exs +++ b/test/open_telemetry_decorator_test.exs @@ -260,32 +260,32 @@ defmodule OpenTelemetryDecoratorTest do use OpenTelemetryDecorator @decorate with_span("SpanKinds.producer", kind: :producer) - def producer() do + def producer do :ok end @decorate with_span("SpanKinds.consumer", kind: :consumer) - def consumer() do + def consumer do :ok end @decorate with_span("SpanKinds.internal", kind: :internal) - def internal() do + def internal do :ok end @decorate with_span("SpanKinds.client", kind: :client) - def client() do + def client do :ok end @decorate with_span("SpanKinds.server", kind: :server) - def server() do + def server do :ok end @decorate with_span("SpanKinds.invalid", kind: :invalid) - def invalid() do + def invalid do :ok end end