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

Enforce one distro is installed #571

Conversation

NathanielRN
Copy link
Contributor

@NathanielRN NathanielRN commented Jul 9, 2021

Description

Small PR to enforce that only one distro be installed when trying to run auto instrumentation.

Additionally, checks that the Configurator that is loaded automatically is a derived class of BaseConfigurator. The idea is that Configurators should come from distros and every distro should provide one. (Even if they just subclass the opentelemetry-sdk package Configurator which does a pretty good configuration).

Follow up to: #551

Type of change

Please delete options that are not relevant.

  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Unfortunately I can't add unit tests because if you import functions from sitecustomize.py it will try to run the whole file and auto instrument which we can't do in a testing environment for now...

But I did confirm locally that an error is thrown only if multiple distros are installed:

$ OTEL_RESOURCE_ATTRIBUTES=service.name=my_auto_app \
OTEL_EXPORTER_OTLP_INSECURE=True \
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 \
LISTEN_ADDRESS=127.0.0.1:8080 \
opentelemetry-instrument python3 auto-instrumentation/flask/application.py

Multiple distros were found: (opentelemetry.distro,opentelemetry.distro_aws,opentelemetry.distro_test). Only one should be installed.
Failed to auto initialize opentelemetry
Traceback (most recent call last):
  File "/Users/enowell/git/opentelemetry-python-contrib/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py", line 132, in initialize
    distro = _load_distros()
  File "/Users/enowell/git/opentelemetry-python-contrib/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py", line 45, in _load_distros
    raise RuntimeError("Cannot Auto Instrument with multiple distros installed.")
RuntimeError: Cannot Auto Instrument with multiple distros installed.
 * Serving Flask app "create_flask_app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)

Does This PR Require a Core Repo Change?

  • No.

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 See comment about testing above.
  • Documentation has been updated

@NathanielRN NathanielRN requested a review from a team as a code owner July 9, 2021 00:32
@NathanielRN NathanielRN requested review from ocelotl and lzchen and removed request for a team July 9, 2021 00:32
@NathanielRN
Copy link
Contributor Author

@owais Here is a PR to enforce only 1 distro be installed on the system! Would appreciate your feedback 😄

@NathanielRN NathanielRN force-pushed the enforce-one-distro-and-configurator branch from 228061f to 6f057bd Compare July 9, 2021 00:45
@@ -96,7 +113,14 @@ def _load_configurators():
)
continue
try:
entry_point.load()().configure() # type: ignore
configurator: BaseConfigurator = entry_point.load()()
if not isinstance(configurator, BaseConfigurator):
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 want to enforce nominal typing at runtime here? I don't see this adding a ton of benefit but these things keep adding up to the "startup" cost of the SDK which can be critical in environments like AWS Lambda with really low resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we consider startup costs should we remove the type check for BaseDistro?

if not isinstance(distro, BaseDistro):
logger.debug(
"%s is not an OpenTelemetry Distro. Skipping",
entry_point.name,
)

I guess it has the benefit of checking a Distro and we know that Distro's have Configurators. I'll remove this but let me know if you think we should remove the BaseDistro check too.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure. What benefit do we get from this message? it's also logging on debug level but we are paying the cost of isinstance always. i personally feel we should remove this. This isn't something that is going to be very helpful to end users IMO. If anyone publishes a package with a distro entrypoint that doesn't satisfy the interface, an attribute/type error would probably be good enough I think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay I agree with you! I will remove it since I'm changing those lines anyways.

raise RuntimeError("Cannot Auto Instrument with multiple distros installed.")

return first_distro.load()()
except IndexError:
Copy link
Contributor

Choose a reason for hiding this comment

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

this would be StopIteration I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, thank you! I changed it and configured that's what we wanted in my tests 😄

opentelemetry-instrument python3 auto-instrumentation/flask/application.py
Initializing Auto Instrumentation without using a distro.
 * Serving Flask app "create_flask_app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)

@NathanielRN NathanielRN requested a review from owais July 9, 2021 21:02
@ocelotl
Copy link
Contributor

ocelotl commented Jul 9, 2021

Hm, not sure if this is the approach we previously discussed. I don't think we should enforce only one distro being installed, but we should have a default one and let the user select one with an environment variable.

@NathanielRN
Copy link
Contributor Author

@ocelotl I think that is Option 1 in issue #551. The votes were in favor of Option 2 when I brought it up again so I added an implementation of it in this PR. I think it's the right way to go, but maybe we can discuss it more in the issue?

@ocelotl
Copy link
Contributor

ocelotl commented Jul 9, 2021

@ocelotl I think that is Option 1 in issue #551. The votes were in favor of Option 2 when I brought it up again so I added an implementation of it in this PR. I think it's the right way to go, but maybe we can discuss it more in the issue?

Ah, yes. Sorry, I forgot to vote. Also, detecting the error when running opentelemetry-instrument is too late. The error should be raised when another additional distro is installed.

@NathanielRN
Copy link
Contributor Author

The error should be raised when another additional distro is installed.

Hm I'm not familiar with how to make packages exclusive from each other at install time... I don't know if you can do that at pip install time. Even if you can, there's always a possibility that a user just unzips the 2nd distro package's contents in the python3.*/ folder and I'm pretty sure you can't throw an error/detect it at that time 😕

@ocelotl
Copy link
Contributor

ocelotl commented Jul 9, 2021

Also, this approach is very inconvenient for someone who may want to switch between more than one distro repeatedly (for testing purposes, for example).

@srikanthccv
Copy link
Member

I have a dumb question, why do we limit to only one distro?

return first_distro.load()()
except StopIteration:
logger.warning(
"Initializing Auto Instrumentation without using a distro."
Copy link
Contributor

Choose a reason for hiding this comment

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

A description of the error would be good.

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 the following description:

logger.warning(
    "Failed to find even one installed distro. Initializing Auto Instrumentation without using a distro."
)

@lzchen
Copy link
Contributor

lzchen commented Jul 12, 2021

@NathanielRN
Is the PR description/title still up to date? I don't see the changes pertaining to Configurator

@NathanielRN
Copy link
Contributor Author

@lonewolf3739

I have a dumb question, why do we limit to only one distro?

It's not a dumb questions 😄 The goal is just to make it easier for the user, because if multiple distros are installed they probably will set conflicting values and produce confusing bugs.

i.e.

opentelemetry-distro-aws will set OTEL_PROPAGATORS=xray

opentelemetry-distro-microsoft will set OTEL_PROPAGATORS=azure

We mentioned this comment in #551 that this would be confusing.

But like @ocelotl said there are cases like testing multiple distros where this setup would be inconvenient. It probably warrants a SIG discussion at this point.

@NathanielRN
Copy link
Contributor Author

@lzchen

Is the PR description/title still up to date? I don't see the changes pertaining to Configurator

Enforcing 1 Configurator is already true as of right now:

if configured is not None:
logger.warning(
"Configuration of %s not loaded, %s already loaded",
entry_point.name,
configured,
)
continue

What I meant in this PR is that we enforce one Distro which means we enforce one Configurator. However I can see why that's confusing, I'll update the title.

@NathanielRN NathanielRN changed the title Enforce one distro and configurator Enforce one distro is installed Jul 12, 2021
@NathanielRN NathanielRN requested a review from lzchen July 12, 2021 19:50
@srikanthccv
Copy link
Member

because if multiple distros are installed they probably will set conflicting values and produce confusing bugs.

The way I imagined this is each distro would add to existing values or creates one if it doesn't exist, for example, the propagator is initially set to jaeger, and the vendor distro such as azure would update it to jaeger,azure. And when there are conflicting cases where there can be only one value then the latest update value is considered (following how we do it resource merge etc...).

@NathanielRN
Copy link
Contributor Author

We decided to go in a different direction for distro, follow the results here: open-telemetry/opentelemetry-python#2005

@NathanielRN NathanielRN deleted the enforce-one-distro-and-configurator branch August 12, 2021 16:21
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.

None yet

5 participants