-
Notifications
You must be signed in to change notification settings - Fork 3
Extend the span attributes & improve the span name. #215
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
Conversation
First attempt at abstracting some of the verbosity of Tracer.set_attributes to a module def, rather than repeating similar code in each def we wish to observe. Currently only setting tracer spans in 2 resolver defs, and only for votes (1 of 2 defs) and create_vote (1 of 3 defs). Not sure we need to also observe the related core api defs, as the data returned is very similar, and the resolver defs 'wrap' the related core api defs.
|
It'd be great to get some feedback on this idea / approach. Some questions that cross my mind:
|
|
I'm also starting to think that we should also be observing the |
|
It's hard to tell what the PR is about from the title, and it's the second time we have this one. Would you please make it more descriptive? See how I edited this one (last update, towards the bottom): #211 |
Yes, sorry. I didn't check the title, and assumed it reflected the commit, forgetting there are 2 commits here. Changed now. |
|
much better 👏 thanks :) |
|
As a noob reading this PR: I like extracting the tracer details so the functions read better 👍. But I'm also trusting some magic in how the attributes are passed and assigned. How do we know this works? Is it reasonable to have a spec that asserts the trace behavior? This is partly a refactor (extraction) and partly extension (more info captured if I read correctly: the whole of binding vars rather than just org id). I don't think it's worth redoing here but often it's nice to isolate the two efforts. It's really nice to learn by reading PRs here. |
|
To elaborate a bit: my reviewer brain reading refactors wants to know there is spec coverage that stays green; reading new functionality I expect new specs too. I don't know Elixir testing well but there should be a way to assert behavior like "when voting expect the tracer service to have been called with ..." |
Good point. There's no specs yet. I think it should be possible to include tests, and I could probably model them on some I have seen in OpenTelemetry repos. I am still wondering if this is even the right approach, but since it does seem to be yielding useful traces (at least better than none), maybe it is time to start developing some.
True. I should really have separated the 2 different types of change. I think, at the moment, the new observability related code is so minimal that this doesn't really present a problem in terms of understanding or separating (should we wish to, say, remove 1 type of change and leave the other). Point taken, though. Thanks for the feedback 👍 |
|
I've just noticed that when we include the related core api def(s), rather than just the resolver def(s),in the trace (by also wrapping in a tracer span), we can get this nice waterfall view on Honeycomb: I removed the related core-api traces in this PR, but now I can see how including them, and more importantly wrapping tracer spans around things like db queries / writes / etc. within the core api actions, could give us more granular info. [Also added to #201] |
lib/liquid_voting/tracers.ex
Outdated
| # Sets general attributes to send in Tracer.with_span block. | ||
| def set_attributes(env, vars) do | ||
| Tracer.set_attributes([ | ||
| {:action, env.function}, |
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 think it might be more useful to name this explicitly as :function. We could then develop this to include the module name + function name, and then name the field something like :mod/func.
|
Though I see the tracer code verbosity, I don't really see much value in abstracting it away if we still need the original I'll review the PR again once the above changes are applied. I think the same might apply to specs: we should at least wait until we have a stable set of traces to spec them out. If we are to spec them out at all, that is. I'm not so sure it's worth doing it. It's not functionality per se, and nor is it user facing. We're the ones using it, and we can easily assert that it's working on Honeycomb itself - manual testing might be enough. It's a debate though: I've myself spec'd out logs in the past, but changed my stance later. We can discuss it down the line. As for the questions and comments:
Good point you brought up. We should anonymize them, so they're kept private while also allowing us to drill down traces based on them. We shouldn't be able to see it, and it's also mandatory to be compliant with GDPR. I'm creating a new issue for this.
👍 yes, we should also trace both success and failure scenarios. And all different variations on them, when present |
oliverbarnes
left a comment
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.
Changes requested in my last comment
This is more similar to how traces for Ecto and Phoenix are, and will be, named. It also means this information is more clearly presented on Honeycomb, as it is listed first in trace rows, and in large text, top-right of page when inspecting a particilar trace.
|
I removed the refactoring to a separate module (of I also added the module name + This is now similar to how traces for Ecto and Phoenix are, and will be, named. It also means this information is more clearly presented on Honeycomb, as it is listed first in trace rows, and in large text, top-right of page when inspecting a particular trace. |
|
Should I extend the attributes to include |
Great, thanks. Can you also update the PR title, please
Makes sense
👌 very nice |
config/config.exs
Outdated
| otel_batch_processor: %{ | ||
| exporter: | ||
| {OpenTelemetry.Honeycomb.Exporter, | ||
| write_key: "520527fcecf7c6b38bd1775da111ead3", dataset: "api-telemetry"} |
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.
This needs to be in a environment variable. We'll need to regenerate our Honeycomb api key as well, now that's it's been exposed :)
All good, btw. Happens to all of us, and it's good when it happens early on so we can get it ingrained in our heads ;)
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 mistake. This doesn't need to be in config.ex at all. Just used for local testing. My fault for rushing.
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.
No prob, happens
| """ | ||
| def list_votes(organization_id) do | ||
| Tracer.with_span "LV/voting" do |
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.
Why is the span being removed 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.
This relates to my general q: Should we be adding traces to the related core functions. E.g. resolver votes/3 calls list_votes. I am not sure a. if list_votes trace gives us useful information over the resolver trace? b. if it is outside the scope of focusing on Absinthe layer?
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 guess if we add it on each layer, we'll see where most processing goes etc. But difference might be negligible, and then we can remove later. I'd stick with it for now
| {:action, "votes"}, | ||
| {:request_id, Logger.metadata()[:request_id]}, | ||
| {:organization_id, organization_id} | ||
| {:vars, binding()} |
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.
which vars are being sent, 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.
All the args passed into the function and their values.
For example for create_vote, we get:
[args: %{participant_email: "rrr@somedomain.com", proposal_url: "https://other_one", yes: true}, email: "rrr@somedomain.com", organization_id: "b7a9cae5-6e3a-48b1-8730-8b5c8d6c9b5a"]
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 was going with the principle that as much info. as possible is preferable.
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.
Ok, I was worried we'd be getting more internal stuff.
But vars[:args][:participant_email] is the same as vars [:email], and we also need to access this atomically in order to anonymise it. I know it's verbose, but I think it's better to access each one of these atomically.
This will also make it more explicit on what we're trying to track
Subsequent PR would be better |
Done. I previously forgot to click 'save' after editing the title. |
Only specifies trace attributes for args used by function, not those that are ignored, using '_'. Include related funcs (list_votes & create_vote) at core layer, as well as existing resolver layer trace spans.
|
I have (re) included the related 'core' functions. We are currently only developing traces in 2 action paths:
We are not yet exhaustively tracing all forms of a function (only one of 3 forms of resolvers/voting.ex/create_vote, for example). |
oliverbarnes
left a comment
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.
Looking good! Just a couple of more changes
lib/liquid_voting/voting.ex
Outdated
| Tracer.with_span "#{__MODULE__} #{inspect(__ENV__.function)}" do | ||
| Tracer.set_attributes([ | ||
| {:request_id, Logger.metadata()[:request_id]}, | ||
| {:vars, |
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.
vars is too vague here, I think. How about params? That's more informative about the vars being the ones submitted in the request.
lib/liquid_voting/voting.ex
Outdated
| {:ok, _delegation} -> vote | ||
| {:error, changeset} -> Repo.rollback(changeset) | ||
| Repo.transaction(fn -> | ||
| # TODO: refactor case statements into small functions. |
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 think refactoring is always in our minds, we don't need to add a TODO. These tend to be there forever and just add noise
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.
Yes, this is an old TODO. Will remove.





commit msg:
"First attempt at abstracting some of the verbosity of Tracer.set_attributes to a module def, rather than repeating similar code in each definition we wish to observe.
Currently only setting tracer spans in 2 resolver defs, and only for votes (1 of 2 defs) and create_vote (1 of 3 defs).
Not sure we need to also observe the related core api defs, as the data returned is very similar, and the resolver defs 'wrap' the related core api defs."
UPDATE: This PR now focuses on extending the span attributes & improving the span name. The refactoring mentioned in this description, is not included.