mlrun 1.7.2__py3-none-any.whl → 1.8.0rc1__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.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +14 -12
- mlrun/__main__.py +3 -3
- mlrun/alerts/alert.py +19 -12
- mlrun/artifacts/__init__.py +0 -2
- mlrun/artifacts/base.py +34 -11
- mlrun/artifacts/dataset.py +16 -16
- mlrun/artifacts/manager.py +13 -13
- mlrun/artifacts/model.py +66 -53
- mlrun/common/constants.py +6 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/feature_set.py +1 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/common/formatters/model_endpoint.py +30 -0
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/model_monitoring/__init__.py +0 -3
- mlrun/common/model_monitoring/helpers.py +1 -1
- mlrun/common/runtimes/constants.py +1 -2
- mlrun/common/schemas/__init__.py +4 -2
- mlrun/common/schemas/artifact.py +0 -6
- mlrun/common/schemas/common.py +50 -0
- mlrun/common/schemas/model_monitoring/__init__.py +8 -1
- mlrun/common/schemas/model_monitoring/constants.py +62 -12
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +149 -0
- mlrun/common/schemas/model_monitoring/model_endpoints.py +21 -5
- mlrun/common/schemas/partition.py +122 -0
- mlrun/config.py +43 -15
- mlrun/data_types/__init__.py +0 -2
- mlrun/data_types/data_types.py +0 -1
- mlrun/data_types/infer.py +3 -1
- mlrun/data_types/spark.py +4 -4
- mlrun/data_types/to_pandas.py +2 -11
- mlrun/datastore/__init__.py +0 -2
- mlrun/datastore/alibaba_oss.py +4 -1
- mlrun/datastore/azure_blob.py +4 -1
- mlrun/datastore/base.py +12 -4
- mlrun/datastore/datastore.py +9 -3
- mlrun/datastore/datastore_profile.py +1 -1
- mlrun/datastore/dbfs_store.py +4 -1
- mlrun/datastore/filestore.py +4 -1
- mlrun/datastore/google_cloud_storage.py +4 -1
- mlrun/datastore/hdfs.py +4 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +4 -1
- mlrun/datastore/s3.py +4 -1
- mlrun/datastore/sources.py +51 -49
- mlrun/datastore/store_resources.py +0 -2
- mlrun/datastore/targets.py +22 -23
- mlrun/datastore/utils.py +2 -2
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +126 -62
- mlrun/db/factory.py +3 -0
- mlrun/db/httpdb.py +767 -231
- mlrun/db/nopdb.py +126 -57
- mlrun/errors.py +2 -2
- mlrun/execution.py +55 -29
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +40 -40
- mlrun/feature_store/common.py +9 -9
- mlrun/feature_store/feature_set.py +20 -18
- mlrun/feature_store/feature_vector.py +27 -24
- mlrun/feature_store/retrieval/base.py +14 -9
- mlrun/feature_store/retrieval/job.py +2 -1
- mlrun/feature_store/steps.py +2 -2
- mlrun/features.py +30 -13
- mlrun/frameworks/__init__.py +1 -2
- mlrun/frameworks/_common/__init__.py +1 -2
- mlrun/frameworks/_common/artifacts_library.py +2 -2
- mlrun/frameworks/_common/mlrun_interface.py +10 -6
- mlrun/frameworks/_common/model_handler.py +29 -27
- mlrun/frameworks/_common/producer.py +3 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
- mlrun/frameworks/_ml_common/__init__.py +1 -2
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_ml_common/model_handler.py +21 -21
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/auto_mlrun/__init__.py +1 -2
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
- mlrun/frameworks/huggingface/__init__.py +1 -2
- mlrun/frameworks/huggingface/model_server.py +9 -9
- mlrun/frameworks/lgbm/__init__.py +47 -44
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
- mlrun/frameworks/lgbm/model_handler.py +15 -11
- mlrun/frameworks/lgbm/model_server.py +11 -7
- mlrun/frameworks/lgbm/utils.py +2 -2
- mlrun/frameworks/onnx/__init__.py +1 -2
- mlrun/frameworks/onnx/dataset.py +3 -3
- mlrun/frameworks/onnx/mlrun_interface.py +2 -2
- mlrun/frameworks/onnx/model_handler.py +7 -5
- mlrun/frameworks/onnx/model_server.py +8 -6
- mlrun/frameworks/parallel_coordinates.py +11 -11
- mlrun/frameworks/pytorch/__init__.py +22 -23
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
- mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
- mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
- mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
- mlrun/frameworks/pytorch/model_handler.py +21 -17
- mlrun/frameworks/pytorch/model_server.py +13 -9
- mlrun/frameworks/sklearn/__init__.py +19 -18
- mlrun/frameworks/sklearn/estimator.py +2 -2
- mlrun/frameworks/sklearn/metric.py +3 -3
- mlrun/frameworks/sklearn/metrics_library.py +8 -6
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
- mlrun/frameworks/sklearn/model_handler.py +4 -3
- mlrun/frameworks/tf_keras/__init__.py +11 -12
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
- mlrun/frameworks/tf_keras/model_handler.py +17 -13
- mlrun/frameworks/tf_keras/model_server.py +12 -8
- mlrun/frameworks/xgboost/__init__.py +19 -18
- mlrun/frameworks/xgboost/model_handler.py +13 -9
- mlrun/launcher/base.py +3 -4
- mlrun/launcher/local.py +1 -1
- mlrun/launcher/remote.py +1 -1
- mlrun/lists.py +4 -3
- mlrun/model.py +108 -44
- mlrun/model_monitoring/__init__.py +1 -2
- mlrun/model_monitoring/api.py +6 -6
- mlrun/model_monitoring/applications/_application_steps.py +13 -15
- mlrun/model_monitoring/applications/histogram_data_drift.py +41 -15
- mlrun/model_monitoring/applications/results.py +55 -3
- mlrun/model_monitoring/controller.py +185 -223
- mlrun/model_monitoring/db/_schedules.py +156 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/stores/__init__.py +1 -1
- mlrun/model_monitoring/db/stores/base/store.py +6 -65
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -97
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +2 -58
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -15
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +6 -257
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +9 -271
- mlrun/model_monitoring/db/tsdb/base.py +74 -22
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +66 -35
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +284 -51
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -17
- mlrun/model_monitoring/helpers.py +97 -1
- mlrun/model_monitoring/model_endpoint.py +4 -2
- mlrun/model_monitoring/stream_processing.py +2 -2
- mlrun/model_monitoring/tracking_policy.py +10 -3
- mlrun/model_monitoring/writer.py +47 -26
- mlrun/package/__init__.py +3 -6
- mlrun/package/context_handler.py +1 -1
- mlrun/package/packager.py +12 -9
- mlrun/package/packagers/__init__.py +0 -2
- mlrun/package/packagers/default_packager.py +14 -11
- mlrun/package/packagers/numpy_packagers.py +16 -7
- mlrun/package/packagers/pandas_packagers.py +18 -18
- mlrun/package/packagers/python_standard_library_packagers.py +25 -11
- mlrun/package/packagers_manager.py +31 -14
- mlrun/package/utils/__init__.py +0 -3
- mlrun/package/utils/_pickler.py +6 -6
- mlrun/platforms/__init__.py +3 -3
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/__init__.py +1 -6
- mlrun/projects/operations.py +27 -27
- mlrun/projects/pipelines.py +85 -215
- mlrun/projects/project.py +444 -158
- mlrun/run.py +9 -9
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +13 -10
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/generators.py +2 -1
- mlrun/runtimes/kubejob.py +4 -5
- mlrun/runtimes/mpijob/__init__.py +0 -2
- mlrun/runtimes/mpijob/abstract.py +7 -6
- mlrun/runtimes/nuclio/api_gateway.py +7 -7
- mlrun/runtimes/nuclio/application/application.py +11 -11
- mlrun/runtimes/nuclio/function.py +14 -14
- mlrun/runtimes/nuclio/serving.py +9 -9
- mlrun/runtimes/pod.py +74 -29
- mlrun/runtimes/remotesparkjob.py +3 -2
- mlrun/runtimes/sparkjob/__init__.py +0 -2
- mlrun/runtimes/sparkjob/spark3job.py +21 -11
- mlrun/runtimes/utils.py +6 -5
- mlrun/serving/merger.py +6 -4
- mlrun/serving/remote.py +18 -17
- mlrun/serving/routers.py +27 -27
- mlrun/serving/server.py +1 -1
- mlrun/serving/states.py +76 -71
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +4 -4
- mlrun/track/__init__.py +1 -1
- mlrun/track/tracker.py +2 -2
- mlrun/track/trackers/mlflow_tracker.py +6 -5
- mlrun/utils/async_http.py +1 -1
- mlrun/utils/helpers.py +72 -28
- mlrun/utils/logger.py +104 -2
- mlrun/utils/notifications/notification/base.py +23 -4
- mlrun/utils/notifications/notification/console.py +1 -1
- mlrun/utils/notifications/notification/git.py +6 -6
- mlrun/utils/notifications/notification/ipython.py +5 -4
- mlrun/utils/notifications/notification/slack.py +1 -1
- mlrun/utils/notifications/notification/webhook.py +13 -17
- mlrun/utils/notifications/notification_pusher.py +23 -19
- mlrun/utils/regex.py +1 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/METADATA +187 -199
- mlrun-1.8.0rc1.dist-info/RECORD +356 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/WHEEL +1 -1
- mlrun-1.7.2.dist-info/RECORD +0 -351
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/LICENSE +0 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
import datetime
|
|
16
16
|
import typing
|
|
17
|
-
import uuid
|
|
18
17
|
|
|
19
18
|
import pandas as pd
|
|
20
19
|
import sqlalchemy
|
|
@@ -75,9 +74,6 @@ class SQLStoreBase(StoreBase):
|
|
|
75
74
|
|
|
76
75
|
def _init_tables(self):
|
|
77
76
|
self._init_model_endpoints_table()
|
|
78
|
-
self._init_application_results_table()
|
|
79
|
-
self._init_application_metrics_table()
|
|
80
|
-
self._init_monitoring_schedules_table()
|
|
81
77
|
|
|
82
78
|
def _init_model_endpoints_table(self):
|
|
83
79
|
self.model_endpoints_table = (
|
|
@@ -89,32 +85,6 @@ class SQLStoreBase(StoreBase):
|
|
|
89
85
|
self.model_endpoints_table
|
|
90
86
|
)
|
|
91
87
|
|
|
92
|
-
def _init_application_results_table(self):
|
|
93
|
-
self.application_results_table = (
|
|
94
|
-
mlrun.model_monitoring.db.stores.sqldb.models._get_application_result_table(
|
|
95
|
-
connection_string=self._sql_connection_string
|
|
96
|
-
)
|
|
97
|
-
)
|
|
98
|
-
self._tables[mm_schemas.FileTargetKind.APP_RESULTS] = (
|
|
99
|
-
self.application_results_table
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
def _init_application_metrics_table(self) -> None:
|
|
103
|
-
self.application_metrics_table = mlrun.model_monitoring.db.stores.sqldb.models._get_application_metrics_table(
|
|
104
|
-
connection_string=self._sql_connection_string
|
|
105
|
-
)
|
|
106
|
-
self._tables[mm_schemas.FileTargetKind.APP_METRICS] = (
|
|
107
|
-
self.application_metrics_table
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
def _init_monitoring_schedules_table(self):
|
|
111
|
-
self.MonitoringSchedulesTable = mlrun.model_monitoring.db.stores.sqldb.models._get_monitoring_schedules_table(
|
|
112
|
-
connection_string=self._sql_connection_string
|
|
113
|
-
)
|
|
114
|
-
self._tables[mm_schemas.FileTargetKind.MONITORING_SCHEDULES] = (
|
|
115
|
-
self.MonitoringSchedulesTable
|
|
116
|
-
)
|
|
117
|
-
|
|
118
88
|
def _write(self, table_name: str, event: dict[str, typing.Any]) -> None:
|
|
119
89
|
"""
|
|
120
90
|
Create a new record in the SQL table.
|
|
@@ -272,12 +242,12 @@ class SQLStoreBase(StoreBase):
|
|
|
272
242
|
|
|
273
243
|
def list_model_endpoints(
|
|
274
244
|
self,
|
|
275
|
-
model: str = None,
|
|
276
|
-
function: str = None,
|
|
277
|
-
labels: list[str] = None,
|
|
278
|
-
top_level: bool = None,
|
|
279
|
-
uids: list = None,
|
|
280
|
-
include_stats: bool = None,
|
|
245
|
+
model: typing.Optional[str] = None,
|
|
246
|
+
function: typing.Optional[str] = None,
|
|
247
|
+
labels: typing.Optional[list[str]] = None,
|
|
248
|
+
top_level: typing.Optional[bool] = None,
|
|
249
|
+
uids: typing.Optional[list] = None,
|
|
250
|
+
include_stats: typing.Optional[bool] = None,
|
|
281
251
|
) -> list[dict[str, typing.Any]]:
|
|
282
252
|
# Generate an empty model endpoints that will be filled afterwards with model endpoint dictionaries
|
|
283
253
|
endpoint_list = []
|
|
@@ -348,182 +318,12 @@ class SQLStoreBase(StoreBase):
|
|
|
348
318
|
|
|
349
319
|
return endpoint_list
|
|
350
320
|
|
|
351
|
-
def write_application_event(
|
|
352
|
-
self,
|
|
353
|
-
event: dict[str, typing.Any],
|
|
354
|
-
kind: mm_schemas.WriterEventKind = mm_schemas.WriterEventKind.RESULT,
|
|
355
|
-
) -> None:
|
|
356
|
-
"""
|
|
357
|
-
Write a new application event in the target table.
|
|
358
|
-
|
|
359
|
-
:param event: An event dictionary that represents the application result or metric,
|
|
360
|
-
should be corresponded to the schema defined in the
|
|
361
|
-
:py:class:`~mm_constants.constants.WriterEvent` object.
|
|
362
|
-
:param kind: The type of the event, can be either "result" or "metric".
|
|
363
|
-
"""
|
|
364
|
-
|
|
365
|
-
if kind == mm_schemas.WriterEventKind.METRIC:
|
|
366
|
-
table = self.application_metrics_table
|
|
367
|
-
table_name = mm_schemas.FileTargetKind.APP_METRICS
|
|
368
|
-
elif kind == mm_schemas.WriterEventKind.RESULT:
|
|
369
|
-
table = self.application_results_table
|
|
370
|
-
table_name = mm_schemas.FileTargetKind.APP_RESULTS
|
|
371
|
-
else:
|
|
372
|
-
raise ValueError(f"Invalid {kind = }")
|
|
373
|
-
|
|
374
|
-
application_result_uid = self._generate_application_result_uid(event, kind=kind)
|
|
375
|
-
criteria = [table.uid == application_result_uid]
|
|
376
|
-
|
|
377
|
-
application_record = self._get(table=table, criteria=criteria)
|
|
378
|
-
if application_record:
|
|
379
|
-
self._convert_to_datetime(
|
|
380
|
-
event=event, key=mm_schemas.WriterEvent.START_INFER_TIME
|
|
381
|
-
)
|
|
382
|
-
self._convert_to_datetime(
|
|
383
|
-
event=event, key=mm_schemas.WriterEvent.END_INFER_TIME
|
|
384
|
-
)
|
|
385
|
-
# Update an existing application result
|
|
386
|
-
self._update(attributes=event, table=table, criteria=criteria)
|
|
387
|
-
else:
|
|
388
|
-
# Write a new application result
|
|
389
|
-
event[mm_schemas.EventFieldType.UID] = application_result_uid
|
|
390
|
-
self._write(table_name=table_name, event=event)
|
|
391
|
-
|
|
392
321
|
@staticmethod
|
|
393
322
|
def _convert_to_datetime(event: dict[str, typing.Any], key: str) -> None:
|
|
394
323
|
if isinstance(event[key], str):
|
|
395
324
|
event[key] = datetime.datetime.fromisoformat(event[key])
|
|
396
325
|
event[key] = event[key].astimezone(tz=datetime.timezone.utc)
|
|
397
326
|
|
|
398
|
-
@staticmethod
|
|
399
|
-
def _generate_application_result_uid(
|
|
400
|
-
event: dict[str, typing.Any],
|
|
401
|
-
kind: mm_schemas.WriterEventKind = mm_schemas.WriterEventKind.RESULT,
|
|
402
|
-
) -> str:
|
|
403
|
-
if kind == mm_schemas.WriterEventKind.RESULT:
|
|
404
|
-
name = event[mm_schemas.ResultData.RESULT_NAME]
|
|
405
|
-
else:
|
|
406
|
-
name = event[mm_schemas.MetricData.METRIC_NAME]
|
|
407
|
-
return "_".join(
|
|
408
|
-
[
|
|
409
|
-
event[mm_schemas.WriterEvent.ENDPOINT_ID],
|
|
410
|
-
event[mm_schemas.WriterEvent.APPLICATION_NAME],
|
|
411
|
-
name,
|
|
412
|
-
]
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
@staticmethod
|
|
416
|
-
def _get_filter_criteria(
|
|
417
|
-
*,
|
|
418
|
-
table: sqlalchemy.orm.decl_api.DeclarativeMeta,
|
|
419
|
-
endpoint_id: str,
|
|
420
|
-
application_name: typing.Optional[str] = None,
|
|
421
|
-
) -> list[BinaryExpression]:
|
|
422
|
-
"""
|
|
423
|
-
Return the filter criteria for the given endpoint_id and application_name.
|
|
424
|
-
Note: the table object must include the relevant columns:
|
|
425
|
-
`endpoint_id` and `application_name`.
|
|
426
|
-
"""
|
|
427
|
-
criteria = [table.endpoint_id == endpoint_id]
|
|
428
|
-
if application_name is not None:
|
|
429
|
-
criteria.append(table.application_name == application_name)
|
|
430
|
-
return criteria
|
|
431
|
-
|
|
432
|
-
def get_last_analyzed(self, endpoint_id: str, application_name: str) -> int:
|
|
433
|
-
"""
|
|
434
|
-
Get the last analyzed time for the provided model endpoint and application.
|
|
435
|
-
|
|
436
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
437
|
-
:param application_name: Registered application name.
|
|
438
|
-
|
|
439
|
-
:return: Timestamp as a Unix time.
|
|
440
|
-
:raise: MLRunNotFoundError if last analyzed value is not found.
|
|
441
|
-
"""
|
|
442
|
-
monitoring_schedule_record = self._get(
|
|
443
|
-
table=self.MonitoringSchedulesTable,
|
|
444
|
-
criteria=self._get_filter_criteria(
|
|
445
|
-
table=self.MonitoringSchedulesTable,
|
|
446
|
-
endpoint_id=endpoint_id,
|
|
447
|
-
application_name=application_name,
|
|
448
|
-
),
|
|
449
|
-
)
|
|
450
|
-
if not monitoring_schedule_record:
|
|
451
|
-
raise mlrun.errors.MLRunNotFoundError(
|
|
452
|
-
f"No last analyzed value has been found for {application_name} "
|
|
453
|
-
f"that processes model endpoint {endpoint_id}"
|
|
454
|
-
)
|
|
455
|
-
return monitoring_schedule_record.last_analyzed
|
|
456
|
-
|
|
457
|
-
def update_last_analyzed(
|
|
458
|
-
self, endpoint_id: str, application_name: str, last_analyzed: int
|
|
459
|
-
):
|
|
460
|
-
"""
|
|
461
|
-
Update the last analyzed time for the provided model endpoint and application.
|
|
462
|
-
|
|
463
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
464
|
-
:param application_name: Registered application name.
|
|
465
|
-
:param last_analyzed: Timestamp as a Unix time that represents the last analyzed time of a certain
|
|
466
|
-
application and model endpoint.
|
|
467
|
-
"""
|
|
468
|
-
criteria = self._get_filter_criteria(
|
|
469
|
-
table=self.MonitoringSchedulesTable,
|
|
470
|
-
endpoint_id=endpoint_id,
|
|
471
|
-
application_name=application_name,
|
|
472
|
-
)
|
|
473
|
-
monitoring_schedule_record = self._get(
|
|
474
|
-
table=self.MonitoringSchedulesTable, criteria=criteria
|
|
475
|
-
)
|
|
476
|
-
if not monitoring_schedule_record:
|
|
477
|
-
# Add a new record with last analyzed value
|
|
478
|
-
self._write(
|
|
479
|
-
table_name=mm_schemas.FileTargetKind.MONITORING_SCHEDULES,
|
|
480
|
-
event={
|
|
481
|
-
mm_schemas.SchedulingKeys.UID: uuid.uuid4().hex,
|
|
482
|
-
mm_schemas.SchedulingKeys.APPLICATION_NAME: application_name,
|
|
483
|
-
mm_schemas.SchedulingKeys.ENDPOINT_ID: endpoint_id,
|
|
484
|
-
mm_schemas.SchedulingKeys.LAST_ANALYZED: last_analyzed,
|
|
485
|
-
},
|
|
486
|
-
)
|
|
487
|
-
|
|
488
|
-
self._update(
|
|
489
|
-
attributes={mm_schemas.SchedulingKeys.LAST_ANALYZED: last_analyzed},
|
|
490
|
-
table=self.MonitoringSchedulesTable,
|
|
491
|
-
criteria=criteria,
|
|
492
|
-
)
|
|
493
|
-
|
|
494
|
-
def _delete_last_analyzed(
|
|
495
|
-
self, endpoint_id: str, application_name: typing.Optional[str] = None
|
|
496
|
-
) -> None:
|
|
497
|
-
criteria = self._get_filter_criteria(
|
|
498
|
-
table=self.MonitoringSchedulesTable,
|
|
499
|
-
endpoint_id=endpoint_id,
|
|
500
|
-
application_name=application_name,
|
|
501
|
-
)
|
|
502
|
-
# Delete the model endpoint record using sqlalchemy ORM
|
|
503
|
-
self._delete(table=self.MonitoringSchedulesTable, criteria=criteria)
|
|
504
|
-
|
|
505
|
-
def _delete_application_result(
|
|
506
|
-
self, endpoint_id: str, application_name: typing.Optional[str] = None
|
|
507
|
-
) -> None:
|
|
508
|
-
criteria = self._get_filter_criteria(
|
|
509
|
-
table=self.application_results_table,
|
|
510
|
-
endpoint_id=endpoint_id,
|
|
511
|
-
application_name=application_name,
|
|
512
|
-
)
|
|
513
|
-
# Delete the relevant records from the results table
|
|
514
|
-
self._delete(table=self.application_results_table, criteria=criteria)
|
|
515
|
-
|
|
516
|
-
def _delete_application_metrics(
|
|
517
|
-
self, endpoint_id: str, application_name: typing.Optional[str] = None
|
|
518
|
-
) -> None:
|
|
519
|
-
criteria = self._get_filter_criteria(
|
|
520
|
-
table=self.application_metrics_table,
|
|
521
|
-
endpoint_id=endpoint_id,
|
|
522
|
-
application_name=application_name,
|
|
523
|
-
)
|
|
524
|
-
# Delete the relevant records from the metrics table
|
|
525
|
-
self._delete(table=self.application_metrics_table, criteria=criteria)
|
|
526
|
-
|
|
527
327
|
def _create_tables_if_not_exist(self):
|
|
528
328
|
self._init_tables()
|
|
529
329
|
|
|
@@ -593,12 +393,6 @@ class SQLStoreBase(StoreBase):
|
|
|
593
393
|
endpoint_id=endpoint_id,
|
|
594
394
|
project=self.project,
|
|
595
395
|
)
|
|
596
|
-
# Delete last analyzed records
|
|
597
|
-
self._delete_last_analyzed(endpoint_id=endpoint_id)
|
|
598
|
-
|
|
599
|
-
# Delete application results and metrics records
|
|
600
|
-
self._delete_application_result(endpoint_id=endpoint_id)
|
|
601
|
-
self._delete_application_metrics(endpoint_id=endpoint_id)
|
|
602
396
|
|
|
603
397
|
# Delete model endpoint record
|
|
604
398
|
self.delete_model_endpoint(endpoint_id=endpoint_id)
|
|
@@ -612,48 +406,3 @@ class SQLStoreBase(StoreBase):
|
|
|
612
406
|
"Successfully deleted model monitoring endpoints resources from the SQL tables",
|
|
613
407
|
project=self.project,
|
|
614
408
|
)
|
|
615
|
-
|
|
616
|
-
def get_model_endpoint_metrics(
|
|
617
|
-
self, endpoint_id: str, type: mm_schemas.ModelEndpointMonitoringMetricType
|
|
618
|
-
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
619
|
-
"""
|
|
620
|
-
Fetch the model endpoint metrics or results (according to `type`) for the
|
|
621
|
-
requested endpoint.
|
|
622
|
-
"""
|
|
623
|
-
logger.debug(
|
|
624
|
-
"Fetching metrics for model endpoint",
|
|
625
|
-
project=self.project,
|
|
626
|
-
endpoint_id=endpoint_id,
|
|
627
|
-
type=type,
|
|
628
|
-
)
|
|
629
|
-
if type == mm_schemas.ModelEndpointMonitoringMetricType.METRIC:
|
|
630
|
-
table = self.application_metrics_table
|
|
631
|
-
name_col = mm_schemas.MetricData.METRIC_NAME
|
|
632
|
-
else:
|
|
633
|
-
table = self.application_results_table
|
|
634
|
-
name_col = mm_schemas.ResultData.RESULT_NAME
|
|
635
|
-
|
|
636
|
-
# Note: the block below does not use self._get, as we need here all the
|
|
637
|
-
# results, not only `one_or_none`.
|
|
638
|
-
with sqlalchemy.orm.Session(self.engine) as session:
|
|
639
|
-
metric_rows = (
|
|
640
|
-
session.query(table) # pyright: ignore[reportOptionalCall]
|
|
641
|
-
.filter(table.endpoint_id == endpoint_id)
|
|
642
|
-
.all()
|
|
643
|
-
)
|
|
644
|
-
|
|
645
|
-
return [
|
|
646
|
-
mm_schemas.ModelEndpointMonitoringMetric(
|
|
647
|
-
project=self.project,
|
|
648
|
-
app=metric_row.application_name,
|
|
649
|
-
type=type,
|
|
650
|
-
name=getattr(metric_row, name_col),
|
|
651
|
-
full_name=mlrun.model_monitoring.helpers._compose_full_name(
|
|
652
|
-
project=self.project,
|
|
653
|
-
app=metric_row.application_name,
|
|
654
|
-
type=type,
|
|
655
|
-
name=getattr(metric_row, name_col),
|
|
656
|
-
),
|
|
657
|
-
)
|
|
658
|
-
for metric_row in metric_rows
|
|
659
|
-
]
|
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
import json
|
|
16
16
|
import typing
|
|
17
17
|
from dataclasses import dataclass
|
|
18
|
-
from http import HTTPStatus
|
|
19
18
|
|
|
20
19
|
import v3io.dataplane
|
|
21
20
|
import v3io.dataplane.output
|
|
@@ -34,14 +33,6 @@ fields_to_encode_decode = [
|
|
|
34
33
|
mm_schemas.EventFieldType.CURRENT_STATS,
|
|
35
34
|
]
|
|
36
35
|
|
|
37
|
-
_METRIC_FIELDS: list[str] = [
|
|
38
|
-
mm_schemas.WriterEvent.APPLICATION_NAME.value,
|
|
39
|
-
mm_schemas.MetricData.METRIC_NAME.value,
|
|
40
|
-
mm_schemas.MetricData.METRIC_VALUE.value,
|
|
41
|
-
mm_schemas.WriterEvent.START_INFER_TIME.value,
|
|
42
|
-
mm_schemas.WriterEvent.END_INFER_TIME.value,
|
|
43
|
-
]
|
|
44
|
-
|
|
45
36
|
|
|
46
37
|
class SchemaField(typing.TypedDict):
|
|
47
38
|
name: str
|
|
@@ -55,37 +46,6 @@ class SchemaParams:
|
|
|
55
46
|
fields: list[SchemaField]
|
|
56
47
|
|
|
57
48
|
|
|
58
|
-
_RESULT_SCHEMA: list[SchemaField] = [
|
|
59
|
-
SchemaField(
|
|
60
|
-
name=mm_schemas.ResultData.RESULT_NAME,
|
|
61
|
-
type=mm_schemas.GrafanaColumnType.STRING,
|
|
62
|
-
nullable=False,
|
|
63
|
-
)
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
_METRIC_SCHEMA: list[SchemaField] = [
|
|
67
|
-
SchemaField(
|
|
68
|
-
name=mm_schemas.WriterEvent.APPLICATION_NAME,
|
|
69
|
-
type=mm_schemas.GrafanaColumnType.STRING,
|
|
70
|
-
nullable=False,
|
|
71
|
-
),
|
|
72
|
-
SchemaField(
|
|
73
|
-
name=mm_schemas.MetricData.METRIC_NAME,
|
|
74
|
-
type=mm_schemas.GrafanaColumnType.STRING,
|
|
75
|
-
nullable=False,
|
|
76
|
-
),
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
_KIND_TO_SCHEMA_PARAMS: dict[mm_schemas.WriterEventKind, SchemaParams] = {
|
|
81
|
-
mm_schemas.WriterEventKind.RESULT: SchemaParams(
|
|
82
|
-
key=mm_schemas.WriterEvent.APPLICATION_NAME, fields=_RESULT_SCHEMA
|
|
83
|
-
),
|
|
84
|
-
mm_schemas.WriterEventKind.METRIC: SchemaParams(
|
|
85
|
-
key="metric_id", fields=_METRIC_SCHEMA
|
|
86
|
-
),
|
|
87
|
-
}
|
|
88
|
-
|
|
89
49
|
_EXCLUDE_SCHEMA_FILTER_EXPRESSION = '__name!=".#schema"'
|
|
90
50
|
|
|
91
51
|
|
|
@@ -227,12 +187,12 @@ class KVStoreBase(StoreBase):
|
|
|
227
187
|
|
|
228
188
|
def list_model_endpoints(
|
|
229
189
|
self,
|
|
230
|
-
model: str = None,
|
|
231
|
-
function: str = None,
|
|
232
|
-
labels: list[str] = None,
|
|
233
|
-
top_level: bool = None,
|
|
234
|
-
uids: list = None,
|
|
235
|
-
include_stats: bool = None,
|
|
190
|
+
model: typing.Optional[str] = None,
|
|
191
|
+
function: typing.Optional[str] = None,
|
|
192
|
+
labels: typing.Optional[list[str]] = None,
|
|
193
|
+
top_level: typing.Optional[bool] = None,
|
|
194
|
+
uids: typing.Optional[list] = None,
|
|
195
|
+
include_stats: typing.Optional[bool] = None,
|
|
236
196
|
) -> list[dict[str, typing.Any]]:
|
|
237
197
|
# # Initialize an empty model endpoints list
|
|
238
198
|
endpoint_list = []
|
|
@@ -339,135 +299,6 @@ class KVStoreBase(StoreBase):
|
|
|
339
299
|
raise_for_status=v3io.dataplane.RaiseForStatus.never,
|
|
340
300
|
)
|
|
341
301
|
|
|
342
|
-
@staticmethod
|
|
343
|
-
def _get_results_table_path(endpoint_id: str) -> str:
|
|
344
|
-
return endpoint_id
|
|
345
|
-
|
|
346
|
-
@staticmethod
|
|
347
|
-
def _get_metrics_table_path(endpoint_id: str) -> str:
|
|
348
|
-
return f"{endpoint_id}_metrics"
|
|
349
|
-
|
|
350
|
-
def write_application_event(
|
|
351
|
-
self,
|
|
352
|
-
event: dict[str, typing.Any],
|
|
353
|
-
kind: mm_schemas.WriterEventKind = mm_schemas.WriterEventKind.RESULT,
|
|
354
|
-
) -> None:
|
|
355
|
-
"""
|
|
356
|
-
Write a new application event in the target table.
|
|
357
|
-
|
|
358
|
-
:param event: An event dictionary that represents the application result, should be corresponded to the
|
|
359
|
-
schema defined in the :py:class:`~mlrun.common.schemas.model_monitoring.constants.WriterEvent`
|
|
360
|
-
object.
|
|
361
|
-
:param kind: The type of the event, can be either "result" or "metric".
|
|
362
|
-
"""
|
|
363
|
-
|
|
364
|
-
container = self.get_v3io_monitoring_apps_container(project_name=self.project)
|
|
365
|
-
endpoint_id = event.pop(mm_schemas.WriterEvent.ENDPOINT_ID)
|
|
366
|
-
|
|
367
|
-
if kind == mm_schemas.WriterEventKind.METRIC:
|
|
368
|
-
table_path = self._get_metrics_table_path(endpoint_id)
|
|
369
|
-
key = f"{event[mm_schemas.WriterEvent.APPLICATION_NAME]}.{event[mm_schemas.MetricData.METRIC_NAME]}"
|
|
370
|
-
attributes = {event_key: event[event_key] for event_key in _METRIC_FIELDS}
|
|
371
|
-
elif kind == mm_schemas.WriterEventKind.RESULT:
|
|
372
|
-
table_path = self._get_results_table_path(endpoint_id)
|
|
373
|
-
key = event.pop(mm_schemas.WriterEvent.APPLICATION_NAME)
|
|
374
|
-
metric_name = event.pop(mm_schemas.ResultData.RESULT_NAME)
|
|
375
|
-
attributes = {metric_name: self._encode_field(json.dumps(event))}
|
|
376
|
-
else:
|
|
377
|
-
raise ValueError(f"Invalid {kind = }")
|
|
378
|
-
|
|
379
|
-
self.client.kv.update(
|
|
380
|
-
container=container,
|
|
381
|
-
table_path=table_path,
|
|
382
|
-
key=key,
|
|
383
|
-
attributes=attributes,
|
|
384
|
-
)
|
|
385
|
-
|
|
386
|
-
schema_file = self.client.kv.new_cursor(
|
|
387
|
-
container=container,
|
|
388
|
-
table_path=table_path,
|
|
389
|
-
filter_expression='__name==".#schema"',
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
if not schema_file.all():
|
|
393
|
-
logger.info(
|
|
394
|
-
"Generating a new V3IO KV schema file",
|
|
395
|
-
container=container,
|
|
396
|
-
table_path=table_path,
|
|
397
|
-
)
|
|
398
|
-
self._generate_kv_schema(
|
|
399
|
-
container=container, table_path=table_path, kind=kind
|
|
400
|
-
)
|
|
401
|
-
logger.info("Updated V3IO KV successfully", key=key)
|
|
402
|
-
|
|
403
|
-
def _generate_kv_schema(
|
|
404
|
-
self, *, container: str, table_path: str, kind: mm_schemas.WriterEventKind
|
|
405
|
-
) -> None:
|
|
406
|
-
"""Generate V3IO KV schema file which will be used by the model monitoring applications dashboard in Grafana."""
|
|
407
|
-
schema_params = _KIND_TO_SCHEMA_PARAMS[kind]
|
|
408
|
-
res = self.client.kv.create_schema(
|
|
409
|
-
container=container,
|
|
410
|
-
table_path=table_path,
|
|
411
|
-
key=schema_params.key,
|
|
412
|
-
fields=schema_params.fields,
|
|
413
|
-
)
|
|
414
|
-
if res.status_code != HTTPStatus.OK:
|
|
415
|
-
raise mlrun.errors.MLRunBadRequestError(
|
|
416
|
-
f"Couldn't infer schema for endpoint {table_path} which is required for Grafana dashboards"
|
|
417
|
-
)
|
|
418
|
-
else:
|
|
419
|
-
logger.info("Generated V3IO KV schema successfully", table_path=table_path)
|
|
420
|
-
|
|
421
|
-
def get_last_analyzed(self, endpoint_id: str, application_name: str) -> int:
|
|
422
|
-
"""
|
|
423
|
-
Get the last analyzed time for the provided model endpoint and application.
|
|
424
|
-
|
|
425
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
426
|
-
:param application_name: Registered application name.
|
|
427
|
-
|
|
428
|
-
:return: Timestamp as a Unix time.
|
|
429
|
-
:raise: MLRunNotFoundError if last analyzed value is not found.
|
|
430
|
-
|
|
431
|
-
"""
|
|
432
|
-
try:
|
|
433
|
-
response = self.client.kv.get(
|
|
434
|
-
container=self._get_monitoring_schedules_container(
|
|
435
|
-
project_name=self.project
|
|
436
|
-
),
|
|
437
|
-
table_path=endpoint_id,
|
|
438
|
-
key=application_name,
|
|
439
|
-
)
|
|
440
|
-
return response.output.item[mm_schemas.SchedulingKeys.LAST_ANALYZED]
|
|
441
|
-
except v3io.dataplane.response.HttpResponseError as err:
|
|
442
|
-
if err.status_code == http.HTTPStatus.NOT_FOUND:
|
|
443
|
-
logger.debug("Last analyzed time not found", err=err)
|
|
444
|
-
raise mlrun.errors.MLRunNotFoundError(
|
|
445
|
-
f"No last analyzed value has been found for {application_name} "
|
|
446
|
-
f"that processes model endpoint {endpoint_id}",
|
|
447
|
-
)
|
|
448
|
-
logger.error("Error while getting last analyzed time", err=err)
|
|
449
|
-
raise err
|
|
450
|
-
|
|
451
|
-
def update_last_analyzed(
|
|
452
|
-
self, endpoint_id: str, application_name: str, last_analyzed: int
|
|
453
|
-
):
|
|
454
|
-
"""
|
|
455
|
-
Update the last analyzed time for the provided model endpoint and application.
|
|
456
|
-
|
|
457
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
458
|
-
:param application_name: Registered application name.
|
|
459
|
-
:param last_analyzed: Timestamp as a Unix time that represents the last analyzed time of a certain
|
|
460
|
-
application and model endpoint.
|
|
461
|
-
"""
|
|
462
|
-
self.client.kv.put(
|
|
463
|
-
container=self._get_monitoring_schedules_container(
|
|
464
|
-
project_name=self.project
|
|
465
|
-
),
|
|
466
|
-
table_path=endpoint_id,
|
|
467
|
-
key=application_name,
|
|
468
|
-
attributes={mm_schemas.SchedulingKeys.LAST_ANALYZED: last_analyzed},
|
|
469
|
-
)
|
|
470
|
-
|
|
471
302
|
def _generate_tsdb_paths(self) -> tuple[str, str]:
|
|
472
303
|
"""Generate a short path to the TSDB resources and a filtered path for the frames object
|
|
473
304
|
:return: A tuple of:
|
|
@@ -524,8 +355,8 @@ class KVStoreBase(StoreBase):
|
|
|
524
355
|
@staticmethod
|
|
525
356
|
def _build_kv_cursor_filter_expression(
|
|
526
357
|
project: str,
|
|
527
|
-
function: str = None,
|
|
528
|
-
model: str = None,
|
|
358
|
+
function: typing.Optional[str] = None,
|
|
359
|
+
model: typing.Optional[str] = None,
|
|
529
360
|
top_level: bool = False,
|
|
530
361
|
) -> str:
|
|
531
362
|
"""
|
|
@@ -631,96 +462,3 @@ class KVStoreBase(StoreBase):
|
|
|
631
462
|
@staticmethod
|
|
632
463
|
def _get_monitoring_schedules_container(project_name: str) -> str:
|
|
633
464
|
return f"users/pipelines/{project_name}/monitoring-schedules/functions"
|
|
634
|
-
|
|
635
|
-
def _extract_results_from_items(
|
|
636
|
-
self, app_items: list[dict[str, str]]
|
|
637
|
-
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
638
|
-
"""Assuming .#schema items are filtered out"""
|
|
639
|
-
metrics: list[mm_schemas.ModelEndpointMonitoringMetric] = []
|
|
640
|
-
for app_item in app_items:
|
|
641
|
-
app_name = app_item.pop("__name")
|
|
642
|
-
for result_name in app_item:
|
|
643
|
-
metrics.append(
|
|
644
|
-
mm_schemas.ModelEndpointMonitoringMetric(
|
|
645
|
-
project=self.project,
|
|
646
|
-
app=app_name,
|
|
647
|
-
type=mm_schemas.ModelEndpointMonitoringMetricType.RESULT,
|
|
648
|
-
name=result_name,
|
|
649
|
-
full_name=mm_schemas.model_endpoints._compose_full_name(
|
|
650
|
-
project=self.project, app=app_name, name=result_name
|
|
651
|
-
),
|
|
652
|
-
)
|
|
653
|
-
)
|
|
654
|
-
return metrics
|
|
655
|
-
|
|
656
|
-
def _extract_metrics_from_items(
|
|
657
|
-
self, result_items: list[dict[str, str]]
|
|
658
|
-
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
659
|
-
metrics: list[mm_schemas.ModelEndpointMonitoringMetric] = []
|
|
660
|
-
logger.debug("Result items", result_items=result_items)
|
|
661
|
-
for result_item in result_items:
|
|
662
|
-
app = result_item[mm_schemas.WriterEvent.APPLICATION_NAME]
|
|
663
|
-
name = result_item[mm_schemas.MetricData.METRIC_NAME]
|
|
664
|
-
metrics.append(
|
|
665
|
-
mm_schemas.ModelEndpointMonitoringMetric(
|
|
666
|
-
project=self.project,
|
|
667
|
-
app=app,
|
|
668
|
-
type=mm_schemas.ModelEndpointMonitoringMetricType.METRIC,
|
|
669
|
-
name=name,
|
|
670
|
-
full_name=mm_schemas.model_endpoints._compose_full_name(
|
|
671
|
-
project=self.project,
|
|
672
|
-
app=app,
|
|
673
|
-
name=name,
|
|
674
|
-
type=mm_schemas.ModelEndpointMonitoringMetricType.METRIC,
|
|
675
|
-
),
|
|
676
|
-
)
|
|
677
|
-
)
|
|
678
|
-
return metrics
|
|
679
|
-
|
|
680
|
-
def get_model_endpoint_metrics(
|
|
681
|
-
self, endpoint_id: str, type: mm_schemas.ModelEndpointMonitoringMetricType
|
|
682
|
-
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
683
|
-
"""Get model monitoring results and metrics on the endpoint"""
|
|
684
|
-
metrics: list[mm_schemas.ModelEndpointMonitoringMetric] = []
|
|
685
|
-
container = self.get_v3io_monitoring_apps_container(self.project)
|
|
686
|
-
if type == mm_schemas.ModelEndpointMonitoringMetricType.METRIC:
|
|
687
|
-
table_path = self._get_metrics_table_path(endpoint_id)
|
|
688
|
-
items_extractor = self._extract_metrics_from_items
|
|
689
|
-
elif type == mm_schemas.ModelEndpointMonitoringMetricType.RESULT:
|
|
690
|
-
table_path = self._get_results_table_path(endpoint_id)
|
|
691
|
-
items_extractor = self._extract_results_from_items
|
|
692
|
-
else:
|
|
693
|
-
raise ValueError(f"Invalid metric {type = }")
|
|
694
|
-
|
|
695
|
-
def scan(
|
|
696
|
-
marker: typing.Optional[str] = None,
|
|
697
|
-
) -> v3io.dataplane.response.Response:
|
|
698
|
-
# TODO: Use AIO client: `v3io.aio.dataplane.client.Client`
|
|
699
|
-
return self.client.kv.scan(
|
|
700
|
-
container=container,
|
|
701
|
-
table_path=table_path,
|
|
702
|
-
marker=marker,
|
|
703
|
-
filter_expression=_EXCLUDE_SCHEMA_FILTER_EXPRESSION,
|
|
704
|
-
)
|
|
705
|
-
|
|
706
|
-
try:
|
|
707
|
-
response = scan()
|
|
708
|
-
except v3io.dataplane.response.HttpResponseError as err:
|
|
709
|
-
if err.status_code == HTTPStatus.NOT_FOUND:
|
|
710
|
-
logger.warning(
|
|
711
|
-
f"Attempt getting {type}s - no data. Check the "
|
|
712
|
-
"project name, endpoint, or wait for the applications to start.",
|
|
713
|
-
container=container,
|
|
714
|
-
table_path=table_path,
|
|
715
|
-
)
|
|
716
|
-
return []
|
|
717
|
-
raise
|
|
718
|
-
|
|
719
|
-
while True:
|
|
720
|
-
output = typing.cast(v3io.dataplane.output.GetItemsOutput, response.output)
|
|
721
|
-
metrics.extend(items_extractor(output.items))
|
|
722
|
-
if output.last:
|
|
723
|
-
break
|
|
724
|
-
response = scan(marker=output.next_marker)
|
|
725
|
-
|
|
726
|
-
return metrics
|