1
1
import pika
2
2
from logging import getLogger
3
- from opentelemetry import trace
4
- from typing import Dict , Callable
5
- from typing import Collection , Any
3
+ from pika .channel import Channel
6
4
from pika .adapters import BaseConnection
5
+ from typing import Dict , Callable , Optional , Collection , Any
6
+ from opentelemetry import trace
7
7
from opentelemetry .propagate import inject
8
8
from opentelemetry .instrumentation .pika import utils
9
9
from opentelemetry .trace import Tracer , TracerProvider
10
+ from opentelemetry .instrumentation .pika import __version__
10
11
from opentelemetry .semconv .trace import MessagingOperationValues
11
12
from opentelemetry .instrumentation .pika .package import _instruments
12
13
from opentelemetry .instrumentation .instrumentor import BaseInstrumentor
15
16
_LOG = getLogger (__name__ )
16
17
CTX_KEY = "__otel_task_span"
17
18
19
+ FUNCTIONS_TO_UNINSTRUMENT = ["basic_publish" ]
18
20
19
- class PikaInstrumentation (BaseInstrumentor ):
21
+
22
+ class PikaInstrumentation (BaseInstrumentor ): # type: ignore
20
23
@staticmethod
21
24
def _instrument_consumers (
22
25
consumers_dict : Dict [str , Callable [..., Any ]], tracer : Tracer
23
26
) -> Any :
24
27
for key , callback in consumers_dict .items ():
25
28
26
29
def decorated_callback (
27
- channel : pika . channel . Channel ,
30
+ channel : Channel ,
28
31
method : pika .spec .Basic .Deliver ,
29
32
properties : pika .spec .BasicProperties ,
30
33
body : bytes ,
@@ -47,12 +50,16 @@ def decorated_callback(
47
50
consumers_dict [key ] = decorated_callback
48
51
49
52
@staticmethod
50
- def _instrument_publish (channel : Any , tracer : Tracer ) -> None :
51
- original_basic_publish = channel . basic_publish
53
+ def _instrument_basic_publish (channel : Channel , tracer : Tracer ) -> None :
54
+ original_function = getattr ( channel , " basic_publish" )
52
55
53
- def decorated_basic_publish (
54
- exchange , routing_key , body , properties = None , mandatory = False
55
- ):
56
+ def decorated_function (
57
+ exchange : str ,
58
+ routing_key : str ,
59
+ body : bytes ,
60
+ properties : pika .spec .BasicProperties = None ,
61
+ mandatory : bool = False ,
62
+ ) -> Any :
56
63
if not properties :
57
64
properties = pika .spec .BasicProperties ()
58
65
span = utils .get_span (
@@ -64,45 +71,69 @@ def decorated_basic_publish(
64
71
)
65
72
with trace .use_span (span , end_on_exit = True ):
66
73
inject (properties .headers )
67
- retval = original_basic_publish (
74
+ retval = original_function (
68
75
exchange , routing_key , body , properties , mandatory
69
76
)
70
77
return retval
71
78
72
- decorated_basic_publish .__setattr__ (
73
- "_original_function" , original_basic_publish
74
- )
75
- channel .basic_publish = decorated_basic_publish
79
+ decorated_function .__setattr__ ("_original_function" , original_function )
80
+ channel .__setattr__ ("basic_publish" , decorated_function )
81
+ channel .basic_publish = decorated_function
82
+
83
+ @staticmethod
84
+ def _instrument_channel_functions (
85
+ channel : Channel , tracer : Tracer
86
+ ) -> None :
87
+ if hasattr (channel , "basic_publish" ):
88
+ PikaInstrumentation ._instrument_basic_publish (channel , tracer )
89
+
90
+ @staticmethod
91
+ def _uninstrument_channel_functions (channel : Channel ) -> None :
92
+ for function_name in FUNCTIONS_TO_UNINSTRUMENT :
93
+ if not hasattr (channel , function_name ):
94
+ continue
95
+ function = getattr (channel , function_name )
96
+ if hasattr (function , "_original_function" ):
97
+ channel .__setattr__ (function_name , function ._original_function )
76
98
77
99
@staticmethod
78
100
def instrument_channel (
79
- channel : Any , tracer_provider : TracerProvider
101
+ channel : Channel ,
102
+ tracer_provider : Optional [TracerProvider ] = None ,
80
103
) -> None :
81
104
if not hasattr (channel , "_impl" ) or not isinstance (
82
- channel ._impl , pika . channel . Channel
105
+ channel ._impl , Channel
83
106
):
84
107
_LOG .error ("Could not find implementation for provided channel!" )
85
108
return
86
- tracer = trace .get_tracer (__name__ , pika .__version__ , tracer_provider )
109
+ tracer = trace .get_tracer (__name__ , __version__ , tracer_provider )
110
+ channel .__setattr__ ("__opentelemetry_tracer" , tracer )
87
111
if channel ._impl ._consumers :
88
112
PikaInstrumentation ._instrument_consumers (
89
113
channel ._impl ._consumers , tracer
90
114
)
91
- PikaInstrumentation ._instrument_publish (channel , tracer )
115
+ PikaInstrumentation ._instrument_channel_functions (channel , tracer )
116
+
117
+ def _instrument (self , ** kwargs : Dict [str , Any ]) -> None :
118
+ channel : Channel = kwargs .get ("channel" , None )
119
+ if not channel or not isinstance (channel , Channel ):
120
+ return
121
+ tracer_provider : TracerProvider = kwargs .get ("tracer_provider" , None )
122
+ PikaInstrumentation .instrument_channel (channel , tracer_provider = tracer_provider )
92
123
93
- def _uninstrument (self , connection : Any , ** kwargs : Dict [str , Any ]) -> None :
94
- if not hasattr (connection , "_impl" ) or not isinstance (
95
- connection ._impl , BaseConnection
124
+ def _uninstrument (self , ** kwargs : Dict [str , Any ]) -> None :
125
+ channel : Channel = kwargs .get ("channel" , None )
126
+ if not channel or not isinstance (channel , Channel ):
127
+ return
128
+ if not hasattr (channel , "_impl" ) or not isinstance (
129
+ channel ._impl , BaseConnection
96
130
):
97
131
_LOG .error ("Could not find implementation for provided channel!" )
98
132
return
99
- for key , callback in connection ._impl ._consumers :
133
+ for key , callback in channel ._impl ._consumers :
100
134
if hasattr (callback , "_original_callback" ):
101
- connection ._consumers [key ] = callback ._original_callback
102
- if hasattr (connection .basic_publish , "_original_function" ):
103
- connection .basic_publish = (
104
- connection .basic_publish ._original_function
105
- )
135
+ channel ._consumers [key ] = callback ._original_callback
136
+ PikaInstrumentation ._uninstrument_channel_functions (channel )
106
137
107
138
def instrumentation_dependencies (self ) -> Collection [str ]:
108
139
return _instruments
0 commit comments