@@ -240,13 +240,15 @@ def response_hook(span: Span, status: str, response_headers: List):
240240"""
241241
242242import weakref
243+ from functools import partial
243244from logging import getLogger
244245from time import time_ns
245246from timeit import default_timer
246247from typing import Collection
247248
248249import flask
249250from packaging import version as package_version
251+ from wrapt import wrap_function_wrapper
250252
251253import opentelemetry .instrumentation .wsgi as otel_wsgi
252254from opentelemetry import context , trace
@@ -264,14 +266,19 @@ def response_hook(span: Span, status: str, response_headers: List):
264266from opentelemetry .instrumentation .propagators import (
265267 get_global_response_propagator ,
266268)
267- from opentelemetry .instrumentation .utils import _start_internal_or_server_span
269+ from opentelemetry .instrumentation .utils import (
270+ _start_internal_or_server_span ,
271+ unwrap ,
272+ )
268273from opentelemetry .metrics import get_meter
274+ from opentelemetry .semconv .attributes .error_attributes import ERROR_TYPE
269275from opentelemetry .semconv .attributes .http_attributes import HTTP_ROUTE
270276from opentelemetry .semconv .metrics import MetricInstruments
271277from opentelemetry .semconv .metrics .http_metrics import (
272278 HTTP_SERVER_REQUEST_DURATION ,
273279)
274280from opentelemetry .semconv .trace import SpanAttributes
281+ from opentelemetry .trace .status import StatusCode
275282from opentelemetry .util ._importlib_metadata import version
276283from opentelemetry .util .http import (
277284 get_excluded_urls ,
@@ -620,6 +627,26 @@ def __init__(self, *args, **kwargs):
620627 self .teardown_request (_teardown_request )
621628
622629
630+ def _cli_command_wrapper (wrapped , instance , args , kwargs , tracer ):
631+ span_name = "cli span name"
632+ span_attributes = {}
633+
634+ print ("AAAAAAAAAAA" , args , kwargs )
635+ print ("AAAAAAAAAAA" , wrapped , instance )
636+
637+ with tracer .start_as_current_span (
638+ name = span_name ,
639+ kind = trace .SpanKind .INTERNAL ,
640+ attributes = span_attributes ,
641+ ) as span :
642+ try :
643+ return wrapped (* args , ** kwargs )
644+ except Exception as exc :
645+ span .set_status (StatusCode .ERROR , str (exc ))
646+ span .set_attribute (ERROR_TYPE , exc .__class__ .__qualname__ )
647+ raise
648+
649+
623650class FlaskInstrumentor (BaseInstrumentor ):
624651 # pylint: disable=protected-access,attribute-defined-outside-init
625652 """An instrumentor for flask.Flask
@@ -662,9 +689,24 @@ def _instrument(self, **kwargs):
662689
663690 flask .Flask = _InstrumentedFlask
664691
692+ # TODO: this is duplicated from _InstrumentedFlask, hopefully will be resolved once moving out of subclassing
693+ tracer = trace .get_tracer (
694+ __name__ ,
695+ __version__ ,
696+ tracer_provider ,
697+ schema_url = _get_schema_url (sem_conv_opt_in_mode ),
698+ )
699+ wrap_function_wrapper (
700+ "flask.cli" ,
701+ "AppGroup.command" ,
702+ partial (_cli_command_wrapper , tracer = tracer ),
703+ )
704+
665705 def _uninstrument (self , ** kwargs ):
666706 flask .Flask = self ._original_flask
667707
708+ unwrap (flask .cli .AppGroup , "command" )
709+
668710 # pylint: disable=too-many-locals
669711 @staticmethod
670712 def instrument_app (
0 commit comments