@@ -80,9 +80,9 @@ def __init__(self, loop: BaseEventLoop, host: str, port: int,
80
80
self ._function_metadata_exception = None
81
81
82
82
# Used for checking if open telemetry is enabled
83
- self .is_opentelemetry_available = False
83
+ self .otel_libs_available = False
84
84
self .context_api = None
85
- self .TraceContextTextMapPropagator = None
85
+ self .trace_context_propagator = None
86
86
87
87
# We allow the customer to change synchronous thread pool max worker
88
88
# count by setting the PYTHON_THREADPOOL_THREAD_COUNT app setting.
@@ -268,16 +268,18 @@ async def _dispatch_grpc_request(self, request):
268
268
self ._grpc_resp_queue .put_nowait (resp )
269
269
270
270
def update_opentelemetry_status (self ):
271
- """Check for OpenTelemetry library availability and update the status attribute."""
271
+ """Check for OpenTelemetry library availability and
272
+ update the status attribute."""
272
273
try :
273
274
from opentelemetry import context as context_api
274
- from opentelemetry .trace .propagation .tracecontext import TraceContextTextMapPropagator
275
+ from opentelemetry .trace .propagation .tracecontext import (
276
+ TraceContextTextMapPropagator )
275
277
276
278
self .context_api = context_api
277
- self .TraceContextTextMapPropagator = TraceContextTextMapPropagator ()
278
- self .is_opentelemetry_available = True
279
+ self .trace_context_propagator = TraceContextTextMapPropagator ()
280
+ self .otel_libs_available = True
279
281
except ImportError :
280
- self .is_opentelemetry_available = False
282
+ self .otel_libs_available = False
281
283
282
284
async def _handle__worker_init_request (self , request ):
283
285
logger .info ('Received WorkerInitRequest, '
@@ -310,7 +312,10 @@ async def _handle__worker_init_request(self, request):
310
312
311
313
self .update_opentelemetry_status ()
312
314
313
- if self .is_opentelemetry_available :
315
+ if self .otel_libs_available :
316
+ # When this capability is enabled, logs are not piped back to the host from
317
+ # the worker. Logs will directly go to where the user has configured the
318
+ # logs to go. This is to ensure that the logs are not duplicated.
314
319
capabilities ["WorkerOpenTelemetryEnabled" ] = _TRUE
315
320
316
321
if DependencyManager .should_load_cx_dependencies ():
@@ -545,12 +550,6 @@ async def _handle__invocation_request(self, request):
545
550
546
551
fi_context = self ._get_context (invoc_request , fi .name , fi .directory )
547
552
548
- if self .is_opentelemetry_available :
549
- carrier = {TRACEPARENT : fi_context .trace_context .trace_parent ,
550
- TRACESTATE : fi_context .trace_context .trace_state }
551
- ctx = self .TraceContextTextMapPropagator .extract (carrier )
552
- self .context_api .attach (ctx )
553
-
554
553
# Use local thread storage to store the invocation ID
555
554
# for a customer's threads
556
555
fi_context .thread_local_storage .invocation_id = invocation_id
@@ -562,6 +561,9 @@ async def _handle__invocation_request(self, request):
562
561
args [name ] = bindings .Out ()
563
562
564
563
if fi .is_async :
564
+ if self .otel_libs_available :
565
+ self .configure_opentelemetry (fi_context , invocation_id )
566
+
565
567
call_result = await self ._run_async_func (
566
568
fi_context , fi .func , args
567
569
)
@@ -570,6 +572,7 @@ async def _handle__invocation_request(self, request):
570
572
self ._sync_call_tp ,
571
573
self ._run_sync_func ,
572
574
invocation_id , fi_context , fi .func , args )
575
+
573
576
if call_result is not None and not fi .has_return :
574
577
raise RuntimeError (f'function { fi .name !r} without a $return '
575
578
'binding returned a non-None value' )
@@ -666,6 +669,10 @@ async def _handle__function_environment_reload_request(self, request):
666
669
# reload_customer_libraries call clears the registry
667
670
bindings .load_binding_registry ()
668
671
672
+ capabilities = {}
673
+ if self .otel_libs_available :
674
+ capabilities ["WorkerOpenTelemetryEnabled" ] = _TRUE
675
+
669
676
if is_envvar_true (PYTHON_ENABLE_INIT_INDEXING ):
670
677
try :
671
678
self .load_function_metadata (
@@ -681,7 +688,7 @@ async def _handle__function_environment_reload_request(self, request):
681
688
func_env_reload_request .function_app_directory )
682
689
683
690
success_response = protos .FunctionEnvironmentReloadResponse (
684
- capabilities = {} ,
691
+ capabilities = capabilities ,
685
692
worker_metadata = self .get_worker_metadata (),
686
693
result = protos .StatusResult (
687
694
status = protos .StatusResult .Success ))
@@ -759,6 +766,14 @@ async def _handle__close_shared_memory_resources_request(self, request):
759
766
request_id = self .request_id ,
760
767
close_shared_memory_resources_response = response )
761
768
769
+ def configure_opentelemetry (self , invocation_context , invocation_id : str ):
770
+ logger .info ("Configuring opentelemetry for invocation id: %s" ,
771
+ invocation_id )
772
+ carrier = {TRACEPARENT : invocation_context .trace_context .trace_parent ,
773
+ TRACESTATE : invocation_context .trace_context .trace_state }
774
+ ctx = self .trace_context_propagator .extract (carrier )
775
+ self .context_api .attach (ctx )
776
+
762
777
@staticmethod
763
778
def _get_context (invoc_request : protos .InvocationRequest , name : str ,
764
779
directory : str ) -> bindings .Context :
@@ -846,6 +861,8 @@ def _run_sync_func(self, invocation_id, context, func, params):
846
861
# invocation_id from ThreadPoolExecutor's threads.
847
862
context .thread_local_storage .invocation_id = invocation_id
848
863
try :
864
+ if self .otel_libs_available :
865
+ self .configure_opentelemetry (context , invocation_id )
849
866
return ExtensionManager .get_sync_invocation_wrapper (context ,
850
867
func )(params )
851
868
finally :
0 commit comments