azpaddypy 0.1.8__py3-none-any.whl → 0.2.0__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 +89 -19
- {azpaddypy-0.1.8.dist-info → azpaddypy-0.2.0.dist-info}/METADATA +1 -1
- azpaddypy-0.2.0.dist-info/RECORD +9 -0
- azpaddypy-0.1.8.dist-info/RECORD +0 -9
- {azpaddypy-0.1.8.dist-info → azpaddypy-0.2.0.dist-info}/WHEEL +0 -0
- {azpaddypy-0.1.8.dist-info → azpaddypy-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {azpaddypy-0.1.8.dist-info → azpaddypy-0.2.0.dist-info}/top_level.txt +0 -0
azpaddypy/mgmt/logging.py
CHANGED
@@ -21,6 +21,33 @@ class AzureLogger:
|
|
21
21
|
using Azure Monitor OpenTelemetry integration with advanced tracing capabilities.
|
22
22
|
"""
|
23
23
|
|
24
|
+
_instances = {}
|
25
|
+
_tracer = None
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
def get_instance(
|
29
|
+
cls,
|
30
|
+
service_name: str,
|
31
|
+
service_version: str = "1.0.0",
|
32
|
+
connection_string: Optional[str] = None,
|
33
|
+
log_level: int = logging.INFO,
|
34
|
+
enable_console_logging: bool = True,
|
35
|
+
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
36
|
+
):
|
37
|
+
"""
|
38
|
+
Get or create a singleton AzureLogger instance for a given service_name.
|
39
|
+
"""
|
40
|
+
if service_name not in cls._instances:
|
41
|
+
cls._instances[service_name] = cls(
|
42
|
+
service_name=service_name,
|
43
|
+
service_version=service_version,
|
44
|
+
connection_string=connection_string,
|
45
|
+
log_level=log_level,
|
46
|
+
enable_console_logging=enable_console_logging,
|
47
|
+
custom_resource_attributes=custom_resource_attributes,
|
48
|
+
)
|
49
|
+
return cls._instances[service_name]
|
50
|
+
|
24
51
|
def __init__(
|
25
52
|
self,
|
26
53
|
service_name: str,
|
@@ -30,17 +57,26 @@ class AzureLogger:
|
|
30
57
|
enable_console_logging: bool = True,
|
31
58
|
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
32
59
|
):
|
33
|
-
|
34
|
-
|
60
|
+
# On first initialization, clean up all lingering loggers, tracers, and meters
|
61
|
+
if not AzureLogger._instances:
|
62
|
+
# Remove all handlers from all loggers except the one being initialized
|
63
|
+
for name, logger in logging.root.manager.loggerDict.items():
|
64
|
+
if isinstance(logger, logging.Logger) and name != service_name:
|
65
|
+
logger.handlers.clear()
|
66
|
+
# Reset OpenTelemetry tracer and meter providers
|
67
|
+
try:
|
68
|
+
from opentelemetry import trace, metrics
|
69
|
+
from opentelemetry.sdk.trace import TracerProvider
|
70
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
35
71
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
72
|
+
trace.set_tracer_provider(TracerProvider())
|
73
|
+
metrics.set_meter_provider(MeterProvider())
|
74
|
+
except Exception as e:
|
75
|
+
print(f"Warning: Failed to reset OpenTelemetry providers: {e}")
|
76
|
+
# Prevent re-initialization if already exists
|
77
|
+
if hasattr(self, "_initialized") and self._initialized:
|
78
|
+
return
|
79
|
+
self._initialized = True
|
44
80
|
self.service_name = service_name
|
45
81
|
self.service_version = service_version
|
46
82
|
self.connection_string = connection_string or os.getenv(
|
@@ -75,19 +111,19 @@ class AzureLogger:
|
|
75
111
|
"Warning: No Application Insights connection string found. Telemetry disabled."
|
76
112
|
)
|
77
113
|
|
78
|
-
# Set up logger without
|
114
|
+
# Set up logger without instrumentation
|
79
115
|
self.logger = logging.getLogger(service_name)
|
80
116
|
self.logger.setLevel(log_level)
|
81
117
|
|
82
|
-
#
|
83
|
-
self.logger.handlers
|
84
|
-
|
85
|
-
|
86
|
-
if enable_console_logging:
|
87
|
-
self._setup_console_handler()
|
118
|
+
# Only add handlers if none exist
|
119
|
+
if not self.logger.handlers:
|
120
|
+
if enable_console_logging:
|
121
|
+
self._setup_console_handler()
|
88
122
|
|
89
|
-
# Get tracer for manual span creation
|
90
|
-
|
123
|
+
# Get tracer for manual span creation (singleton per class)
|
124
|
+
if AzureLogger._tracer is None:
|
125
|
+
AzureLogger._tracer = trace.get_tracer(__name__)
|
126
|
+
self.tracer = AzureLogger._tracer
|
91
127
|
|
92
128
|
# Initialize correlation context
|
93
129
|
self._correlation_id = None
|
@@ -175,6 +211,10 @@ class AzureLogger:
|
|
175
211
|
|
176
212
|
return enhanced_extra
|
177
213
|
|
214
|
+
def exception(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
215
|
+
"""Log debug message with enhanced context"""
|
216
|
+
self.logger.exception(message, extra=self._enhance_extra(extra))
|
217
|
+
|
178
218
|
def debug(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
179
219
|
"""Log debug message with enhanced context"""
|
180
220
|
self.logger.debug(message, extra=self._enhance_extra(extra))
|
@@ -602,6 +642,36 @@ class AzureLogger:
|
|
602
642
|
except Exception as e:
|
603
643
|
self.warning(f"Failed to flush telemetry: {e}")
|
604
644
|
|
645
|
+
async def flush_async(self):
|
646
|
+
"""Asynchronously flush all pending telemetry data"""
|
647
|
+
if self._telemetry_enabled:
|
648
|
+
try:
|
649
|
+
from opentelemetry.sdk.trace import TracerProvider
|
650
|
+
|
651
|
+
tracer_provider = trace.get_tracer_provider()
|
652
|
+
if hasattr(tracer_provider, "force_flush"):
|
653
|
+
await asyncio.to_thread(
|
654
|
+
tracer_provider.force_flush, timeout_millis=5000
|
655
|
+
)
|
656
|
+
except Exception as e:
|
657
|
+
self.warning(f"Failed to async flush telemetry: {e}")
|
658
|
+
|
659
|
+
def add_handler(self, handler: logging.Handler):
|
660
|
+
"""Add a logging handler to the logger."""
|
661
|
+
self.logger.addHandler(handler)
|
662
|
+
|
663
|
+
def remove_handler(self, handler: logging.Handler):
|
664
|
+
"""Remove a logging handler from the logger."""
|
665
|
+
self.logger.removeHandler(handler)
|
666
|
+
|
667
|
+
def list_handlers(self) -> list:
|
668
|
+
"""List all handlers attached to the logger."""
|
669
|
+
return self.logger.handlers
|
670
|
+
|
671
|
+
def clear_handlers(self):
|
672
|
+
"""Remove all handlers from the logger."""
|
673
|
+
self.logger.handlers.clear()
|
674
|
+
|
605
675
|
|
606
676
|
# Factory functions for easy instantiation
|
607
677
|
def create_app_logger(
|
@@ -0,0 +1,9 @@
|
|
1
|
+
azpaddypy/mgmt/__init__.py,sha256=5-0eZuJMZlCONZNJ5hEvWXfvLIM36mg7FsEVs32bY_A,183
|
2
|
+
azpaddypy/mgmt/logging.py,sha256=UYlep7e3TddWo1EtJliGg45Zv-22iSbIYdC8Iz1STKU,28462
|
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.0.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
6
|
+
azpaddypy-0.2.0.dist-info/METADATA,sha256=EDK4QI8b__iy5AX6PmYxKsUmegQStO_y9WUzQiAZ5zw,304
|
7
|
+
azpaddypy-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
azpaddypy-0.2.0.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
9
|
+
azpaddypy-0.2.0.dist-info/RECORD,,
|
azpaddypy-0.1.8.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
azpaddypy/mgmt/__init__.py,sha256=5-0eZuJMZlCONZNJ5hEvWXfvLIM36mg7FsEVs32bY_A,183
|
2
|
-
azpaddypy/mgmt/logging.py,sha256=9u114Ji-cwBMUf8D02i_b_Ei2dZc3TaIUH4uJv_tmSc,25451
|
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.1.8.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
6
|
-
azpaddypy-0.1.8.dist-info/METADATA,sha256=vwBe_KHlAk23N630AgWpt3pM_4apYslPh9t4HrfMvTg,304
|
7
|
-
azpaddypy-0.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
azpaddypy-0.1.8.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
9
|
-
azpaddypy-0.1.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|