|
13 | 13 | """Placeholder docstring"""
|
14 | 14 | from __future__ import absolute_import
|
15 | 15 |
|
16 |
| -import enum |
17 | 16 | import datetime
|
| 17 | +import enum |
18 | 18 | import json
|
19 | 19 | import logging
|
20 | 20 | import os
|
| 21 | +import re |
21 | 22 | import tempfile
|
22 | 23 | import time
|
23 |
| -from uuid import uuid4 |
24 | 24 | from copy import deepcopy
|
| 25 | +from uuid import uuid4 |
| 26 | + |
25 | 27 | from botocore.exceptions import ClientError
|
26 | 28 |
|
27 | 29 | import sagemaker.local.data
|
28 |
| - |
29 |
| -from sagemaker.local.image import _SageMakerContainer |
30 |
| -from sagemaker.local.utils import copy_directory_structure, move_to_destination, get_docker_host |
31 |
| -from sagemaker.utils import DeferredError, get_config_value, format_tags |
32 | 30 | from sagemaker.local.exceptions import StepExecutionException
|
| 31 | +from sagemaker.local.image import _SageMakerContainer |
| 32 | +from sagemaker.local.utils import (copy_directory_structure, get_docker_host, |
| 33 | + move_to_destination) |
| 34 | +from sagemaker.utils import DeferredError, format_tags, get_config_value |
33 | 35 |
|
34 | 36 | logger = logging.getLogger(__name__)
|
35 | 37 |
|
@@ -272,9 +274,42 @@ def describe(self):
|
272 | 274 | "AlgorithmSpecification": {
|
273 | 275 | "ContainerEntrypoint": self.container.container_entrypoint,
|
274 | 276 | },
|
| 277 | + "FinalMetricDataList": self._extract_final_metrics() |
275 | 278 | }
|
276 | 279 | return response
|
277 | 280 |
|
| 281 | + def _extract_final_metrics(self): |
| 282 | + """Extract metrics from container logs using metric definitions.""" |
| 283 | + if not hasattr(self.container, 'logs') or not self.container.logs: |
| 284 | + return [] |
| 285 | + |
| 286 | + # Get metric definitions from container |
| 287 | + metric_definitions = getattr(self.container, 'metric_definitions', []) |
| 288 | + if not metric_definitions: |
| 289 | + return [] |
| 290 | + |
| 291 | + final_metrics = [] |
| 292 | + logs = self.container.logs |
| 293 | + |
| 294 | + for metric_def in metric_definitions: |
| 295 | + metric_name = metric_def.get('Name') |
| 296 | + regex_pattern = metric_def.get('Regex') |
| 297 | + |
| 298 | + if not metric_name or not regex_pattern: |
| 299 | + continue |
| 300 | + |
| 301 | + # Find all matches in logs |
| 302 | + matches = re.findall(regex_pattern, logs) |
| 303 | + if matches: |
| 304 | + # Use the last match as final metric |
| 305 | + final_value = float(matches[-1]) |
| 306 | + final_metrics.append({ |
| 307 | + 'MetricName': metric_name, |
| 308 | + 'Value': final_value, |
| 309 | + 'Timestamp': self.end_time or datetime.now() |
| 310 | + }) |
| 311 | + |
| 312 | + return final_metrics |
278 | 313 |
|
279 | 314 | class _LocalTransformJob(object):
|
280 | 315 | """Placeholder docstring"""
|
@@ -711,8 +746,8 @@ def __init__(
|
711 | 746 | PipelineExecutionDisplayName=None,
|
712 | 747 | local_session=None,
|
713 | 748 | ):
|
714 |
| - from sagemaker.workflow.pipeline import PipelineGraph |
715 | 749 | from sagemaker import LocalSession
|
| 750 | + from sagemaker.workflow.pipeline import PipelineGraph |
716 | 751 |
|
717 | 752 | self.pipeline = pipeline
|
718 | 753 | self.pipeline_execution_name = execution_id
|
@@ -809,7 +844,7 @@ def mark_step_executing(self, step_name):
|
809 | 844 |
|
810 | 845 | def _initialize_step_execution(self, steps):
|
811 | 846 | """Initialize step_execution dict."""
|
812 |
| - from sagemaker.workflow.steps import StepTypeEnum, Step |
| 847 | + from sagemaker.workflow.steps import Step, StepTypeEnum |
813 | 848 |
|
814 | 849 | supported_steps_types = (
|
815 | 850 | StepTypeEnum.TRAINING,
|
|
0 commit comments