azpaddypy 0.1.9__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 +86 -20
- {azpaddypy-0.1.9.dist-info → azpaddypy-0.2.0.dist-info}/METADATA +1 -1
- azpaddypy-0.2.0.dist-info/RECORD +9 -0
- azpaddypy-0.1.9.dist-info/RECORD +0 -9
- {azpaddypy-0.1.9.dist-info → azpaddypy-0.2.0.dist-info}/WHEEL +0 -0
- {azpaddypy-0.1.9.dist-info → azpaddypy-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {azpaddypy-0.1.9.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
|
@@ -174,7 +210,7 @@ class AzureLogger:
|
|
174
210
|
enhanced_extra.update(extra)
|
175
211
|
|
176
212
|
return enhanced_extra
|
177
|
-
|
213
|
+
|
178
214
|
def exception(self, message: str, extra: Optional[Dict[str, Any]] = None):
|
179
215
|
"""Log debug message with enhanced context"""
|
180
216
|
self.logger.exception(message, extra=self._enhance_extra(extra))
|
@@ -606,6 +642,36 @@ class AzureLogger:
|
|
606
642
|
except Exception as e:
|
607
643
|
self.warning(f"Failed to flush telemetry: {e}")
|
608
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
|
+
|
609
675
|
|
610
676
|
# Factory functions for easy instantiation
|
611
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.9.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
azpaddypy/mgmt/__init__.py,sha256=5-0eZuJMZlCONZNJ5hEvWXfvLIM36mg7FsEVs32bY_A,183
|
2
|
-
azpaddypy/mgmt/logging.py,sha256=TCOjec_DSvN4wqqzGihn24XXjUZ2NpFm2cG3UxYUWSA,25666
|
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.9.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
6
|
-
azpaddypy-0.1.9.dist-info/METADATA,sha256=srjAa16qE_vCvXvKucLGUCC00EnxPB7CIU4L80_WWwQ,304
|
7
|
-
azpaddypy-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
azpaddypy-0.1.9.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
9
|
-
azpaddypy-0.1.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|