init
This commit is contained in:
parent
a38d6f00ea
commit
199e0c4663
5 changed files with 184 additions and 0 deletions
13
Dockerfile
Normal file
13
Dockerfile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
FROM python:3.9-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "main.py"]
|
||||
31
docker-compose.yaml
Normal file
31
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#vrsion: '3.8'
|
||||
|
||||
services:
|
||||
owen-exporter:
|
||||
build: .
|
||||
container_name: owen-exporter
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- LOGIN=l_salnikov@internet.ru
|
||||
- PASSWORD=}v]CT]Q"_g7>4H%
|
||||
ports:
|
||||
- "8000:8000"
|
||||
networks:
|
||||
- monitoring-net
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./prometheus:/etc/prometheus
|
||||
networks:
|
||||
- monitoring-net
|
||||
depends_on:
|
||||
- owen-exporter
|
||||
|
||||
networks:
|
||||
monitoring-net:
|
||||
driver: bridge
|
||||
128
main.py
Executable file
128
main.py
Executable file
|
|
@ -0,0 +1,128 @@
|
|||
import json
|
||||
import time
|
||||
import os
|
||||
import requests
|
||||
import logging
|
||||
from prometheus_client import start_http_server, Gauge
|
||||
from unidecode import unidecode
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Настройка логгирования
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Устанавливаем соответствие кириллицы латинице
|
||||
TRANS_TABLE = str.maketrans({
|
||||
"у": "u", "с": "s", "т": "t", "а": "a", "н": "n", "о": "o", "в": "v", "л": "l",
|
||||
"е": "e", "ч": "ch", "а": "a", "с": "s", "т": "t", "ь": "", "п": "p", "ч": "ch",
|
||||
"-": "_", ".": "_", "'": "", "`": "", '"': "", "h": "h", "h": "h" # Оставляем 'h' как есть
|
||||
})
|
||||
|
||||
def sanitize_metric_name(name):
|
||||
# Удаляем все недопустимые символы
|
||||
name = unidecode(name) # Транслитерация сначала
|
||||
name = name.lower() # Приводим к нижнему регистру
|
||||
name = name.translate(TRANS_TABLE) # Применяем таблицу замен
|
||||
|
||||
# Дополнительная очистка от недопустимых символов
|
||||
valid_chars = []
|
||||
for c in name:
|
||||
if c.isalpha() or c.isdigit() or c == '_':
|
||||
valid_chars.append(c)
|
||||
elif c in ['-', '.', ' ']:
|
||||
valid_chars.append('_')
|
||||
|
||||
name = ''.join(valid_chars)
|
||||
|
||||
# Удаляем повторяющиеся подчеркивания
|
||||
name = '_'.join(filter(None, name.split('_')))
|
||||
|
||||
# Добавляем префикс, если имя начинается с цифры
|
||||
if name and name[0].isdigit():
|
||||
name = f"metric_{name}"
|
||||
|
||||
# Проверяем, что имя не пустое
|
||||
if not name:
|
||||
name = 'unnamed_metric'
|
||||
|
||||
return name
|
||||
|
||||
def get_token():
|
||||
login = os.getenv("LOGIN")
|
||||
password = os.getenv("PASSWORD")
|
||||
|
||||
if not login or not password:
|
||||
logger.error("Логин или пароль не заданы в .env")
|
||||
raise ValueError("Логин или пароль не заданы в .env")
|
||||
|
||||
data = {'login': login, 'password': password}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
try:
|
||||
req = requests.post("https://api.owencloud.ru/v1/auth/open/", json=data, headers=headers)
|
||||
req.raise_for_status()
|
||||
return "Bearer " + req.json()["token"]
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Ошибка авторизации: {e}")
|
||||
return None
|
||||
|
||||
def load_json_data():
|
||||
token = get_token()
|
||||
if not token:
|
||||
logger.error("Не удалось получить токен. Завершаем работу.")
|
||||
return []
|
||||
|
||||
device_id = "459205"
|
||||
headers = {'Authorization': token}
|
||||
data = json.dumps({'filter': ''})
|
||||
|
||||
try:
|
||||
req = requests.post(f"https://api.owencloud.ru/v1/device/{device_id}", data=data, headers=headers)
|
||||
req.raise_for_status()
|
||||
json_response = req.json()
|
||||
return json_response.get("parameters", [])
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Ошибка запроса устройства: {e}")
|
||||
return []
|
||||
|
||||
metrics = {}
|
||||
|
||||
def main():
|
||||
logger.info("Запуск сервера Prometheus на порту 8000")
|
||||
start_http_server(8000)
|
||||
logger.info("Сервер запущен")
|
||||
|
||||
while True:
|
||||
parameters = load_json_data()
|
||||
|
||||
if parameters:
|
||||
for param in parameters:
|
||||
try:
|
||||
metric_name = sanitize_metric_name(param["name"])
|
||||
value = float(param["value"])
|
||||
|
||||
if metric_name not in metrics:
|
||||
metrics[metric_name] = Gauge(metric_name, "Описание метрики")
|
||||
logger.info(f"Создана новая метрика: {metric_name}")
|
||||
|
||||
metrics[metric_name].set(value)
|
||||
logger.debug(f"Метрика {metric_name} обновлена: {value}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка обработки параметра {param}: {e}")
|
||||
|
||||
time.sleep(60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
8
prometheus/prometheus.yml
Normal file
8
prometheus/prometheus.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'owen-exporter'
|
||||
static_configs:
|
||||
- targets: ['owen-exporter:8000']
|
||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
prometheus_client
|
||||
requests
|
||||
unidecode
|
||||
python-dotenv
|
||||
Loading…
Reference in a new issue