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

Fix HTTP instrumentation not being suppressed #1116

Merged

Conversation

carolabadeer
Copy link
Contributor

@carolabadeer carolabadeer commented Jun 2, 2022

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

This change aims to fix the issue outlined in #930 where urllib3 downstream spans are not being suppressed with a requests upstream, causing an extra span to be created.

The root cause of this bug lies in the create_key() method in opentelemetry context which adds a unique uuid to the end of each key created. Since a new _SUPPRESS_HTTP_INSTRUMENTATION key is being created in the instrumentation for each library, this results in a different key being created by each instrumentation instead of the creation of a single key that suppresses HTTP instrumentation so proceeding libraries know not to instrument further.

This fix involves creating the _SUPPRESS_HTTP_INSTRUMENTATION once in opentelemetry context to avoid the bug that causes a new suppress http instrumentation key to be created by each instrumentation. By having only 1 key that is accessible to all instrumentations, its true value can be passed on from one instrumentation to the next without being set to None every time the instrumentation of a new library begins. This does not conflict with the context spec since the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is meant to be shared, and creating a unique version of it in each library instrumentation is not the correct implementation of this concept.

Fixes #930

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Tox unit tests for each affected library

Does This PR Require a Core Repo Change?

  • Yes, please refer to PR # 2729 in the core repo

Checklist:

See contributing.md for styleguide, changelog guidelines, and more.

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Jun 2, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

@carolabadeer carolabadeer marked this pull request as ready for review June 7, 2022 23:38
@carolabadeer carolabadeer requested a review from a team June 7, 2022 23:38
Copy link
Contributor

@NathanielRN NathanielRN left a comment

Choose a reason for hiding this comment

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

🎉

@@ -188,6 +189,18 @@ def test_suppress_instrumentation(self):

self.assert_span(num_spans=0)

def test_suppress_http_instrumentation(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a test that tests the scenario of being instrumented with multiple http instrumentations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Testing a scenario with multiple http instrumentations would require testing across multiple packages at the same time (for example, requests and urllib3 to replicate the problem raised in issue #930) in the form of integration tests and not unit tests, which I think would be out of scope in this PR.

@@ -87,6 +87,7 @@ def response_hook(span, service_name, operation_name, result):
from wrapt import wrap_function_wrapper

from opentelemetry import context as context_api
from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs a FIXME to remind us to fix the importing of a private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added, thanks for the feedback!

@lzchen lzchen merged commit 6503cdf into open-telemetry:main Jun 20, 2022
sk- added a commit to sk-/opentelemetry-python-contrib that referenced this pull request Sep 10, 2022
This PR adds the target information for metrics reported by instrumentation/asgi.

Unfortunately, there's no ASGI standard to reliably get this information, and I was only able to get it for FastAPI.

I also tried to get the info with Sanic and Starlette (encode/starlette#685), but there's nothing in the scope allowing to recreate the route.

Besides the included unit tests, the logic was tested using the following app:

```python
import io
import fastapi

app = fastapi.FastAPI()

def dump_scope(scope):
    b = io.StringIO()
    print(scope, file=b)
    return b.getvalue()

@app.get("/test/{id}")
def test(id: str, req: fastapi.Request):
    print(req.scope)
    return {"target": _collect_target_attribute(req.scope), "scope": dump_scope(req.scope)}

sub_app = fastapi.FastAPI()

@sub_app.get("/test/{id}")
def sub_test(id: str, req: fastapi.Request):
    print(req.scope)
    return {"target": _collect_target_attribute(req.scope), "scope": dump_scope(req.scope)}

app.mount("/sub", sub_app)
```

Partially fixes open-telemetry#1116

Note to reviewers: I tried to touch as less as possible, so that we don;t require a refactor before this change. However, we could consider changing `collect_request_attributes` so that it returns both a trace attributes and a metrics attributes.
Wihout that change we cannot add the `HTTP_TARGET` attribute to the list of metric atttributes, because it will be present but with high cardinality.
sk- added a commit to sk-/opentelemetry-python-contrib that referenced this pull request Sep 10, 2022
This PR adds the target information for metrics reported by instrumentation/asgi.

Unfortunately, there's no ASGI standard to reliably get this information, and I was only able to get it for FastAPI.

I also tried to get the info with Sanic and Starlette (encode/starlette#685), but there's nothing in the scope allowing to recreate the route.

Besides the included unit tests, the logic was tested using the following app:

```python
import io
import fastapi

app = fastapi.FastAPI()

def dump_scope(scope):
    b = io.StringIO()
    print(scope, file=b)
    return b.getvalue()

@app.get("/test/{id}")
def test(id: str, req: fastapi.Request):
    print(req.scope)
    return {"target": _collect_target_attribute(req.scope), "scope": dump_scope(req.scope)}

sub_app = fastapi.FastAPI()

@sub_app.get("/test/{id}")
def sub_test(id: str, req: fastapi.Request):
    print(req.scope)
    return {"target": _collect_target_attribute(req.scope), "scope": dump_scope(req.scope)}

app.mount("/sub", sub_app)
```

Partially fixes open-telemetry#1116

Note to reviewers: I tried to touch as less as possible, so that we don;t require a refactor before this change. However, we could consider changing `collect_request_attributes` so that it returns both a trace attributes and a metrics attributes.
Wihout that change we cannot add the `HTTP_TARGET` attribute to the list of metric atttributes, because it will be present but with high cardinality.
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.

[Regression] urllib3 downstream instrumentation not getting suppressed (with requests, boto3 upstream)
5 participants