mlrun 1.7.0rc37__py3-none-any.whl → 1.7.0rc39__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/alerts/alert.py +34 -30
- mlrun/common/schemas/alert.py +3 -0
- mlrun/common/schemas/model_monitoring/constants.py +4 -0
- mlrun/common/schemas/notification.py +4 -3
- mlrun/datastore/alibaba_oss.py +2 -2
- mlrun/datastore/azure_blob.py +124 -31
- mlrun/datastore/base.py +1 -1
- mlrun/datastore/dbfs_store.py +2 -2
- mlrun/datastore/google_cloud_storage.py +83 -20
- mlrun/datastore/s3.py +2 -2
- mlrun/datastore/sources.py +54 -0
- mlrun/datastore/targets.py +9 -53
- mlrun/db/httpdb.py +6 -1
- mlrun/errors.py +8 -0
- mlrun/execution.py +7 -0
- mlrun/feature_store/api.py +5 -0
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/retrieval/job.py +1 -0
- mlrun/model.py +29 -3
- mlrun/model_monitoring/api.py +9 -0
- mlrun/model_monitoring/applications/_application_steps.py +36 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +15 -13
- mlrun/model_monitoring/controller.py +15 -11
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +14 -11
- mlrun/model_monitoring/db/tsdb/base.py +121 -1
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +85 -47
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +100 -12
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +23 -1
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +214 -36
- mlrun/model_monitoring/helpers.py +16 -17
- mlrun/model_monitoring/stream_processing.py +68 -27
- mlrun/projects/operations.py +1 -1
- mlrun/projects/pipelines.py +19 -30
- mlrun/projects/project.py +76 -52
- mlrun/run.py +8 -6
- mlrun/runtimes/__init__.py +19 -8
- mlrun/runtimes/nuclio/api_gateway.py +9 -0
- mlrun/runtimes/nuclio/application/application.py +64 -9
- mlrun/runtimes/nuclio/function.py +1 -1
- mlrun/runtimes/pod.py +2 -2
- mlrun/runtimes/remotesparkjob.py +2 -5
- mlrun/runtimes/sparkjob/spark3job.py +7 -9
- mlrun/serving/v2_serving.py +1 -0
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/helpers.py +21 -0
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/METADATA +14 -11
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/RECORD +52 -52
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/WHEEL +1 -1
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc37.dist-info → mlrun-1.7.0rc39.dist-info}/top_level.txt +0 -0
|
@@ -17,6 +17,8 @@ from dataclasses import dataclass
|
|
|
17
17
|
from io import StringIO
|
|
18
18
|
from typing import Optional, Union
|
|
19
19
|
|
|
20
|
+
import taosws
|
|
21
|
+
|
|
20
22
|
import mlrun.common.schemas.model_monitoring as mm_schemas
|
|
21
23
|
import mlrun.common.types
|
|
22
24
|
|
|
@@ -28,6 +30,9 @@ class _TDEngineColumnType:
|
|
|
28
30
|
self.data_type = data_type
|
|
29
31
|
self.length = length
|
|
30
32
|
|
|
33
|
+
def values_to_column(self, values):
|
|
34
|
+
raise NotImplementedError()
|
|
35
|
+
|
|
31
36
|
def __str__(self):
|
|
32
37
|
if self.length is not None:
|
|
33
38
|
return f"{self.data_type}({self.length})"
|
|
@@ -44,6 +49,26 @@ class _TDEngineColumn(mlrun.common.types.StrEnum):
|
|
|
44
49
|
BINARY_10000 = _TDEngineColumnType("BINARY", 10000)
|
|
45
50
|
|
|
46
51
|
|
|
52
|
+
def values_to_column(values, column_type):
|
|
53
|
+
if column_type == _TDEngineColumn.TIMESTAMP:
|
|
54
|
+
timestamps = [round(timestamp.timestamp() * 1000) for timestamp in values]
|
|
55
|
+
return taosws.millis_timestamps_to_column(timestamps)
|
|
56
|
+
if column_type == _TDEngineColumn.FLOAT:
|
|
57
|
+
return taosws.floats_to_column(values)
|
|
58
|
+
if column_type == _TDEngineColumn.INT:
|
|
59
|
+
return taosws.ints_to_column(values)
|
|
60
|
+
if column_type == _TDEngineColumn.BINARY_40:
|
|
61
|
+
return taosws.binary_to_column(values)
|
|
62
|
+
if column_type == _TDEngineColumn.BINARY_64:
|
|
63
|
+
return taosws.binary_to_column(values)
|
|
64
|
+
if column_type == _TDEngineColumn.BINARY_10000:
|
|
65
|
+
return taosws.binary_to_column(values)
|
|
66
|
+
|
|
67
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
68
|
+
f"unsupported column type '{column_type}'"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
47
72
|
@dataclass
|
|
48
73
|
class TDEngineSchema:
|
|
49
74
|
"""
|
|
@@ -55,13 +80,14 @@ class TDEngineSchema:
|
|
|
55
80
|
def __init__(
|
|
56
81
|
self,
|
|
57
82
|
super_table: str,
|
|
58
|
-
columns: dict[str,
|
|
83
|
+
columns: dict[str, _TDEngineColumn],
|
|
59
84
|
tags: dict[str, str],
|
|
85
|
+
database: Optional[str] = None,
|
|
60
86
|
):
|
|
61
87
|
self.super_table = super_table
|
|
62
88
|
self.columns = columns
|
|
63
89
|
self.tags = tags
|
|
64
|
-
self.database = _MODEL_MONITORING_DATABASE
|
|
90
|
+
self.database = database or _MODEL_MONITORING_DATABASE
|
|
65
91
|
|
|
66
92
|
def _create_super_table_query(self) -> str:
|
|
67
93
|
columns = ", ".join(f"{col} {val}" for col, val in self.columns.items())
|
|
@@ -83,11 +109,23 @@ class TDEngineSchema:
|
|
|
83
109
|
|
|
84
110
|
def _insert_subtable_query(
|
|
85
111
|
self,
|
|
112
|
+
connection: taosws.Connection,
|
|
86
113
|
subtable: str,
|
|
87
114
|
values: dict[str, Union[str, int, float, datetime.datetime]],
|
|
88
|
-
) ->
|
|
89
|
-
|
|
90
|
-
|
|
115
|
+
) -> taosws.TaosStmt:
|
|
116
|
+
stmt = connection.statement()
|
|
117
|
+
question_marks = ", ".join("?" * len(self.columns))
|
|
118
|
+
stmt.prepare(f"INSERT INTO ? VALUES ({question_marks});")
|
|
119
|
+
stmt.set_tbname_tags(subtable, [])
|
|
120
|
+
|
|
121
|
+
bind_params = []
|
|
122
|
+
|
|
123
|
+
for col_name, col_type in self.columns.items():
|
|
124
|
+
val = values[col_name]
|
|
125
|
+
bind_params.append(values_to_column([val], col_type))
|
|
126
|
+
|
|
127
|
+
stmt.bind_param(bind_params)
|
|
128
|
+
return stmt
|
|
91
129
|
|
|
92
130
|
def _delete_subtable_query(
|
|
93
131
|
self,
|
|
@@ -188,53 +226,53 @@ class TDEngineSchema:
|
|
|
188
226
|
|
|
189
227
|
@dataclass
|
|
190
228
|
class AppResultTable(TDEngineSchema):
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
database = _MODEL_MONITORING_DATABASE
|
|
229
|
+
def __init__(self, database: Optional[str] = None):
|
|
230
|
+
super_table = mm_schemas.TDEngineSuperTables.APP_RESULTS
|
|
231
|
+
columns = {
|
|
232
|
+
mm_schemas.WriterEvent.END_INFER_TIME: _TDEngineColumn.TIMESTAMP,
|
|
233
|
+
mm_schemas.WriterEvent.START_INFER_TIME: _TDEngineColumn.TIMESTAMP,
|
|
234
|
+
mm_schemas.ResultData.RESULT_VALUE: _TDEngineColumn.FLOAT,
|
|
235
|
+
mm_schemas.ResultData.RESULT_STATUS: _TDEngineColumn.INT,
|
|
236
|
+
}
|
|
237
|
+
tags = {
|
|
238
|
+
mm_schemas.EventFieldType.PROJECT: _TDEngineColumn.BINARY_64,
|
|
239
|
+
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
240
|
+
mm_schemas.WriterEvent.APPLICATION_NAME: _TDEngineColumn.BINARY_64,
|
|
241
|
+
mm_schemas.ResultData.RESULT_NAME: _TDEngineColumn.BINARY_64,
|
|
242
|
+
mm_schemas.ResultData.RESULT_KIND: _TDEngineColumn.INT,
|
|
243
|
+
}
|
|
244
|
+
super().__init__(super_table, columns, tags, database)
|
|
208
245
|
|
|
209
246
|
|
|
210
247
|
@dataclass
|
|
211
248
|
class Metrics(TDEngineSchema):
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
249
|
+
def __init__(self, database: Optional[str] = None):
|
|
250
|
+
super_table = mm_schemas.TDEngineSuperTables.METRICS
|
|
251
|
+
columns = {
|
|
252
|
+
mm_schemas.WriterEvent.END_INFER_TIME: _TDEngineColumn.TIMESTAMP,
|
|
253
|
+
mm_schemas.WriterEvent.START_INFER_TIME: _TDEngineColumn.TIMESTAMP,
|
|
254
|
+
mm_schemas.MetricData.METRIC_VALUE: _TDEngineColumn.FLOAT,
|
|
255
|
+
}
|
|
256
|
+
tags = {
|
|
257
|
+
mm_schemas.EventFieldType.PROJECT: _TDEngineColumn.BINARY_64,
|
|
258
|
+
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
259
|
+
mm_schemas.WriterEvent.APPLICATION_NAME: _TDEngineColumn.BINARY_64,
|
|
260
|
+
mm_schemas.MetricData.METRIC_NAME: _TDEngineColumn.BINARY_64,
|
|
261
|
+
}
|
|
262
|
+
super().__init__(super_table, columns, tags, database)
|
|
226
263
|
|
|
227
264
|
|
|
228
265
|
@dataclass
|
|
229
266
|
class Predictions(TDEngineSchema):
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
267
|
+
def __init__(self, database: Optional[str] = None):
|
|
268
|
+
super_table = mm_schemas.TDEngineSuperTables.PREDICTIONS
|
|
269
|
+
columns = {
|
|
270
|
+
mm_schemas.EventFieldType.TIME: _TDEngineColumn.TIMESTAMP,
|
|
271
|
+
mm_schemas.EventFieldType.LATENCY: _TDEngineColumn.FLOAT,
|
|
272
|
+
mm_schemas.EventKeyMetrics.CUSTOM_METRICS: _TDEngineColumn.BINARY_10000,
|
|
273
|
+
}
|
|
274
|
+
tags = {
|
|
275
|
+
mm_schemas.EventFieldType.PROJECT: _TDEngineColumn.BINARY_64,
|
|
276
|
+
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
277
|
+
}
|
|
278
|
+
super().__init__(super_table, columns, tags, database)
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import typing
|
|
16
16
|
from datetime import datetime
|
|
17
|
+
from typing import Union
|
|
17
18
|
|
|
18
19
|
import pandas as pd
|
|
19
20
|
import taosws
|
|
@@ -57,15 +58,26 @@ class TDEngineConnector(TSDBConnector):
|
|
|
57
58
|
except taosws.QueryError:
|
|
58
59
|
# Database already exists
|
|
59
60
|
pass
|
|
60
|
-
|
|
61
|
+
try:
|
|
62
|
+
conn.execute(f"USE {self.database}")
|
|
63
|
+
except taosws.QueryError as e:
|
|
64
|
+
raise mlrun.errors.MLRunTSDBConnectionFailure(
|
|
65
|
+
f"Failed to use TDEngine database {self.database}, {mlrun.errors.err_to_str(e)}"
|
|
66
|
+
)
|
|
61
67
|
return conn
|
|
62
68
|
|
|
63
69
|
def _init_super_tables(self):
|
|
64
70
|
"""Initialize the super tables for the TSDB."""
|
|
65
71
|
self.tables = {
|
|
66
|
-
mm_schemas.TDEngineSuperTables.APP_RESULTS: tdengine_schemas.AppResultTable(
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
mm_schemas.TDEngineSuperTables.APP_RESULTS: tdengine_schemas.AppResultTable(
|
|
73
|
+
self.database
|
|
74
|
+
),
|
|
75
|
+
mm_schemas.TDEngineSuperTables.METRICS: tdengine_schemas.Metrics(
|
|
76
|
+
self.database
|
|
77
|
+
),
|
|
78
|
+
mm_schemas.TDEngineSuperTables.PREDICTIONS: tdengine_schemas.Predictions(
|
|
79
|
+
self.database
|
|
80
|
+
),
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
def create_tables(self):
|
|
@@ -96,6 +108,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
96
108
|
table_name = (
|
|
97
109
|
f"{table_name}_" f"{event[mm_schemas.ResultData.RESULT_NAME]}"
|
|
98
110
|
).replace("-", "_")
|
|
111
|
+
event.pop(mm_schemas.ResultData.CURRENT_STATS, None)
|
|
99
112
|
|
|
100
113
|
else:
|
|
101
114
|
# Write a new metric
|
|
@@ -104,14 +117,30 @@ class TDEngineConnector(TSDBConnector):
|
|
|
104
117
|
f"{table_name}_" f"{event[mm_schemas.MetricData.METRIC_NAME]}"
|
|
105
118
|
).replace("-", "_")
|
|
106
119
|
|
|
120
|
+
# Convert the datetime strings to datetime objects
|
|
121
|
+
event[mm_schemas.WriterEvent.END_INFER_TIME] = self._convert_to_datetime(
|
|
122
|
+
val=event[mm_schemas.WriterEvent.END_INFER_TIME]
|
|
123
|
+
)
|
|
124
|
+
event[mm_schemas.WriterEvent.START_INFER_TIME] = self._convert_to_datetime(
|
|
125
|
+
val=event[mm_schemas.WriterEvent.START_INFER_TIME]
|
|
126
|
+
)
|
|
127
|
+
|
|
107
128
|
create_table_query = table._create_subtable_query(
|
|
108
129
|
subtable=table_name, values=event
|
|
109
130
|
)
|
|
110
131
|
self._connection.execute(create_table_query)
|
|
111
|
-
|
|
112
|
-
|
|
132
|
+
|
|
133
|
+
insert_statement = table._insert_subtable_query(
|
|
134
|
+
self._connection,
|
|
135
|
+
subtable=table_name,
|
|
136
|
+
values=event,
|
|
113
137
|
)
|
|
114
|
-
|
|
138
|
+
insert_statement.add_batch()
|
|
139
|
+
insert_statement.execute()
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def _convert_to_datetime(val: typing.Union[str, datetime]) -> datetime:
|
|
143
|
+
return datetime.fromisoformat(val) if isinstance(val, str) else val
|
|
115
144
|
|
|
116
145
|
def apply_monitoring_stream_steps(self, graph):
|
|
117
146
|
"""
|
|
@@ -156,6 +185,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
156
185
|
after="ProcessBeforeTDEngine",
|
|
157
186
|
)
|
|
158
187
|
|
|
188
|
+
def handle_model_error(self, graph, **kwargs) -> None:
|
|
189
|
+
pass
|
|
190
|
+
|
|
159
191
|
def delete_tsdb_resources(self):
|
|
160
192
|
"""
|
|
161
193
|
Delete all project resources in the TSDB connector, such as model endpoints data and drift results.
|
|
@@ -246,11 +278,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
246
278
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
247
279
|
f"Failed to query table {table} in database {self.database}, {str(e)}"
|
|
248
280
|
)
|
|
249
|
-
columns = []
|
|
250
|
-
for column in query_result.fields:
|
|
251
|
-
columns.append(column.name())
|
|
252
281
|
|
|
253
|
-
|
|
282
|
+
df_columns = [field.name() for field in query_result.fields]
|
|
283
|
+
return pd.DataFrame(query_result, columns=df_columns)
|
|
254
284
|
|
|
255
285
|
def read_metrics_data(
|
|
256
286
|
self,
|
|
@@ -274,13 +304,22 @@ class TDEngineConnector(TSDBConnector):
|
|
|
274
304
|
],
|
|
275
305
|
],
|
|
276
306
|
]:
|
|
307
|
+
timestamp_column = mm_schemas.WriterEvent.END_INFER_TIME
|
|
308
|
+
columns = [timestamp_column, mm_schemas.WriterEvent.APPLICATION_NAME]
|
|
277
309
|
if type == "metrics":
|
|
278
310
|
table = mm_schemas.TDEngineSuperTables.METRICS
|
|
279
311
|
name = mm_schemas.MetricData.METRIC_NAME
|
|
312
|
+
columns += [name, mm_schemas.MetricData.METRIC_VALUE]
|
|
280
313
|
df_handler = self.df_to_metrics_values
|
|
281
314
|
elif type == "results":
|
|
282
315
|
table = mm_schemas.TDEngineSuperTables.APP_RESULTS
|
|
283
316
|
name = mm_schemas.ResultData.RESULT_NAME
|
|
317
|
+
columns += [
|
|
318
|
+
name,
|
|
319
|
+
mm_schemas.ResultData.RESULT_VALUE,
|
|
320
|
+
mm_schemas.ResultData.RESULT_STATUS,
|
|
321
|
+
mm_schemas.ResultData.RESULT_KIND,
|
|
322
|
+
]
|
|
284
323
|
df_handler = self.df_to_results_values
|
|
285
324
|
else:
|
|
286
325
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -300,7 +339,8 @@ class TDEngineConnector(TSDBConnector):
|
|
|
300
339
|
start=start,
|
|
301
340
|
end=end,
|
|
302
341
|
filter_query=filter_query,
|
|
303
|
-
timestamp_column=
|
|
342
|
+
timestamp_column=timestamp_column,
|
|
343
|
+
columns=columns,
|
|
304
344
|
)
|
|
305
345
|
|
|
306
346
|
df[mm_schemas.WriterEvent.END_INFER_TIME] = pd.to_datetime(
|
|
@@ -377,6 +417,54 @@ class TDEngineConnector(TSDBConnector):
|
|
|
377
417
|
), # pyright: ignore[reportArgumentType]
|
|
378
418
|
)
|
|
379
419
|
|
|
420
|
+
def get_last_request(
|
|
421
|
+
self,
|
|
422
|
+
endpoint_ids: Union[str, list[str]],
|
|
423
|
+
start: Union[datetime, str] = "0",
|
|
424
|
+
end: Union[datetime, str] = "now",
|
|
425
|
+
) -> pd.DataFrame:
|
|
426
|
+
pass
|
|
427
|
+
|
|
428
|
+
def get_drift_status(
|
|
429
|
+
self,
|
|
430
|
+
endpoint_ids: Union[str, list[str]],
|
|
431
|
+
start: Union[datetime, str] = "now-24h",
|
|
432
|
+
end: Union[datetime, str] = "now",
|
|
433
|
+
) -> pd.DataFrame:
|
|
434
|
+
pass
|
|
435
|
+
|
|
436
|
+
def get_metrics_metadata(
|
|
437
|
+
self,
|
|
438
|
+
endpoint_id: str,
|
|
439
|
+
start: Union[datetime, str] = "0",
|
|
440
|
+
end: Union[datetime, str] = "now",
|
|
441
|
+
) -> pd.DataFrame:
|
|
442
|
+
pass
|
|
443
|
+
|
|
444
|
+
def get_results_metadata(
|
|
445
|
+
self,
|
|
446
|
+
endpoint_id: str,
|
|
447
|
+
start: Union[datetime, str] = "0",
|
|
448
|
+
end: Union[datetime, str] = "now",
|
|
449
|
+
) -> pd.DataFrame:
|
|
450
|
+
pass
|
|
451
|
+
|
|
452
|
+
def get_error_count(
|
|
453
|
+
self,
|
|
454
|
+
endpoint_ids: Union[str, list[str]],
|
|
455
|
+
start: Union[datetime, str] = "0",
|
|
456
|
+
end: Union[datetime, str] = "now",
|
|
457
|
+
) -> pd.DataFrame:
|
|
458
|
+
pass
|
|
459
|
+
|
|
460
|
+
def get_avg_latency(
|
|
461
|
+
self,
|
|
462
|
+
endpoint_ids: Union[str, list[str]],
|
|
463
|
+
start: Union[datetime, str] = "0",
|
|
464
|
+
end: Union[datetime, str] = "now",
|
|
465
|
+
) -> pd.DataFrame:
|
|
466
|
+
pass
|
|
467
|
+
|
|
380
468
|
# Note: this function serves as a reference for checking the TSDB for the existence of a metric.
|
|
381
469
|
#
|
|
382
470
|
# def read_prediction_metric_for_endpoint_if_exists(
|
|
@@ -11,7 +11,7 @@
|
|
|
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
|
+
from datetime import datetime
|
|
15
15
|
from typing import Any
|
|
16
16
|
|
|
17
17
|
import mlrun.feature_store.steps
|
|
@@ -20,6 +20,7 @@ from mlrun.common.schemas.model_monitoring import (
|
|
|
20
20
|
EventKeyMetrics,
|
|
21
21
|
EventLiveStats,
|
|
22
22
|
)
|
|
23
|
+
from mlrun.utils import logger
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def _normalize_dict_for_v3io_frames(event: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -134,3 +135,24 @@ class FilterAndUnpackKeys(mlrun.feature_store.steps.MapClass):
|
|
|
134
135
|
else:
|
|
135
136
|
unpacked[key] = new_event[key]
|
|
136
137
|
return unpacked if unpacked else None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class ErrorExtractor(mlrun.feature_store.steps.MapClass):
|
|
141
|
+
def __init__(self, **kwargs):
|
|
142
|
+
"""
|
|
143
|
+
Prepare the event for insertion into the errors TSDB table.
|
|
144
|
+
"""
|
|
145
|
+
super().__init__(**kwargs)
|
|
146
|
+
|
|
147
|
+
def do(self, event):
|
|
148
|
+
error = event.get("error")
|
|
149
|
+
timestamp = datetime.fromisoformat(event.get("when"))
|
|
150
|
+
endpoint_id = event[EventFieldType.ENDPOINT_ID]
|
|
151
|
+
event = {
|
|
152
|
+
EventFieldType.MODEL_ERROR: str(error),
|
|
153
|
+
EventFieldType.ENDPOINT_ID: endpoint_id,
|
|
154
|
+
EventFieldType.TIMESTAMP: timestamp,
|
|
155
|
+
EventFieldType.ERROR_COUNT: 1.0,
|
|
156
|
+
}
|
|
157
|
+
logger.info("Write error to errors TSDB table", event=event)
|
|
158
|
+
return event
|