Skip to content

Hybrid agent set status#1599

Merged
hmstepanek merged 6 commits intodevelop-hybrid-core-tracingfrom
hybrid-agent-set-status
Dec 22, 2025
Merged

Hybrid agent set status#1599
hmstepanek merged 6 commits intodevelop-hybrid-core-tracingfrom
hybrid-agent-set-status

Conversation

@lrafeei
Copy link
Contributor

@lrafeei lrafeei commented Dec 4, 2025

This PR adds status setting capabilities as well as adding to the record_exception functionality.

(Note that record_exception is not fully complete at this point.)

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ ACTION actionlint 7 0 0 0.82s
✅ MARKDOWN markdownlint 7 0 0 0 1.32s
✅ PYTHON ruff 972 1 0 0 1.02s
✅ PYTHON ruff-format 972 1 0 0 0.36s
✅ YAML prettier 15 0 0 0 1.44s
✅ YAML v8r 15 0 0 6.18s
✅ YAML yamllint 15 0 0 0.69s

See detailed reports in MegaLinter artifacts

MegaLinter is graciously provided by OX Security

@mergify mergify bot added the tests-failing Tests failing in CI. label Dec 4, 2025
@codecov-commenter
Copy link

codecov-commenter commented Dec 4, 2025

Codecov Report

❌ Patch coverage is 81.25000% with 6 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop-hybrid-core-tracing@5577ffd). Learn more about missing BASE report.

Files with missing lines Patch % Lines
newrelic/api/opentelemetry.py 81.25% 2 Missing and 4 partials ⚠️
Additional details and impacted files
@@                      Coverage Diff                       @@
##             develop-hybrid-core-tracing    #1599   +/-   ##
==============================================================
  Coverage                               ?   79.87%           
==============================================================
  Files                                  ?      213           
  Lines                                  ?    25087           
  Branches                               ?     3988           
==============================================================
  Hits                                   ?    20039           
  Misses                                 ?     3619           
  Partials                               ?     1429           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mergify mergify bot added the merge-conflicts Merge conflicts detected. label Dec 8, 2025
@lrafeei lrafeei force-pushed the hybrid-agent-set-status branch from d6f4701 to bf60a3c Compare December 12, 2025 01:04
@mergify mergify bot removed the merge-conflicts Merge conflicts detected. label Dec 12, 2025
@lrafeei lrafeei force-pushed the hybrid-agent-set-status branch from bf60a3c to 2b2f909 Compare December 12, 2025 19:05
@lrafeei lrafeei marked this pull request as ready for review December 12, 2025 20:39
@lrafeei lrafeei requested a review from a team as a code owner December 12, 2025 20:39
@lrafeei lrafeei force-pushed the hybrid-agent-set-status branch from 1d76d52 to d967a27 Compare December 17, 2025 17:50
@mergify mergify bot added the merge-conflicts Merge conflicts detected. label Dec 17, 2025
@lrafeei lrafeei force-pushed the hybrid-agent-set-status branch from d967a27 to 44e9c3c Compare December 18, 2025 00:59
@mergify mergify bot removed the merge-conflicts Merge conflicts detected. label Dec 18, 2025
Copy link
Contributor

@hmstepanek hmstepanek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good-I had just a couple suggestions/questions.

return False

return getattr(self.nr_transaction, "priority", 1) > 0
# If priority is either not set at this point
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is perhaps a merge conflict cause this is the same logic as the previous code except if it's None we set it to 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized that this does something slightly different than that: the transaction.priority attribute is always going to exist, but it is initially set to None. This getattr function only returns 1 if it does not have the priority attribute at all.

So, when it is set to None and it tries to do a comparison, it fails.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooooh oops-you are right!

since this will be either invalid or unnecessary.
"""
if isinstance(status, Status):
if (self.status and self.status.status_code is StatusCode.OK) or status.is_unset:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it even possible for self.status to be None here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I couldn't think of a scenario where it would be, but I got a bit nervous about missing a use case.

if isinstance(status, Status):
if (self.status and self.status.status_code is StatusCode.OK) or status.is_unset:
return
if description is not None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this just a limitation of the Status type? Maybe add a comment here explaining this.

Copy link
Contributor Author

@lrafeei lrafeei Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The set_status function is a bit confusing initially; it can take in a Status (which has attributes StatusCode and an optional description) or a StatusCode. So, if just the StatusCode is passed in, we can pass in a description as well. If a Status type is passed in, it should already have the StatusCode and description in there, so passing in another description is redundant at best and conflicting at worse. So, the description being passed in this case is ignored.

attributes.update({"exception.escaped": escaped})
else:
self.nr_trace.notice_error(error_args, attributes=attributes)
attributes = {"exception.escaped": escaped}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this even possible that attributes is None? It would also enter this else clause if attributes was empty which seems unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For framework instrumentations, no. If custom instrumentation is used, it is possible not to have attributes defined when starting a span.


self.set_attributes(attributes)

notice_error(error_args, attributes=attributes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to map anything to expected or ignored params in notice error here?

Copy link
Contributor Author

@lrafeei lrafeei Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got the impression that these were slightly different interpretations. My understanding was that

  1. OpenTelemetry's expected flag was to denote whether record_exception() was called explicitly within a piece of code as opposed to being called within __end__()
  2. New Relic's expected flag was something explicitly passed in through a notice_error() call within a piece of code. If the expected flag is not set, it then goes to the application's configuration to see if the error class or error status code are already set in a user's ignore list(s).

Based on my understanding of this, I did not think we should be passing that in under the hood.

otel_span = trace.get_current_span()
otel_span.set_attribute("otel_span_attribute_FT", "OTel span attribute from FT")

@dt_enabled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on with these dt_enabled's?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had neglected to put them in alongside the validate_span_events validators and it just happened to not fail until now.

return _conditional_decorator


@pytest.mark.parametrize(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have a test that tests providing a description?

lrafeei and others added 2 commits December 19, 2025 15:58
Co-authored-by: Hannah Stepanek <hstepanek@newrelic.com>
@lrafeei lrafeei requested a review from hmstepanek December 20, 2025 01:39
@hmstepanek hmstepanek merged commit 2eebf4f into develop-hybrid-core-tracing Dec 22, 2025
6 checks passed
@hmstepanek hmstepanek deleted the hybrid-agent-set-status branch December 22, 2025 22:05
@mergify mergify bot removed the tests-failing Tests failing in CI. label Dec 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants