2424from opencensus .ext .azure .common .protocol import (
2525 Data ,
2626 Envelope ,
27+ Event ,
2728 ExceptionData ,
2829 Message ,
2930)
3334
3435logger = logging .getLogger (__name__ )
3536
36- __all__ = ['AzureLogHandler' ]
37+ __all__ = ['AzureEventHandler' , ' AzureLogHandler' ]
3738
3839
3940class BaseLogHandler (logging .Handler ):
40- def __init__ (self ):
41+
42+ def __init__ (self , ** options ):
4143 super (BaseLogHandler , self ).__init__ ()
44+ self .options = Options (** options )
45+ utils .validate_instrumentation_key (self .options .instrumentation_key )
46+ if not 0 <= self .options .logging_sampling_rate <= 1 :
47+ raise ValueError ('Sampling must be in the range: [0,1]' )
48+ self .export_interval = self .options .export_interval
49+ self .max_batch_size = self .options .max_batch_size
50+ self .storage = LocalFileStorage (
51+ path = self .options .storage_path ,
52+ max_size = self .options .storage_max_size ,
53+ maintenance_period = self .options .storage_maintenance_period ,
54+ retention_period = self .options .storage_retention_period ,
55+ )
56+ self ._telemetry_processors = []
57+ self .addFilter (SamplingFilter (self .options .logging_sampling_rate ))
4258 self ._queue = Queue (capacity = 8192 ) # TODO: make this configurable
4359 self ._worker = Worker (self ._queue , self )
4460 self ._worker .start ()
4561
62+ def _export (self , batch , event = None ): # pragma: NO COVER
63+ try :
64+ if batch :
65+ envelopes = [self .log_record_to_envelope (x ) for x in batch ]
66+ envelopes = self .apply_telemetry_processors (envelopes )
67+ result = self ._transmit (envelopes )
68+ if result > 0 :
69+ self .storage .put (envelopes , result )
70+ if event :
71+ if isinstance (event , QueueExitEvent ):
72+ self ._transmit_from_storage () # send files before exit
73+ return
74+ if len (batch ) < self .options .max_batch_size :
75+ self ._transmit_from_storage ()
76+ finally :
77+ if event :
78+ event .set ()
79+
4680 def close (self ):
81+ self .storage .close ()
4782 self ._worker .stop ()
4883
4984 def createLock (self ):
@@ -52,14 +87,7 @@ def createLock(self):
5287 def emit (self , record ):
5388 self ._queue .put (record , block = False )
5489
55- def _export (self , batch , event = None ):
56- try :
57- return self .export (batch )
58- finally :
59- if event :
60- event .set ()
61-
62- def export (self , batch ):
90+ def log_record_to_envelope (self , record ):
6391 raise NotImplementedError # pragma: NO COVER
6492
6593 def flush (self , timeout = None ):
@@ -121,74 +149,18 @@ def filter(self, record):
121149
122150
123151class AzureLogHandler (TransportMixin , ProcessorMixin , BaseLogHandler ):
124- """Handler for logging to Microsoft Azure Monitor.
125-
126- :param options: Options for the log handler.
127- """
128-
129- def __init__ (self , ** options ):
130- self .options = Options (** options )
131- utils .validate_instrumentation_key (self .options .instrumentation_key )
132- if not 0 <= self .options .logging_sampling_rate <= 1 :
133- raise ValueError ('Sampling must be in the range: [0,1]' )
134- self .export_interval = self .options .export_interval
135- self .max_batch_size = self .options .max_batch_size
136- self .storage = LocalFileStorage (
137- path = self .options .storage_path ,
138- max_size = self .options .storage_max_size ,
139- maintenance_period = self .options .storage_maintenance_period ,
140- retention_period = self .options .storage_retention_period ,
141- )
142- self ._telemetry_processors = []
143- super (AzureLogHandler , self ).__init__ ()
144- self .addFilter (SamplingFilter (self .options .logging_sampling_rate ))
145-
146- def close (self ):
147- self .storage .close ()
148- super (AzureLogHandler , self ).close ()
149-
150- def _export (self , batch , event = None ): # pragma: NO COVER
151- try :
152- if batch :
153- envelopes = [self .log_record_to_envelope (x ) for x in batch ]
154- envelopes = self .apply_telemetry_processors (envelopes )
155- result = self ._transmit (envelopes )
156- if result > 0 :
157- self .storage .put (envelopes , result )
158- if event :
159- if isinstance (event , QueueExitEvent ):
160- self ._transmit_from_storage () # send files before exit
161- return
162- if len (batch ) < self .options .max_batch_size :
163- self ._transmit_from_storage ()
164- finally :
165- if event :
166- event .set ()
152+ """Handler for logging to Microsoft Azure Monitor."""
167153
168154 def log_record_to_envelope (self , record ):
169- envelope = Envelope (
170- iKey = self .options .instrumentation_key ,
171- tags = dict (utils .azure_monitor_context ),
172- time = utils .timestamp_to_iso_str (record .created ),
173- )
155+ envelope = create_envelope (self .options .instrumentation_key , record )
174156
175- envelope .tags ['ai.operation.id' ] = getattr (
176- record ,
177- 'traceId' ,
178- '00000000000000000000000000000000' ,
179- )
180- envelope .tags ['ai.operation.parentId' ] = '|{}.{}.' .format (
181- envelope .tags ['ai.operation.id' ],
182- getattr (record , 'spanId' , '0000000000000000' ),
183- )
184157 properties = {
185158 'process' : record .processName ,
186159 'module' : record .module ,
187160 'fileName' : record .pathname ,
188161 'lineNumber' : record .lineno ,
189162 'level' : record .levelname ,
190163 }
191-
192164 if (hasattr (record , 'custom_dimensions' ) and
193165 isinstance (record .custom_dimensions , dict )):
194166 properties .update (record .custom_dimensions )
@@ -230,3 +202,43 @@ def log_record_to_envelope(self, record):
230202 )
231203 envelope .data = Data (baseData = data , baseType = 'MessageData' )
232204 return envelope
205+
206+
207+ class AzureEventHandler (TransportMixin , ProcessorMixin , BaseLogHandler ):
208+ """Handler for sending custom events to Microsoft Azure Monitor."""
209+
210+ def log_record_to_envelope (self , record ):
211+ envelope = create_envelope (self .options .instrumentation_key , record )
212+
213+ properties = {}
214+ if (hasattr (record , 'custom_dimensions' ) and
215+ isinstance (record .custom_dimensions , dict )):
216+ properties .update (record .custom_dimensions )
217+
218+ envelope .name = 'Microsoft.ApplicationInsights.Event'
219+ data = Event (
220+ name = self .format (record ),
221+ properties = properties ,
222+ )
223+ envelope .data = Data (baseData = data , baseType = 'EventData' )
224+
225+ return envelope
226+
227+
228+ def create_envelope (instrumentation_key , record ):
229+ envelope = Envelope (
230+ iKey = instrumentation_key ,
231+ tags = dict (utils .azure_monitor_context ),
232+ time = utils .timestamp_to_iso_str (record .created ),
233+ )
234+ envelope .tags ['ai.operation.id' ] = getattr (
235+ record ,
236+ 'traceId' ,
237+ '00000000000000000000000000000000' ,
238+ )
239+ envelope .tags ['ai.operation.parentId' ] = '|{}.{}.' .format (
240+ envelope .tags ['ai.operation.id' ],
241+ getattr (record , 'spanId' , '0000000000000000' ),
242+ )
243+
244+ return envelope
0 commit comments