flexmetric 0.1.4__tar.gz → 0.3.0__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.
- flexmetric-0.3.0/PKG-INFO +243 -0
- flexmetric-0.3.0/README.md +214 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/metric_process/database_processing.py +32 -19
- flexmetric-0.3.0/flexmetric/metric_process/expiring_queue.py +56 -0
- flexmetric-0.3.0/flexmetric/metric_process/process_commands.py +111 -0
- flexmetric-0.3.0/flexmetric/metric_process/prometheus_agent.py +248 -0
- flexmetric-0.3.0/flexmetric/metric_process/views.py +38 -0
- flexmetric-0.3.0/flexmetric.egg-info/PKG-INFO +243 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric.egg-info/SOURCES.txt +4 -1
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric.egg-info/requires.txt +1 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/setup.py +4 -3
- flexmetric-0.1.4/PKG-INFO +0 -152
- flexmetric-0.1.4/README.md +0 -124
- flexmetric-0.1.4/flexmetric/metric_process/prometheus_agent.py +0 -143
- flexmetric-0.1.4/flexmetric.egg-info/PKG-INFO +0 -152
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/__init__.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/config/__init__.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/config/configuration.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/file_recognition/__init__.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/file_recognition/exec_file.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/logging_module/__init__.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/logging_module/logger.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric/metric_process/__init__.py +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric.egg-info/dependency_links.txt +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric.egg-info/entry_points.txt +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/flexmetric.egg-info/top_level.txt +0 -0
- {flexmetric-0.1.4 → flexmetric-0.3.0}/setup.cfg +0 -0
@@ -0,0 +1,243 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: flexmetric
|
3
|
+
Version: 0.3.0
|
4
|
+
Summary: A secure flexible Prometheus exporter for commands, databases, functions, and scripts.
|
5
|
+
Home-page: https://github.com/nikhillingadhal1999/custom_prometheus_agent
|
6
|
+
Author: Nikhil Lingadhal
|
7
|
+
License: MIT
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.7
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: prometheus_client
|
14
|
+
Requires-Dist: PyYAML
|
15
|
+
Requires-Dist: psutil
|
16
|
+
Requires-Dist: setuptools
|
17
|
+
Requires-Dist: wheel
|
18
|
+
Requires-Dist: twine
|
19
|
+
Requires-Dist: flask
|
20
|
+
Dynamic: author
|
21
|
+
Dynamic: classifier
|
22
|
+
Dynamic: description
|
23
|
+
Dynamic: description-content-type
|
24
|
+
Dynamic: home-page
|
25
|
+
Dynamic: license
|
26
|
+
Dynamic: requires-dist
|
27
|
+
Dynamic: requires-python
|
28
|
+
Dynamic: summary
|
29
|
+
|
30
|
+
# FlexMetric
|
31
|
+
|
32
|
+
FlexMetric is a lightweight, flexible, and extensible Prometheus exporter that allows you to securely expose system metrics, database query results, Python function outputs, and externally submitted metrics—via an optional Flask API with HTTPS support—as Prometheus-compatible metrics, all with minimal setup and maximum customization.
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
## Features
|
37
|
+
|
38
|
+
- Run shell commands and expose the results as Prometheus metrics.
|
39
|
+
➔ **Harmful commands (e.g., file deletion, system shutdown) are blocked for safety.**
|
40
|
+
- Execute SQL queries (e.g., SQLite) and monitor database statistics.
|
41
|
+
➔ **Potentially dangerous queries (e.g., `DROP`, `DELETE`, `TRUNCATE`) are not allowed.**
|
42
|
+
- Automatically discover and expose Python function outputs as metrics.
|
43
|
+
- Expose an optional **Flask API** (`/update_metric`) to receive external metrics dynamically.
|
44
|
+
- Modular and easy to extend—add your own custom integrations.
|
45
|
+
- Built-in Prometheus HTTP server (`/metrics`) with configurable port.
|
46
|
+
- **Supports HTTPS** to securely expose both metrics and API endpoints.
|
47
|
+
- **Input sanitization** is performed to ensure only safe commands and queries are executed.
|
48
|
+
|
49
|
+
|
50
|
+
---
|
51
|
+
|
52
|
+
## Installation
|
53
|
+
|
54
|
+
Install from PyPI:
|
55
|
+
|
56
|
+
```bash
|
57
|
+
pip install flexmetric
|
58
|
+
```
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
Run FlexMetric from the command line:
|
62
|
+
|
63
|
+
```bash
|
64
|
+
flexmetric --commands --commands-config commands.yaml --port 8000
|
65
|
+
```
|
66
|
+
|
67
|
+
## Available Modes
|
68
|
+
|
69
|
+
FlexMetric supports multiple modes that can be used individually or combined to expose metrics:
|
70
|
+
|
71
|
+
| Mode | Description | Required Configuration File(s) |
|
72
|
+
|-----------------|------------------------------------------------------------------------|------------------------------------------|
|
73
|
+
| `--commands` | Runs system commands and exports outputs as Prometheus metrics. | `commands.yaml` |
|
74
|
+
| `--database` | Executes SQL queries on databases and exports results. | `database.yaml` and `queries.yaml` |
|
75
|
+
| `--functions` | Discovers and runs user-defined Python functions and exports outputs. | `executable_functions.txt` |
|
76
|
+
| `--expose-api` | Exposes a Flask API (`/update_metric`) to receive external metrics. | *No configuration file required* |
|
77
|
+
### Example of Using Multiple Modes Together
|
78
|
+
|
79
|
+
```bash
|
80
|
+
flexmetric --commands --commands-config commands.yaml --database --database-config database.yaml --queries-config queries.yaml
|
81
|
+
```
|
82
|
+
|
83
|
+
## Configuration File Examples
|
84
|
+
|
85
|
+
Below are example configurations for each supported mode.
|
86
|
+
|
87
|
+
## Using the Flask API in FlexMetric
|
88
|
+
|
89
|
+
To use the Flask API for submitting external metrics, you need to start the agent with the `--expose-api` flag along with the Flask host and port.
|
90
|
+
|
91
|
+
### Start FlexMetric with Flask API
|
92
|
+
|
93
|
+
```bash
|
94
|
+
flexmetric --expose-api --port <port> --host <host>
|
95
|
+
```
|
96
|
+
|
97
|
+
## Example: Running FlexMetric with Flask API
|
98
|
+
|
99
|
+
To run FlexMetric with both Prometheus metrics and the Flask API enabled:
|
100
|
+
|
101
|
+
```bash
|
102
|
+
flexmetric --expose-api --port 5000 --host 0.0.0.0
|
103
|
+
```
|
104
|
+
|
105
|
+
Prometheus metrics exposed at:
|
106
|
+
http://localhost:5000/metrics
|
107
|
+
|
108
|
+
Flask API exposed at:
|
109
|
+
http://localhost:5000/update_metric
|
110
|
+
|
111
|
+
### Submitting a Metric to the Flask API
|
112
|
+
```bash
|
113
|
+
curl -X POST http://localhost:5000/update_metric \
|
114
|
+
-H "Content-Type: application/json" \
|
115
|
+
-d '{
|
116
|
+
"result": [
|
117
|
+
{ "label": "cpu_usage", "value": 42.5 }
|
118
|
+
],
|
119
|
+
"labels": ["cpu"]
|
120
|
+
}'
|
121
|
+
|
122
|
+
```
|
123
|
+
|
124
|
+
### Using flex metrics in secure mode
|
125
|
+
|
126
|
+
```bash
|
127
|
+
flexmetric --port 5000 --host 0.0.0.0 --enable-https --ssl-cert=cert.pem --ssl-key=key.pem
|
128
|
+
```
|
129
|
+
Prometheus metrics exposed at:
|
130
|
+
https://localhost:5000/metrics
|
131
|
+
|
132
|
+
Flask API exposed at:
|
133
|
+
https://localhost:5000/update_metric
|
134
|
+
|
135
|
+
### Submitting a Metric to the Flask API
|
136
|
+
```bash
|
137
|
+
curl -k -X POST https://localhost:5000/update_metric \
|
138
|
+
-H "Content-Type: application/json" \
|
139
|
+
-d '{
|
140
|
+
"result": [
|
141
|
+
{ "label": "cpu_usage", "value": 42.5 }
|
142
|
+
],
|
143
|
+
"labels": ["cpu"]
|
144
|
+
}'
|
145
|
+
|
146
|
+
```
|
147
|
+
|
148
|
+
### commands.yaml
|
149
|
+
|
150
|
+
```yaml
|
151
|
+
commands:
|
152
|
+
- name: disk_usage
|
153
|
+
command: df -h
|
154
|
+
label: path
|
155
|
+
timeout_seconds: 60
|
156
|
+
```
|
157
|
+
```yaml
|
158
|
+
databases:
|
159
|
+
- name: mydb
|
160
|
+
db_type: sqlite
|
161
|
+
db_connection: /path/to/my.db
|
162
|
+
````
|
163
|
+
```yaml
|
164
|
+
queries:
|
165
|
+
- name: user_count
|
166
|
+
db_type: sqlite
|
167
|
+
db_name: mydb
|
168
|
+
query: "SELECT COUNT(*) FROM users;"
|
169
|
+
label: table
|
170
|
+
label_value: users
|
171
|
+
```
|
172
|
+
executable_functions.txt
|
173
|
+
```
|
174
|
+
function_name_1
|
175
|
+
function_name_2
|
176
|
+
```
|
177
|
+
|
178
|
+
## Python Function Output Format
|
179
|
+
|
180
|
+
When using the `--functions` mode, each Python function you define is expected to return a dictionary in the following format:
|
181
|
+
|
182
|
+
```python
|
183
|
+
{
|
184
|
+
'result': [
|
185
|
+
{'label': <label_or_labels>, 'value': <numeric_value>}
|
186
|
+
],
|
187
|
+
'labels': [<label_name_1>]
|
188
|
+
}
|
189
|
+
```
|
190
|
+
|
191
|
+
### Explanation:
|
192
|
+
|
193
|
+
| Key | Description |
|
194
|
+
|--------|---------------------------------------------------------------------------|
|
195
|
+
| `result` | A list of dictionaries, each containing a `label` and a corresponding numeric `value`. |
|
196
|
+
| `labels` | A list of label names (used as Prometheus labels). |
|
197
|
+
|
198
|
+
|
199
|
+
## Command-Line Options
|
200
|
+
|
201
|
+
The following command-line options are available when running FlexMetric:
|
202
|
+
|
203
|
+
| Option | Description | Default |
|
204
|
+
|---------------------|----------------------------------------------------------|----------------------------|
|
205
|
+
| `--port` | Port for the Prometheus metrics server (`/metrics`) | `8000` |
|
206
|
+
| `--commands` | Enable commands mode | |
|
207
|
+
| `--commands-config` | Path to commands YAML file | `commands.yaml` |
|
208
|
+
| `--database` | Enable database mode | |
|
209
|
+
| `--database-config` | Path to database YAML file | `database.yaml` |
|
210
|
+
| `--queries-config` | Path to queries YAML file | `queries.yaml` |
|
211
|
+
| `--functions` | Enable Python functions mode | |
|
212
|
+
| `--functions-file` | Path to functions file | `executable_functions.txt` |
|
213
|
+
| `--expose-api` | Enable Flask API mode to receive external metrics | |
|
214
|
+
| `--flask-port` | Port for the Flask API (`/update_metric`) | `5000` |
|
215
|
+
| `--flask-host` | Hostname for the Flask API | `0.0.0.0` |
|
216
|
+
| `--enable-https` | Enable HTTPS for the Flask API | |
|
217
|
+
| `--ssl-cert` | Path to SSL certificate file (`cert.pem`) | |
|
218
|
+
| `--ssl-key` | Path to SSL private key file (`key.pem`) | |
|
219
|
+
|
220
|
+
### Example Command:
|
221
|
+
|
222
|
+
```bash
|
223
|
+
flexmetric --commands --commands-config commands.yaml --port 8000
|
224
|
+
```
|
225
|
+
## Example Prometheus Output
|
226
|
+
|
227
|
+
Once FlexMetric is running, the `/metrics` endpoint will expose metrics in the Prometheus format.
|
228
|
+
|
229
|
+
Example output:
|
230
|
+
```bash
|
231
|
+
disk_usage_gauge{path="/"} 45.0
|
232
|
+
```
|
233
|
+
|
234
|
+
Each metric includes labels and numeric values that Prometheus can scrape and visualize.
|
235
|
+
|
236
|
+
---
|
237
|
+
|
238
|
+
## Future Enhancements
|
239
|
+
|
240
|
+
The following features are planned or under consideration to improve FlexMetric:
|
241
|
+
|
242
|
+
- Support for additional databases such as PostgreSQL and MySQL.
|
243
|
+
- Enhanced support for more complex scripts and richer label extraction.
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# FlexMetric
|
2
|
+
|
3
|
+
FlexMetric is a lightweight, flexible, and extensible Prometheus exporter that allows you to securely expose system metrics, database query results, Python function outputs, and externally submitted metrics—via an optional Flask API with HTTPS support—as Prometheus-compatible metrics, all with minimal setup and maximum customization.
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
- Run shell commands and expose the results as Prometheus metrics.
|
10
|
+
➔ **Harmful commands (e.g., file deletion, system shutdown) are blocked for safety.**
|
11
|
+
- Execute SQL queries (e.g., SQLite) and monitor database statistics.
|
12
|
+
➔ **Potentially dangerous queries (e.g., `DROP`, `DELETE`, `TRUNCATE`) are not allowed.**
|
13
|
+
- Automatically discover and expose Python function outputs as metrics.
|
14
|
+
- Expose an optional **Flask API** (`/update_metric`) to receive external metrics dynamically.
|
15
|
+
- Modular and easy to extend—add your own custom integrations.
|
16
|
+
- Built-in Prometheus HTTP server (`/metrics`) with configurable port.
|
17
|
+
- **Supports HTTPS** to securely expose both metrics and API endpoints.
|
18
|
+
- **Input sanitization** is performed to ensure only safe commands and queries are executed.
|
19
|
+
|
20
|
+
|
21
|
+
---
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Install from PyPI:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
pip install flexmetric
|
29
|
+
```
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Run FlexMetric from the command line:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
flexmetric --commands --commands-config commands.yaml --port 8000
|
36
|
+
```
|
37
|
+
|
38
|
+
## Available Modes
|
39
|
+
|
40
|
+
FlexMetric supports multiple modes that can be used individually or combined to expose metrics:
|
41
|
+
|
42
|
+
| Mode | Description | Required Configuration File(s) |
|
43
|
+
|-----------------|------------------------------------------------------------------------|------------------------------------------|
|
44
|
+
| `--commands` | Runs system commands and exports outputs as Prometheus metrics. | `commands.yaml` |
|
45
|
+
| `--database` | Executes SQL queries on databases and exports results. | `database.yaml` and `queries.yaml` |
|
46
|
+
| `--functions` | Discovers and runs user-defined Python functions and exports outputs. | `executable_functions.txt` |
|
47
|
+
| `--expose-api` | Exposes a Flask API (`/update_metric`) to receive external metrics. | *No configuration file required* |
|
48
|
+
### Example of Using Multiple Modes Together
|
49
|
+
|
50
|
+
```bash
|
51
|
+
flexmetric --commands --commands-config commands.yaml --database --database-config database.yaml --queries-config queries.yaml
|
52
|
+
```
|
53
|
+
|
54
|
+
## Configuration File Examples
|
55
|
+
|
56
|
+
Below are example configurations for each supported mode.
|
57
|
+
|
58
|
+
## Using the Flask API in FlexMetric
|
59
|
+
|
60
|
+
To use the Flask API for submitting external metrics, you need to start the agent with the `--expose-api` flag along with the Flask host and port.
|
61
|
+
|
62
|
+
### Start FlexMetric with Flask API
|
63
|
+
|
64
|
+
```bash
|
65
|
+
flexmetric --expose-api --port <port> --host <host>
|
66
|
+
```
|
67
|
+
|
68
|
+
## Example: Running FlexMetric with Flask API
|
69
|
+
|
70
|
+
To run FlexMetric with both Prometheus metrics and the Flask API enabled:
|
71
|
+
|
72
|
+
```bash
|
73
|
+
flexmetric --expose-api --port 5000 --host 0.0.0.0
|
74
|
+
```
|
75
|
+
|
76
|
+
Prometheus metrics exposed at:
|
77
|
+
http://localhost:5000/metrics
|
78
|
+
|
79
|
+
Flask API exposed at:
|
80
|
+
http://localhost:5000/update_metric
|
81
|
+
|
82
|
+
### Submitting a Metric to the Flask API
|
83
|
+
```bash
|
84
|
+
curl -X POST http://localhost:5000/update_metric \
|
85
|
+
-H "Content-Type: application/json" \
|
86
|
+
-d '{
|
87
|
+
"result": [
|
88
|
+
{ "label": "cpu_usage", "value": 42.5 }
|
89
|
+
],
|
90
|
+
"labels": ["cpu"]
|
91
|
+
}'
|
92
|
+
|
93
|
+
```
|
94
|
+
|
95
|
+
### Using flex metrics in secure mode
|
96
|
+
|
97
|
+
```bash
|
98
|
+
flexmetric --port 5000 --host 0.0.0.0 --enable-https --ssl-cert=cert.pem --ssl-key=key.pem
|
99
|
+
```
|
100
|
+
Prometheus metrics exposed at:
|
101
|
+
https://localhost:5000/metrics
|
102
|
+
|
103
|
+
Flask API exposed at:
|
104
|
+
https://localhost:5000/update_metric
|
105
|
+
|
106
|
+
### Submitting a Metric to the Flask API
|
107
|
+
```bash
|
108
|
+
curl -k -X POST https://localhost:5000/update_metric \
|
109
|
+
-H "Content-Type: application/json" \
|
110
|
+
-d '{
|
111
|
+
"result": [
|
112
|
+
{ "label": "cpu_usage", "value": 42.5 }
|
113
|
+
],
|
114
|
+
"labels": ["cpu"]
|
115
|
+
}'
|
116
|
+
|
117
|
+
```
|
118
|
+
|
119
|
+
### commands.yaml
|
120
|
+
|
121
|
+
```yaml
|
122
|
+
commands:
|
123
|
+
- name: disk_usage
|
124
|
+
command: df -h
|
125
|
+
label: path
|
126
|
+
timeout_seconds: 60
|
127
|
+
```
|
128
|
+
```yaml
|
129
|
+
databases:
|
130
|
+
- name: mydb
|
131
|
+
db_type: sqlite
|
132
|
+
db_connection: /path/to/my.db
|
133
|
+
````
|
134
|
+
```yaml
|
135
|
+
queries:
|
136
|
+
- name: user_count
|
137
|
+
db_type: sqlite
|
138
|
+
db_name: mydb
|
139
|
+
query: "SELECT COUNT(*) FROM users;"
|
140
|
+
label: table
|
141
|
+
label_value: users
|
142
|
+
```
|
143
|
+
executable_functions.txt
|
144
|
+
```
|
145
|
+
function_name_1
|
146
|
+
function_name_2
|
147
|
+
```
|
148
|
+
|
149
|
+
## Python Function Output Format
|
150
|
+
|
151
|
+
When using the `--functions` mode, each Python function you define is expected to return a dictionary in the following format:
|
152
|
+
|
153
|
+
```python
|
154
|
+
{
|
155
|
+
'result': [
|
156
|
+
{'label': <label_or_labels>, 'value': <numeric_value>}
|
157
|
+
],
|
158
|
+
'labels': [<label_name_1>]
|
159
|
+
}
|
160
|
+
```
|
161
|
+
|
162
|
+
### Explanation:
|
163
|
+
|
164
|
+
| Key | Description |
|
165
|
+
|--------|---------------------------------------------------------------------------|
|
166
|
+
| `result` | A list of dictionaries, each containing a `label` and a corresponding numeric `value`. |
|
167
|
+
| `labels` | A list of label names (used as Prometheus labels). |
|
168
|
+
|
169
|
+
|
170
|
+
## Command-Line Options
|
171
|
+
|
172
|
+
The following command-line options are available when running FlexMetric:
|
173
|
+
|
174
|
+
| Option | Description | Default |
|
175
|
+
|---------------------|----------------------------------------------------------|----------------------------|
|
176
|
+
| `--port` | Port for the Prometheus metrics server (`/metrics`) | `8000` |
|
177
|
+
| `--commands` | Enable commands mode | |
|
178
|
+
| `--commands-config` | Path to commands YAML file | `commands.yaml` |
|
179
|
+
| `--database` | Enable database mode | |
|
180
|
+
| `--database-config` | Path to database YAML file | `database.yaml` |
|
181
|
+
| `--queries-config` | Path to queries YAML file | `queries.yaml` |
|
182
|
+
| `--functions` | Enable Python functions mode | |
|
183
|
+
| `--functions-file` | Path to functions file | `executable_functions.txt` |
|
184
|
+
| `--expose-api` | Enable Flask API mode to receive external metrics | |
|
185
|
+
| `--flask-port` | Port for the Flask API (`/update_metric`) | `5000` |
|
186
|
+
| `--flask-host` | Hostname for the Flask API | `0.0.0.0` |
|
187
|
+
| `--enable-https` | Enable HTTPS for the Flask API | |
|
188
|
+
| `--ssl-cert` | Path to SSL certificate file (`cert.pem`) | |
|
189
|
+
| `--ssl-key` | Path to SSL private key file (`key.pem`) | |
|
190
|
+
|
191
|
+
### Example Command:
|
192
|
+
|
193
|
+
```bash
|
194
|
+
flexmetric --commands --commands-config commands.yaml --port 8000
|
195
|
+
```
|
196
|
+
## Example Prometheus Output
|
197
|
+
|
198
|
+
Once FlexMetric is running, the `/metrics` endpoint will expose metrics in the Prometheus format.
|
199
|
+
|
200
|
+
Example output:
|
201
|
+
```bash
|
202
|
+
disk_usage_gauge{path="/"} 45.0
|
203
|
+
```
|
204
|
+
|
205
|
+
Each metric includes labels and numeric values that Prometheus can scrape and visualize.
|
206
|
+
|
207
|
+
---
|
208
|
+
|
209
|
+
## Future Enhancements
|
210
|
+
|
211
|
+
The following features are planned or under consideration to improve FlexMetric:
|
212
|
+
|
213
|
+
- Support for additional databases such as PostgreSQL and MySQL.
|
214
|
+
- Enhanced support for more complex scripts and richer label extraction.
|
@@ -2,15 +2,20 @@ import yaml
|
|
2
2
|
import sqlite3
|
3
3
|
import re
|
4
4
|
|
5
|
+
|
5
6
|
def read_yaml_file(file_path):
|
6
|
-
with open(file_path,
|
7
|
+
with open(file_path, "r") as f:
|
7
8
|
return yaml.safe_load(f)
|
8
9
|
|
10
|
+
|
9
11
|
def get_database_config(databases, db_name):
|
10
12
|
for db in databases:
|
11
|
-
if db[
|
13
|
+
if db["name"] == db_name:
|
12
14
|
return db
|
13
|
-
raise ValueError(
|
15
|
+
raise ValueError(
|
16
|
+
f"[ERROR] Database config for '{db_name}' not found in database.yaml."
|
17
|
+
)
|
18
|
+
|
14
19
|
|
15
20
|
def execute_sqlite_query(db_path, query):
|
16
21
|
try:
|
@@ -24,11 +29,13 @@ def execute_sqlite_query(db_path, query):
|
|
24
29
|
print(f"[ERROR] SQLite query failed on {db_path}: {e}")
|
25
30
|
return None
|
26
31
|
|
32
|
+
|
27
33
|
def is_safe_query(query):
|
28
34
|
# Remove leading spaces and brackets
|
29
35
|
cleaned_query = query.strip().lower()
|
30
36
|
# Match only queries that start with "select"
|
31
|
-
return re.match(r
|
37
|
+
return re.match(r"^\(*\s*select", cleaned_query) is not None
|
38
|
+
|
32
39
|
|
33
40
|
def process_database_queries(queries_file, databases_file):
|
34
41
|
# Get queries from queries file
|
@@ -36,24 +43,26 @@ def process_database_queries(queries_file, databases_file):
|
|
36
43
|
# Get database from database file
|
37
44
|
databases_config = read_yaml_file(databases_file)
|
38
45
|
|
39
|
-
commands = queries_config.get(
|
40
|
-
databases = databases_config.get(
|
46
|
+
commands = queries_config.get("commands", [])
|
47
|
+
databases = databases_config.get("databases", [])
|
41
48
|
|
42
49
|
all_results = []
|
43
50
|
|
44
51
|
for cmd in commands:
|
45
52
|
try:
|
46
|
-
db_conf = get_database_config(databases, cmd[
|
53
|
+
db_conf = get_database_config(databases, cmd["database"])
|
47
54
|
|
48
|
-
if db_conf[
|
49
|
-
print(
|
55
|
+
if db_conf["db_type"] != "sqlite":
|
56
|
+
print(
|
57
|
+
f"[WARN] Unsupported database type: {db_conf['db_type']} in command {cmd['name']}"
|
58
|
+
)
|
50
59
|
continue
|
51
60
|
|
52
|
-
db_path = db_conf[
|
53
|
-
query = cmd[
|
54
|
-
label = cmd[
|
55
|
-
label_value = cmd[
|
56
|
-
# check if query is safe
|
61
|
+
db_path = db_conf["db_connection"]
|
62
|
+
query = cmd["query"]
|
63
|
+
label = cmd["label"]
|
64
|
+
label_value = cmd["label_value"]
|
65
|
+
# check if query is safe
|
57
66
|
if is_safe_query(query):
|
58
67
|
value = execute_sqlite_query(db_path, query)
|
59
68
|
else:
|
@@ -62,14 +71,18 @@ def process_database_queries(queries_file, databases_file):
|
|
62
71
|
|
63
72
|
if value is not None:
|
64
73
|
result = {
|
65
|
-
|
66
|
-
|
74
|
+
"result": [{"label": label_value, "value": value}],
|
75
|
+
"labels": [label],
|
67
76
|
}
|
68
77
|
all_results.append(result)
|
69
78
|
else:
|
70
|
-
print(
|
79
|
+
print(
|
80
|
+
f"[INFO] No result for command '{cmd['name']}' on database '{cmd['database']}'"
|
81
|
+
)
|
71
82
|
|
72
83
|
except Exception as e:
|
73
|
-
print(
|
84
|
+
print(
|
85
|
+
f"[ERROR] Processing command '{cmd.get('name', 'unknown')}' failed: {e}"
|
86
|
+
)
|
74
87
|
|
75
|
-
return all_results
|
88
|
+
return all_results
|
@@ -0,0 +1,56 @@
|
|
1
|
+
from collections import deque
|
2
|
+
import threading
|
3
|
+
import time
|
4
|
+
import sched
|
5
|
+
|
6
|
+
class ExpiringMetricQueue:
|
7
|
+
def __init__(self, expiry_seconds=60, cleanup_interval=5):
|
8
|
+
self.queue = deque()
|
9
|
+
self.expiry_seconds = expiry_seconds
|
10
|
+
self.cleanup_interval = cleanup_interval
|
11
|
+
self.lock = threading.Lock()
|
12
|
+
self.scheduler = sched.scheduler(time.time, time.sleep)
|
13
|
+
self._start_cleanup()
|
14
|
+
|
15
|
+
def put(self, metric):
|
16
|
+
metric['timestamp'] = time.time()
|
17
|
+
with self.lock:
|
18
|
+
self.queue.append(metric)
|
19
|
+
|
20
|
+
def pop_all(self):
|
21
|
+
with self.lock:
|
22
|
+
items = list(self.queue)
|
23
|
+
self.queue.clear()
|
24
|
+
cleaned_items = []
|
25
|
+
for item in items:
|
26
|
+
cleaned_item = {k: v for k, v in item.items() if k != 'timestamp'}
|
27
|
+
cleaned_items.append(cleaned_item)
|
28
|
+
|
29
|
+
return cleaned_items
|
30
|
+
|
31
|
+
def _start_cleanup_thread(self):
|
32
|
+
thread = threading.Thread(target=self._cleanup, daemon=True)
|
33
|
+
thread.start()
|
34
|
+
|
35
|
+
def _start_cleanup(self):
|
36
|
+
def scheduled_cleanup():
|
37
|
+
self._cleanup()
|
38
|
+
# Schedule next run
|
39
|
+
self.scheduler.enter(self.cleanup_interval, 1, scheduled_cleanup)
|
40
|
+
|
41
|
+
# Schedule first run immediately
|
42
|
+
self.scheduler.enter(0, 1, scheduled_cleanup)
|
43
|
+
threading.Thread(target=self.scheduler.run, daemon=True).start()
|
44
|
+
|
45
|
+
def _cleanup(self):
|
46
|
+
current_time = time.time()
|
47
|
+
with self.lock:
|
48
|
+
original_len = len(self.queue)
|
49
|
+
self.queue = deque(
|
50
|
+
[item for item in self.queue if current_time - item['timestamp'] <= self.expiry_seconds]
|
51
|
+
)
|
52
|
+
cleaned = original_len - len(self.queue)
|
53
|
+
if cleaned > 0:
|
54
|
+
print(f"[MetricQueue] Cleaned {cleaned} expired metrics")
|
55
|
+
|
56
|
+
metric_queue = ExpiringMetricQueue(expiry_seconds=60, cleanup_interval=60)
|