azpaddypy 0.3.2__py3-none-any.whl → 0.3.4__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 +126 -13
- {azpaddypy-0.3.2.dist-info → azpaddypy-0.3.4.dist-info}/METADATA +1 -1
- {azpaddypy-0.3.2.dist-info → azpaddypy-0.3.4.dist-info}/RECORD +6 -6
- {azpaddypy-0.3.2.dist-info → azpaddypy-0.3.4.dist-info}/WHEEL +0 -0
- {azpaddypy-0.3.2.dist-info → azpaddypy-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {azpaddypy-0.3.2.dist-info → azpaddypy-0.3.4.dist-info}/top_level.txt +0 -0
azpaddypy/mgmt/logging.py
CHANGED
@@ -3,6 +3,7 @@ import os
|
|
3
3
|
import functools
|
4
4
|
import time
|
5
5
|
import asyncio
|
6
|
+
import uuid
|
6
7
|
from typing import Optional, Dict, Any, Union, Callable
|
7
8
|
from datetime import datetime
|
8
9
|
from azure.monitor.opentelemetry import configure_azure_monitor
|
@@ -19,12 +20,23 @@ class AzureLogger:
|
|
19
20
|
tracking, baggage propagation, and automated function tracing for Azure
|
20
21
|
applications with seamless local development support.
|
21
22
|
|
23
|
+
CLOUD ROLE NAME INTEGRATION:
|
24
|
+
The service_name parameter automatically sets the cloud role name for
|
25
|
+
Application Insights. When multiple services emit telemetry to the same
|
26
|
+
Application Insights resource, each service will appear as a separate
|
27
|
+
node on the Application Map, enabling proper service topology visualization.
|
28
|
+
|
29
|
+
CORRELATION ID AUTOMATION:
|
30
|
+
The trace_function decorator automatically generates UUID4 correlation IDs
|
31
|
+
when none are manually set, ensuring consistent distributed tracing across
|
32
|
+
all function calls without requiring manual configuration.
|
33
|
+
|
22
34
|
Supports all standard logging levels (debug, info, warning, error, exception,
|
23
35
|
critical) with enhanced context including trace IDs, correlation IDs, and
|
24
36
|
baggage propagation.
|
25
37
|
|
26
38
|
Attributes:
|
27
|
-
service_name: Service identifier for telemetry
|
39
|
+
service_name: Service identifier for telemetry and cloud role name
|
28
40
|
service_version: Service version for context
|
29
41
|
connection_string: Application Insights connection string
|
30
42
|
logger: Python logger instance
|
@@ -40,17 +52,24 @@ class AzureLogger:
|
|
40
52
|
enable_console_logging: bool = True,
|
41
53
|
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
42
54
|
instrumentation_options: Optional[Dict[str, Any]] = None,
|
55
|
+
cloud_role_name: Optional[str] = None,
|
43
56
|
):
|
44
57
|
"""Initialize Azure Logger with OpenTelemetry tracing.
|
45
58
|
|
59
|
+
The service_name parameter automatically sets the cloud role name for
|
60
|
+
Application Insights Application Map visualization. When multiple services
|
61
|
+
emit telemetry to the same Application Insights resource, each service
|
62
|
+
will appear as a separate node on the Application Map.
|
63
|
+
|
46
64
|
Args:
|
47
|
-
service_name: Service identifier for telemetry
|
65
|
+
service_name: Service identifier for telemetry and cloud role name
|
48
66
|
service_version: Service version for metadata
|
49
67
|
connection_string: Application Insights connection string
|
50
68
|
log_level: Python logging level (default: INFO)
|
51
69
|
enable_console_logging: Enable console output for local development
|
52
70
|
custom_resource_attributes: Additional OpenTelemetry resource attributes
|
53
71
|
instrumentation_options: Azure Monitor instrumentation options
|
72
|
+
cloud_role_name: Override cloud role name (defaults to service_name)
|
54
73
|
"""
|
55
74
|
self.service_name = service_name
|
56
75
|
self.service_version = service_version
|
@@ -58,9 +77,14 @@ class AzureLogger:
|
|
58
77
|
"APPLICATIONINSIGHTS_CONNECTION_STRING"
|
59
78
|
)
|
60
79
|
|
80
|
+
# Use explicit cloud role name or default to service name
|
81
|
+
effective_cloud_role_name = cloud_role_name or service_name
|
82
|
+
self.cloud_role_name = effective_cloud_role_name
|
83
|
+
|
61
84
|
# Configure resource attributes
|
85
|
+
# NOTE: service.name automatically maps to cloud role name in Application Insights
|
62
86
|
resource_attributes = {
|
63
|
-
"service.name":
|
87
|
+
"service.name": effective_cloud_role_name,
|
64
88
|
"service.version": service_version,
|
65
89
|
"service.instance.id": os.getenv("WEBSITE_INSTANCE_ID", "local"),
|
66
90
|
}
|
@@ -100,7 +124,8 @@ class AzureLogger:
|
|
100
124
|
self._correlation_id = None
|
101
125
|
|
102
126
|
self.info(
|
103
|
-
f"Azure Logger initialized for service '{service_name}' v{service_version}"
|
127
|
+
f"Azure Logger initialized for service '{service_name}' v{service_version} "
|
128
|
+
f"(cloud role: '{effective_cloud_role_name}')"
|
104
129
|
)
|
105
130
|
|
106
131
|
def _setup_console_handler(self):
|
@@ -115,16 +140,27 @@ class AzureLogger:
|
|
115
140
|
def set_correlation_id(self, correlation_id: str):
|
116
141
|
"""Set correlation ID for request/transaction tracking.
|
117
142
|
|
143
|
+
Manually sets the correlation ID that will be used for all subsequent
|
144
|
+
tracing operations. This value takes precedence over auto-generated
|
145
|
+
correlation IDs in the trace_function decorator.
|
146
|
+
|
118
147
|
Args:
|
119
148
|
correlation_id: Unique identifier for transaction correlation
|
149
|
+
|
150
|
+
Note:
|
151
|
+
If not set manually, the trace_function decorator will automatically
|
152
|
+
generate a UUID4 correlation_id on first use.
|
120
153
|
"""
|
121
154
|
self._correlation_id = correlation_id
|
122
155
|
|
123
156
|
def get_correlation_id(self) -> Optional[str]:
|
124
157
|
"""Get current correlation ID.
|
125
158
|
|
159
|
+
Returns the currently active correlation ID, whether manually set
|
160
|
+
or automatically generated by the trace_function decorator.
|
161
|
+
|
126
162
|
Returns:
|
127
|
-
Current correlation ID if set, otherwise None
|
163
|
+
Current correlation ID if set (manual or auto-generated), otherwise None
|
128
164
|
"""
|
129
165
|
return self._correlation_id
|
130
166
|
|
@@ -167,8 +203,16 @@ class AzureLogger:
|
|
167
203
|
|
168
204
|
Returns:
|
169
205
|
Enhanced dictionary with service context, correlation ID, trace
|
170
|
-
context, and baggage items
|
206
|
+
context, and baggage items, with built-in LogRecord attributes filtered out
|
171
207
|
"""
|
208
|
+
# Define built-in LogRecord attributes that should not be overwritten
|
209
|
+
reserved_attributes = {
|
210
|
+
'name', 'msg', 'args', 'levelname', 'levelno', 'pathname', 'filename',
|
211
|
+
'module', 'exc_info', 'exc_text', 'stack_info', 'lineno', 'funcName',
|
212
|
+
'created', 'msecs', 'relativeCreated', 'thread', 'threadName',
|
213
|
+
'processName', 'process', 'getMessage'
|
214
|
+
}
|
215
|
+
|
172
216
|
enhanced_extra = {
|
173
217
|
"service_name": self.service_name,
|
174
218
|
"service_version": self.service_version,
|
@@ -185,13 +229,34 @@ class AzureLogger:
|
|
185
229
|
enhanced_extra["trace_id"] = format(span_context.trace_id, "032x")
|
186
230
|
enhanced_extra["span_id"] = format(span_context.span_id, "016x")
|
187
231
|
|
188
|
-
# Add baggage items
|
232
|
+
# Add baggage items, filtering out any reserved attribute names
|
189
233
|
baggage_items = self.get_all_baggage()
|
190
234
|
if baggage_items:
|
191
|
-
|
235
|
+
# Filter baggage items to avoid conflicts with LogRecord attributes
|
236
|
+
filtered_baggage = {k: v for k, v in baggage_items.items() if k not in reserved_attributes}
|
237
|
+
if filtered_baggage:
|
238
|
+
enhanced_extra["baggage"] = filtered_baggage
|
239
|
+
|
240
|
+
# Log warning if any baggage keys were filtered out
|
241
|
+
filtered_baggage_keys = set(baggage_items.keys()) - set(filtered_baggage.keys())
|
242
|
+
if filtered_baggage_keys:
|
243
|
+
# Use the base logger directly to avoid infinite recursion
|
244
|
+
self.logger.warning(
|
245
|
+
f"Filtered out reserved LogRecord attributes from baggage: {filtered_baggage_keys}"
|
246
|
+
)
|
192
247
|
|
193
248
|
if isinstance(extra, dict):
|
194
|
-
|
249
|
+
# Filter out any keys that would conflict with built-in LogRecord attributes
|
250
|
+
filtered_extra = {k: v for k, v in extra.items() if k not in reserved_attributes}
|
251
|
+
enhanced_extra.update(filtered_extra)
|
252
|
+
|
253
|
+
# Log warning if any keys were filtered out
|
254
|
+
filtered_keys = set(extra.keys()) - set(filtered_extra.keys())
|
255
|
+
if filtered_keys:
|
256
|
+
# Use the base logger directly to avoid infinite recursion
|
257
|
+
self.logger.warning(
|
258
|
+
f"Filtered out reserved LogRecord attributes from extra data: {filtered_keys}"
|
259
|
+
)
|
195
260
|
|
196
261
|
return enhanced_extra
|
197
262
|
|
@@ -481,16 +546,38 @@ class AzureLogger:
|
|
481
546
|
log_args: bool = True,
|
482
547
|
log_result: bool = False
|
483
548
|
) -> Callable:
|
484
|
-
"""Decorator for automatic function execution tracing.
|
549
|
+
"""Decorator for automatic function execution tracing with correlation ID support.
|
485
550
|
|
486
551
|
Supports both synchronous and asynchronous functions with comprehensive
|
487
|
-
logging and OpenTelemetry span creation.
|
552
|
+
logging and OpenTelemetry span creation. Automatically generates and manages
|
553
|
+
correlation IDs for distributed tracing.
|
554
|
+
|
555
|
+
CORRELATION ID AUTOMATION:
|
556
|
+
- If no correlation_id is set, automatically generates a UUID4 correlation_id
|
557
|
+
- If correlation_id is manually set, preserves the existing value
|
558
|
+
- Correlation_id is automatically added to all spans and log entries
|
559
|
+
- Ensures consistent tracing across function calls
|
488
560
|
|
489
561
|
Args:
|
490
562
|
function_name: Custom span name (defaults to function name)
|
491
563
|
log_execution: Whether to log execution metrics
|
492
564
|
log_args: Whether to log function arguments
|
493
565
|
log_result: Whether to log function result
|
566
|
+
|
567
|
+
Returns:
|
568
|
+
Decorated function with automatic tracing and correlation ID support
|
569
|
+
|
570
|
+
Example:
|
571
|
+
# Automatic correlation_id generation
|
572
|
+
@logger.trace_function()
|
573
|
+
def my_function():
|
574
|
+
return "result"
|
575
|
+
|
576
|
+
# Manual correlation_id (preserved)
|
577
|
+
logger.set_correlation_id("manual-id")
|
578
|
+
@logger.trace_function()
|
579
|
+
def my_function():
|
580
|
+
return "result"
|
494
581
|
"""
|
495
582
|
|
496
583
|
def decorator(func):
|
@@ -498,6 +585,11 @@ class AzureLogger:
|
|
498
585
|
async def async_wrapper(*args, **kwargs):
|
499
586
|
span_name = function_name or f"{func.__module__}.{func.__name__}"
|
500
587
|
with self.tracer.start_as_current_span(span_name) as span:
|
588
|
+
# Auto-generate correlation_id if not set - ensures consistent tracing
|
589
|
+
# Manual correlation_ids take precedence over auto-generated ones
|
590
|
+
if not self._correlation_id:
|
591
|
+
self._correlation_id = str(uuid.uuid4())
|
592
|
+
|
501
593
|
self._setup_span_for_function_trace(
|
502
594
|
span, func, True, log_args, args, kwargs, log_result, log_execution
|
503
595
|
)
|
@@ -531,6 +623,11 @@ class AzureLogger:
|
|
531
623
|
def sync_wrapper(*args, **kwargs):
|
532
624
|
span_name = function_name or f"{func.__module__}.{func.__name__}"
|
533
625
|
with self.tracer.start_as_current_span(span_name) as span:
|
626
|
+
# Auto-generate correlation_id if not set - ensures consistent tracing
|
627
|
+
# Manual correlation_ids take precedence over auto-generated ones
|
628
|
+
if not self._correlation_id:
|
629
|
+
self._correlation_id = str(uuid.uuid4())
|
630
|
+
|
534
631
|
self._setup_span_for_function_trace(
|
535
632
|
span, func, False, log_args, args, kwargs, log_result, log_execution
|
536
633
|
)
|
@@ -675,19 +772,23 @@ def create_app_logger(
|
|
675
772
|
enable_console_logging: bool = True,
|
676
773
|
custom_resource_attributes: Optional[Dict[str, str]] = None,
|
677
774
|
instrumentation_options: Optional[Dict[str, Any]] = None,
|
775
|
+
cloud_role_name: Optional[str] = None,
|
678
776
|
) -> AzureLogger:
|
679
777
|
"""Create cached AzureLogger instance for applications.
|
680
778
|
|
681
779
|
Returns existing logger if one with same configuration exists.
|
780
|
+
The service_name automatically becomes the cloud role name in Application Insights
|
781
|
+
unless explicitly overridden with cloud_role_name parameter.
|
682
782
|
|
683
783
|
Args:
|
684
|
-
service_name: Service identifier for telemetry
|
784
|
+
service_name: Service identifier for telemetry and cloud role name
|
685
785
|
service_version: Service version for metadata
|
686
786
|
connection_string: Application Insights connection string
|
687
787
|
log_level: Python logging level
|
688
788
|
enable_console_logging: Enable console output
|
689
789
|
custom_resource_attributes: Additional OpenTelemetry resource attributes
|
690
790
|
instrumentation_options: Azure Monitor instrumentation options
|
791
|
+
cloud_role_name: Override cloud role name (defaults to service_name)
|
691
792
|
|
692
793
|
Returns:
|
693
794
|
Configured AzureLogger instance
|
@@ -709,6 +810,7 @@ def create_app_logger(
|
|
709
810
|
log_level,
|
710
811
|
enable_console_logging,
|
711
812
|
attr_items,
|
813
|
+
cloud_role_name,
|
712
814
|
)
|
713
815
|
|
714
816
|
if params_key in _loggers:
|
@@ -721,6 +823,8 @@ def create_app_logger(
|
|
721
823
|
log_level=log_level,
|
722
824
|
enable_console_logging=enable_console_logging,
|
723
825
|
custom_resource_attributes=custom_resource_attributes,
|
826
|
+
instrumentation_options=instrumentation_options,
|
827
|
+
cloud_role_name=cloud_role_name,
|
724
828
|
)
|
725
829
|
_loggers[params_key] = logger
|
726
830
|
return logger
|
@@ -732,15 +836,21 @@ def create_function_logger(
|
|
732
836
|
service_version: str = "1.0.0",
|
733
837
|
connection_string: Optional[str] = None,
|
734
838
|
instrumentation_options: Optional[Dict[str, Any]] = None,
|
839
|
+
cloud_role_name: Optional[str] = None,
|
735
840
|
) -> AzureLogger:
|
736
841
|
"""Create AzureLogger optimized for Azure Functions.
|
737
842
|
|
843
|
+
Automatically creates cloud role name in the format '{function_app_name}.{function_name}'
|
844
|
+
unless explicitly overridden. This ensures each function appears as a separate
|
845
|
+
component in the Application Insights Application Map.
|
846
|
+
|
738
847
|
Args:
|
739
848
|
function_app_name: Azure Function App name
|
740
849
|
function_name: Specific function name
|
741
850
|
service_version: Service version for metadata
|
742
851
|
connection_string: Application Insights connection string
|
743
852
|
instrumentation_options: Azure Monitor instrumentation options
|
853
|
+
cloud_role_name: Override cloud role name (defaults to '{function_app_name}.{function_name}')
|
744
854
|
|
745
855
|
Returns:
|
746
856
|
Configured AzureLogger with Azure Functions context
|
@@ -751,10 +861,13 @@ def create_function_logger(
|
|
751
861
|
"azure.resource.type": "function",
|
752
862
|
}
|
753
863
|
|
864
|
+
default_service_name = f"{function_app_name}.{function_name}"
|
865
|
+
|
754
866
|
return create_app_logger(
|
755
|
-
service_name=
|
867
|
+
service_name=default_service_name,
|
756
868
|
service_version=service_version,
|
757
869
|
connection_string=connection_string,
|
758
870
|
custom_resource_attributes=custom_attributes,
|
759
871
|
instrumentation_options=instrumentation_options,
|
872
|
+
cloud_role_name=cloud_role_name,
|
760
873
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: azpaddypy
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.4
|
4
4
|
Summary: Comprehensive Python logger for Azure, integrating OpenTelemetry for advanced, structured, and distributed tracing.
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
6
6
|
Classifier: Operating System :: OS Independent
|
@@ -1,10 +1,10 @@
|
|
1
1
|
azpaddypy/mgmt/__init__.py,sha256=-jH8Ftx9C8qu4yF5dMVEapVZhNwG7m4QCUjyutesOoY,278
|
2
2
|
azpaddypy/mgmt/identity.py,sha256=mA_krQslMsK_sDob-z-QA0B9khK_JUO2way7xwPopR8,12001
|
3
|
-
azpaddypy/mgmt/logging.py,sha256=
|
3
|
+
azpaddypy/mgmt/logging.py,sha256=pivPsHeySF1Dyx6HKCSos7HBOYyJMVeRP25wYZu3Sno,35117
|
4
4
|
azpaddypy/test_function/__init__.py,sha256=0NjUl36wvUWV79GpRwBFkgkBaC6uDZsTdaSVOIHMFEU,3481
|
5
5
|
azpaddypy/test_function/function_app.py,sha256=6nX54-iq0L1l_hZpD6E744-j79oLxdaldFyWDCpwH7c,3867
|
6
|
-
azpaddypy-0.3.
|
7
|
-
azpaddypy-0.3.
|
8
|
-
azpaddypy-0.3.
|
9
|
-
azpaddypy-0.3.
|
10
|
-
azpaddypy-0.3.
|
6
|
+
azpaddypy-0.3.4.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
|
7
|
+
azpaddypy-0.3.4.dist-info/METADATA,sha256=QDqVtpO7pbf_VGJM4e3W6QHV0VtOB3gc6kH8pAoe7jQ,705
|
8
|
+
azpaddypy-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
9
|
+
azpaddypy-0.3.4.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
|
10
|
+
azpaddypy-0.3.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|