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

Falcon monkey patching fails with subclassed apps or wrong import order #683

Open
adriangb opened this issue Sep 16, 2021 · 3 comments
Open
Labels
bug Something isn't working help wanted Extra attention is needed instrumentation

Comments

@adriangb
Copy link
Contributor

This could be considered a bug, poorly documented behavior or just fragility of monkey patching.

import falcon

# in app.py or something
class MyApp(falcon.App):
    ...

# in main.py or something
import falcon
from falcon import App
from opentelemetry.instrumentation.falcon import FalconInstrumentor

from app import MyApp

FalconInstrumentor.instrument()

App()  # won't be instrumented
MyApp()  # won't be instrumented
falcon.App()  # will be instrumented

This can be fixed by instrumenting before from falcon import App and from app import MyApp:

import falcon

# in app.py or something
class MyApp(falcon.App):
    ...

# in main.py or something
import falcon
from opentelemetry.instrumentation.falcon import FalconInstrumentor
FalconInstrumentor.instrument()
from falcon import App

from app import MyApp

App()  # won't be instrumented
MyApp()  # won't be instrumented
falcon.App()  # will be instrumented

But:

  1. Linters won't be happy
  2. This is super ugly
  3. The only way to figure this out is to dig deep into the OpenTelemetry source code, understand where/how the monkey patching is happening and then apply the fix. It's not exactly documented.

I understand the desire to provide users with "auto-instrumentation" by means a single function call / even running opentelemetry-instrument on unmodified code. It's super cool! But it can't be the only way to do things. As demonstrated here there are a lot of rough edges to this.

It would be nice if the API was presented in a layered fashion:

  1. opentelemetry-instrument
  2. FalconInstrumentor.instrument()
  3. Falcon Middleware + WSGI middleware that just calls some public methods / uses a public context manager.
  4. Falcon Middleware + the public context manager

This way, users can just go with opentelemtry-instrument if that works for them. But if that doesn't work, they have the option to peel back the onion, read a bit deeper into the docs and understand how to add the middleware themselves and such. This also decreases the burden of functionality of auto-instrumentation: if in certain situations it is too hard / fragile / hacky to get something working via auto-instrumentation, but it is possible with a bit more work (e.g. a WSGI wrapper), this can be documented as "if you want XYZ advanced feature, you can instrument yourself and configure it following this example".

@adriangb adriangb added the bug Something isn't working label Sep 16, 2021
@owais
Copy link
Contributor

owais commented Sep 17, 2021

You've correctly discovered that instrumentation must be applied/activated before importing any the libraries that are to be instrumented. It may work for some apps even if it is applied post-import but by design it is supposed to be applied pre-import.

There are a few things being raised here.

  1. Document that instrumentation should be applied before imported the instrumented library.
  2. Make the Falcon middleware part of the public API so users can use that directly without the instrumentation ceremony.
  3. Perhaps add an instrument_app() method like Flask so that users can use the auto-inject mechanism on a single app/api instance.
app = MyFalconApp()
FalconInstrumentor.instrument_app(app)

My only concern is about 2. I think it can be useful to make the middleware available for direct use but using the middleware directly might not always result in the same telemetry data as generated by auto-instrumentation but I suppose if that is documented, it should be fine.

I don't see why we cannot do these but I'd suggest to open a different issue for each topic.

@ocelotl
Copy link
Contributor

ocelotl commented Sep 27, 2021

This problem is one of the reasons option 3 was used in the Flask instrumentation, I suggest we follow the same approach to fix this one.

@adriangb
Copy link
Contributor Author

Yep that does seem like a good first step at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed instrumentation
Projects
None yet
Development

No branches or pull requests

4 participants