Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed modules/src/.gitkeep
Empty file.
37 changes: 37 additions & 0 deletions modules/src/count_events/count_events.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
39 changes: 39 additions & 0 deletions modules/src/count_events/count_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2025 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from mlrun.model_monitoring.applications import (
ModelMonitoringApplicationBase, ModelMonitoringApplicationMetric,
)
import mlrun.model_monitoring.applications.context as mm_context


class CountApp(ModelMonitoringApplicationBase):
def do_tracking(
self, monitoring_context: mm_context.MonitoringApplicationContext
) -> ModelMonitoringApplicationMetric:
sample_df = monitoring_context.sample_df
monitoring_context.logger.debug("Sample data-frame", sample_df=sample_df)
count = len(sample_df)
monitoring_context.logger.info(
"Counted events for model endpoint window",
model_endpoint_name=monitoring_context.model_endpoint.metadata.name,
count=count,
start=monitoring_context.start_infer_time,
end=monitoring_context.end_infer_time,
)
return ModelMonitoringApplicationMetric(
name="count",
value=count,
)
17 changes: 17 additions & 0 deletions modules/src/count_events/item.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: v1
categories:
- model-serving
description: Count events in each time window
example:
generationDate: 2025-09-16:12-25
hidden: false
labels:
author: iguazio
mlrunVersion: 1.10.0-rc27
name: count_events
spec:
filename: count_events.py
image: mlrun/mlrun
kind: monitoring_application
requirements:
version: 1.0.0
3 changes: 3 additions & 0 deletions modules/src/count_events/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mlrun==1.10.0-rc27
pandas==2.1.4
pytest~=8.2
75 changes: 75 additions & 0 deletions modules/src/count_events/test_count_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright 2025 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


from mlrun.model_monitoring.applications import ModelMonitoringApplicationMetric
import mlrun.model_monitoring.applications.context as mm_context

from count_events import CountApp

from unittest.mock import Mock
from datetime import datetime
import pandas as pd
import pytest

class TestCountApp:
"""Test suite for CountApp class."""

def setup_method(self):
"""Set up test fixtures before each test method."""
self.count_app = CountApp()
@staticmethod
def _create_mock_monitoring_context(sample_df, model_endpoint_name="test-model"):
"""Helper method to create a mock monitoring context."""
mock_context = Mock(spec=mm_context.MonitoringApplicationContext)

# Mock the sample dataframe
mock_context.sample_df = sample_df

# Mock the logger
mock_logger = Mock()
mock_context.logger = mock_logger

# Mock the model endpoint
mock_model_endpoint = Mock()
mock_model_endpoint.metadata.name = model_endpoint_name
mock_context.model_endpoint = mock_model_endpoint

# Mock time attributes
mock_context.start_infer_time = datetime(2025, 1, 1, 10, 0, 0)
mock_context.end_infer_time = datetime(2025, 1, 1, 11, 0, 0)

return mock_context


@pytest.mark.parametrize("df_size", [0, 1, 10, 100, 1000])
def test_do_tracking_with_various_dataframe_sizes(self, df_size):
"""Test do_tracking with various dataframe sizes using parametrized test."""
# Arrange
if df_size == 0:
test_df = pd.DataFrame()
else:
test_df = pd.DataFrame({"col1": range(df_size)})

mock_context = self._create_mock_monitoring_context(test_df)

# Act
result = self.count_app.do_tracking(mock_context)

# Assert
assert isinstance(result, ModelMonitoringApplicationMetric)
assert result.value == df_size
assert result.name == "count"