detectkit 0.1.0__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.
Files changed (49) hide show
  1. detectkit/__init__.py +17 -0
  2. detectkit/alerting/__init__.py +13 -0
  3. detectkit/alerting/channels/__init__.py +21 -0
  4. detectkit/alerting/channels/base.py +191 -0
  5. detectkit/alerting/channels/email.py +146 -0
  6. detectkit/alerting/channels/factory.py +193 -0
  7. detectkit/alerting/channels/mattermost.py +53 -0
  8. detectkit/alerting/channels/slack.py +55 -0
  9. detectkit/alerting/channels/telegram.py +110 -0
  10. detectkit/alerting/channels/webhook.py +139 -0
  11. detectkit/alerting/orchestrator.py +368 -0
  12. detectkit/cli/__init__.py +1 -0
  13. detectkit/cli/commands/__init__.py +1 -0
  14. detectkit/cli/commands/init.py +282 -0
  15. detectkit/cli/commands/run.py +427 -0
  16. detectkit/cli/commands/test_alert.py +184 -0
  17. detectkit/cli/main.py +186 -0
  18. detectkit/config/__init__.py +30 -0
  19. detectkit/config/metric_config.py +467 -0
  20. detectkit/config/profile.py +285 -0
  21. detectkit/config/project_config.py +164 -0
  22. detectkit/core/__init__.py +6 -0
  23. detectkit/core/interval.py +132 -0
  24. detectkit/core/models.py +106 -0
  25. detectkit/database/__init__.py +27 -0
  26. detectkit/database/clickhouse_manager.py +385 -0
  27. detectkit/database/internal_tables.py +581 -0
  28. detectkit/database/manager.py +324 -0
  29. detectkit/database/tables.py +134 -0
  30. detectkit/detectors/__init__.py +6 -0
  31. detectkit/detectors/base.py +222 -0
  32. detectkit/detectors/factory.py +138 -0
  33. detectkit/detectors/statistical/__init__.py +8 -0
  34. detectkit/detectors/statistical/iqr.py +230 -0
  35. detectkit/detectors/statistical/mad.py +423 -0
  36. detectkit/detectors/statistical/manual_bounds.py +177 -0
  37. detectkit/detectors/statistical/zscore.py +225 -0
  38. detectkit/loaders/__init__.py +6 -0
  39. detectkit/loaders/metric_loader.py +470 -0
  40. detectkit/loaders/query_template.py +164 -0
  41. detectkit/orchestration/__init__.py +9 -0
  42. detectkit/orchestration/task_manager.py +698 -0
  43. detectkit/utils/__init__.py +1 -0
  44. detectkit-0.1.0.dist-info/METADATA +231 -0
  45. detectkit-0.1.0.dist-info/RECORD +49 -0
  46. detectkit-0.1.0.dist-info/WHEEL +5 -0
  47. detectkit-0.1.0.dist-info/entry_points.txt +2 -0
  48. detectkit-0.1.0.dist-info/licenses/LICENSE +21 -0
  49. detectkit-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,164 @@
1
+ """
2
+ SQL query templating with Jinja2.
3
+
4
+ Provides templating capabilities for SQL queries with built-in variables
5
+ and custom context.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Any, Dict, Optional
10
+
11
+ from jinja2 import Environment, StrictUndefined, Template, TemplateSyntaxError, Undefined, UndefinedError
12
+
13
+
14
+ class QueryTemplate:
15
+ """
16
+ SQL query template renderer using Jinja2.
17
+
18
+ Supports:
19
+ - Variable substitution: {{ variable }}
20
+ - Conditionals: {% if condition %}...{% endif %}
21
+ - Loops: {% for item in items %}...{% endfor %}
22
+ - Built-in variables: from_date, to_date, interval_seconds
23
+
24
+ Example:
25
+ >>> template = QueryTemplate()
26
+ >>> query = "SELECT * FROM metrics WHERE timestamp >= '{{ from_date }}'"
27
+ >>> rendered = template.render(
28
+ ... query,
29
+ ... {"from_date": "2024-01-01", "to_date": "2024-01-02"}
30
+ ... )
31
+ >>> print(rendered)
32
+ SELECT * FROM metrics WHERE timestamp >= '2024-01-01'
33
+ """
34
+
35
+ def __init__(self, strict: bool = True):
36
+ """
37
+ Initialize Jinja2 environment.
38
+
39
+ Args:
40
+ strict: If True, raise error on undefined variables
41
+ """
42
+ self._env = Environment(
43
+ autoescape=False, # Don't escape SQL
44
+ trim_blocks=True, # Remove newlines after blocks
45
+ lstrip_blocks=True, # Remove leading whitespace before blocks
46
+ undefined=StrictUndefined if strict else Undefined, # Raise on undefined vars
47
+ )
48
+
49
+ def render(
50
+ self,
51
+ query: str,
52
+ context: Optional[Dict[str, Any]] = None,
53
+ dtk_start_time: Optional[datetime] = None,
54
+ dtk_end_time: Optional[datetime] = None,
55
+ interval_seconds: Optional[int] = None,
56
+ ) -> str:
57
+ """
58
+ Render SQL query template with context.
59
+
60
+ Args:
61
+ query: SQL query template string
62
+ context: Custom variables for template
63
+ dtk_start_time: Built-in variable for time range start
64
+ dtk_end_time: Built-in variable for time range end
65
+ interval_seconds: Built-in variable for interval
66
+
67
+ Returns:
68
+ Rendered SQL query
69
+
70
+ Raises:
71
+ TemplateSyntaxError: If template syntax is invalid
72
+ Exception: If template rendering fails
73
+
74
+ Example:
75
+ >>> template = QueryTemplate()
76
+ >>> query = '''
77
+ ... SELECT
78
+ ... timestamp,
79
+ ... value
80
+ ... FROM {{ table_name }}
81
+ ... WHERE timestamp >= '{{ dtk_start_time }}'
82
+ ... AND timestamp < '{{ dtk_end_time }}'
83
+ ... {% if interval_seconds %}
84
+ ... AND interval = {{ interval_seconds }}
85
+ ... {% endif %}
86
+ ... '''
87
+ >>> rendered = template.render(
88
+ ... query,
89
+ ... context={"table_name": "cpu_metrics"},
90
+ ... dtk_start_time=datetime(2024, 1, 1),
91
+ ... dtk_end_time=datetime(2024, 1, 2),
92
+ ... interval_seconds=600
93
+ ... )
94
+ """
95
+ # Build context with built-in and custom variables
96
+ template_context = {}
97
+
98
+ # Add built-in variables (format datetime to string for SQL compatibility)
99
+ if dtk_start_time is not None:
100
+ # Format as ISO 8601 "YYYY-MM-DD HH:MM:SS" - works in ClickHouse, PostgreSQL, MySQL, SQLite
101
+ template_context["dtk_start_time"] = dtk_start_time.strftime("%Y-%m-%d %H:%M:%S")
102
+ if dtk_end_time is not None:
103
+ template_context["dtk_end_time"] = dtk_end_time.strftime("%Y-%m-%d %H:%M:%S")
104
+ if interval_seconds is not None:
105
+ template_context["interval_seconds"] = interval_seconds
106
+
107
+ # Add custom variables (overwrites built-ins if conflict)
108
+ if context:
109
+ template_context.update(context)
110
+
111
+ # Compile and render template
112
+ try:
113
+ template = self._env.from_string(query)
114
+ return template.render(template_context)
115
+ except TemplateSyntaxError as e:
116
+ raise TemplateSyntaxError(
117
+ f"Invalid template syntax: {e.message}", e.lineno
118
+ )
119
+ except Exception as e:
120
+ raise Exception(f"Template rendering failed: {e}")
121
+
122
+ def render_with_defaults(
123
+ self,
124
+ query: str,
125
+ context: Optional[Dict[str, Any]] = None,
126
+ dtk_start_time: Optional[datetime] = None,
127
+ dtk_end_time: Optional[datetime] = None,
128
+ interval_seconds: Optional[int] = None,
129
+ ) -> str:
130
+ """
131
+ Render query with sensible defaults for missing variables.
132
+
133
+ This is useful for testing and development where you might not
134
+ have all variables defined. Use {{ var | default('value') }} syntax
135
+ in templates.
136
+
137
+ Args:
138
+ query: SQL query template
139
+ context: Custom variables
140
+ dtk_start_time: Start time
141
+ dtk_end_time: End time
142
+ interval_seconds: Interval in seconds
143
+
144
+ Returns:
145
+ Rendered SQL query
146
+
147
+ Example:
148
+ >>> template = QueryTemplate()
149
+ >>> # Use default filter for missing variables
150
+ >>> query = "SELECT * FROM {{ table | default('metrics') }}"
151
+ >>> rendered = template.render_with_defaults(query)
152
+ >>> print(rendered)
153
+ SELECT * FROM metrics
154
+ """
155
+ # Create non-strict environment for this render
156
+ non_strict_template = QueryTemplate(strict=False)
157
+
158
+ return non_strict_template.render(
159
+ query,
160
+ context=context,
161
+ dtk_start_time=dtk_start_time,
162
+ dtk_end_time=dtk_end_time,
163
+ interval_seconds=interval_seconds,
164
+ )
@@ -0,0 +1,9 @@
1
+ """Task orchestration for detectkit."""
2
+
3
+ from detectkit.orchestration.task_manager import PipelineStep, TaskManager, TaskStatus
4
+
5
+ __all__ = [
6
+ "TaskManager",
7
+ "PipelineStep",
8
+ "TaskStatus",
9
+ ]