Skip to content

Commit 38cf59a

Browse files
authored
[Count Events] Add count events module (#899)
* [Count Events] Add `count_events` model monitoring application (#897) * add count_events module * adding cw * remove gitkeep and fix item yaml * [Count Events] Add empty notebook for build marketplace CI (#898) * add count_events module * adding cw * remove gitkeep and fix item yaml * add empty nb for CI * Update example field in item.yaml
1 parent e714d3e commit 38cf59a

File tree

6 files changed

+171
-0
lines changed

6 files changed

+171
-0
lines changed

modules/src/.gitkeep

Whitespace-only changes.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "initial_id",
7+
"metadata": {
8+
"collapsed": true
9+
},
10+
"outputs": [],
11+
"source": [
12+
""
13+
]
14+
}
15+
],
16+
"metadata": {
17+
"kernelspec": {
18+
"display_name": "Python 3",
19+
"language": "python",
20+
"name": "python3"
21+
},
22+
"language_info": {
23+
"codemirror_mode": {
24+
"name": "ipython",
25+
"version": 2
26+
},
27+
"file_extension": ".py",
28+
"mimetype": "text/x-python",
29+
"name": "python",
30+
"nbconvert_exporter": "python",
31+
"pygments_lexer": "ipython2",
32+
"version": "2.7.6"
33+
}
34+
},
35+
"nbformat": 4,
36+
"nbformat_minor": 5
37+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2025 Iguazio
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
from mlrun.model_monitoring.applications import (
17+
ModelMonitoringApplicationBase, ModelMonitoringApplicationMetric,
18+
)
19+
import mlrun.model_monitoring.applications.context as mm_context
20+
21+
22+
class CountApp(ModelMonitoringApplicationBase):
23+
def do_tracking(
24+
self, monitoring_context: mm_context.MonitoringApplicationContext
25+
) -> ModelMonitoringApplicationMetric:
26+
sample_df = monitoring_context.sample_df
27+
monitoring_context.logger.debug("Sample data-frame", sample_df=sample_df)
28+
count = len(sample_df)
29+
monitoring_context.logger.info(
30+
"Counted events for model endpoint window",
31+
model_endpoint_name=monitoring_context.model_endpoint.metadata.name,
32+
count=count,
33+
start=monitoring_context.start_infer_time,
34+
end=monitoring_context.end_infer_time,
35+
)
36+
return ModelMonitoringApplicationMetric(
37+
name="count",
38+
value=count,
39+
)

modules/src/count_events/item.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: v1
2+
categories:
3+
- model-serving
4+
description: Count events in each time window
5+
example: count_events.ipynb
6+
generationDate: 2025-09-16:12-25
7+
hidden: false
8+
labels:
9+
author: iguazio
10+
mlrunVersion: 1.10.0-rc27
11+
name: count_events
12+
spec:
13+
filename: count_events.py
14+
image: mlrun/mlrun
15+
kind: monitoring_application
16+
requirements:
17+
version: 1.0.0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mlrun==1.10.0-rc27
2+
pandas==2.1.4
3+
pytest~=8.2
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright 2025 Iguazio
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
17+
from mlrun.model_monitoring.applications import ModelMonitoringApplicationMetric
18+
import mlrun.model_monitoring.applications.context as mm_context
19+
20+
from count_events import CountApp
21+
22+
from unittest.mock import Mock
23+
from datetime import datetime
24+
import pandas as pd
25+
import pytest
26+
27+
class TestCountApp:
28+
"""Test suite for CountApp class."""
29+
30+
def setup_method(self):
31+
"""Set up test fixtures before each test method."""
32+
self.count_app = CountApp()
33+
@staticmethod
34+
def _create_mock_monitoring_context(sample_df, model_endpoint_name="test-model"):
35+
"""Helper method to create a mock monitoring context."""
36+
mock_context = Mock(spec=mm_context.MonitoringApplicationContext)
37+
38+
# Mock the sample dataframe
39+
mock_context.sample_df = sample_df
40+
41+
# Mock the logger
42+
mock_logger = Mock()
43+
mock_context.logger = mock_logger
44+
45+
# Mock the model endpoint
46+
mock_model_endpoint = Mock()
47+
mock_model_endpoint.metadata.name = model_endpoint_name
48+
mock_context.model_endpoint = mock_model_endpoint
49+
50+
# Mock time attributes
51+
mock_context.start_infer_time = datetime(2025, 1, 1, 10, 0, 0)
52+
mock_context.end_infer_time = datetime(2025, 1, 1, 11, 0, 0)
53+
54+
return mock_context
55+
56+
57+
@pytest.mark.parametrize("df_size", [0, 1, 10, 100, 1000])
58+
def test_do_tracking_with_various_dataframe_sizes(self, df_size):
59+
"""Test do_tracking with various dataframe sizes using parametrized test."""
60+
# Arrange
61+
if df_size == 0:
62+
test_df = pd.DataFrame()
63+
else:
64+
test_df = pd.DataFrame({"col1": range(df_size)})
65+
66+
mock_context = self._create_mock_monitoring_context(test_df)
67+
68+
# Act
69+
result = self.count_app.do_tracking(mock_context)
70+
71+
# Assert
72+
assert isinstance(result, ModelMonitoringApplicationMetric)
73+
assert result.value == df_size
74+
assert result.name == "count"
75+

0 commit comments

Comments
 (0)