diff --git a/History/2026-08-20-logging-file.md b/History/2026-08-20-logging-file.md new file mode 100644 index 0000000..8e0fa6d --- /dev/null +++ b/History/2026-08-20-logging-file.md @@ -0,0 +1,24 @@ +# 2026-08-20 — Файловый лог в поде (v0.0.52) + +## Проблема +В v0.0.51 добавили логирование в stderr, но на платформе Штурвал +`kubectl logs` НЕ показывает stdout/stderr приложения (fd 1/2 python -> pipe, +который читает супервизор платформы, а не kubelet). Логи приложения недоступны. + +## Решение +`setup_logging()` в site/app.py: +- логи в stderr (для локального запуска) +- + `FileHandler` в `/tmp/drhider.log` (путь через env `LOG_FILE`) +- уровень через env `LOG_LEVEL` (DEBUG/INFO/WARNING) +- root.handlers.clear() + свои handler'ы (не полагаемся на basicConfig) +- если файл не открылся — не падаем, пишем в stderr + +## Как читать логи в поде +``` +kubectl exec -n 20a75175-a58c-49cb-b8fa-e86367b1a8dc -c app -- cat /tmp/drhider.log +``` +(или tail -f). Версия 0.0.52. + +## Проверено локально +Файл /tmp/drhider.log создаётся, пишет "Logging configured, version=0.0.52" +и сообщения логгеров. diff --git a/site/app.py b/site/app.py index ff7f2bc..2722fa9 100644 --- a/site/app.py +++ b/site/app.py @@ -21,27 +21,38 @@ if _sys_path_root not in sys.path: sys.path.insert(0, _sys_path_root) # Версия приложения (меняется при изменениях) -VERSION = "0.0.51" +VERSION = "0.0.52" def setup_logging(): - """Настроить логирование. Уровень берётся из env LOG_LEVEL (DEBUG/INFO/WARNING).""" + """Настроить логирование. Уровень из env LOG_LEVEL (DEBUG/INFO/WARNING). + + Логи пишутся в stderr (для локального запуска) И в файл /tmp/drhider.log + (для кубера, где stdout/stderr контейнера может не попадать в kubectl logs). + Путь файла можно переопределить env LOG_FILE. + """ level_name = os.environ.get("LOG_LEVEL", "INFO").upper() level = getattr(logging, level_name, logging.INFO) - logging.basicConfig( - level=level, - format="%(asctime)s %(levelname)s [%(name)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - stream=sys.stderr, - force=True, - ) - logging.getLogger("drhider").setLevel(level) - logging.getLogger("app").setLevel(level) - logging.getLogger("routes").setLevel(level) - logging.getLogger("session").setLevel(level) - logging.getLogger(__name__).setLevel(level) + log_file = os.environ.get("LOG_FILE", "/tmp/drhider.log") + fmt = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s", "%Y-%m-%d %H:%M:%S") + root = logging.getLogger() + root.setLevel(level) + root.handlers.clear() + sh = logging.StreamHandler(sys.stderr) + sh.setLevel(level) + sh.setFormatter(fmt) + root.addHandler(sh) + try: + fh = logging.FileHandler(log_file, encoding="utf-8") + fh.setLevel(level) + fh.setFormatter(fmt) + root.addHandler(fh) + except Exception as e: # файл не открылся — не падаем + sys.stderr.write(f"[app] cannot open log file {log_file}: {e}\n") + for name in ("drhider", "app", "routes", "session", __name__): + logging.getLogger(name).setLevel(level) log = logging.getLogger("app") - log.info("Logging configured, level=%s, version=%s", level_name, VERSION) + log.info("Logging configured, level=%s, version=%s, file=%s", level_name, VERSION, log_file) def create_app():