Merge branch 'release/0.1.0'

This commit is contained in:
Jörn-Michael Miehe 2023-09-02 16:34:04 +00:00
commit efb178ab6b
11 changed files with 115 additions and 54 deletions

15
.drone.yml Normal file
View file

@ -0,0 +1,15 @@
---
kind: pipeline
name: default
type: docker
steps:
- name: docker
image: plugins/docker
settings:
repo: yavook/kiwi-simple-metrics
auto_tag: true
username:
from_secret: DOCKER_USERNAME
password:
from_secret: DOCKER_PASSWORD

8
.vscode/launch.json vendored
View file

@ -10,10 +10,10 @@
"request": "launch", "request": "launch",
"module": "kiwi_simple_metrics.main", "module": "kiwi_simple_metrics.main",
"env": { "env": {
"METRIC__INTERVAL": "5", "METRICS__INTERVAL": "5",
"METRIC__LOG__ENABLED": "True", "METRICS__LOG__ENABLED": "True",
"METRIC__DISK__PATHS": "[\"/var\", \"/\", \"/dev\"]", "METRICS__EXTERNAL__ENABLED": "True",
"METRIC__EXTERNAL__EXECUTABLES": "[\"${workspaceFolder}/dummy-metric\"]", "METRICS__EXTERNAL__EXECUTABLES": "[\"${workspaceFolder}/example/dummy-metric\"]",
}, },
"justMyCode": true "justMyCode": true
} }

20
Dockerfile Normal file
View file

@ -0,0 +1,20 @@
FROM python:3.11-alpine
ENV \
PYTHONUNBUFFERED=1
COPY . /usr/src/app
RUN set -ex; \
# buildtime deps
apk add --no-cache \
--virtual .build-deps \
build-base \
gcc \
linux-headers \
;
RUN set -ex; \
pip3 --no-cache-dir install /usr/src/app
ENTRYPOINT ["kiwi-simple-metrics"]

View file

@ -1,3 +1,53 @@
# vscode-python3 # kiwi-simple-metrics
Use this template to jumpstart python development using Visual Studio Code! [![Build Status](https://github.drone.yavook.de/api/badges/yavook/kiwi-simple-metrics/status.svg)](https://github.drone.yavook.de/yavook/kiwi-simple-metrics)
> `kiwi` - simple, consistent, powerful
A lightweight monitoring solution for [`kiwi-scp`](https://github.com/yavook/kiwi-scp), created with [`uptime-kuma`](https://github.com/louislam/uptime-kuma) in mind. Also [on Docker Hub](https://hub.docker.com/r/yavook/kiwi-simple-metrics).
## Quick start
The minimal config to add to one of your `docker-compose.yml` is this:
```yaml
metrics:
image: yavook/kiwi-simple-metrics:0.1
```
- admittedly not useful, but it *does* run monitoring
- every 600 seconds (10 minutes), metrics are evaluated
- measures cpu, memory and swap, and disk usage at "/"
- does not log to stdout
- does not trigger any webhooks
Every aspect of kiwi-simple-metrics can be tweaked by environment variables, so this is a more reasonable configuration example:
```yaml
metrics:
image: yavook/kiwi-simple-metrics:0.1
environment:
METRICS__LOG__ENABLED: "True"
METRICS__WEBHOOK__URL: "https://my.webhook.host/success?report={result}"
METRICS__WEBHOOK__FAIL: "https://my.webhook.host/failure?report={result}"
```
- same metrics as above
- logs reports to stdout
- triggers webhooks (`{result}` is the placeholder for the result string)
## Configuration
These are the environment variables you most likely need:
- `METRICS__INTERVAL`: Time in seconds between metrics evaluation (default: `600`, i.e. 10 minutes)
- `METRICS__LOG__ENABLED`: If truthy, logs reports to stdout (default: `False`)
- `METRICS__[M]__ENABLED`, `METRICS__[M]__THRESHOLD` (with `[M]` from `CPU`, `MEMORY`, `DISK`): Enable or disable each metric, and set its failure threshold
- `METRICS__MEMORY__SWAP`: How swap space is handled in the "memory" report (default: `include`)
- `METRICS__DISK__PATHS`: At which paths the disk usage is measured (default: `["/"]`)
- `METRICS__EXTERNAL__ENABLED`, `METRICS__EXTERNAL__EXECUTABLES`: Setup for `external values`, as further defined in [`metrics/external.py`](./tree/master/kiwi_simple_metrics/metrics/external.py) (default: `False`, `[]`)
- `METRICS__WEBHOOK__URL`, `METRICS__WEBHOOK__FAIL`: Which webhooks to push the reports to (default: `None`, `None`)
All settings can be found in the `SETTINGS` variable defined by module [`kiwi_simple_metrics.settings` in `settings/__init__.py`](./tree/master/kiwi_simple_metrics/settings/__init__.py). For default values, refer to the respective python files.
Example: The above `METRICS__LOG__ENABLED` refers to `SETTINGS.log.enabled`, defined by model [`LogSettings` in `settings/misc.py`](./tree/master/kiwi_simple_metrics/settings/misc.py).

View file

@ -1,8 +0,0 @@
#!/bin/sh
echo "Dummy"
echo "95"
echo "normal"
awk "BEGIN{srand(); r=rand(); print r * 100}"
exit 0

8
example/dummy-metric Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
echo "Dummy" # name
echo "95" # threshold
echo "normal" # inversion
awk "BEGIN{srand(); r=rand(); print r * 100}" # value
exit 0

View file

@ -102,6 +102,9 @@ class Report:
reports = [data.report for data in get_data()] reports = [data.report for data in get_data()]
if not reports:
return None
return cls( return cls(
result=settings.report_outer.format( result=settings.report_outer.format(
name=settings.name, name=settings.name,
@ -123,7 +126,7 @@ class Report:
requests.get( requests.get(
url=str(url).format( url=str(url).format(
urllib.parse.quote_plus(self.result) result=urllib.parse.quote_plus(self.result)
), ),
verify=not SETTINGS.webhook.insecure, verify=not SETTINGS.webhook.insecure,
) )

View file

@ -6,7 +6,7 @@ from .metric import MetricSettings
class Settings(BaseSettings): class Settings(BaseSettings):
model_config = SettingsConfigDict( model_config = SettingsConfigDict(
env_prefix="METRIC__", env_prefix="METRICS__",
env_nested_delimiter="__", env_nested_delimiter="__",
) )

View file

@ -1,8 +1,8 @@
import math import math
from typing import Any, Literal from typing import Any, Literal
from pydantic import (BaseModel, DirectoryPath, Field, FieldValidationInfo, from pydantic import (BaseModel, DirectoryPath, FieldValidationInfo, FilePath,
FilePath, field_validator) field_validator)
class MetricSettings(BaseModel): class MetricSettings(BaseModel):
@ -54,7 +54,7 @@ class CpuMS(MetricSettings):
name: str = "CPU" name: str = "CPU"
threshold: float = math.inf threshold: float = math.inf
# timespan to analyze average CPU usage # timespan in seconds to measure average CPU usage
interval: float = 1 interval: float = 1
@ -81,21 +81,19 @@ class DiskMS(MetricSettings):
count: int | None = 1 count: int | None = 1
# paths to check for disk space # paths to check for disk space
paths: list[DirectoryPath] = Field(default_factory=list) paths: list[DirectoryPath] = [DirectoryPath("/")]
class ExternalMS(MetricSettings): class ExternalMS(MetricSettings):
name: str = "External Metric" name: str = "External Metric"
enabled: bool = False
threshold: float = 0 threshold: float = 0
# always include all defined external values!
count: None = None
# path to executable files # path to executable files
executables: list[FilePath] = Field(default_factory=list) executables: list[FilePath] = []
# wait at most this many seconds for each executable # wait at most this many seconds for each executable
timeout: int = 60 timeout: int = 60
@field_validator("count", mode="after")
@classmethod
def force_none(cls, _) -> int | None:
"""Don't accept a `count` value for the external metric!"""
return None

View file

@ -1,25 +0,0 @@
from pydantic import BaseModel
class SubModel(BaseModel):
optional: int = 42
required: str
class Settings(BaseModel):
sub: SubModel = SubModel(required="foo")
sub2: SubModel = SubModel(required="bar")
def main() -> None:
settings = Settings.model_validate({
"sub": {"optional": "69"},
})
# settings = Settings()
print(settings.model_dump())
if __name__ == "__main__":
main()

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
authors = ["Jörn-Michael Miehe <40151420+ldericher@users.noreply.github.com>"] authors = ["Jörn-Michael Miehe <40151420+ldericher@users.noreply.github.com>"]
description = "" description = "A lightweight monitoring solution for kiwi-scp"
license = "MIT" license = "MIT"
name = "kiwi-simple-metrics" name = "kiwi-simple-metrics"
packages = [{include = "kiwi_simple_metrics"}] packages = [{include = "kiwi_simple_metrics"}]
@ -9,8 +9,8 @@ version = "0.1.0"
[tool.poetry.dependencies] [tool.poetry.dependencies]
psutil = "^5.9.5" psutil = "^5.9.5"
python = "^3.11"
pydantic-settings = "^2.0.3" pydantic-settings = "^2.0.3"
python = "^3.11"
requests = "^2.31.0" requests = "^2.31.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]