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

Manual instrumentation falcon #1365

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7da21de
instrument class
TheAnshul756 Sep 30, 2022
d01e18e
add middleware
TheAnshul756 Sep 30, 2022
1f17708
remove middleware
TheAnshul756 Sep 30, 2022
d6ddd28
fix function name
TheAnshul756 Oct 1, 2022
4c8bf49
add test for manual instrumentation
TheAnshul756 Oct 1, 2022
7d69130
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 5, 2022
b6ed177
fix response middleware
TheAnshul756 Oct 6, 2022
18373fc
fix approach to add attributes
TheAnshul756 Oct 6, 2022
b8c6bfc
Merge branch 'manual-instrumentation-falcon' of https://github.com/Th…
TheAnshul756 Oct 6, 2022
9b4c622
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 6, 2022
a705af7
working manual instrumentation but with returning method
TheAnshul756 Oct 6, 2022
71f8ddb
Merge branch 'manual-instrumentation-falcon' of https://github.com/Th…
TheAnshul756 Oct 6, 2022
f924719
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Oct 7, 2022
e430d8e
fix lint
TheAnshul756 Oct 7, 2022
0597e22
Merge branch 'manual-instrumentation-falcon' of https://github.com/Th…
TheAnshul756 Oct 7, 2022
6fa5f27
add change log
TheAnshul756 Oct 7, 2022
2709724
fix lint
TheAnshul756 Oct 7, 2022
4891737
fix typo
TheAnshul756 Oct 7, 2022
d396e2a
add tests
TheAnshul756 Oct 7, 2022
9289fd2
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Oct 10, 2022
426eb85
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 10, 2022
6a43e7c
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Oct 13, 2022
4494be8
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Oct 17, 2022
3617c0b
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 21, 2022
313b082
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 23, 2022
99cbd28
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Oct 25, 2022
30158bc
Merge branch 'main' into manual-instrumentation-falcon
sanketmehta28 Oct 28, 2022
3671dbb
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Oct 29, 2022
0550d16
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Nov 2, 2022
eb96e2e
fix attriibute error
TheAnshul756 Nov 7, 2022
e455490
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Nov 7, 2022
fb32c33
Merge branch 'manual-instrumentation-falcon' of https://github.com/Th…
TheAnshul756 Nov 7, 2022
5a5b85c
add test for attribute validity
TheAnshul756 Nov 7, 2022
b27bd91
Merge branch 'main' into manual-instrumentation-falcon
sanketmehta28 Nov 18, 2022
76aeda6
Merge branch 'main' into manual-instrumentation-falcon
ocelotl Nov 21, 2022
7c6be9e
Merge branch 'main' into manual-instrumentation-falcon
ocelotl Nov 28, 2022
fb5e9e2
Merge branch 'main' into manual-instrumentation-falcon
TheAnshul756 Dec 6, 2022
2eff5f6
Merge branch 'main' into manual-instrumentation-falcon
srikanthccv Dec 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `opentelemetry-instrumentation-django` Fixed bug where auto-instrumentation fails when django is installed and settings are not configured.
([#1369](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1369))
- `opentelemetry-instrumentation-system-metrics` add supports to collect system thread count. ([#1339](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1339))
- Manual Instrumentation in Falcon
([#1365](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1365))
- `opentelemetry-exporter-richconsole` Fixing RichConsoleExpoter to allow multiple traces, fixing duplicate spans and include resources ([#1336](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1336))
- `opentelemetry-instrumentation-asgi` Add support for regular expression matching and sanitization of HTTP headers.
([#1333](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1333))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,72 @@ def process_response(
propagator = get_global_response_propagator()
if propagator:
propagator.inject(resp, setter=_response_propagation_setter)

if self._response_hook:
self._response_hook(span, req, resp)


def _prepare_middleware_tuple(
middleware_tuple, trace_middleware, independent_middleware
):
request_mw, resource_mw, response_mw = middleware_tuple

new_request_mw = []
new_response_mw = []
new_resource_mw = []

process_request = getattr(trace_middleware, "process_request")
setattr(process_request.__func__, "_is_otel_method", True)
process_resource = getattr(trace_middleware, "process_resource")
setattr(process_resource.__func__, "_is_otel_method", True)
process_response = getattr(trace_middleware, "process_response")
setattr(process_response.__func__, "_is_otel_method", True)

for each in response_mw:
new_response_mw.append(each)

if independent_middleware:
new_request_mw.insert(0, process_request)
new_response_mw.append(process_response)
else:
new_request_mw.insert(0, (process_request, process_response))
new_resource_mw.insert(0, process_resource)
for each in request_mw:
new_request_mw.append(each)
for each in resource_mw:
new_resource_mw.append(each)

return (
tuple(new_request_mw),
tuple(new_resource_mw),
tuple(new_response_mw),
)


def remove_trace_middleware(middleware_tuple):
request_mw, resource_mw, response_mw = middleware_tuple
new_request_mw = []
for each in request_mw:
if isinstance(each, tuple) and not hasattr(each[0], "_is_otel_method"):
new_request_mw.append(each)
elif not isinstance(each, tuple) and not hasattr(
each, "_is_otel_method"
):
new_request_mw.append(each)

new_response_mw = [
x for x in response_mw if not hasattr(x, "_is_otel_method")
]
new_resource_mw = [
x for x in resource_mw if not hasattr(x, "_is_otel_method")
]

return (
tuple(new_request_mw),
tuple(new_resource_mw),
tuple(new_response_mw),
)


class FalconInstrumentor(BaseInstrumentor):
# pylint: disable=protected-access,attribute-defined-outside-init
"""An instrumentor for falcon.API
Expand All @@ -502,8 +563,103 @@ class FalconInstrumentor(BaseInstrumentor):
def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

# pylint:disable=no-self-use
def _remove_instrumented_middleware(self, app):
@staticmethod
def instrument_app(
app,
request_hook=None,
response_hook=None,
tracer_provider=None,
meter_provider=None,
excluded_urls=None,
**opts,
):
if not hasattr(app, "_is_instrumented_by_opentelemetry"):

try:
app._otel_excluded_urls = (
excluded_urls
if excluded_urls is not None
else get_excluded_urls("FALCON")
)
app._otel_tracer = trace.get_tracer(
__name__, __version__, tracer_provider
)
app._otel_meter = get_meter(
__name__, __version__, meter_provider
)
app.duration_histogram = app._otel_meter.create_histogram(
name="http.server.duration",
unit="ms",
description="measures the duration of the inbound HTTP request",
)
app.active_requests_counter = app._otel_meter.create_up_down_counter(
name="http.server.active_requests",
unit="requests",
description="measures the number of concurrent HTTP requests that are currently in-flight",
)
app._is_instrumented_by_opentelemetry = False
except AttributeError:

class FalconAPI(_InstrumentedFalconAPI):
def __init__(self, *args, **kwargs):
for attribute in app.__slots__:
setattr(
self, attribute, getattr(app, attribute, None)
)
self._otel_excluded_urls = (
excluded_urls
if excluded_urls is not None
else get_excluded_urls("FALCON")
)
self._otel_tracer = trace.get_tracer(
__name__, __version__, tracer_provider
)
self._otel_meter = get_meter(
__name__, __version__, meter_provider
)
self.duration_histogram = self._otel_meter.create_histogram(
name="http.server.duration",
unit="ms",
description="measures the duration of the inbound HTTP request",
)
self.active_requests_counter = self._otel_meter.create_up_down_counter(
name="http.server.active_requests",
unit="requests",
description="measures the number of concurrent HTTP requests that are currently in-flight",
)
self._is_instrumented_by_opentelemetry = False

app = FalconAPI()

if not getattr(app, "_is_instrumented_by_opentelemetry", False):
trace_middleware = _TraceMiddleware(
app._otel_tracer,
opts.pop(
"traced_request_attributes",
get_traced_request_attrs("FALCON"),
),
request_hook,
response_hook,
)
if _falcon_version == 3:
app._unprepared_middleware.insert(0, trace_middleware)
app._middleware = app._prepare_middleware(
app._unprepared_middleware,
independent_middleware=app._independent_middleware,
)
else:
app._middleware = _prepare_middleware_tuple(
app._middleware,
trace_middleware,
app._independent_middleware,
)
if app not in _InstrumentedFalconAPI._instrumented_falcon_apps:
_InstrumentedFalconAPI._instrumented_falcon_apps.add(app)
app._is_instrumented_by_opentelemetry = True
return app

@staticmethod
def uninstrument_app(app):
if (
hasattr(app, "_is_instrumented_by_opentelemetry")
and app._is_instrumented_by_opentelemetry
Expand All @@ -518,7 +674,7 @@ def _remove_instrumented_middleware(self, app):
app._unprepared_middleware,
independent_middleware=app._independent_middleware,
)
else:
elif hasattr(app, "_middleware_list"):
app._middlewares_list = [
x
for x in app._middlewares_list
Expand All @@ -529,6 +685,8 @@ def _remove_instrumented_middleware(self, app):
app._middlewares_list,
independent_middleware=app._independent_middleware,
)
else:
app._middleware = remove_trace_middleware(app._middleware)
app._is_instrumented_by_opentelemetry = False

def _instrument(self, **opts):
Expand All @@ -543,6 +701,6 @@ def __init__(self, *args, **kwargs):

def _uninstrument(self, **kwargs):
for app in _InstrumentedFalconAPI._instrumented_falcon_apps:
self._remove_instrumented_middleware(app)
FalconInstrumentor.uninstrument_app(app)
_InstrumentedFalconAPI._instrumented_falcon_apps.clear()
setattr(falcon, _instrument_app, self._original_falcon_api)
Loading