-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add source code attributes to Elixir tracer macros #550
base: main
Are you sure you want to change the base?
Add source code attributes to Elixir tracer macros #550
Conversation
Map.new() | ||
|> Map.update(:attributes, source_attrs, &Map.merge(&1, source_attrs)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map.new() | |
|> Map.update(:attributes, source_attrs, &Map.merge(&1, source_attrs)) | |
Map.update(:attributes, source_attrs, source_attrs) |
Isn't this the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I misread entirely :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least I think... the &1
applies to the &Map.merge/2
, right? And no thte pipe?
But I realize I still don't see where the original opt attributes are being merged with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoopsie, you're absolutely right, I was toying with that while debugging and removed the original opt attributes.
Nice! Could you add a simple test? Could even just extend one of the existing tests in |
How can I check the attributes set in the current span? I'm having trouble finding an example. |
This test adds attributes and then checks they are in the outputted span https://github.com/open-telemetry/opentelemetry-erlang/blob/main/test/otel_tests.exs#L33-L46 -- could just add to that test that the source code attributes are also there. |
Perfect! I didn't realize there were tests at the root of the repo too. I'll have tests ready in a jiffy. |
Do I need to do anything special to run the tests locally? When I try to run $ mix test
===> Analyzing applications...
===> Compiling opentelemetry
=WARNING REPORT==== 5-Mar-2023::12:19:44.385057 ===
FORMAT ERROR: "OTLP exporter module `opentelemetry_exporter` not found. Verify you have included the `opentelemetry_exporter` dependency." - [opentelemetry_exporter]
There are no tests to run |
I also checked CI, and I ran $ mix test --no-start test/otel_tests.exs
===> Analyzing applications...
===> Compiling opentelemetry
== Compilation error in file test/otel_tests.exs ==
** (RuntimeError) error parsing file /home/rosa/workspace/opentelemetry-erlang/_build/test/lib/opentelemetry/src/otel_tracer.hrl, got: {:error, :enoent}
(elixir 1.14.3) lib/record/extractor.ex:84: Record.Extractor.read_file/2
(elixir 1.14.3) lib/record/extractor.ex:50: Record.Extractor.extract_record/2
test/otel_tests.exs:12: (module)
(elixir 1.14.3) lib/kernel/parallel_compiler.ex:449: Kernel.ParallelCompiler.require_file/2
(elixir 1.14.3) lib/kernel/parallel_compiler.ex:342: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/7 |
You may need to first run |
code_attrs = unquote(code_attrs) | ||
start_opts = | ||
Map.new(unquote(start_opts)) | ||
|> Map.put(unquote(thread_id_key), :erlang.system_info(:scheduler_id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this adding the thread id attribute to start_opts
instead of the attributes
?
Also, is the Map.new
needed?
And I'd suggest moving the thread_id
to code_attributes()
so it doesn't have to be duplicated, and may mean this whole pipeline can be reduced to a Map.update
. The fewer map creations/updates the better :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I'll fix that. And I'll see how removing the Map.new
turns out.
I moved thread_id
out of code_attributes
because I was worried that I was getting the compile-time scheduler instead of the runtime one, so I wanted to move it to inside the quote
block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, the __CALLER__
calls work because they are macros but :erlang.system_info(:scheduler_id)
is going to be run at compile time?
Sounds right. I get confused with this macro stuff, esp when its macros in macros :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! I'm trying to wrap my head around macros myself, I don't work with them much.
So I tried removing the Map.new
and the tests failed, there was a test that passes start opts as a keyword list. Since opts
is user input and this function is dealing with it as a map, I think it's a good defensive move.
I got the tests figured out! Now they're actually, y'know, testing this change. Thank you for the guidance :). This should be all set for another once-over. |
@Cantido hey, sorry, can you add a changelog entry for this and then I'll merge it? Or actually, I'll go merge your one changing the macros to functions and then you'll want to rebase on that. |
Sure thing! |
6d4809c
to
cde2961
Compare
I'm stalling a little on this because I learned almost no language does this by default. I'm leaning towards it still being good to do always since it is only part of the macro. Manual calls to the |
thread_id_key: thread_id_key | ||
] do | ||
code_attrs = Map.put(code_attrs, thread_id_key, :erlang.system_info(:scheduler_id)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you mentioned not thinking it should be the scheduler id but the pid before. I wonder if we shouldn't just leave out the thread attribute for now. I'd like to get the pid in but not sure what attribute key to use for it yet and don't want to have our hands tied by backwards compatibility if we add this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Cantido do you think you'll have time to update this PR to remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can certainly do that!
quote do | ||
code_attrs = | ||
Map.put(unquote(code_attrs), unquote(thread_id_key), :erlang.system_info(:scheduler_id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like thread_id is still in here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, I haven't had a chance to properly sit down with this and get any context back. I promise I will get to that soon.
This change adds thread & source code attributes spans created with the Elixir API, as described here: https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/span-general/#general-thread-attributes. This is related to #517, but it does not close it since I wasn't able to do the Erlang part (I don't know Erlang). I can certainly do the Elixir part though 😄.
I tested this in a project with Jaeger, and the attributes were all correct, despite my lack of skill with macros.