detectkit 0.16.0__tar.gz → 0.16.1__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.16.0/detectkit.egg-info → detectkit-0.16.1}/PKG-INFO +1 -1
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/__init__.py +1 -1
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/webhook.py +25 -11
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/alerting.md +5 -3
- {detectkit-0.16.0 → detectkit-0.16.1/detectkit.egg-info}/PKG-INFO +1 -1
- {detectkit-0.16.0 → detectkit-0.16.1}/LICENSE +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/MANIFEST.in +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/README.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/base.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/branding.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/email.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/factory.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/mattermost.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/slack.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/channels/telegram.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_base.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_decision.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_recovery.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/_types.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/_output.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/cli.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/overview.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/rules/project.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/clean.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/init.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/init_claude.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/run.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/test_alert.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/commands/unlock.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/main.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/metric_config.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/profile.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/project_config.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/config/validator.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/interval.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/core/models.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/_sql_manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/clickhouse_manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_alert_states.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_base.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_datapoints.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_detections.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_maintenance.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_metrics.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_schema.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/_tasks.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/internal_tables/manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/mysql_manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/postgres_manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/database/tables.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/base.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/factory.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/seasonality.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/_windowed.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/iqr.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/mad.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/manual_bounds.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/detectors/statistical/zscore.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/metric_loader.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/loaders/query_template.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/error_dispatch.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_base.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_load_step.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/_types.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/orchestration/task_manager/manager.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/__init__.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/datetime_utils.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/env_interpolation.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/json_utils.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit/utils/stats.py +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/SOURCES.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/dependency_links.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/entry_points.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/requires.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/detectkit.egg-info/top_level.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/pyproject.toml +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/requirements.txt +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/setup.cfg +0 -0
- {detectkit-0.16.0 → detectkit-0.16.1}/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.16.
|
|
7
|
+
__version__ = "0.16.1"
|
|
8
8
|
|
|
9
9
|
from detectkit.core.interval import Interval
|
|
10
10
|
from detectkit.core.models import ColumnDefinition, TableModel
|
|
@@ -293,20 +293,21 @@ class WebhookChannel(BaseAlertChannel):
|
|
|
293
293
|
err = f"{ctx['error_type']}: {ctx['error_message']}".strip(": ")
|
|
294
294
|
full("Error", code(err))
|
|
295
295
|
|
|
296
|
-
#
|
|
297
|
-
#
|
|
298
|
-
|
|
296
|
+
# Links block — kept as its own flexible field, but every entry is a
|
|
297
|
+
# compact clickable label, never a raw URL string. A Grafana dashboard
|
|
298
|
+
# URL can be a paragraph long once it carries variables; nobody should
|
|
299
|
+
# read that in an alert, so we hide it behind the label and render in the
|
|
300
|
+
# platform's link syntax. Holds dashboard + any extra links + the "how to
|
|
301
|
+
# read this alert" guide, joined by " · ".
|
|
302
|
+
link_parts = []
|
|
299
303
|
if alert_data.dashboard_url:
|
|
300
|
-
|
|
304
|
+
link_parts.append(self._link_markup(alert_data.dashboard_url, "Dashboard"))
|
|
301
305
|
for label, url in alert_data.links.items():
|
|
302
|
-
|
|
303
|
-
if link_lines:
|
|
304
|
-
full("Links", "\n".join(link_lines))
|
|
305
|
-
|
|
306
|
-
# "How to read this alert" — the last field, a bare URL (auto-linkified on
|
|
307
|
-
# both Slack and Mattermost) pointing readers at the interpretation guide.
|
|
306
|
+
link_parts.append(self._link_markup(url, label))
|
|
308
307
|
if ctx["help_url"]:
|
|
309
|
-
|
|
308
|
+
link_parts.append(self._link_markup(ctx["help_url"], ctx["help_label"]))
|
|
309
|
+
if link_parts:
|
|
310
|
+
full("Links", " · ".join(link_parts))
|
|
310
311
|
|
|
311
312
|
# A plain-text one-liner for notification previews / unsupported clients.
|
|
312
313
|
if kind == "no_data":
|
|
@@ -328,6 +329,19 @@ class WebhookChannel(BaseAlertChannel):
|
|
|
328
329
|
"mrkdwn_in": ["text", "fields"],
|
|
329
330
|
}
|
|
330
331
|
|
|
332
|
+
def _link_markup(self, url: str, label: str) -> str:
|
|
333
|
+
"""Render *label* as a clickable link in the target platform's syntax.
|
|
334
|
+
|
|
335
|
+
Slack incoming webhooks (``hooks.slack.com``) use ``<url|label>``;
|
|
336
|
+
Mattermost and other webhooks use markdown ``[label](url)``. This keeps a
|
|
337
|
+
link a short clickable phrase instead of a raw URL — important because a
|
|
338
|
+
real dashboard URL (e.g. Grafana with many variables) can be extremely
|
|
339
|
+
long, and no one should have to read it inside an alert.
|
|
340
|
+
"""
|
|
341
|
+
if "hooks.slack.com" in self.webhook_url:
|
|
342
|
+
return f"<{url}|{label}>"
|
|
343
|
+
return f"[{label}]({url})"
|
|
344
|
+
|
|
331
345
|
@staticmethod
|
|
332
346
|
def _unix_ts(ts: Any) -> int | None:
|
|
333
347
|
"""Epoch seconds (UTC) for a naive-UTC timestamp, or None on failure."""
|
|
@@ -167,9 +167,11 @@ config needed. Control it project-wide with `alert_help_url` in
|
|
|
167
167
|
Per-channel rendering (defaults only; resolved by
|
|
168
168
|
`ProjectConfig.resolve_alert_help_url`):
|
|
169
169
|
|
|
170
|
-
- **Slack / Mattermost / generic webhook** — a
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
- **Slack / Mattermost / generic webhook** — a clickable `How to read this alert`
|
|
171
|
+
label in the compact `Links` field (alongside `Dashboard` + any extra links),
|
|
172
|
+
never a raw URL. Rendered in the platform's link syntax (Slack `<url|label>`,
|
|
173
|
+
Mattermost/generic markdown links) so a long dashboard URL stays hidden behind
|
|
174
|
+
its label.
|
|
173
175
|
- **Telegram** — appended to the links line (after the optional "Open dashboard"
|
|
174
176
|
link) as an `<a>` link reading `How to read this alert`.
|
|
175
177
|
- **Email** — in the footer, after `Sent by detectkit · <project>` (and any CC),
|
|
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
|
{detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md
RENAMED
|
File without changes
|
{detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md
RENAMED
|
File without changes
|
{detectkit-0.16.0 → detectkit-0.16.1}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md
RENAMED
|
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
|