azpaddypy 0.2.2__py3-none-any.whl → 0.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- azpaddypy/mgmt/logging.py +234 -170
- azpaddypy-0.2.3.dist-info/METADATA +19 -0
- azpaddypy-0.2.3.dist-info/RECORD +9 -0
- azpaddypy-0.2.2.dist-info/METADATA +0 -10
- azpaddypy-0.2.2.dist-info/RECORD +0 -9
- {azpaddypy-0.2.2.dist-info → azpaddypy-0.2.3.dist-info}/WHEEL +0 -0
- {azpaddypy-0.2.2.dist-info → azpaddypy-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {azpaddypy-0.2.2.dist-info → azpaddypy-0.2.3.dist-info}/top_level.txt +0 -0
azpaddypy/mgmt/logging.py
CHANGED
@@ -4,29 +4,28 @@ import json
|
|
4
4
|
import functools
|
5
5
|
import time
|
6
6
|
import asyncio
|
7
|
-
from typing import Optional, Dict, Any, Union,
|
7
|
+
from typing import Optional, Dict, Any, Union, Callable
|
8
8
|
from datetime import datetime
|
9
9
|
from azure.monitor.opentelemetry import configure_azure_monitor
|
10
|
+
from opentelemetry.metrics import get_meter_provider
|
11
|
+
from opentelemetry.trace import get_tracer_provider
|
12
|
+
from opentelemetry._logs import get_logger_provider
|
10
13
|
from opentelemetry import trace
|
11
14
|
from opentelemetry.trace import Status, StatusCode, Span
|
12
|
-
from opentelemetry.sdk.trace import TracerProvider
|
13
|
-
from opentelemetry.sdk.resources import Resource
|
14
15
|
from opentelemetry import baggage
|
15
16
|
from opentelemetry.context import Context
|
16
17
|
|
17
18
|
|
18
19
|
class AzureLogger:
|
19
|
-
_instance = None
|
20
|
-
_initialized = False
|
21
|
-
"""
|
22
|
-
Comprehensive logging class for Azure Functions and Azure Web Apps
|
23
|
-
using Azure Monitor OpenTelemetry integration with advanced tracing capabilities.
|
24
20
|
"""
|
21
|
+
A comprehensive logging class for Azure applications.
|
22
|
+
|
23
|
+
This logger integrates with Azure Monitor OpenTelemetry for distributed
|
24
|
+
tracing and structured logging, providing advanced capabilities for
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return cls._instance
|
26
|
+
It supports correlation tracking, baggage propagation, and automated
|
27
|
+
tracing for functions and dependencies.
|
28
|
+
"""
|
30
29
|
|
31
30
|
def __init__(
|
32
31
|
self,
|
@@ -36,10 +35,8 @@ class AzureLogger:
|
|
36
35
|
log_level: int = logging.INFO,
|
37
36
|
enable_console_logging: bool = True,
|
38
37
|
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
38
|
+
clean_legacy_logging: bool = True,
|
39
39
|
):
|
40
|
-
if self.__class__._initialized:
|
41
|
-
return
|
42
|
-
self.__class__._initialized = True
|
43
40
|
"""
|
44
41
|
Initialize the Azure Logger with OpenTelemetry tracing
|
45
42
|
|
@@ -50,7 +47,20 @@ class AzureLogger:
|
|
50
47
|
log_level: Logging level (default: INFO)
|
51
48
|
enable_console_logging: Enable console output for local development
|
52
49
|
custom_resource_attributes: Additional resource attributes
|
50
|
+
clean_legacy_logging: A flag to clean up legacy logging providers.
|
53
51
|
"""
|
52
|
+
if clean_legacy_logging:
|
53
|
+
# cleaning stale loggers
|
54
|
+
logger_provider = get_logger_provider()
|
55
|
+
if logger_provider:
|
56
|
+
logger_provider.shutdown()
|
57
|
+
tracer_provider = get_tracer_provider()
|
58
|
+
if tracer_provider:
|
59
|
+
tracer_provider.shutdown()
|
60
|
+
meter_provider = get_meter_provider()
|
61
|
+
if meter_provider:
|
62
|
+
meter_provider.shutdown()
|
63
|
+
|
54
64
|
self.service_name = service_name
|
55
65
|
self.service_version = service_version
|
56
66
|
self.connection_string = connection_string or os.getenv(
|
@@ -107,7 +117,12 @@ class AzureLogger:
|
|
107
117
|
)
|
108
118
|
|
109
119
|
def _setup_console_handler(self):
|
110
|
-
"""
|
120
|
+
"""Sets up a console handler for logging to the standard output.
|
121
|
+
|
122
|
+
This is useful for local development and debugging purposes. The handler
|
123
|
+
is configured with a structured formatter to ensure log messages are
|
124
|
+
consistent and easy to read.
|
125
|
+
"""
|
111
126
|
console_handler = logging.StreamHandler()
|
112
127
|
formatter = logging.Formatter(
|
113
128
|
"%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(pathname)s:%(lineno)d"
|
@@ -116,11 +131,22 @@ class AzureLogger:
|
|
116
131
|
self.logger.addHandler(console_handler)
|
117
132
|
|
118
133
|
def set_correlation_id(self, correlation_id: str):
|
119
|
-
"""
|
134
|
+
"""Sets a correlation ID for tracking a request or transaction.
|
135
|
+
|
136
|
+
This ID is automatically included in all subsequent logs and traces,
|
137
|
+
allowing for easy filtering and correlation of telemetry data.
|
138
|
+
|
139
|
+
Args:
|
140
|
+
correlation_id: The unique identifier for the transaction.
|
141
|
+
"""
|
120
142
|
self._correlation_id = correlation_id
|
121
143
|
|
122
144
|
def get_correlation_id(self) -> Optional[str]:
|
123
|
-
"""
|
145
|
+
"""Retrieves the current correlation ID.
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
The current correlation ID if it has been set, otherwise None.
|
149
|
+
"""
|
124
150
|
return self._correlation_id
|
125
151
|
|
126
152
|
def set_baggage(self, key: str, value: str) -> Context:
|
@@ -138,27 +164,38 @@ class AzureLogger:
|
|
138
164
|
|
139
165
|
def get_baggage(self, key: str) -> Optional[str]:
|
140
166
|
"""
|
141
|
-
|
167
|
+
Retrieves a baggage item from the current OpenTelemetry context.
|
142
168
|
|
143
169
|
Args:
|
144
|
-
key:
|
170
|
+
key: The baggage key.
|
145
171
|
|
146
172
|
Returns:
|
147
|
-
|
173
|
+
The baggage value if it exists, otherwise None.
|
148
174
|
"""
|
149
175
|
return baggage.get_baggage(key)
|
150
176
|
|
151
177
|
def get_all_baggage(self) -> Dict[str, str]:
|
152
178
|
"""
|
153
|
-
|
179
|
+
Retrieves all baggage items from the current OpenTelemetry context.
|
154
180
|
|
155
181
|
Returns:
|
156
|
-
|
182
|
+
A dictionary containing all baggage items.
|
157
183
|
"""
|
158
184
|
return dict(baggage.get_all())
|
159
185
|
|
160
186
|
def _enhance_extra(self, extra: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
161
|
-
"""
|
187
|
+
"""
|
188
|
+
Enriches log records with contextual information.
|
189
|
+
|
190
|
+
This method adds service details, correlation IDs, trace context,
|
191
|
+
and baggage items to the log's `extra` dictionary.
|
192
|
+
|
193
|
+
Args:
|
194
|
+
extra: An optional dictionary of custom data to include.
|
195
|
+
|
196
|
+
Returns:
|
197
|
+
The enhanced dictionary with added contextual data.
|
198
|
+
"""
|
162
199
|
enhanced_extra = {
|
163
200
|
"service_name": self.service_name,
|
164
201
|
"service_version": self.service_version,
|
@@ -186,15 +223,15 @@ class AzureLogger:
|
|
186
223
|
return enhanced_extra
|
187
224
|
|
188
225
|
def debug(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
189
|
-
"""
|
226
|
+
"""Logs a debug message with enhanced context."""
|
190
227
|
self.logger.debug(message, extra=self._enhance_extra(extra))
|
191
228
|
|
192
229
|
def info(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
193
|
-
"""
|
230
|
+
"""Logs an info message with enhanced context."""
|
194
231
|
self.logger.info(message, extra=self._enhance_extra(extra))
|
195
232
|
|
196
233
|
def warning(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
197
|
-
"""
|
234
|
+
"""Logs a warning message with enhanced context."""
|
198
235
|
self.logger.warning(message, extra=self._enhance_extra(extra))
|
199
236
|
|
200
237
|
def error(
|
@@ -203,11 +240,11 @@ class AzureLogger:
|
|
203
240
|
extra: Optional[Dict[str, Any]] = None,
|
204
241
|
exc_info: bool = True,
|
205
242
|
):
|
206
|
-
"""
|
243
|
+
"""Logs an error message with enhanced context and exception info."""
|
207
244
|
self.logger.error(message, extra=self._enhance_extra(extra), exc_info=exc_info)
|
208
245
|
|
209
246
|
def critical(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
210
|
-
"""
|
247
|
+
"""Logs a critical message with enhanced context."""
|
211
248
|
self.logger.critical(message, extra=self._enhance_extra(extra))
|
212
249
|
|
213
250
|
def log_function_execution(
|
@@ -218,13 +255,16 @@ class AzureLogger:
|
|
218
255
|
extra: Optional[Dict[str, Any]] = None,
|
219
256
|
):
|
220
257
|
"""
|
221
|
-
|
258
|
+
Logs a custom event for a function's execution metrics.
|
259
|
+
|
260
|
+
This captures performance data such as duration and success status,
|
261
|
+
which can be queried in Azure Monitor.
|
222
262
|
|
223
263
|
Args:
|
224
|
-
function_name:
|
225
|
-
duration_ms:
|
226
|
-
success:
|
227
|
-
extra: Additional custom properties
|
264
|
+
function_name: The name of the executed function.
|
265
|
+
duration_ms: The execution duration in milliseconds.
|
266
|
+
success: A flag indicating whether the function executed successfully.
|
267
|
+
extra: Additional custom properties to include in the log.
|
228
268
|
"""
|
229
269
|
log_data = {
|
230
270
|
"function_name": function_name,
|
@@ -320,13 +360,105 @@ class AzureLogger:
|
|
320
360
|
|
321
361
|
return span
|
322
362
|
|
363
|
+
def _setup_span_for_function_trace(
|
364
|
+
self,
|
365
|
+
span: Span,
|
366
|
+
func: Callable,
|
367
|
+
is_async: bool,
|
368
|
+
log_args: bool,
|
369
|
+
args: tuple,
|
370
|
+
kwargs: dict,
|
371
|
+
):
|
372
|
+
"""Helper to set up span attributes for function tracing."""
|
373
|
+
span.set_attribute("function.name", func.__name__)
|
374
|
+
span.set_attribute("function.module", func.__module__)
|
375
|
+
span.set_attribute("service.name", self.service_name)
|
376
|
+
span.set_attribute("function.is_async", is_async)
|
377
|
+
|
378
|
+
if self._correlation_id:
|
379
|
+
span.set_attribute("correlation.id", self._correlation_id)
|
380
|
+
|
381
|
+
if log_args:
|
382
|
+
if args:
|
383
|
+
span.set_attribute("function.args_count", len(args))
|
384
|
+
if kwargs:
|
385
|
+
span.set_attribute("function.kwargs_count", len(kwargs))
|
386
|
+
|
387
|
+
def _handle_function_success(
|
388
|
+
self,
|
389
|
+
span: Span,
|
390
|
+
func: Callable,
|
391
|
+
duration_ms: float,
|
392
|
+
result: Any,
|
393
|
+
log_result: bool,
|
394
|
+
log_execution: bool,
|
395
|
+
is_async: bool,
|
396
|
+
args: tuple,
|
397
|
+
kwargs: dict,
|
398
|
+
):
|
399
|
+
"""Helper to handle successful function execution tracing."""
|
400
|
+
span.set_attribute("function.duration_ms", duration_ms)
|
401
|
+
span.set_attribute("function.success", True)
|
402
|
+
span.set_status(Status(StatusCode.OK))
|
403
|
+
|
404
|
+
if log_result and result is not None:
|
405
|
+
span.set_attribute("function.has_result", True)
|
406
|
+
span.set_attribute("function.result_type", type(result).__name__)
|
407
|
+
|
408
|
+
if log_execution:
|
409
|
+
self.log_function_execution(
|
410
|
+
func.__name__,
|
411
|
+
duration_ms,
|
412
|
+
True,
|
413
|
+
{
|
414
|
+
"args_count": len(args) if args else 0,
|
415
|
+
"kwargs_count": len(kwargs) if kwargs else 0,
|
416
|
+
"is_async": is_async,
|
417
|
+
},
|
418
|
+
)
|
419
|
+
|
420
|
+
log_prefix = "Async function" if is_async else "Function"
|
421
|
+
self.debug(f"{log_prefix} execution completed: {func.__name__}")
|
422
|
+
|
423
|
+
def _handle_function_exception(
|
424
|
+
self,
|
425
|
+
span: Span,
|
426
|
+
func: Callable,
|
427
|
+
duration_ms: float,
|
428
|
+
e: Exception,
|
429
|
+
log_execution: bool,
|
430
|
+
is_async: bool,
|
431
|
+
):
|
432
|
+
"""Helper to handle failed function execution tracing."""
|
433
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
434
|
+
span.record_exception(e)
|
435
|
+
span.set_attribute("function.duration_ms", duration_ms)
|
436
|
+
span.set_attribute("function.success", False)
|
437
|
+
span.set_attribute("error.type", type(e).__name__)
|
438
|
+
span.set_attribute("error.message", str(e))
|
439
|
+
|
440
|
+
if log_execution:
|
441
|
+
self.log_function_execution(
|
442
|
+
func.__name__,
|
443
|
+
duration_ms,
|
444
|
+
False,
|
445
|
+
{
|
446
|
+
"error_type": type(e).__name__,
|
447
|
+
"error_message": str(e),
|
448
|
+
"is_async": is_async,
|
449
|
+
},
|
450
|
+
)
|
451
|
+
|
452
|
+
log_prefix = "Async function" if is_async else "Function"
|
453
|
+
self.error(f"{log_prefix} execution failed: {func.__name__} - {str(e)}")
|
454
|
+
|
323
455
|
def trace_function(
|
324
456
|
self,
|
325
457
|
function_name: Optional[str] = None,
|
326
458
|
log_args: bool = False,
|
327
459
|
log_result: bool = False,
|
328
460
|
log_execution: bool = True,
|
329
|
-
):
|
461
|
+
) -> Callable:
|
330
462
|
"""
|
331
463
|
Decorator to automatically trace function execution with comprehensive logging.
|
332
464
|
Supports both synchronous and asynchronous functions.
|
@@ -342,166 +474,64 @@ class AzureLogger:
|
|
342
474
|
@functools.wraps(func)
|
343
475
|
async def async_wrapper(*args, **kwargs):
|
344
476
|
span_name = function_name or f"{func.__module__}.{func.__name__}"
|
345
|
-
|
346
477
|
with self.tracer.start_as_current_span(span_name) as span:
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
span.set_attribute("service.name", self.service_name)
|
351
|
-
span.set_attribute("function.is_async", True)
|
352
|
-
|
353
|
-
if self._correlation_id:
|
354
|
-
span.set_attribute("correlation.id", self._correlation_id)
|
355
|
-
|
356
|
-
if log_args and args:
|
357
|
-
span.set_attribute("function.args_count", len(args))
|
358
|
-
if log_args and kwargs:
|
359
|
-
span.set_attribute("function.kwargs_count", len(kwargs))
|
360
|
-
|
478
|
+
self._setup_span_for_function_trace(
|
479
|
+
span, func, True, log_args, args, kwargs
|
480
|
+
)
|
361
481
|
start_time = time.time()
|
362
|
-
|
363
482
|
try:
|
364
483
|
self.debug(
|
365
484
|
f"Starting async function execution: {func.__name__}"
|
366
485
|
)
|
367
|
-
|
368
486
|
result = await func(*args, **kwargs)
|
369
487
|
duration_ms = (time.time() - start_time) * 1000
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
)
|
381
|
-
|
382
|
-
if log_execution:
|
383
|
-
self.log_function_execution(
|
384
|
-
func.__name__,
|
385
|
-
duration_ms,
|
386
|
-
True,
|
387
|
-
{
|
388
|
-
"args_count": len(args) if args else 0,
|
389
|
-
"kwargs_count": len(kwargs) if kwargs else 0,
|
390
|
-
"is_async": True,
|
391
|
-
},
|
392
|
-
)
|
393
|
-
|
394
|
-
self.debug(
|
395
|
-
f"Async function execution completed: {func.__name__}"
|
488
|
+
self._handle_function_success(
|
489
|
+
span,
|
490
|
+
func,
|
491
|
+
duration_ms,
|
492
|
+
result,
|
493
|
+
log_result,
|
494
|
+
log_execution,
|
495
|
+
True,
|
496
|
+
args,
|
497
|
+
kwargs,
|
396
498
|
)
|
397
499
|
return result
|
398
|
-
|
399
500
|
except Exception as e:
|
400
501
|
duration_ms = (time.time() - start_time) * 1000
|
401
|
-
|
402
|
-
|
403
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
404
|
-
span.record_exception(e)
|
405
|
-
span.set_attribute("function.duration_ms", duration_ms)
|
406
|
-
span.set_attribute("function.success", False)
|
407
|
-
span.set_attribute("error.type", type(e).__name__)
|
408
|
-
span.set_attribute("error.message", str(e))
|
409
|
-
|
410
|
-
if log_execution:
|
411
|
-
self.log_function_execution(
|
412
|
-
func.__name__,
|
413
|
-
duration_ms,
|
414
|
-
False,
|
415
|
-
{
|
416
|
-
"error_type": type(e).__name__,
|
417
|
-
"error_message": str(e),
|
418
|
-
"is_async": True,
|
419
|
-
},
|
420
|
-
)
|
421
|
-
|
422
|
-
self.error(
|
423
|
-
f"Async function execution failed: {func.__name__} - {str(e)}"
|
502
|
+
self._handle_function_exception(
|
503
|
+
span, func, duration_ms, e, log_execution, True
|
424
504
|
)
|
425
505
|
raise
|
426
506
|
|
427
507
|
@functools.wraps(func)
|
428
508
|
def sync_wrapper(*args, **kwargs):
|
429
509
|
span_name = function_name or f"{func.__module__}.{func.__name__}"
|
430
|
-
|
431
510
|
with self.tracer.start_as_current_span(span_name) as span:
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
span.set_attribute("service.name", self.service_name)
|
436
|
-
span.set_attribute("function.is_async", False)
|
437
|
-
|
438
|
-
if self._correlation_id:
|
439
|
-
span.set_attribute("correlation.id", self._correlation_id)
|
440
|
-
|
441
|
-
if log_args and args:
|
442
|
-
span.set_attribute("function.args_count", len(args))
|
443
|
-
if log_args and kwargs:
|
444
|
-
span.set_attribute("function.kwargs_count", len(kwargs))
|
445
|
-
|
511
|
+
self._setup_span_for_function_trace(
|
512
|
+
span, func, False, log_args, args, kwargs
|
513
|
+
)
|
446
514
|
start_time = time.time()
|
447
|
-
|
448
515
|
try:
|
449
516
|
self.debug(f"Starting function execution: {func.__name__}")
|
450
|
-
|
451
517
|
result = func(*args, **kwargs)
|
452
518
|
duration_ms = (time.time() - start_time) * 1000
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
if log_execution:
|
466
|
-
self.log_function_execution(
|
467
|
-
func.__name__,
|
468
|
-
duration_ms,
|
469
|
-
True,
|
470
|
-
{
|
471
|
-
"args_count": len(args) if args else 0,
|
472
|
-
"kwargs_count": len(kwargs) if kwargs else 0,
|
473
|
-
"is_async": False,
|
474
|
-
},
|
475
|
-
)
|
476
|
-
|
477
|
-
self.debug(f"Function execution completed: {func.__name__}")
|
519
|
+
self._handle_function_success(
|
520
|
+
span,
|
521
|
+
func,
|
522
|
+
duration_ms,
|
523
|
+
result,
|
524
|
+
log_result,
|
525
|
+
log_execution,
|
526
|
+
False,
|
527
|
+
args,
|
528
|
+
kwargs,
|
529
|
+
)
|
478
530
|
return result
|
479
|
-
|
480
531
|
except Exception as e:
|
481
532
|
duration_ms = (time.time() - start_time) * 1000
|
482
|
-
|
483
|
-
|
484
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
485
|
-
span.record_exception(e)
|
486
|
-
span.set_attribute("function.duration_ms", duration_ms)
|
487
|
-
span.set_attribute("function.success", False)
|
488
|
-
span.set_attribute("error.type", type(e).__name__)
|
489
|
-
span.set_attribute("error.message", str(e))
|
490
|
-
|
491
|
-
if log_execution:
|
492
|
-
self.log_function_execution(
|
493
|
-
func.__name__,
|
494
|
-
duration_ms,
|
495
|
-
False,
|
496
|
-
{
|
497
|
-
"error_type": type(e).__name__,
|
498
|
-
"error_message": str(e),
|
499
|
-
"is_async": False,
|
500
|
-
},
|
501
|
-
)
|
502
|
-
|
503
|
-
self.error(
|
504
|
-
f"Function execution failed: {func.__name__} - {str(e)}"
|
533
|
+
self._handle_function_exception(
|
534
|
+
span, func, duration_ms, e, log_execution, False
|
505
535
|
)
|
506
536
|
raise
|
507
537
|
|
@@ -614,6 +644,9 @@ class AzureLogger:
|
|
614
644
|
|
615
645
|
|
616
646
|
# Factory functions for easy instantiation
|
647
|
+
_loggers: Dict[Any, "AzureLogger"] = {}
|
648
|
+
|
649
|
+
|
617
650
|
def create_app_logger(
|
618
651
|
service_name: str,
|
619
652
|
service_version: str = "1.0.0",
|
@@ -621,9 +654,11 @@ def create_app_logger(
|
|
621
654
|
log_level: int = logging.INFO,
|
622
655
|
enable_console_logging: bool = True,
|
623
656
|
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
657
|
+
clean_legacy_logging: bool = True,
|
624
658
|
) -> AzureLogger:
|
625
659
|
"""
|
626
|
-
Factory function to create an AzureLogger instance
|
660
|
+
Factory function to create an AzureLogger instance. If a logger with the
|
661
|
+
same configuration has already been created, it will be returned.
|
627
662
|
|
628
663
|
Args:
|
629
664
|
service_name: Name of your service/application
|
@@ -632,18 +667,45 @@ def create_app_logger(
|
|
632
667
|
log_level: Logging level
|
633
668
|
enable_console_logging: Enable console output
|
634
669
|
custom_resource_attributes: Additional resource attributes
|
670
|
+
clean_legacy_logging: Whether to clean up legacy logging providers.
|
635
671
|
|
636
672
|
Returns:
|
637
673
|
Configured AzureLogger instance
|
638
674
|
"""
|
639
|
-
|
675
|
+
resolved_connection_string = connection_string or os.getenv(
|
676
|
+
"APPLICATIONINSIGHTS_CONNECTION_STRING"
|
677
|
+
)
|
678
|
+
|
679
|
+
attr_items = (
|
680
|
+
tuple(sorted(custom_resource_attributes.items()))
|
681
|
+
if custom_resource_attributes
|
682
|
+
else None
|
683
|
+
)
|
684
|
+
|
685
|
+
params_key = (
|
686
|
+
service_name,
|
687
|
+
service_version,
|
688
|
+
resolved_connection_string,
|
689
|
+
log_level,
|
690
|
+
enable_console_logging,
|
691
|
+
attr_items,
|
692
|
+
clean_legacy_logging,
|
693
|
+
)
|
694
|
+
|
695
|
+
if params_key in _loggers:
|
696
|
+
return _loggers[params_key]
|
697
|
+
|
698
|
+
logger = AzureLogger(
|
640
699
|
service_name=service_name,
|
641
700
|
service_version=service_version,
|
642
701
|
connection_string=connection_string,
|
643
702
|
log_level=log_level,
|
644
703
|
enable_console_logging=enable_console_logging,
|
645
704
|
custom_resource_attributes=custom_resource_attributes,
|
705
|
+
clean_legacy_logging=clean_legacy_logging,
|
646
706
|
)
|
707
|
+
_loggers[params_key] = logger
|
708
|
+
return logger
|
647
709
|
|
648
710
|
|
649
711
|
def create_function_logger(
|
@@ -651,6 +713,7 @@ def create_function_logger(
|
|
651
713
|
function_name: str,
|
652
714
|
service_version: str = "1.0.0",
|
653
715
|
connection_string: Optional[str] = None,
|
716
|
+
clean_legacy_logging: bool = True,
|
654
717
|
) -> AzureLogger:
|
655
718
|
"""
|
656
719
|
Factory function specifically for Azure Functions
|
@@ -675,4 +738,5 @@ def create_function_logger(
|
|
675
738
|
service_version=service_version,
|
676
739
|
connection_string=connection_string,
|
677
740
|
custom_resource_attributes=custom_attributes,
|
741
|
+
clean_legacy_logging=clean_legacy_logging,
|
678
742
|
)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: azpaddypy
|
3
|
+
Version: 0.2.3
|
4
|
+
Summary: Comprehensive Python logger for Azure, integrating OpenTelemetry for advanced, structured, and distributed tracing.
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
7
|
+
Classifier: Operating System :: OS Independent
|
8
|
+
Requires-Python: >=3.11
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
License-File: LICENSE
|
11
|
+
Requires-Dist: azure-monitor-opentelemetry==1.6.10
|
12
|
+
Provides-Extra: dev
|
13
|
+
Requires-Dist: trio>=0.22.2; extra == "dev"
|
14
|
+
Requires-Dist: azure-functions>=1.17.0; extra == "dev"
|
15
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
16
|
+
Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
|
17
|
+
Requires-Dist: anyio>=3.7.1; extra == "dev"
|
18
|
+
Requires-Dist: pip; extra == "dev"
|
19
|
+
Dynamic: license-file
|
@@ -0,0 +1,9 @@
|
|
1
|
+
azpaddypy/mgmt/__init__.py,sha256=5-0eZuJMZlCONZNJ5hEvWXfvLIM36mg7FsEVs32bY_A,183
|
2
|
+
azpaddypy/mgmt/logging.py,sha256=LI7pvMuiUbT-RoW5wImyWxZTzexxvA6IDSD4RVyxCkg,26918
|
3
|
+
azpaddypy/test_function/__init__.py,sha256=0NjUl36wvUWV79GpRwBFkgkBaC6uDZsTdaSVOIHMFEU,3481
|
4
|
+
azpaddypy/test_function/function_app.py,sha256=6nX54-iq0L1l_hZpD6E744-j79oLxdaldFyWDCpwH7c,3867
|
5
|
+
azpaddypy-0.2.3.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
6
|
+
azpaddypy-0.2.3.dist-info/METADATA,sha256=vEWDGAtY5Cxvz3qLRA9fJEeUjFObLaElceLsZGsyDi0,799
|
7
|
+
azpaddypy-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
azpaddypy-0.2.3.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
9
|
+
azpaddypy-0.2.3.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: azpaddypy
|
3
|
-
Version: 0.2.2
|
4
|
-
Summary: Add your description here
|
5
|
-
Classifier: Operating System :: OS Independent
|
6
|
-
Requires-Python: >=3.11
|
7
|
-
Description-Content-Type: text/markdown
|
8
|
-
License-File: LICENSE
|
9
|
-
Requires-Dist: azure-monitor-opentelemetry==1.6.10
|
10
|
-
Dynamic: license-file
|
azpaddypy-0.2.2.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
azpaddypy/mgmt/__init__.py,sha256=5-0eZuJMZlCONZNJ5hEvWXfvLIM36mg7FsEVs32bY_A,183
|
2
|
-
azpaddypy/mgmt/logging.py,sha256=A-56GNbSWAFnKNPcoa-NfTINbBWvJf-p4ZGxUz7M4uQ,25777
|
3
|
-
azpaddypy/test_function/__init__.py,sha256=0NjUl36wvUWV79GpRwBFkgkBaC6uDZsTdaSVOIHMFEU,3481
|
4
|
-
azpaddypy/test_function/function_app.py,sha256=6nX54-iq0L1l_hZpD6E744-j79oLxdaldFyWDCpwH7c,3867
|
5
|
-
azpaddypy-0.2.2.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
6
|
-
azpaddypy-0.2.2.dist-info/METADATA,sha256=AM8Zw5IFOQVOQcd5zB2J473u1jSy9oDqOtoLpU-mhjc,304
|
7
|
-
azpaddypy-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
azpaddypy-0.2.2.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
9
|
-
azpaddypy-0.2.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|