36
36
from elasticapm .conf import constants
37
37
from elasticapm .instrumentation .packages .base import AbstractInstrumentedModule
38
38
from elasticapm .traces import DroppedSpan , capture_span , execution_context
39
- from elasticapm .utils .disttracing import TraceParent
39
+ from elasticapm .utils .disttracing import TraceParent , TracingOptions
40
40
41
41
42
42
class KafkaInstrumentation (AbstractInstrumentedModule ):
@@ -48,6 +48,7 @@ class KafkaInstrumentation(AbstractInstrumentedModule):
48
48
]
49
49
provider_name = "kafka"
50
50
name = "kafka"
51
+ creates_transactions = True
51
52
52
53
def _trace_send (self , instance , wrapped , * args , destination_info = None , ** kwargs ):
53
54
topic = args [0 ] if args else kwargs ["topic" ]
@@ -68,7 +69,10 @@ def _trace_send(self, instance, wrapped, *args, destination_info=None, **kwargs)
68
69
) as span :
69
70
transaction = execution_context .get_transaction ()
70
71
if transaction :
71
- tp = transaction .trace_parent .copy_from (span_id = span .id )
72
+ tp = transaction .trace_parent .copy_from (
73
+ span_id = span .id if span else transaction .id ,
74
+ trace_options = None if span else TracingOptions (recorded = False ),
75
+ )
72
76
if headers :
73
77
headers .append ((constants .TRACEPARENT_BINARY_HEADER_NAME , tp .to_binary ()))
74
78
else :
@@ -79,22 +83,17 @@ def _trace_send(self, instance, wrapped, *args, destination_info=None, **kwargs)
79
83
else :
80
84
kwargs ["headers" ] = headers
81
85
result = wrapped (* args , ** kwargs )
82
- if instance and instance ._metadata .controller and not isinstance (span , DroppedSpan ):
86
+ if span and instance and instance ._metadata .controller and not isinstance (span , DroppedSpan ):
83
87
address = instance ._metadata .controller [1 ]
84
88
port = instance ._metadata .controller [2 ]
85
89
span .context ["destination" ]["address" ] = address
86
90
span .context ["destination" ]["port" ] = port
87
91
return result
88
92
89
- def call_if_sampling (self , module , method , wrapped , instance , args , kwargs ):
90
- # Contrasting to the superclass implementation, we *always* want to
91
- # return a proxied connection, even if there is no ongoing elasticapm
92
- # transaction yet. This ensures that we instrument the cursor once
93
- # the transaction started.
94
- return self .call (module , method , wrapped , instance , args , kwargs )
95
-
96
93
def call (self , module , method , wrapped , instance , args , kwargs ):
97
94
client = get_client ()
95
+ if client is None :
96
+ return wrapped (* args , ** kwargs )
98
97
destination_info = {
99
98
"service" : {"name" : "kafka" , "resource" : "kafka/" , "type" : "messaging" },
100
99
}
@@ -118,7 +117,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):
118
117
"destination" : destination_info ,
119
118
},
120
119
) as span :
121
- if not isinstance (span , DroppedSpan ) and instance ._subscription .subscription :
120
+ if span and not isinstance (span , DroppedSpan ) and instance ._subscription .subscription :
122
121
span .name += " from " + ", " .join (sorted (instance ._subscription .subscription ))
123
122
results = wrapped (* args , ** kwargs )
124
123
return results
@@ -146,7 +145,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):
146
145
except StopIteration :
147
146
span .cancel ()
148
147
raise
149
- if not isinstance (span , DroppedSpan ):
148
+ if span and not isinstance (span , DroppedSpan ):
150
149
topic = result [0 ]
151
150
if client .should_ignore_topic (topic ):
152
151
span .cancel ()
0 commit comments