Skip to content

Commit 4935f70

Browse files
diondrapeckbastrik
andauthored
[ml] Add parent logging fixes (#34611)
* Resolve merge conflict * Make backward compatible (#34607) * Remove trigger method from merge resolution --------- Co-authored-by: Mickey Zhang <[email protected]>
1 parent 2611487 commit 4935f70

28 files changed

+257
-237
lines changed

sdk/ml/azure-ai-ml/azure/ai/ml/_ml_client.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from functools import singledispatch
1111
from itertools import product
1212
from pathlib import Path
13-
from typing import Any, Optional, Tuple, TypeVar, Union
13+
from typing import Any, Dict, Optional, Tuple, TypeVar, Union
1414

1515
from azure.ai.ml._azure_environments import (
1616
CloudArgumentKeys,
@@ -269,12 +269,12 @@ def __init__(
269269

270270
user_agent = kwargs.get("user_agent", None)
271271

272-
app_insights_handler = get_appinsights_log_handler(
272+
app_insights_handler: Tuple = get_appinsights_log_handler(
273273
user_agent,
274274
**{"properties": properties},
275275
enable_telemetry=self._operation_config.enable_telemetry,
276276
)
277-
app_insights_handler_kwargs = {"app_insights_handler": app_insights_handler}
277+
app_insights_handler_kwargs: Dict[str, Tuple] = {"app_insights_handler": app_insights_handler}
278278

279279
base_url = _get_base_url_from_metadata(cloud_name=cloud_name, is_local_mfe=True)
280280
self._base_url = base_url
@@ -442,7 +442,7 @@ def __init__(
442442
self._service_client_10_2022_preview,
443443
self._operation_container,
444444
self._credential,
445-
**app_insights_handler_kwargs,
445+
**app_insights_handler_kwargs, # type: ignore[arg-type]
446446
)
447447
self._operation_container.add(AzureMLResourceType.REGISTRY, self._registries) # type: ignore[arg-type]
448448

@@ -463,15 +463,15 @@ def __init__(
463463
self._operation_scope,
464464
self._operation_config,
465465
self._service_client_08_2023_preview,
466-
**app_insights_handler_kwargs,
466+
**app_insights_handler_kwargs, # type: ignore[arg-type]
467467
)
468468
self._operation_container.add(AzureMLResourceType.COMPUTE, self._compute)
469469
self._datastores = DatastoreOperations(
470470
operation_scope=self._operation_scope,
471471
operation_config=self._operation_config,
472472
serviceclient_2023_04_01_preview=self._service_client_04_2023_preview,
473473
serviceclient_2024_01_01_preview=self._service_client_01_2024_preview,
474-
**ops_kwargs,
474+
**ops_kwargs, # type: ignore[arg-type]
475475
)
476476
self._operation_container.add(AzureMLResourceType.DATASTORE, self._datastores)
477477
self._models = ModelOperations(
@@ -487,23 +487,23 @@ def __init__(
487487
workspace_rg=self._ws_rg,
488488
workspace_sub=self._ws_sub,
489489
registry_reference=registry_reference,
490-
**app_insights_handler_kwargs,
490+
**app_insights_handler_kwargs, # type: ignore[arg-type]
491491
)
492492
self._operation_container.add(AzureMLResourceType.MODEL, self._models)
493493
self._code = CodeOperations(
494494
self._ws_operation_scope if registry_reference else self._operation_scope,
495495
self._operation_config,
496496
self._service_client_10_2021_dataplanepreview if registry_name else self._service_client_04_2023,
497497
self._datastores,
498-
**ops_kwargs,
498+
**ops_kwargs, # type: ignore[arg-type]
499499
)
500500
self._operation_container.add(AzureMLResourceType.CODE, self._code)
501501
self._environments = EnvironmentOperations(
502502
self._ws_operation_scope if registry_reference else self._operation_scope,
503503
self._operation_config,
504504
self._service_client_10_2021_dataplanepreview if registry_name else self._service_client_04_2023_preview,
505505
self._operation_container,
506-
**ops_kwargs,
506+
**ops_kwargs, # type: ignore[arg-type]
507507
)
508508
self._operation_container.add(AzureMLResourceType.ENVIRONMENT, self._environments)
509509
self._local_endpoint_helper = _LocalEndpointHelper(requests_pipeline=self._requests_pipeline)
@@ -516,7 +516,7 @@ def __init__(
516516
self._local_endpoint_helper,
517517
self._credential,
518518
requests_pipeline=self._requests_pipeline,
519-
**ops_kwargs,
519+
**ops_kwargs, # type: ignore[arg-type]
520520
)
521521
self._batch_endpoints = BatchEndpointOperations(
522522
self._operation_scope,
@@ -526,7 +526,7 @@ def __init__(
526526
self._credential,
527527
requests_pipeline=self._requests_pipeline,
528528
service_client_09_2020_dataplanepreview=self._service_client_09_2020_dataplanepreview,
529-
**ops_kwargs,
529+
**ops_kwargs, # type: ignore[arg-type]
530530
)
531531
self._operation_container.add(AzureMLResourceType.BATCH_ENDPOINT, self._batch_endpoints)
532532
self._operation_container.add(AzureMLResourceType.ONLINE_ENDPOINT, self._online_endpoints)
@@ -537,7 +537,7 @@ def __init__(
537537
self._operation_container,
538538
self._local_deployment_helper,
539539
self._credential,
540-
**ops_kwargs,
540+
**ops_kwargs, # type: ignore[arg-type]
541541
)
542542
self._batch_deployments = BatchDeploymentOperations(
543543
self._operation_scope,
@@ -569,7 +569,7 @@ def __init__(
569569
self._service_client_10_2021_dataplanepreview if registry_name else self._service_client_10_2022,
570570
self._operation_container,
571571
self._preflight,
572-
**ops_kwargs,
572+
**ops_kwargs, # type: ignore[arg-type]
573573
)
574574
self._operation_container.add(AzureMLResourceType.COMPONENT, self._components)
575575
self._jobs = JobOperations(
@@ -602,7 +602,7 @@ def __init__(
602602
self._operation_scope,
603603
self._credential,
604604
_service_client_kwargs=kwargs,
605-
**ops_kwargs,
605+
**ops_kwargs, # type: ignore[arg-type]
606606
)
607607
self._operation_container.add(
608608
AzureMLResourceType.VIRTUALCLUSTER, self._virtual_clusters # type: ignore[arg-type]
@@ -615,7 +615,7 @@ def __init__(
615615
self._service_client_08_2023_preview,
616616
self._operation_container,
617617
self._credential,
618-
**app_insights_handler_kwargs,
618+
**app_insights_handler_kwargs, # type: ignore[arg-type]
619619
)
620620

621621
self._featuresets = FeatureSetOperations(
@@ -624,22 +624,22 @@ def __init__(
624624
self._service_client_10_2023,
625625
self._service_client_08_2023_preview,
626626
self._datastores,
627-
**ops_kwargs,
627+
**ops_kwargs, # type: ignore[arg-type]
628628
)
629629

630630
self._featurestoreentities = FeatureStoreEntityOperations(
631631
self._operation_scope,
632632
self._operation_config,
633633
self._service_client_10_2023,
634-
**ops_kwargs,
634+
**ops_kwargs, # type: ignore[arg-type]
635635
)
636636

637637
self._workspace_hubs = WorkspaceHubOperations(
638638
self._operation_scope,
639639
self._service_client_08_2023_preview,
640640
self._operation_container,
641641
self._credential,
642-
**app_insights_handler_kwargs,
642+
**app_insights_handler_kwargs, # type: ignore[arg-type]
643643
)
644644
self._operation_container.add(AzureMLResourceType.WORKSPACE_HUB, self._workspace_hubs) # type: ignore[arg-type]
645645

sdk/ml/azure-ai-ml/azure/ai/ml/_telemetry/activity.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from marshmallow import ValidationError
2525

26+
from azure.ai.ml._utils._logger_utils import OpsLogger
2627
from azure.ai.ml._utils.utils import _is_user_error_from_exception_type, _is_user_error_from_status_code, _str_to_bool
2728
from azure.ai.ml.exceptions import ErrorCategory, MlException
2829
from azure.core.exceptions import HttpResponseError
@@ -260,8 +261,8 @@ def monitor_with_activity(
260261
To monitor, use the ``@monitor_with_activity`` decorator. As an alternative, you can also wrap the
261262
logical block of code with the ``log_activity()`` method.
262263
263-
:param logger: The logger adapter.
264-
:type logger: logging.LoggerAdapter
264+
:param logger: The operations logging class, containing loggers and tracer for the package and module
265+
:type logger: ~azure.ai.ml._utils._logger_utils.OpsLogger
265266
:param activity_name: The name of the activity. The name should be unique per the wrapped logical code block.
266267
:type activity_name: str
267268
:param activity_type: One of PUBLICAPI, INTERNALCALL, or CLIENTPROXY which represent an incoming API call,
@@ -275,8 +276,19 @@ def monitor_with_activity(
275276
def monitor(f):
276277
@functools.wraps(f)
277278
def wrapper(*args, **kwargs):
278-
with log_activity(logger, activity_name or f.__name__, activity_type, custom_dimensions):
279-
return f(*args, **kwargs)
279+
tracer = logger.package_tracer if isinstance(logger, OpsLogger) else None
280+
if tracer:
281+
with tracer.span():
282+
with log_activity(
283+
logger.package_logger, activity_name or f.__name__, activity_type, custom_dimensions
284+
):
285+
return f(*args, **kwargs)
286+
elif hasattr(logger, "package_logger"):
287+
with log_activity(logger.package_logger, activity_name or f.__name__, activity_type, custom_dimensions):
288+
return f(*args, **kwargs)
289+
else:
290+
with log_activity(logger, activity_name or f.__name__, activity_type, custom_dimensions):
291+
return f(*args, **kwargs)
280292

281293
return wrapper
282294

@@ -300,7 +312,7 @@ def monitor_with_telemetry_mixin(
300312
will collect from return value.
301313
To monitor, use the ``@monitor_with_telemetry_mixin`` decorator.
302314
303-
:param logger: The logger adapter.
315+
:param logger: The operations logging class, containing loggers and tracer for the package and module
304316
:type logger: logging.LoggerAdapter
305317
:param activity_name: The name of the activity. The name should be unique per the wrapped logical code block.
306318
:type activity_name: str
@@ -315,6 +327,8 @@ def monitor_with_telemetry_mixin(
315327
:return:
316328
"""
317329

330+
logger = logger.package_logger if isinstance(logger, OpsLogger) else logger
331+
318332
def monitor(f):
319333
def _collect_from_parameters(f, args, kwargs, extra_keys):
320334
dimensions = {}

sdk/ml/azure-ai-ml/azure/ai/ml/_telemetry/logging_handler.py

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
import logging
1010
import platform
1111
import traceback
12+
from typing import Optional, Tuple, Union
1213

1314
from opencensus.ext.azure.common import utils
1415
from opencensus.ext.azure.common.protocol import Data, Envelope, ExceptionData, Message
1516
from opencensus.ext.azure.log_exporter import AzureLogHandler
17+
from opencensus.ext.azure.trace_exporter import AzureExporter
1618
from opencensus.trace import config_integration
19+
from opencensus.trace.samplers import ProbabilitySampler
20+
from opencensus.trace.tracer import Tracer
1721

1822
from azure.ai.ml._user_agent import USER_AGENT
1923

@@ -87,7 +91,7 @@ def get_appinsights_log_handler(
8791
component_name=None,
8892
enable_telemetry=True,
8993
**kwargs,
90-
):
94+
) -> Tuple[Union["AzureMLSDKLogHandler", logging.NullHandler], Optional[Tracer]]:
9195
"""Enable the OpenCensus logging handler for specified logger and instrumentation key to send info to AppInsights.
9296
9397
:param user_agent: Information about the user's browser.
@@ -102,22 +106,23 @@ def get_appinsights_log_handler(
102106
:paramtype enable_telemetry: bool
103107
:keyword kwargs: Optional keyword arguments for adding additional information to messages.
104108
:paramtype kwargs: dict
105-
:return: The logging handler.
106-
:rtype: AzureMLSDKLogHandler
109+
:return: The logging handler and tracer.
110+
:rtype: Tuple[Union[AzureMLSDKLogHandler, logging.NullHandler], Optional[opencensus.trace.tracer.Tracer]]
107111
"""
108112
try:
109113
if instrumentation_key is None:
110114
instrumentation_key = INSTRUMENTATION_KEY
111115

112116
if not in_jupyter_notebook() or not enable_telemetry:
113-
return logging.NullHandler()
117+
return (logging.NullHandler(), None)
114118

115119
if not user_agent or not user_agent.lower() == USER_AGENT.lower():
116-
return logging.NullHandler()
120+
return (logging.NullHandler(), None)
117121

118-
if "properties" in kwargs and "subscription_id" in kwargs.get("properties"):
119-
if kwargs.get("properties")["subscription_id"] in test_subscriptions:
120-
return logging.NullHandler()
122+
if kwargs:
123+
if "properties" in kwargs and "subscription_id" in kwargs.get("properties"): # type: ignore[operator]
124+
if kwargs.get("properties")["subscription_id"] in test_subscriptions: # type: ignore[index]
125+
return (logging.NullHandler(), None)
121126

122127
child_namespace = component_name or __name__
123128
current_logger = logging.getLogger(AML_INTERNAL_LOGGER_NAMESPACE).getChild(child_namespace)
@@ -135,10 +140,15 @@ def get_appinsights_log_handler(
135140
)
136141
current_logger.addHandler(handler)
137142

138-
return handler
143+
tracer = Tracer(
144+
exporter=AzureExporter(connection_string=f"InstrumentationKey={instrumentation_key}"),
145+
sampler=ProbabilitySampler(1.0),
146+
)
147+
148+
return (handler, tracer)
139149
except Exception: # pylint: disable=broad-except
140150
# ignore any exceptions, telemetry collection errors shouldn't block an operation
141-
return logging.NullHandler()
151+
return (logging.NullHandler(), None)
142152

143153

144154
# cspell:ignore AzureMLSDKLogHandler
@@ -173,14 +183,20 @@ def log_record_to_envelope(self, record):
173183
if self._is_telemetry_collection_disabled:
174184
return None
175185

176-
envelope = create_envelope(self.options.instrumentation_key, record)
186+
envelope = Envelope(
187+
iKey=self.options.instrumentation_key,
188+
tags=dict(utils.azure_monitor_context),
189+
time=utils.timestamp_to_iso_str(record.created),
190+
)
177191

178192
properties = {
179193
"process": record.processName,
180194
"module": record.module,
181195
"level": record.levelname,
182-
"operation_id": envelope.tags.get("ai.ml.operation.id"),
183-
"operation_parent_id": envelope.tags.get("ai.ml.operation.parentId"),
196+
"activity_id": record.properties.get("activity_id", "00000000-0000-0000-0000-000000000000"),
197+
"client-request-id": record.properties.get("client_request_id", "00000000-0000-0000-0000-000000000000"),
198+
"span_id": record.spanId,
199+
"trace_id": record.traceId,
184200
}
185201

186202
if hasattr(record, "custom_dimensions") and isinstance(record.custom_dimensions, dict):
@@ -237,21 +253,3 @@ def log_record_to_envelope(self, record):
237253
)
238254
envelope.data = Data(baseData=data, baseType="MessageData")
239255
return envelope
240-
241-
242-
def create_envelope(instrumentation_key, record):
243-
envelope = Envelope(
244-
iKey=instrumentation_key,
245-
tags=dict(utils.azure_monitor_context),
246-
time=utils.timestamp_to_iso_str(record.created),
247-
)
248-
envelope.tags["ai.ml.operation.id"] = getattr(
249-
record,
250-
"traceId",
251-
"00000000000000000000000000000000",
252-
)
253-
envelope.tags[
254-
"ai.ml.operation.parentId"
255-
] = f"|{envelope.tags.get('ai.ml.operation.id')}.{getattr(record, 'spanId', '0000000000000000')}"
256-
257-
return envelope

sdk/ml/azure-ai-ml/azure/ai/ml/_utils/_logger_utils.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import logging
66
import sys
7+
from typing import Dict
78

89
from azure.ai.ml._telemetry.logging_handler import AML_INTERNAL_LOGGER_NAMESPACE
910

@@ -22,9 +23,12 @@ class OpsLogger:
2223
def __init__(self, name: str):
2324
self.package_logger: logging.Logger = logging.getLogger(AML_INTERNAL_LOGGER_NAMESPACE + name)
2425
self.package_logger.propagate = False
26+
self.package_tracer = None
2527
self.module_logger = logging.getLogger(name)
2628
self.custom_dimensions = {}
2729

28-
def update_info(self, data: dict) -> None:
30+
def update_info(self, data: Dict) -> None:
2931
if "app_insights_handler" in data:
30-
self.package_logger.addHandler(data.pop("app_insights_handler"))
32+
logger, tracer = data.pop("app_insights_handler")
33+
self.package_logger.addHandler(logger)
34+
self.package_tracer = tracer

0 commit comments

Comments
 (0)