feat: replace all print statements with proper logging system
This commit is contained in:
parent
f3221d6102
commit
a49714ab14
@ -17,6 +17,7 @@ import docker
|
|||||||
|
|
||||||
from app.core.auth import get_current_user
|
from app.core.auth import get_current_user
|
||||||
from app.core.docker import docker_client, DEFAULT_TAIL
|
from app.core.docker import docker_client, DEFAULT_TAIL
|
||||||
|
from app.core.logger import api_logger
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ def api_logs_stats(container_id: str, current_user: str = Depends(get_current_us
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting log stats for {container_id}: {e}")
|
api_logger.error(f"Error getting log stats for {container_id}: {e}")
|
||||||
return JSONResponse({"error": str(e)}, status_code=500)
|
return JSONResponse({"error": str(e)}, status_code=500)
|
||||||
|
|
||||||
@router.get("/{container_id}")
|
@router.get("/{container_id}")
|
||||||
@ -193,7 +194,7 @@ def api_logs(
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting logs for {container_id}: {e}")
|
api_logger.error(f"Error getting logs for {container_id}: {e}")
|
||||||
return JSONResponse({"error": str(e)}, status_code=500)
|
return JSONResponse({"error": str(e)}, status_code=500)
|
||||||
|
|
||||||
@router.post("/snapshot")
|
@router.post("/snapshot")
|
||||||
|
@ -14,6 +14,7 @@ from fastapi.responses import JSONResponse
|
|||||||
|
|
||||||
from app.core.auth import verify_token, get_current_user
|
from app.core.auth import verify_token, get_current_user
|
||||||
from app.core.docker import docker_client, DEFAULT_TAIL
|
from app.core.docker import docker_client, DEFAULT_TAIL
|
||||||
|
from app.core.logger import websocket_logger
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@ -93,30 +94,30 @@ async def ws_logs(ws: WebSocket, container_id: str, tail: int = DEFAULT_TAIL, to
|
|||||||
|
|
||||||
# Получаем логи (только последние строки, без follow)
|
# Получаем логи (только последние строки, без follow)
|
||||||
try:
|
try:
|
||||||
print(f"Getting logs for container {container.name} (ID: {container.id[:12]})")
|
websocket_logger.info(f"Getting logs for container {container.name} (ID: {container.id[:12]})")
|
||||||
logs = container.logs(tail=tail).decode(errors="ignore")
|
logs = container.logs(tail=tail).decode(errors="ignore")
|
||||||
if logs:
|
if logs:
|
||||||
await ws.send_text(logs)
|
await ws.send_text(logs)
|
||||||
else:
|
else:
|
||||||
await ws.send_text("No logs available")
|
await ws.send_text("No logs available")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting logs for {container.name}: {e}")
|
websocket_logger.error(f"Error getting logs for {container.name}: {e}")
|
||||||
await ws.send_text(f"ERROR getting logs: {e}")
|
await ws.send_text(f"ERROR getting logs: {e}")
|
||||||
|
|
||||||
# Простое WebSocket соединение - только отправляем логи один раз
|
# Простое WebSocket соединение - только отправляем логи один раз
|
||||||
print(f"WebSocket connection established for {container.name}")
|
websocket_logger.info(f"WebSocket connection established for {container.name}")
|
||||||
|
|
||||||
except WebSocketDisconnect:
|
except WebSocketDisconnect:
|
||||||
print(f"WebSocket client disconnected for container {container.name}")
|
websocket_logger.info(f"WebSocket client disconnected for container {container.name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"WebSocket error for {container.name}: {e}")
|
websocket_logger.error(f"WebSocket error for {container.name}: {e}")
|
||||||
try:
|
try:
|
||||||
await ws.send_text(f"ERROR: {e}")
|
await ws.send_text(f"ERROR: {e}")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
print(f"Closing WebSocket connection for container {container.name}")
|
websocket_logger.info(f"Closing WebSocket connection for container {container.name}")
|
||||||
await ws.close()
|
await ws.close()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
11
app/app.py
11
app/app.py
@ -11,8 +11,9 @@ from fastapi import FastAPI, Request, HTTPException
|
|||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
||||||
from app.core.config import DEBUG_MODE, SNAP_DIR, STATIC_DIR
|
from app.core.config import DEBUG_MODE, SNAP_DIR, STATIC_DIR, APP_PORT
|
||||||
from app.api.v1.router import api_router, pages_router
|
from app.api.v1.router import api_router, pages_router
|
||||||
|
from app.core.logger import app_logger
|
||||||
|
|
||||||
# Инициализация FastAPI
|
# Инициализация FastAPI
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
@ -81,11 +82,11 @@ app.include_router(pages_router)
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
print(f"LogBoard+ http://0.0.0.0:{APP_PORT}")
|
app_logger.info(f"LogBoard+ http://0.0.0.0:{APP_PORT}")
|
||||||
print(f"Debug mode: {'ON' if DEBUG_MODE else 'OFF'}")
|
app_logger.info(f"Debug mode: {'ON' if DEBUG_MODE else 'OFF'}")
|
||||||
if DEBUG_MODE:
|
if DEBUG_MODE:
|
||||||
print("Swagger UI: http://0.0.0.0:{}/docs".format(APP_PORT))
|
app_logger.info("Swagger UI: http://0.0.0.0:{}/docs".format(APP_PORT))
|
||||||
print("ReDoc: http://0.0.0.0:{}/redoc".format(APP_PORT))
|
app_logger.info("ReDoc: http://0.0.0.0:{}/redoc".format(APP_PORT))
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app,
|
app,
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
|
@ -18,6 +18,7 @@ from app.core.config import (
|
|||||||
DEFAULT_PROJECTS,
|
DEFAULT_PROJECTS,
|
||||||
SKIP_UNHEALTHY
|
SKIP_UNHEALTHY
|
||||||
)
|
)
|
||||||
|
from app.core.logger import docker_logger
|
||||||
|
|
||||||
# Инициализация Docker клиента
|
# Инициализация Docker клиента
|
||||||
docker_client = docker.from_env()
|
docker_client = docker.from_env()
|
||||||
@ -33,13 +34,13 @@ def load_excluded_containers() -> List[str]:
|
|||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
return data.get("excluded_containers", [])
|
return data.get("excluded_containers", [])
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("⚠️ Файл app/excluded_containers.json не найден, используем пустой список")
|
docker_logger.warning("Файл app/excluded_containers.json не найден, используем пустой список")
|
||||||
return []
|
return []
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"❌ Ошибка парсинга app/excluded_containers.json: {e}")
|
docker_logger.error(f"Ошибка парсинга app/excluded_containers.json: {e}")
|
||||||
return []
|
return []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Ошибка загрузки app/excluded_containers.json: {e}")
|
docker_logger.error(f"Ошибка загрузки app/excluded_containers.json: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def save_excluded_containers(containers: List[str]) -> bool:
|
def save_excluded_containers(containers: List[str]) -> bool:
|
||||||
@ -57,7 +58,7 @@ def save_excluded_containers(containers: List[str]) -> bool:
|
|||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Ошибка сохранения app/excluded_containers.json: {e}")
|
docker_logger.error(f"Ошибка сохранения app/excluded_containers.json: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_all_projects() -> List[str]:
|
def get_all_projects() -> List[str]:
|
||||||
@ -105,11 +106,11 @@ def get_all_projects() -> List[str]:
|
|||||||
projects.add("standalone")
|
projects.add("standalone")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Ошибка получения списка проектов: {e}")
|
docker_logger.error(f"Ошибка получения списка проектов: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
result = sorted(list(projects))
|
result = sorted(list(projects))
|
||||||
print(f"📋 Доступные проекты (с учетом исключенных контейнеров): {result}")
|
docker_logger.info(f"Доступные проекты (с учетом исключенных контейнеров): {result}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def list_containers(projects: Optional[List[str]] = None, include_stopped: bool = False) -> List[Dict]:
|
def list_containers(projects: Optional[List[str]] = None, include_stopped: bool = False) -> List[Dict]:
|
||||||
@ -121,7 +122,7 @@ def list_containers(projects: Optional[List[str]] = None, include_stopped: bool
|
|||||||
# Загружаем список исключенных контейнеров из JSON файла
|
# Загружаем список исключенных контейнеров из JSON файла
|
||||||
excluded_containers = load_excluded_containers()
|
excluded_containers = load_excluded_containers()
|
||||||
|
|
||||||
print(f"🚫 Список исключенных контейнеров: {excluded_containers}")
|
docker_logger.info(f"Список исключенных контейнеров: {excluded_containers}")
|
||||||
|
|
||||||
items = []
|
items = []
|
||||||
excluded_count = 0
|
excluded_count = 0
|
||||||
@ -198,7 +199,7 @@ def list_containers(projects: Optional[List[str]] = None, include_stopped: bool
|
|||||||
# Фильтрация исключенных контейнеров
|
# Фильтрация исключенных контейнеров
|
||||||
if basic_info["name"] in excluded_containers:
|
if basic_info["name"] in excluded_containers:
|
||||||
excluded_count += 1
|
excluded_count += 1
|
||||||
print(f"⚠️ Пропускаем исключенный контейнер: {basic_info['name']}")
|
docker_logger.warning(f"Пропускаем исключенный контейнер: {basic_info['name']}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Добавляем контейнер в список
|
# Добавляем контейнер в список
|
||||||
@ -206,11 +207,11 @@ def list_containers(projects: Optional[List[str]] = None, include_stopped: bool
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Пропускаем контейнеры с критическими ошибками
|
# Пропускаем контейнеры с критическими ошибками
|
||||||
print(f"⚠️ Пропускаем проблемный контейнер {c.name if hasattr(c, 'name') else 'unknown'} (ID: {c.id[:12]}): {e}")
|
docker_logger.warning(f"Пропускаем проблемный контейнер {c.name if hasattr(c, 'name') else 'unknown'} (ID: {c.id[:12]}): {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Ошибка получения списка контейнеров: {e}")
|
docker_logger.error(f"Ошибка получения списка контейнеров: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Сортируем по проекту, сервису и имени
|
# Сортируем по проекту, сервису и имени
|
||||||
@ -236,8 +237,8 @@ def list_containers(projects: Optional[List[str]] = None, include_stopped: bool
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f"📊 Статистика: найдено {len(items)} контейнеров, исключено {excluded_count} контейнеров")
|
docker_logger.info(f"Статистика: найдено {len(items)} контейнеров, исключено {excluded_count} контейнеров")
|
||||||
for project, stats in project_stats.items():
|
for project, stats in project_stats.items():
|
||||||
print(f" 📦 {project}: {stats['visible']} видимых, {stats['excluded']} исключенных")
|
docker_logger.info(f" 📦 {project}: {stats['visible']} видимых, {stats['excluded']} исключенных")
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
64
app/core/logger.py
Normal file
64
app/core/logger.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
LogBoard+ - Конфигурация логгера
|
||||||
|
Автор: Сергей Антропов
|
||||||
|
Сайт: https://devops.org.ru
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import os
|
||||||
|
from app.core.config import DEBUG_MODE
|
||||||
|
|
||||||
|
def setup_logger(name: str = "logboard", level: Optional[str] = None) -> logging.Logger:
|
||||||
|
"""
|
||||||
|
Настраивает и возвращает логгер для приложения
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Имя логгера
|
||||||
|
level: Уровень логирования (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Настроенный логгер
|
||||||
|
"""
|
||||||
|
# Определяем уровень логирования
|
||||||
|
if level is None:
|
||||||
|
level = os.getenv("LOG_LEVEL", "DEBUG" if DEBUG_MODE else "INFO")
|
||||||
|
|
||||||
|
# Создаем логгер
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.setLevel(getattr(logging, level.upper()))
|
||||||
|
|
||||||
|
# Очищаем существующие обработчики
|
||||||
|
logger.handlers.clear()
|
||||||
|
|
||||||
|
# Создаем форматтер
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Создаем обработчик для консоли
|
||||||
|
console_handler = logging.StreamHandler(sys.stdout)
|
||||||
|
console_handler.setLevel(getattr(logging, level.upper()))
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
# Добавляем обработчик к логгеру
|
||||||
|
logger.addHandler(console_handler)
|
||||||
|
|
||||||
|
# Предотвращаем дублирование логов
|
||||||
|
logger.propagate = False
|
||||||
|
|
||||||
|
return logger
|
||||||
|
|
||||||
|
# Создаем основной логгер приложения
|
||||||
|
app_logger = setup_logger("logboard")
|
||||||
|
|
||||||
|
# Создаем специализированные логгеры
|
||||||
|
auth_logger = setup_logger("logboard.auth")
|
||||||
|
docker_logger = setup_logger("logboard.docker")
|
||||||
|
api_logger = setup_logger("logboard.api")
|
||||||
|
websocket_logger = setup_logger("logboard.websocket")
|
@ -102,6 +102,9 @@ WEB_VERSION=1.0.0
|
|||||||
# В продакшене обязательно установите в false
|
# В продакшене обязательно установите в false
|
||||||
DEBUG_MODE=false
|
DEBUG_MODE=false
|
||||||
|
|
||||||
|
# Уровень логирования (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# НАСТРОЙКИ ПРОИЗВОДИТЕЛЬНОСТИ
|
# НАСТРОЙКИ ПРОИЗВОДИТЕЛЬНОСТИ
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
Loading…
x
Reference in New Issue
Block a user