diff --git a/.gitignore b/.gitignore
index 5977428..7d1dc03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,11 @@ res/*
media_manager/indexer/indexers/prowlarr.http
*.egg-info
.env
+config
+images
+data
+res
+
web/cache/
diff --git a/Writerside/mm.tree b/Writerside/mm.tree
index dda72df..7c906ec 100644
--- a/Writerside/mm.tree
+++ b/Writerside/mm.tree
@@ -17,6 +17,7 @@
+
diff --git a/Writerside/topics/Logging.md b/Writerside/topics/Logging.md
new file mode 100644
index 0000000..9e03cad
--- /dev/null
+++ b/Writerside/topics/Logging.md
@@ -0,0 +1,11 @@
+# Logging
+
+MediaManager automatically logs events and errors to help with troubleshooting and monitoring. These logs are emitted to
+the console (stdout) by default, and to a json-formatted log file.
+
+## Configuring Logging
+
+The location of the log file can be configured with the `LOG_FILE` environment variable. By default, the log file is
+located at
+`/app/config/media_manager.log`. When changing the log file location, ensure that the directory exists, is writable by the
+MediaManager container and that it is a full path.
\ No newline at end of file
diff --git a/media_manager/main.py b/media_manager/main.py
index 07a07c3..399afff 100644
--- a/media_manager/main.py
+++ b/media_manager/main.py
@@ -4,8 +4,16 @@ import sys
from logging.config import dictConfig
from pythonjsonlogger.json import JsonFormatter
from pathlib import Path
+from datetime import datetime, timezone
+class ISOJsonFormatter(JsonFormatter):
+ def formatTime(self, record, datefmt=None):
+ dt = datetime.fromtimestamp(record.created, tz=timezone.utc)
+ return dt.isoformat(timespec="milliseconds").replace("+00:00", "Z")
+
+
+LOG_FILE = Path(os.getenv("LOG_FILE", "/app/config/media_manager.log"))
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
@@ -14,7 +22,13 @@ LOGGING_CONFIG = {
"format": "%(asctime)s - %(levelname)s - %(name)s - %(funcName)s(): %(message)s"
},
"json": {
- "()": JsonFormatter,
+ "()": ISOJsonFormatter,
+ "format": "%(asctime)s %(levelname)s %(name)s %(message)s",
+ "rename_fields": {
+ "levelname": "level",
+ "asctime": "timestamp",
+ "name": "module",
+ },
},
},
"handlers": {
@@ -26,11 +40,16 @@ LOGGING_CONFIG = {
"file": {
"class": "logging.handlers.RotatingFileHandler",
"formatter": "json",
- "filename": "./log.txt",
+ "filename": str(LOG_FILE),
"maxBytes": 10485760,
"backupCount": 5,
+ "encoding": "utf-8",
},
},
+ "root": {
+ "level": "DEBUG",
+ "handlers": ["console", "file"],
+ },
"loggers": {
"uvicorn": {"handlers": ["console", "file"], "level": "DEBUG"},
"uvicorn.access": {"handlers": ["console", "file"], "level": "DEBUG"},
@@ -102,7 +121,6 @@ from fastapi import FastAPI, APIRouter # noqa: E402
from fastapi.middleware.cors import CORSMiddleware # noqa: E402
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware # noqa: E402
from starlette.responses import Response # noqa: E402
-from datetime import datetime # noqa: E402
from contextlib import asynccontextmanager # noqa: E402
from apscheduler.schedulers.background import BackgroundScheduler # noqa: E402
from apscheduler.triggers.cron import CronTrigger # noqa: E402