Dev 2 #2

Merged
KerradKerridi merged 2 commits from dev-2 into main 2025-09-09 19:22:41 +00:00
9 changed files with 2187 additions and 206 deletions
Showing only changes of commit b34da5015d - Show all commits

View File

@@ -1,4 +1,4 @@
.PHONY: help build up down logs clean restart status deploy backup restore update clean-monitoring monitoring check-deps check-bot-deps
.PHONY: help build up down logs clean restart status deploy backup restore update clean-monitoring monitoring check-deps check-bot-deps check-anonBot-deps
help: ## Показать справку
@echo "🏗️ Production Infrastructure - Доступные команды:"
@@ -11,6 +11,7 @@ help: ## Показать справку
@echo " Grafana: http://localhost:3000 (admin/admin)"
@echo " Server Monitor: http://localhost:9091/health"
@echo " Bot Health: http://localhost:8080/health"
@echo " AnonBot Health: http://localhost:8081/health"
build: ## Собрать все контейнеры
docker-compose build
@@ -36,6 +37,9 @@ logs-grafana: ## Показать логи Grafana
logs-bot: ## Показать логи Telegram бота
docker-compose logs -f telegram-bot
logs-anonBot: ## Показать логи AnonBot
docker-compose logs -f anon-bot
restart: ## Перезапустить все сервисы
docker-compose down
docker-compose build --no-cache
@@ -53,12 +57,16 @@ restart-grafana: ## Перезапустить только Grafana
restart-bot: ## Перезапустить только Telegram бота
docker-compose restart telegram-bot
restart-anonBot: ## Перезапустить только AnonBot
docker-compose restart anon-bot
status: ## Показать статус контейнеров
docker-compose ps
health: ## Проверить здоровье сервисов
@echo "🏥 Checking service health..."
@curl -f http://localhost:8080/health || echo "❌ Bot health check failed"
@curl -f http://localhost:8081/health || echo "❌ AnonBot health check failed"
@curl -f http://localhost:9090/-/healthy || echo "❌ Prometheus health check failed"
@curl -f http://localhost:3000/api/health || echo "❌ Grafana health check failed"
@curl -f http://localhost:9091/health || echo "❌ Server monitor health check failed"
@@ -120,22 +128,26 @@ start: build up ## Собрать и запустить все сервисы
@echo "📊 Prometheus: http://localhost:9090"
@echo "📈 Grafana: http://localhost:3000 (admin/admin)"
@echo "🤖 Bot Health: http://localhost:8080/health"
@echo "🔒 AnonBot Health: http://localhost:8081/health"
@echo "📡 Server Monitor: http://localhost:9091/health"
@echo "📝 Логи: make logs"
stop: down ## Остановить все сервисы
@echo "🛑 Все сервисы остановлены"
test: check-deps check-bot-deps ## Запустить все тесты в проекте
test: check-deps check-bot-deps check-anonBot-deps ## Запустить все тесты в проекте
@echo "🧪 Запускаю все тесты в проекте..."
@echo "📊 Тесты инфраструктуры..."
@python3 -m pytest tests/infra/ -q --tb=no
@echo "🤖 Тесты Telegram бота..."
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ -q --tb=no
@echo "🔒 Тесты AnonBot..."
@cd bots/AnonBot && python3 -m pytest tests/ -q --tb=no
@echo "✅ Все тесты завершены!"
@echo "📈 Общая статистика:"
@echo " - Инфраструктура: $(shell python3 count_tests.py | head -1) тестов"
@echo " - Telegram бот: $(shell python3 count_tests.py | head -2 | tail -1) тестов"
@echo " - AnonBot: $(shell python3 count_tests.py | head -3 | tail -1) тестов"
@echo " - Всего: $(shell python3 count_tests.py | tail -1) тестов"
test-all: ## Запустить все тесты в одном процессе (только для разработчиков)
@@ -152,16 +164,23 @@ test-bot: check-bot-deps ## Запустить тесты Telegram бота
@echo "🤖 Запускаю тесты Telegram бота..."
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ -v
test-coverage: check-deps check-bot-deps ## Запустить все тесты с отчетом о покрытии
test-anonBot: check-anonBot-deps ## Запустить тесты AnonBot
@echo "🔒 Запускаю тесты AnonBot..."
@cd bots/AnonBot && python3 -m pytest tests/ -v
test-coverage: check-deps check-bot-deps check-anonBot-deps ## Запустить все тесты с отчетом о покрытии
@echo "📊 Запускаю все тесты с отчетом о покрытии..."
@echo "📈 Покрытие для инфраструктуры..."
@python3 -m pytest tests/infra/ --cov=infra --cov-report=term-missing --cov-report=html:htmlcov/infra
@echo "🤖 Покрытие для Telegram бота..."
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ --cov=helper_bot --cov-report=term-missing --cov-report=html:htmlcov/bot
@echo "🔒 Покрытие для AnonBot..."
@cd bots/AnonBot && python3 -m pytest tests/ --cov=. --cov-report=term-missing --cov-report=html:htmlcov/anonbot
@echo "📊 Отчеты о покрытии сохранены в htmlcov/"
@echo "📈 Общая статистика:"
@echo " - Инфраструктура: $(shell python3 count_tests.py | head -1) тестов"
@echo " - Telegram бот: $(shell python3 count_tests.py | head -2 | tail -1) тестов"
@echo " - AnonBot: $(shell python3 count_tests.py | head -3 | tail -1) тестов"
@echo " - Всего: $(shell python3 count_tests.py | tail -1) тестов"
test-clean: ## Очистить все файлы тестирования и отчеты
@@ -173,6 +192,9 @@ test-clean: ## Очистить все файлы тестирования и о
@rm -rf bots/telegram-helper-bot/.pytest_cache/
@rm -rf bots/telegram-helper-bot/htmlcov/
@rm -rf bots/telegram-helper-bot/.coverage
@rm -rf bots/AnonBot/.pytest_cache/
@rm -rf bots/AnonBot/htmlcov/
@rm -rf bots/AnonBot/.coverage
@find . -name "*.pyc" -delete 2>/dev/null || true
@find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
@echo "✅ Файлы тестирования очищены"
@@ -187,6 +209,8 @@ check-ports: ## Проверить занятые порты
@lsof -i :9091 2>/dev/null || echo " Free"
@echo "Port 8080 (Telegram Bot):"
@lsof -i :8080 2>/dev/null || echo " Free"
@echo "Port 8081 (AnonBot):"
@lsof -i :8081 2>/dev/null || echo " Free"
check-grafana: ## Проверить состояние Grafana
@echo "📊 Checking Grafana status..."
@@ -202,6 +226,11 @@ check-bot-deps: ## Проверить зависимости Telegram бота
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -c "import aiogram, aiosqlite, pytest" 2>/dev/null || (echo "❌ Отсутствуют зависимости бота. Установите: cd bots/telegram-helper-bot && source .venv/bin/activate && pip install -r requirements.txt" && exit 1)
@echo "✅ Зависимости Telegram бота установлены"
check-anonBot-deps: ## Проверить зависимости AnonBot
@echo "🔍 Проверяю зависимости AnonBot..."
@cd bots/AnonBot && python3 -c "import aiogram, aiosqlite, pytest, loguru, pydantic" 2>/dev/null || (echo "❌ Отсутствуют зависимости AnonBot. Установите: cd bots/AnonBot && pip install -r requirements.txt" && exit 1)
@echo "✅ Зависимости AnonBot установлены"
logs-tail: ## Показать последние логи всех сервисов
@echo "📝 Recent logs from all services:"
@docker-compose logs --tail=50

View File

@@ -130,11 +130,64 @@ services:
deploy:
resources:
limits:
memory: 512M
memory: 256M
cpus: '0.5'
reservations:
memory: 128M
cpus: '0.25'
# AnonBot - Anonymous Q&A Bot
anon-bot:
build:
context: ./bots/AnonBot
dockerfile: Dockerfile
container_name: bots_anon_bot
restart: unless-stopped
env_file:
- ./bots/AnonBot/.env
ports:
- "8081:8081"
environment:
- PYTHONPATH=/app
- PYTHONUNBUFFERED=1
- DOCKER_CONTAINER=true
- LOG_LEVEL=${LOG_LEVEL:-INFO}
# AnonBot settings
- ANON_BOT_TOKEN=${BOT_TOKEN}
- ANON_BOT_ADMINS=${ADMINS}
- ANON_BOT_DATABASE_PATH=/app/database/anon_qna.db
- ANON_BOT_DEBUG=${DEBUG:-false}
- ANON_BOT_MAX_QUESTION_LENGTH=${MAX_QUESTION_LENGTH:-1000}
- ANON_BOT_MAX_ANSWER_LENGTH=${MAX_ANSWER_LENGTH:-2000}
# Rate limiting settings
- RATE_LIMIT_ENV=${RATE_LIMIT_ENV:-production}
- RATE_LIMIT_MESSAGES_PER_SECOND=${RATE_LIMIT_MESSAGES_PER_SECOND:-0.5}
- RATE_LIMIT_BURST_LIMIT=${RATE_LIMIT_BURST_LIMIT:-2}
- RATE_LIMIT_RETRY_MULTIPLIER=${RATE_LIMIT_RETRY_MULTIPLIER:-1.5}
- RATE_LIMIT_MAX_RETRY_DELAY=${RATE_LIMIT_MAX_RETRY_DELAY:-30.0}
- RATE_LIMIT_MAX_RETRIES=${RATE_LIMIT_MAX_RETRIES:-3}
volumes:
- ./bots/AnonBot/database:/app/database:rw
- ./bots/AnonBot/logs:/app/logs:rw
- ./bots/AnonBot/.env:/app/.env:ro
networks:
- bots_network
depends_on:
- prometheus
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.25'
reservations:
memory: 128M
cpus: '0.1'
volumes:
prometheus_data:

View File

@@ -0,0 +1,874 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "anon_bot_active_users",
"interval": "",
"legendFormat": "Active Users",
"refId": "A"
}
],
"title": "Active Users",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 6,
"y": 0
},
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "anon_bot_active_questions",
"interval": "",
"legendFormat": "Active Questions",
"refId": "A"
}
],
"title": "Active Questions",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_questions_total{status=\"created\"}[5m]) * 60",
"interval": "",
"legendFormat": "Questions Created/min",
"refId": "A"
},
{
"expr": "rate(anon_bot_questions_total{status=\"processed\"}[5m]) * 60",
"interval": "",
"legendFormat": "Questions Processed/min",
"refId": "B"
},
{
"expr": "rate(anon_bot_questions_total{status=\"rejected\"}[5m]) * 60",
"interval": "",
"legendFormat": "Questions Rejected/min",
"refId": "C"
},
{
"expr": "rate(anon_bot_questions_total{status=\"deleted\"}[5m]) * 60",
"interval": "",
"legendFormat": "Questions Deleted/min",
"refId": "D"
}
],
"title": "Questions Flow (per minute)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_answers_total{status=\"sent\"}[5m]) * 60",
"interval": "",
"legendFormat": "Answers Sent/min",
"refId": "A"
},
{
"expr": "rate(anon_bot_answers_total{status=\"delivered\"}[5m]) * 60",
"interval": "",
"legendFormat": "Answers Delivered/min",
"refId": "B"
},
{
"expr": "rate(anon_bot_answers_total{status=\"delivery_failed\"}[5m]) * 60",
"interval": "",
"legendFormat": "Delivery Failed/min",
"refId": "C"
}
],
"title": "Answers Flow (per minute)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_users_total{action=\"created\"}[5m]) * 60",
"interval": "",
"legendFormat": "New Users/min",
"refId": "A"
},
{
"expr": "rate(anon_bot_users_total{action=\"updated\"}[5m]) * 60",
"interval": "",
"legendFormat": "Updated Users/min",
"refId": "B"
}
],
"title": "User Activity (per minute)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 16
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "sum(rate(anon_bot_messages_total[1d])) by (message_type)",
"interval": "",
"legendFormat": "{{message_type}} (daily)",
"refId": "A"
}
],
"title": "Daily Trends - Messages",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 16
},
"id": 7,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "sum(rate(anon_bot_questions_total[1d])) by (status)",
"interval": "",
"legendFormat": "{{status}} (daily)",
"refId": "A"
}
],
"title": "Daily Trends - Questions",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 0,
"y": 24
},
"id": 8,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "anon_bot_active_users",
"interval": "",
"legendFormat": "Live Active Users",
"refId": "A"
}
],
"title": "Live Activity - Active Users",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 6,
"y": 24
},
"id": 9,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "rate(anon_bot_messages_total[1m]) * 60",
"interval": "",
"legendFormat": "Messages/min",
"refId": "A"
}
],
"title": "Messages per Minute",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 12,
"y": 24
},
"id": 10,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "rate(anon_bot_questions_total[1h]) * 3600",
"interval": "",
"legendFormat": "Questions/hour",
"refId": "A"
}
],
"title": "Questions per Hour",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 18,
"y": 24
},
"id": 11,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "rate(anon_bot_answers_total[1m]) * 60",
"interval": "",
"legendFormat": "Answers/min",
"refId": "A"
}
],
"title": "Answers per Minute",
"type": "stat"
}
],
"refresh": "5s",
"schemaVersion": 30,
"style": "dark",
"tags": [
"anonbot",
"overview",
"monitoring"
],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "AnonBot Overview",
"uid": "anonbot-overview",
"version": 1,
"weekStart": ""
}

View File

@@ -0,0 +1,877 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "histogram_quantile(0.95, rate(anon_bot_message_processing_seconds_bucket[5m]))",
"interval": "",
"legendFormat": "Message Processing 95th percentile",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, rate(anon_bot_question_processing_seconds_bucket[5m]))",
"interval": "",
"legendFormat": "Question Processing 95th percentile",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, rate(anon_bot_answer_processing_seconds_bucket[5m]))",
"interval": "",
"legendFormat": "Answer Processing 95th percentile",
"refId": "C"
}
],
"title": "Response Time - 95th Percentile",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_message_processing_seconds_bucket[5m])",
"interval": "",
"legendFormat": "{{le}}",
"refId": "A"
}
],
"title": "Latency Heatmap - Message Processing",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "histogram_quantile(0.95, rate(anon_bot_db_query_duration_seconds_bucket[5m]))",
"interval": "",
"legendFormat": "DB Query 95th percentile - {{operation}}/{{table}}",
"refId": "A"
}
],
"title": "Database Performance - Query Duration",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 0,
"y": 16
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "anon_bot_db_connections_active",
"interval": "",
"legendFormat": "Active DB Connections",
"refId": "A"
}
],
"title": "Database Connections - Active",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 80
},
{
"color": "red",
"value": 100
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 6,
"x": 6,
"y": 16
},
"id": 5,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "8.5.0",
"targets": [
{
"expr": "anon_bot_db_pool_utilization_percent",
"interval": "",
"legendFormat": "Pool Utilization %",
"refId": "A"
}
],
"title": "DB Pool Utilization",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_messages_total{status=\"success\"}[5m]) / rate(anon_bot_messages_total[5m]) * 100",
"interval": "",
"legendFormat": "Messages Success Rate",
"refId": "A"
},
{
"expr": "rate(anon_bot_questions_total{status=\"processed\"}[5m]) / rate(anon_bot_questions_total[5m]) * 100",
"interval": "",
"legendFormat": "Questions Success Rate",
"refId": "B"
},
{
"expr": "rate(anon_bot_answers_total{status=\"sent\"}[5m]) / rate(anon_bot_answers_total[5m]) * 100",
"interval": "",
"legendFormat": "Answers Success Rate",
"refId": "C"
}
],
"title": "Success/Error Rates",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 16
},
"id": 7,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_errors_total[5m])",
"interval": "",
"legendFormat": "{{component}} - {{error_type}}",
"refId": "A"
}
],
"title": "Error Rate by Component",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 24
},
"id": 8,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "sum(rate(anon_bot_errors_total[5m])) by (error_type)",
"interval": "",
"legendFormat": "{{error_type}}",
"refId": "A"
}
],
"title": "Error Types Distribution",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 24
},
"id": 9,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_db_queries_total{status=\"error\"}[5m])",
"interval": "",
"legendFormat": "{{operation}}/{{table}}",
"refId": "A"
}
],
"title": "Database Errors",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 32
},
"id": 10,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "rate(anon_bot_pagination_errors_total[5m])",
"interval": "",
"legendFormat": "{{entity_type}} - {{error_type}}",
"refId": "A"
}
],
"title": "Pagination Errors",
"type": "timeseries"
}
],
"refresh": "5s",
"schemaVersion": 30,
"style": "dark",
"tags": [
"anonbot",
"performance",
"monitoring"
],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Performance AnonBot",
"uid": "anonbot-performance",
"version": 1,
"weekStart": ""
}

View File

@@ -361,6 +361,284 @@
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8}
},
{
"id": 11,
"title": "AnonBot Health Status",
"type": "timeseries",
"targets": [
{
"expr": "rate(anon_bot_errors_total[5m])",
"legendFormat": "{{component}} - {{error_type}}"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"unit": "short"
}
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 24}
},
{
"id": 12,
"title": "AnonBot Database Connections",
"type": "timeseries",
"targets": [
{
"expr": "anon_bot_db_connections_active",
"legendFormat": "Active Connections"
},
{
"expr": "rate(anon_bot_db_connections_total[5m])",
"legendFormat": "Total Connections/min - {{status}}"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"unit": "short"
}
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 24}
},
{
"id": 13,
"title": "AnonBot System Health",
"type": "stat",
"targets": [
{
"expr": "anon_bot_active_users",
"legendFormat": "Active Users"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 10},
{"color": "red", "value": 50}
]
},
"unit": "short"
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"gridPos": {"h": 8, "w": 6, "x": 0, "y": 32}
},
{
"id": 14,
"title": "AnonBot Active Questions",
"type": "stat",
"targets": [
{
"expr": "anon_bot_active_questions",
"legendFormat": "Active Questions"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 20},
{"color": "red", "value": 100}
]
},
"unit": "short"
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"gridPos": {"h": 8, "w": 6, "x": 6, "y": 32}
},
{
"id": 15,
"title": "AnonBot Message Rate",
"type": "stat",
"targets": [
{
"expr": "rate(anon_bot_messages_total[1m]) * 60",
"legendFormat": "Messages/min"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 10},
{"color": "red", "value": 50}
]
},
"unit": "short"
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"gridPos": {"h": 8, "w": 6, "x": 12, "y": 32}
},
{
"id": 16,
"title": "AnonBot Error Rate",
"type": "stat",
"targets": [
{
"expr": "rate(anon_bot_errors_total[5m])",
"legendFormat": "Errors/min"
}
],
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 1},
{"color": "red", "value": 5}
]
},
"unit": "short"
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"gridPos": {"h": 8, "w": 6, "x": 18, "y": 32}
}
],
"time": {

View File

@@ -1,188 +0,0 @@
# PID Manager - Управление процессами ботов
## Описание
`pid_manager.py` - это общий модуль для управления PID файлами всех ботов в проекте. Он обеспечивает создание, отслеживание и очистку PID файлов для мониторинга состояния процессов.
## Использование
### Для новых ботов
Чтобы добавить PID мониторинг в новый бот, выполните следующие шаги:
1. **Импортируйте PID менеджер в ваш скрипт запуска:**
```python
import sys
import os
# Добавляем путь к инфраструктуре в sys.path
infra_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'infra', 'monitoring')
if infra_path not in sys.path:
sys.path.insert(0, infra_path)
from pid_manager import get_bot_pid_manager
```
2. **Создайте PID менеджер в начале main функции:**
```python
async def main():
# Создаем PID менеджер для отслеживания процесса (если доступен)
pid_manager = None
if get_bot_pid_manager:
pid_manager = get_bot_pid_manager("your_bot_name") # Замените на имя вашего бота
if not pid_manager.create_pid_file():
logger.error("Не удалось создать PID файл, завершаем работу")
return
else:
logger.info("PID менеджер недоступен, запуск без PID файла")
# Ваш код запуска бота...
```
3. **Очистите PID файл при завершении:**
```python
try:
# Ваш код работы бота...
finally:
# Очищаем PID файл (если PID менеджер доступен)
if pid_manager:
pid_manager.cleanup_pid_file()
```
### Для мониторинга
Чтобы добавить новый бот в систему мониторинга:
```python
from infra.monitoring.metrics_collector import MetricsCollector
# Создаем экземпляр коллектора метрик
collector = MetricsCollector()
# Добавляем новый бот в мониторинг
collector.add_bot_to_monitoring("your_bot_name")
# Теперь можно проверять статус
status, uptime = collector.check_process_status("your_bot_name")
```
## Структура файлов
```
prod/
├── infra/
│ └── monitoring/
│ ├── pid_manager.py # Основной модуль
│ ├── metrics_collector.py # Мониторинг процессов
│ └── README_PID_MANAGER.md # Эта документация
├── bots/
│ ├── telegram-helper-bot/
│ │ └── run_helper.py # Использует PID менеджер
│ └── your-new-bot/
│ └── run_your_bot.py # Будет использовать PID менеджер
├── helper_bot.pid # PID файл helper_bot
├── your_bot.pid # PID файл вашего бота
└── .gitignore # Содержит *.pid
```
## API
### PIDManager
- `create_pid_file()` - Создает PID файл
- `cleanup_pid_file()` - Удаляет PID файл
- `is_running()` - Проверяет, запущен ли процесс
- `get_pid()` - Получает PID из файла
### Функции
- `get_bot_pid_manager(bot_name)` - Создает PID менеджер для бота
- `create_pid_manager(process_name, project_root)` - Создает PID менеджер с настройками
## Примеры
### Простой бот
```python
import asyncio
from pid_manager import get_bot_pid_manager
async def main():
# Создаем PID менеджер
pid_manager = get_bot_pid_manager("simple_bot")
if not pid_manager.create_pid_file():
print("Не удалось создать PID файл")
return
try:
# Ваш код бота
print("Бот запущен...")
await asyncio.sleep(3600) # Работаем час
finally:
# Очищаем PID файл
pid_manager.cleanup_pid_file()
if __name__ == '__main__':
asyncio.run(main())
```
### Бот с обработкой сигналов
```python
import asyncio
import signal
from pid_manager import get_bot_pid_manager
async def main():
pid_manager = get_bot_pid_manager("advanced_bot")
if not pid_manager.create_pid_file():
return
# Флаг для корректного завершения
shutdown_event = asyncio.Event()
def signal_handler(signum, frame):
print(f"Получен сигнал {signum}, завершаем работу...")
shutdown_event.set()
# Регистрируем обработчики сигналов
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
try:
# Ваш код бота
await shutdown_event.wait()
finally:
pid_manager.cleanup_pid_file()
if __name__ == '__main__':
asyncio.run(main())
```
## Примечания
- PID файлы создаются в корне проекта
- Все PID файлы автоматически игнорируются Git (см. `.gitignore`)
- PID менеджер автоматически обрабатывает сигналы SIGTERM и SIGINT
- При завершении процесса PID файл автоматически удаляется
- Система мониторинга автоматически находит PID файлы в корне проекта
## Изолированный запуск
При запуске бота изолированно (без доступа к основному проекту):
- PID менеджер автоматически не создается
- Бот запускается без PID файла
- В логах появляется сообщение "PID менеджер недоступен (изолированный запуск), PID файл не создается"
- Это позволяет запускать бота в любой среде без ошибок
## Автоматическое определение
Система автоматически определяет доступность PID менеджера:
1. **В основном проекте**: PID менеджер доступен, создается PID файл для мониторинга
2. **Изолированно**: PID менеджер недоступен, бот работает без PID файла
3. **Fallback**: Если PID менеджер недоступен, бот продолжает работать нормально

View File

@@ -64,6 +64,39 @@ class MessageSender:
logger.error(f"Ошибка при отправке сообщения в Telegram: {e}")
return False
async def get_anonbot_status(self) -> Tuple[str, str]:
"""Получение статуса AnonBot через HTTP API"""
try:
async with aiohttp.ClientSession() as session:
# AnonBot доступен через Docker network
url = "http://bots_anon_bot:8081/status"
async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as response:
if response.status == 200:
data = await response.json()
status = data.get('status', 'unknown')
uptime = data.get('uptime', 'unknown')
# Форматируем статус с эмодзи
if status == 'running':
status_emoji = ""
elif status == 'stopped':
status_emoji = ""
else:
status_emoji = "⚠️"
return f"{status_emoji}", uptime
else:
logger.warning(f"AnonBot API вернул статус {response.status}")
return "⚠️ AnonBot", "API недоступен"
except aiohttp.ClientError as e:
logger.warning(f"Ошибка подключения к AnonBot API: {e}")
return "", "Недоступен"
except Exception as e:
logger.error(f"Неожиданная ошибка при получении статуса AnonBot: {e}")
return "⚠️", "Ошибка"
def should_send_status(self) -> bool:
"""Проверка, нужно ли отправить статус (каждые N минут)"""
now = datetime.now()
@@ -147,11 +180,14 @@ class MessageSender:
else:
return "🚨"
def get_status_message(self, system_info: Dict) -> str:
async def get_status_message(self, system_info: Dict) -> str:
"""Формирование сообщения со статусом сервера"""
try:
helper_bot_status, helper_bot_uptime = self.metrics_collector.check_process_status('helper_bot')
# Получаем статус AnonBot
anonbot_status, anonbot_uptime = await self.get_anonbot_status()
# Получаем эмодзи для всех метрик
cpu_emoji = self._get_cpu_emoji(system_info['cpu_percent'])
ram_emoji = self._get_memory_emoji(system_info['ram_percent'])
@@ -183,6 +219,7 @@ Read: <b>{system_info['disk_read_speed']}</b> | Write: <b>{system_info['disk_wri
**🤖 Процессы:**
{helper_bot_status} helper-bot - {helper_bot_uptime}
{anonbot_status} AnonBot - {anonbot_uptime}
---------------------------------
⏰ Uptime сервера: {system_info['system_uptime']}
🔍 Уровень мониторинга: {level_text} ({monitoring_level})"""
@@ -259,7 +296,7 @@ Read: <b>{system_info['disk_read_speed']}</b> | Write: <b>{system_info['disk_wri
logger.error("Не удалось получить информацию о системе")
return False
status_message = self.get_status_message(system_info)
status_message = await self.get_status_message(system_info)
success = await self.send_telegram_message(self.group_for_logs, status_message)
# Обновляем время последней отправки только при успешной отправке

View File

@@ -590,13 +590,16 @@ class MetricsCollector:
alerts.append(('cpu', system_info['cpu_percent'], f"Нагрузка за 1 мин: {system_info['load_avg_1m']}"))
logger.warning(f"CPU ALERT: {system_info['cpu_percent']:.1f}% > {self.threshold}% (задержка {self.alert_delays['cpu']}s)")
else:
# CPU ниже порога - сбрасываем состояние
# CPU ниже порога - сбрасываем состояние только если был активный алерт
if self.alert_states['cpu']:
self.alert_states['cpu'] = False
recoveries.append(('cpu', system_info['cpu_percent']))
logger.info(f"CPU RECOVERY: {system_info['cpu_percent']:.1f}% < {self.recovery_threshold}%")
# Сбрасываем время начала превышения
# Сбрасываем время начала превышения только после отправки алерта
self.alert_start_times['cpu'] = None
elif system_info['cpu_percent'] < self.recovery_threshold and self.alert_start_times['cpu'] is not None:
# Если CPU опустился значительно ниже порога, сбрасываем время начала превышения
logger.debug(f"CPU значительно ниже порога {self.recovery_threshold}%: {system_info['cpu_percent']:.1f}% - сбрасываем время начала превышения")
self.alert_start_times['cpu'] = None
# Проверка RAM с задержкой
@@ -613,13 +616,16 @@ class MetricsCollector:
alerts.append(('ram', system_info['ram_percent'], f"Используется: {system_info['ram_used']} GB из {system_info['ram_total']} GB"))
logger.warning(f"RAM ALERT: {system_info['ram_percent']:.1f}% > {self.threshold}% (задержка {self.alert_delays['ram']}s)")
else:
# RAM ниже порога - сбрасываем состояние
# RAM ниже порога - сбрасываем состояние только если был активный алерт
if self.alert_states['ram']:
self.alert_states['ram'] = False
recoveries.append(('ram', system_info['ram_percent']))
logger.info(f"RAM RECOVERY: {system_info['ram_percent']:.1f}% < {self.recovery_threshold}%")
# Сбрасываем время начала превышения
# Сбрасываем время начала превышения только после отправки алерта
self.alert_start_times['ram'] = None
elif system_info['ram_percent'] < self.recovery_threshold and self.alert_start_times['ram'] is not None:
# Если RAM опустился значительно ниже порога, сбрасываем время начала превышения
logger.debug(f"RAM значительно ниже порога {self.recovery_threshold}%: {system_info['ram_percent']:.1f}% - сбрасываем время начала превышения")
self.alert_start_times['ram'] = None
# Проверка диска с задержкой
@@ -636,13 +642,16 @@ class MetricsCollector:
alerts.append(('disk', system_info['disk_percent'], f"Свободно: {system_info['disk_free']} GB на /"))
logger.warning(f"DISK ALERT: {system_info['disk_percent']:.1f}% > {self.threshold}% (задержка {self.alert_delays['disk']}s)")
else:
# Диск ниже порога - сбрасываем состояние
# Диск ниже порога - сбрасываем состояние только если был активный алерт
if self.alert_states['disk']:
self.alert_states['disk'] = False
recoveries.append(('disk', system_info['disk_percent']))
logger.info(f"DISK RECOVERY: {system_info['disk_percent']:.1f}% < {self.recovery_threshold}%")
# Сбрасываем время начала превышения
# Сбрасываем время начала превышения только после отправки алерта
self.alert_start_times['disk'] = None
elif system_info['disk_percent'] < self.recovery_threshold and self.alert_start_times['disk'] is not None:
# Если диск опустился значительно ниже порога, сбрасываем время начала превышения
logger.debug(f"Disk значительно ниже порога {self.recovery_threshold}%: {system_info['disk_percent']:.1f}% - сбрасываем время начала превышения")
self.alert_start_times['disk'] = None
return alerts, recoveries

View File

@@ -32,6 +32,18 @@ scrape_configs:
scrape_timeout: 10s
honor_labels: true
- job_name: 'anon-bot'
static_configs:
- targets: ['bots_anon_bot:8081'] # AnonBot на порту 8081
labels:
bot_name: 'anon-bot'
environment: 'production'
service: 'anon-bot'
metrics_path: '/metrics'
scrape_interval: 15s
scrape_timeout: 10s
honor_labels: true
alerting:
alertmanagers:
- static_configs: