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

Add Flask Instrumentation fixes #601

Merged
merged 25 commits into from
May 5, 2020

Conversation

ocelotl
Copy link
Contributor

@ocelotl ocelotl commented Apr 20, 2020

Fixes #599

This is just a separate PR to keep the Flask changes from blocking the instrumentation enhancements.

@ocelotl ocelotl added the instrumentation Related to the instrumentation of third party libraries or frameworks label Apr 20, 2020
@ocelotl ocelotl requested a review from a team April 20, 2020 19:08
@ocelotl ocelotl self-assigned this Apr 20, 2020
@ocelotl ocelotl force-pushed the issue_599 branch 2 times, most recently from 7cc2f19 to d111d44 Compare April 23, 2020 21:35
@lzchen
Copy link
Contributor

lzchen commented Apr 27, 2020

Reopening up the discussion.
The changes here are good. It address @mauriciovasquezbernal comments on your previous PR. I'm still wondering if patching the class instead of the app itself is the way to go.

@mauriciovasquezbernal
Copy link
Member

I think it is actually not addressing my comments yet.
I have some concerns about they way instrument is implemented here and how it should be used #579 (comment).

I exposed an alternative to this here #579 (review).

@ocelotl
Copy link
Contributor Author

ocelotl commented Apr 28, 2020

I think it is actually not addressing my comments yet.
I have some concerns about they way instrument is implemented here and how it should be used #579 (comment).

I exposed an alternative to this here #579 (review).

Adding @mauriciovasquezbernal comments from past reviews:

Even if I don't completely agree with having an ABC and so on, I think the changes to BaseInstrumentor in the last iteration are good. Making it a singleton and allowing arbitrary arguments helps.

However I think the changes to the Flask are not that good, the proposed way for users to enable instrumentation is rather complicated. I still think we should have instrument and uninstrument methods that are simple to use (just a single call, few parameters and not return value) that are used by both, the automatic instrumentation command and the users. I'm aware that in the users case this function could not work in all the cases, for instance if you call it too late in the code after importing some modules, but I think that with correct documentation and warnings they would be very useful.

For the programmatic case, we could use a much simpler approach, just expose and let the user interact with InstrumentedFlask.

from opentelemetry.ext.flask import InstrumentedFlask as Flask
app = Flask(...) # app will be instrumented

or

from flask import Flask
from opentelemetry.ext.flask import InstrumentedFlask
app1 = Flask(...) # this won't be instrument
app2 = InstrumentedFlask(...) # this will be 

The instrument method should be used for automatic instrumentation and when the user want's to instrument everything in that framework, the later with some restrictions, like enforcing a proper order in the imports.

from opentelemetry.ext.flask import FlaskInstrumentor
FlaskInstrumentor().instrument()

from flask import Flask # needed to do after

app = Flask(...) # instrumented

The following case won't work, but we could print a warning to the user that the flask module is already imported and it might not work.

from flask import Flask
from opentelemetry.ext.flask import FlaskInstrumentor
FlaskInstrumentor().instrument()

app = Flask(...) # uninstrumented, reference to Flask was taken before instrumenting

@ocelotl ocelotl added the needs reviewers PRs with this label are ready for review and needs people to review to move forward. label Apr 29, 2020
Copy link
Member

@mauriciovasquezbernal mauriciovasquezbernal left a comment

Choose a reason for hiding this comment

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

Overall looks good to me.

I have some concerns about the conditionals in the (un)-instrument_app functions. I'll do a more detailed review starting next week.

@ocelotl
Copy link
Contributor Author

ocelotl commented Apr 30, 2020

Addressed all your comments, @mauriciovasquezbernal, please review again when you have a moment. @lzchen, these changes address your previous concern about doing instrumentation by replacing the Flask class, please take a look.

Thanks!

@lzchen
Copy link
Contributor

lzchen commented May 1, 2020

This looks good. I'm curious as to whether we can merge the two methods of auto-instrumentation and programmatic instrumentation but still have it patch an Flask app instance instead of the class.
Similar to what we are doing in SQLAlchemy.

@ocelotl
Copy link
Contributor Author

ocelotl commented May 1, 2020

This looks good. I'm curious as to whether we can merge the two methods of auto-instrumentation and programmatic instrumentation but still have it patch an Flask app instance instead of the class.
Similar to what we are doing in SQLAlchemy.

It is possible but we preferred not to do so. We prefer not to have a method whose actions are different depending on the optional attributes it gets, we rather use **kwargs in _instrument only to pass configuration attributes that will override the configuration options read from the Configuration object.

Copy link
Contributor

@lzchen lzchen left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@mauriciovasquezbernal mauriciovasquezbernal left a comment

Choose a reason for hiding this comment

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

I like the changes in FlaskInstrumentor.
I think the tests could be improved a bit, specially removing code duplication and simplifying the programmatic / automatic tests to avoid checking things that are already covered in other cases.

ext/opentelemetry-ext-flask/tests/test_programmatic.py Outdated Show resolved Hide resolved
docs/getting-started.rst Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_automatic.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/base_test.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_automatic.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_automatic.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_automatic.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_automatic.py Outdated Show resolved Hide resolved
ext/opentelemetry-ext-flask/tests/test_programmatic.py Outdated Show resolved Hide resolved
@mauriciovasquezbernal
Copy link
Member

btw, would you mind moving the entry point definitions to setup.cfg file to keep things uniform with other instrumentations?

@ocelotl
Copy link
Contributor Author

ocelotl commented May 5, 2020

All your comments have been addressed, @mauriciovasquezbernal, thanks for the review!

Copy link
Member

@mauriciovasquezbernal mauriciovasquezbernal left a comment

Choose a reason for hiding this comment

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

Some minor nits. LGTM now, thanks for handling the feedback.

super().tearDown()
with self.disable_logging():
FlaskInstrumentor().uninstrument_app(self.app)

Choose a reason for hiding this comment

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

Is it worth to check that calling (un)-instrument twice doesn't cause any issue?


trace.get_tracer_provider().add_span_processor(
SimpleExportSpanProcessor(ConsoleSpanExporter())
)


app = flask.Flask(__name__)

Choose a reason for hiding this comment

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

Not related to this PR, but is this example missing app.run(), how am I supposed to run it?

app.wsgi_app = app._original_wsgi_app

# FIXME add support for other Flask blueprints that are not None
app.before_request_funcs[None].remove(_before_request)
Copy link
Member

Choose a reason for hiding this comment

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

have you considered using the instrumented flag to turn off and on behavior, like the pymongo instrumentation?

Or you could remove by value by comparing the id of the function:

for k, v in before_request_funcs.items():
    if v is _before_request:
        del before_request_funcs[k]

Although the latter feels more error prone as you are relying on the data structure remaining the same across different versions of flask. The checking of the _is_instrumented value feels more robust here.

Copy link
Member

@toumorokoshi toumorokoshi left a comment

Choose a reason for hiding this comment

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

I think one small edge case around making sure uninstrument is robust, but all looks good otherwise!

Copy link
Member

@toumorokoshi toumorokoshi left a comment

Choose a reason for hiding this comment

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

The issue I raised currently won't affect anyone, since the instrumentation only instruments apps.

@toumorokoshi toumorokoshi merged commit c074853 into open-telemetry:master May 5, 2020
@ocelotl ocelotl deleted the issue_599 branch May 5, 2020 17:00
srikanthccv pushed a commit to srikanthccv/opentelemetry-python that referenced this pull request Nov 1, 2020
…y#601)

* chore(plugin-mongodb-core): add missing codecov script

* fix(mongodb-plugin): check currentSpan against undefined

* chore(scope-managers): return undefined if no scope is found (following open-telemetry#569)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
instrumentation Related to the instrumentation of third party libraries or frameworks needs reviewers PRs with this label are ready for review and needs people to review to move forward.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Move Flask instrumentation enhancements in a separate PR
4 participants