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.
- detectkit/__init__.py +17 -0
- detectkit/alerting/__init__.py +13 -0
- detectkit/alerting/channels/__init__.py +21 -0
- detectkit/alerting/channels/base.py +191 -0
- detectkit/alerting/channels/email.py +146 -0
- detectkit/alerting/channels/factory.py +193 -0
- detectkit/alerting/channels/mattermost.py +53 -0
- detectkit/alerting/channels/slack.py +55 -0
- detectkit/alerting/channels/telegram.py +110 -0
- detectkit/alerting/channels/webhook.py +139 -0
- detectkit/alerting/orchestrator.py +368 -0
- detectkit/cli/__init__.py +1 -0
- detectkit/cli/commands/__init__.py +1 -0
- detectkit/cli/commands/init.py +282 -0
- detectkit/cli/commands/run.py +427 -0
- detectkit/cli/commands/test_alert.py +184 -0
- detectkit/cli/main.py +186 -0
- detectkit/config/__init__.py +30 -0
- detectkit/config/metric_config.py +467 -0
- detectkit/config/profile.py +285 -0
- detectkit/config/project_config.py +164 -0
- detectkit/core/__init__.py +6 -0
- detectkit/core/interval.py +132 -0
- detectkit/core/models.py +106 -0
- detectkit/database/__init__.py +27 -0
- detectkit/database/clickhouse_manager.py +385 -0
- detectkit/database/internal_tables.py +581 -0
- detectkit/database/manager.py +324 -0
- detectkit/database/tables.py +134 -0
- detectkit/detectors/__init__.py +6 -0
- detectkit/detectors/base.py +222 -0
- detectkit/detectors/factory.py +138 -0
- detectkit/detectors/statistical/__init__.py +8 -0
- detectkit/detectors/statistical/iqr.py +230 -0
- detectkit/detectors/statistical/mad.py +423 -0
- detectkit/detectors/statistical/manual_bounds.py +177 -0
- detectkit/detectors/statistical/zscore.py +225 -0
- detectkit/loaders/__init__.py +6 -0
- detectkit/loaders/metric_loader.py +470 -0
- detectkit/loaders/query_template.py +164 -0
- detectkit/orchestration/__init__.py +9 -0
- detectkit/orchestration/task_manager.py +698 -0
- detectkit/utils/__init__.py +1 -0
- detectkit-0.1.0.dist-info/METADATA +231 -0
- detectkit-0.1.0.dist-info/RECORD +49 -0
- detectkit-0.1.0.dist-info/WHEEL +5 -0
- detectkit-0.1.0.dist-info/entry_points.txt +2 -0
- detectkit-0.1.0.dist-info/licenses/LICENSE +21 -0
- 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
|
+
)
|