detectkit 0.5.1__tar.gz → 0.5.3__tar.gz
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.
- {detectkit-0.5.1/detectkit.egg-info → detectkit-0.5.3}/PKG-INFO +1 -1
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/__init__.py +1 -1
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/base.py +29 -3
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/commands/test_alert.py +9 -3
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/error_dispatch.py +1 -0
- {detectkit-0.5.1 → detectkit-0.5.3/detectkit.egg-info}/PKG-INFO +1 -1
- {detectkit-0.5.1 → detectkit-0.5.3}/pyproject.toml +1 -1
- {detectkit-0.5.1 → detectkit-0.5.3}/LICENSE +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/MANIFEST.in +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/README.md +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/email.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/factory.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/mattermost.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/slack.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/telegram.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/channels/webhook.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_base.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_decision.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_recovery.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/_types.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/commands/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/commands/init.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/commands/run.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/cli/main.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/config/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/config/metric_config.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/config/profile.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/config/project_config.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/config/validator.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/core/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/core/interval.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/core/models.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/clickhouse_manager.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_alert_states.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_base.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_datapoints.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_detections.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_metrics.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_schema.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/_tasks.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/internal_tables/manager.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/manager.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/database/tables.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/base.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/factory.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/seasonality.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/statistical/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/statistical/iqr.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/statistical/mad.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/statistical/manual_bounds.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/detectors/statistical/zscore.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/loaders/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/loaders/metric_loader.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/loaders/query_template.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/_base.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/_load_step.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/_types.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/orchestration/task_manager/manager.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/utils/__init__.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/utils/datetime_utils.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/utils/env_interpolation.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/utils/json_utils.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit/utils/stats.py +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit.egg-info/SOURCES.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit.egg-info/dependency_links.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit.egg-info/entry_points.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit.egg-info/requires.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/detectkit.egg-info/top_level.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/requirements.txt +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/setup.cfg +0 -0
- {detectkit-0.5.1 → detectkit-0.5.3}/setup.py +0 -0
|
@@ -4,7 +4,7 @@ detectk - Anomaly Detection for Time-Series Metrics
|
|
|
4
4
|
A Python library for data analysts and engineers to monitor metrics with automatic anomaly detection.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "0.5.
|
|
7
|
+
__version__ = "0.5.3"
|
|
8
8
|
|
|
9
9
|
from detectkit.core.interval import Interval
|
|
10
10
|
from detectkit.core.models import ColumnDefinition, TableModel
|
|
@@ -32,6 +32,10 @@ class AlertData:
|
|
|
32
32
|
consecutive_count: Number of consecutive anomalies
|
|
33
33
|
is_recovery: True for recovery notifications
|
|
34
34
|
is_no_data: True for missing-data alerts (no_data_alert)
|
|
35
|
+
project_name: Optional ``detectkit_project.yml`` name. Surfaces
|
|
36
|
+
as ``{project_name}`` in templates and as a ``[name] `` prefix
|
|
37
|
+
in the default error title. Lets multiple projects share the
|
|
38
|
+
same alert channel without ambiguity.
|
|
35
39
|
"""
|
|
36
40
|
|
|
37
41
|
metric_name: str
|
|
@@ -53,6 +57,7 @@ class AlertData:
|
|
|
53
57
|
error_message: str | None = None
|
|
54
58
|
description: str | None = None
|
|
55
59
|
mentions: list[str] = field(default_factory=list)
|
|
60
|
+
project_name: str | None = None
|
|
56
61
|
|
|
57
62
|
|
|
58
63
|
class BaseAlertChannel(ABC):
|
|
@@ -188,6 +193,12 @@ class BaseAlertChannel(ABC):
|
|
|
188
193
|
mentions_str = self.format_mentions(alert_data.mentions)
|
|
189
194
|
mentions_line = f"\n{mentions_str}" if mentions_str else ""
|
|
190
195
|
|
|
196
|
+
# Project name + synth prefix for templates. Prefix is empty when
|
|
197
|
+
# project_name is None so default templates render cleanly for
|
|
198
|
+
# callers that don't set it.
|
|
199
|
+
project_name = alert_data.project_name or ""
|
|
200
|
+
project_name_prefix = f"[{alert_data.project_name}] " if alert_data.project_name else ""
|
|
201
|
+
|
|
191
202
|
# Format message
|
|
192
203
|
if alert_data.is_error:
|
|
193
204
|
status = "ERROR"
|
|
@@ -201,6 +212,8 @@ class BaseAlertChannel(ABC):
|
|
|
201
212
|
try:
|
|
202
213
|
message = template.format(
|
|
203
214
|
metric_name=alert_data.metric_name,
|
|
215
|
+
project_name=project_name,
|
|
216
|
+
project_name_prefix=project_name_prefix,
|
|
204
217
|
timestamp=ts_str,
|
|
205
218
|
timezone=alert_data.timezone,
|
|
206
219
|
value=value_for_template,
|
|
@@ -282,7 +295,14 @@ class BaseAlertChannel(ABC):
|
|
|
282
295
|
else:
|
|
283
296
|
title_template = self.get_default_title_template()
|
|
284
297
|
|
|
285
|
-
|
|
298
|
+
project_name = alert_data.project_name or ""
|
|
299
|
+
project_name_prefix = f"[{alert_data.project_name}] " if alert_data.project_name else ""
|
|
300
|
+
|
|
301
|
+
return title_template.format(
|
|
302
|
+
metric_name=alert_data.metric_name,
|
|
303
|
+
project_name=project_name,
|
|
304
|
+
project_name_prefix=project_name_prefix,
|
|
305
|
+
)
|
|
286
306
|
|
|
287
307
|
def get_default_template(self) -> str:
|
|
288
308
|
"""
|
|
@@ -369,8 +389,14 @@ class BaseAlertChannel(ABC):
|
|
|
369
389
|
)
|
|
370
390
|
|
|
371
391
|
def get_default_error_title_template(self) -> str:
|
|
372
|
-
"""Default title template for project-level error alerts.
|
|
373
|
-
|
|
392
|
+
"""Default title template for project-level error alerts.
|
|
393
|
+
|
|
394
|
+
Includes the project name as a ``[name] `` prefix when set so
|
|
395
|
+
multiple detectkit projects routed to the same alert channel
|
|
396
|
+
stay distinguishable. The prefix collapses to an empty string
|
|
397
|
+
when ``AlertData.project_name`` is None.
|
|
398
|
+
"""
|
|
399
|
+
return "{project_name_prefix}Pipeline error: {metric_name}"
|
|
374
400
|
|
|
375
401
|
def __repr__(self) -> str:
|
|
376
402
|
"""String representation of channel."""
|
|
@@ -20,6 +20,7 @@ from detectkit.utils.datetime_utils import now_utc
|
|
|
20
20
|
|
|
21
21
|
def create_mock_alert_data(
|
|
22
22
|
metric_config: MetricConfig,
|
|
23
|
+
alerting_config,
|
|
23
24
|
timezone_display: str = "UTC",
|
|
24
25
|
) -> AlertData:
|
|
25
26
|
"""
|
|
@@ -27,6 +28,10 @@ def create_mock_alert_data(
|
|
|
27
28
|
|
|
28
29
|
Args:
|
|
29
30
|
metric_config: Metric configuration
|
|
31
|
+
alerting_config: Single ``AlertingConfig`` from
|
|
32
|
+
``metric_config.alerting`` to source mentions/timezone from.
|
|
33
|
+
``metric_config.alerting`` is a list — the test command
|
|
34
|
+
iterates it and passes one entry at a time.
|
|
30
35
|
timezone_display: Timezone for display
|
|
31
36
|
|
|
32
37
|
Returns:
|
|
@@ -35,8 +40,9 @@ def create_mock_alert_data(
|
|
|
35
40
|
# Use current time
|
|
36
41
|
now = now_utc()
|
|
37
42
|
|
|
38
|
-
#
|
|
39
|
-
|
|
43
|
+
# Mentions are per-AlertingConfig (different alert routes can mention
|
|
44
|
+
# different teams). Pull them from the specific config we're testing.
|
|
45
|
+
mentions = list(alerting_config.mentions) if alerting_config else []
|
|
40
46
|
|
|
41
47
|
# Create realistic mock data
|
|
42
48
|
return AlertData(
|
|
@@ -147,7 +153,7 @@ def run_test_alert(metric_name: str, profile: str | None = None):
|
|
|
147
153
|
print(f" Timezone: {timezone_display}")
|
|
148
154
|
print(f" Channels: {', '.join(alerting_config.channels)}\n")
|
|
149
155
|
|
|
150
|
-
alert_data = create_mock_alert_data(metric_config, timezone_display)
|
|
156
|
+
alert_data = create_mock_alert_data(metric_config, alerting_config, timezone_display)
|
|
151
157
|
|
|
152
158
|
success_count = 0
|
|
153
159
|
for channel_name in alerting_config.channels:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|