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

Make open-telemetry a soft dependency [RHELDST-27627] #196

Merged
merged 2 commits into from
Nov 13, 2024

Conversation

amcmahon-rh
Copy link
Contributor

Several client tools (e.g. rhsm-tools) make use of various parts of pubtools for interaction with pulp. This has caused issues with rcm-dev, as we have specifically avoided making open-telemetry packages available for CLI clients.

This change introduces a new TracingWrapper class that acts as a pass through for when opentelemetry isn't installed.

if OPENTELEMETRY_AVAILABLE:
TRACE_WRAPPER = ServerTracingWrapper()
else:
log.warning(
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer not to WARN here, the problem is that we don't really have control over where get_trace_wrapper is called, and how many times.

This could easily result in several duplicate warnings produced every time certain tools are run, confusing the users. Note, if a tool fails for any reason, and it output some warnings prior to the failure, there's usually going to be some users who assume the warned-about problem caused the failure.

Can we perhaps do one of these?

  • make it DEBUG instead of WARN - that means it's still possible to tell whether this code path is taken by increasing the log level.
  • or keep it as WARN but only if OTEL_TRACING environment variable has been set to true (the same condition used to initialize _enabled_trace). Because this would indicate that someone is explicitly asking for OTEL tracing in an environment where it's not available.

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've reworked this change to just disable the tracing if OTEL isn't available, this is much more straight forward. I've changed the log to debug. I think it's important to have some logging here, as we're silencing an exception.

"Open-telemetry package is not available, falling "
"back to pass through tracer."
)
CLITracingWrapper()
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be assigned to TRACE_WRAPPER ?

src/pubtools/_impl/tracing.py Outdated Show resolved Hide resolved
def _instrument_func(func):
@functools.wraps(func)
def wrap(_):
pass
Copy link
Member

Choose a reason for hiding this comment

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

This seems to be broken in two ways:

  • func is never called, so this decorator replaces every decorated function with a replacement which does nothing.
  • wrap accepts only a single positional argument. This means @instrument_func will break any function with a signature other than "single positional argument". The general recipe for a generic decorator is to accept any number of positional and named arguments.

These are severe bugs to the point of not working at all, so if there aren't any tests which caught this, there should be some.

That being said, if you follow my suggestion in the other thread of not introducing a separate class for this, we'd be reusing the existing instrument_func implementation which is already tested.


def force_flush(self):
"""Flush trace data into OTEL collectors"""
log.warning(
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 this warrants a warning, I think it can just be understood that force_flush does nothing if the feature is disabled.

The nature of the function is already that it can potentially do nothing (as there is not necessarily any data in need of flushing).



def test_client_tracing_fallback(monkeypatch):
def mock_import(name, *args, **kwargs):
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 get how this test could work:

pubtools._impl.tracing has already been imported and OPENTELEMETRY_AVAILABLE initialized at line 7 of this file. This is long before test_client_tracing_fallback has been invoked, and before monkeypatch.setattr is called.

Have you confirmed that this code is actually reached?

@amcmahon-rh amcmahon-rh force-pushed the otel-soft-dep branch 2 times, most recently from 2c6a40a to 03287c5 Compare November 11, 2024 12:15
Copy link
Member

@rohanpm rohanpm left a comment

Choose a reason for hiding this comment

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

One more thing which might be missing from this:

requirements.txt still unconditionally depends on the otel libraries.

I know the ultimate goal is to fix problems with some RPMs, so one easy option is to just patch out those dependencies during RPM build, knowing that the source code is now able to cope with it.

However you might also consider grouping those as "extra" dependencies, which I believe would look like this:

diff --git a/requirements.txt b/requirements.txt
index a38c65c..c0ec2d3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,2 @@
 pluggy
 setuptools
-opentelemetry-api
-opentelemetry-sdk
diff --git a/setup.py b/setup.py
index 100b504..cfc26d3 100644
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,9 @@ setup(
         "Topic :: Software Development :: Libraries :: Python Modules",
     ],
     install_requires=get_requirements(),
+    extras_require={
+        "tracing": ["opentelemetry-api", "opentelemetry-sdk"],
+    },
     python_requires=">=3.6",
     project_urls={
         "Documentation": "https://release-engineering.github.io/pubtools/",

That would make the otel libraries not required by default,
while a service like Pub could declare a dependency on
pubtools[tracing] rather than just pubtools in order to pull them in.

if (
os.getenv("OTEL_TRACING", "").lower() == "true"
) and not OPENTELEMETRY_AVAILABLE:
log.debug(
Copy link
Member

Choose a reason for hiding this comment

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

Ideally there should be a test which reaches this line.

You could probably monkeypatch.setattr(tracing, "OPENTELEMETRY_AVAILABLE", False) from within a test to force it to behave as though otel libraries are not available even when they are.

except ImportError:
# Clients aren't expected to have open-telemetry. This flag will be used in
# TracingWrapper to provide pass through functions.
OPENTELEMETRY_AVAILABLE = False
Copy link
Member

Choose a reason for hiding this comment

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

This could have a pragma: no cover added to pass the coverage check, given that it's probably not worth maintaining two separate test environments with otel present vs missing.

@rohanpm
Copy link
Member

rohanpm commented Nov 12, 2024

Could you please rebase it? The dependency files were bumped since your last commit.

Several client tools (e.g. rhsm-tools) make use of various parts of
pubtools for interaction with pulp. This has caused issues with
rcm-dev, as we have specifically avoided making open-telemetry
packages available for CLI clients.

This change introduces a new TracingWrapper class that acts as a pass
through for when opentelemetry isn't installed.
@amcmahon-rh amcmahon-rh merged commit b66561b into release-engineering:main Nov 13, 2024
5 checks passed
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