Skip to content
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

otel instrumentation for outgoing calls using generated clientlibs #19

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

acer618
Copy link

@acer618 acer618 commented Nov 7, 2024

Proposed change to add otel instrumentation as discussed in # 3 Scope

Prior work done for static clientlibs: https://sourcegraph.yelpcorp.com/python-packages/yelp_openapi/-/blob/yelp_openapi/clientlib/otel_tween.py

Note:

  1. Did not end up creating a new repo: swagger_otel for this purpose. Wanted to re-use decorate_client.py plus zipkin will go away ideally in next 2-3 quarters and we can rename this repo to swagger_otel if necessary.

  2. I've added some comments in the PR where I need help/guidance.

request_options.setdefault('headers', {})

# what is the right way to get the Request object. can we use contruct_request
# https://github.com/Yelp/bravado/blob/master/bravado/client.py#L283C5-L283C22
Copy link
Author

Choose a reason for hiding this comment

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

What is the right way to get the Request object?

Copy link
Member

Choose a reason for hiding this comment

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

There's no guarantee we're in a pyramid request context when this is being called. We should not rely on it. You'd need whatever the otel equivalent of py_zipkin's Stack type, I suspect. If this was built internally--which I'm somewhat more inclined to--then we could maybe reuse distributed-context's mechanisms? Also, perhaps you're mixing up this library up with pyramid-zipkin, which would have access to the pyramid request context.

Copy link
Author

Choose a reason for hiding this comment

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

tl;dr
I've used contruct_request from bravado to get the Request object.

Yeah that makes sense this is instrumenting for a outgoing call (not an incoming call where pyramid.request.Request would be available).
For zipkin_decorator it was straightforward since we the zipkin context was used to just inject B3 headers in the outgoing call.
For otel, the context itself is available in the trace object and we can inject zipkin and otel headers. But the additional functionality being added here is the generation of a CLIENT span. For this purpose a bunch of fields are needed: url, path, etc and hence the need for a Request object. This wont be available in the otel/zipkin context.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see I misunderstood which request you meant. I think this should be fine, although I don't think any other bravado decorator has done anything like this before.

@acer618 acer618 changed the title WIP: otel instrumentation for outgoing calls using generated clientlibs otel instrumentation for outgoing calls using generated clientlibs Nov 15, 2024
@contextmanager
def handle_exception(
self,
) -> Any:
Copy link
Member

Choose a reason for hiding this comment

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

The correct return type here is Iterator[None]

Comment on lines +91 to +93
def __dir__(self) -> list[str]:
return dir(self.resource) # pragma: no cover

Copy link
Member

Choose a reason for hiding this comment

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

I don't think overriding __dir__ is desirable here, especially since we're not overriding __getattr__

Comment on lines +152 to +154

def __dir__(self) -> list[str]:
return dir(self._client) # pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

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

Also here.

Comment on lines +71 to +79
try:
operation(*args, **kwargs)
except HTTPError as e:
span.set_attribute("error.type", e.__class__.__name__)
span.set_status(trace.Status(trace.StatusCode.ERROR, e.message))
span.set_attribute("http.response.status_code", e.status_code)
raise e

return operation
Copy link
Member

Choose a reason for hiding this comment

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

This logic won't work as is. Calling an operation will never raise an HTTPError as you must call result or response on it. You'll need to create a wrapper future class in order to implement the logic you want.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry this is an issue

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for catching this! Will work on a fix.

Comment on lines +71 to +79
try:
operation(*args, **kwargs)
except HTTPError as e:
span.set_attribute("error.type", e.__class__.__name__)
span.set_status(trace.Status(trace.StatusCode.ERROR, e.message))
span.set_attribute("http.response.status_code", e.status_code)
raise e

return operation
Copy link
Member

Choose a reason for hiding this comment

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

Sorry this is an issue

Comment on lines 88 to 90
span = trace.get_current_span()
span.set_attribute("error.type", e.__class__.__name__)
span.set_attribute("http.response.status_code", "500")
Copy link
Member

Choose a reason for hiding this comment

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

Is this still correct? Do we even need this try/except anymore?

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.

2 participants