base setup
This commit is contained in:
0
at_django_boilerplate/core/logging/__init__.py
Executable file
0
at_django_boilerplate/core/logging/__init__.py
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
46
at_django_boilerplate/core/logging/config.py
Executable file
46
at_django_boilerplate/core/logging/config.py
Executable file
@@ -0,0 +1,46 @@
|
||||
from pathlib import Path
|
||||
|
||||
def get_logging_config(base_dir: Path):
|
||||
log_dir = base_dir / "logs"
|
||||
log_dir.mkdir(exist_ok=True)
|
||||
|
||||
return {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "[{asctime}] [{levelname}] {name}: {message}",
|
||||
"style": "{",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "default",
|
||||
},
|
||||
"file": {
|
||||
"class": "logging.handlers.TimedRotatingFileHandler",
|
||||
"filename": log_dir / "django.log",
|
||||
"when": "midnight",
|
||||
"backupCount": 7,
|
||||
"formatter": "default",
|
||||
"delay": True,
|
||||
},
|
||||
"mail_admins": {
|
||||
"class": "django.utils.log.AdminEmailHandler",
|
||||
"level": "ERROR",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
"django.request": {
|
||||
"handlers": ["console", "file", "mail_admins"],
|
||||
"level": "ERROR",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
128
at_django_boilerplate/core/logging/views.py
Executable file
128
at_django_boilerplate/core/logging/views.py
Executable file
@@ -0,0 +1,128 @@
|
||||
# utils/log_viewer.py
|
||||
from pathlib import Path
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render
|
||||
from datetime import datetime
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def tail(filepath, lines=500, chunk_size=1024):
|
||||
with open(filepath, "rb") as f:
|
||||
f.seek(0, 2)
|
||||
file_size = f.tell()
|
||||
|
||||
buffer = b""
|
||||
pointer = file_size
|
||||
|
||||
while pointer > 0 and buffer.count(b"\n") < lines:
|
||||
read_size = min(chunk_size, pointer)
|
||||
pointer -= read_size
|
||||
f.seek(pointer)
|
||||
buffer = f.read(read_size) + buffer
|
||||
|
||||
return buffer.decode(errors="ignore").splitlines()[-lines:]
|
||||
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def log_list(request):
|
||||
log_dir = Path(settings.BASE_DIR) / "logs"
|
||||
|
||||
files = []
|
||||
for f in log_dir.glob("*.log"):
|
||||
stat = f.stat()
|
||||
files.append({
|
||||
"name": f.name,
|
||||
"size": stat.st_size,
|
||||
"mtime": timezone.make_aware(
|
||||
datetime.fromtimestamp(stat.st_mtime))
|
||||
})
|
||||
|
||||
return render(request, "logging/logs_list.html", {"files": files})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# @staff_member_required
|
||||
# def log_detail(request, filename):
|
||||
# log_dir = Path(settings.LOG_VIEWER_DIR)
|
||||
# file_path = log_dir / filename
|
||||
|
||||
# if not file_path.exists():
|
||||
# raise Http404
|
||||
|
||||
# lines = tail(file_path, settings.LOG_VIEWER_MAX_LINES)
|
||||
|
||||
# return render(
|
||||
# request,
|
||||
# "logging/log_detail.html",
|
||||
# {"filename": filename, "lines": lines},
|
||||
# )
|
||||
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
from django.http import Http404
|
||||
|
||||
LOG_PATTERN = re.compile(
|
||||
r"""
|
||||
^\[
|
||||
(?P<time>[\d\-:\s,]+)
|
||||
\]\s+\[
|
||||
(?P<level>DEBUG|INFO|WARNING|ERROR|CRITICAL)
|
||||
\]\s+
|
||||
(?P<logger>[^:]+):
|
||||
\s+
|
||||
(?P<message>.*)
|
||||
$
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
LEVEL_ORDER = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
|
||||
|
||||
def log_detail(request, filename):
|
||||
log_dir = Path(settings.LOG_VIEWER_DIR)
|
||||
|
||||
file_path = log_dir / filename
|
||||
if not file_path.exists() or not file_path.is_file():
|
||||
raise Http404("Log file not found")
|
||||
|
||||
lines = []
|
||||
|
||||
with file_path.open("r", errors="replace") as f:
|
||||
for raw in f:
|
||||
raw = raw.rstrip("\n")
|
||||
|
||||
match = LOG_PATTERN.match(raw)
|
||||
if match:
|
||||
data = match.groupdict()
|
||||
data["raw"] = raw
|
||||
data["is_trace"] = False
|
||||
else:
|
||||
# stack trace / continuation line
|
||||
data = {
|
||||
"time": "",
|
||||
"level": "",
|
||||
"logger": "",
|
||||
"message": raw,
|
||||
"raw": raw,
|
||||
"is_trace": True,
|
||||
}
|
||||
|
||||
lines.append(data)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"logging/log_detail.html",
|
||||
{
|
||||
"filename": filename,
|
||||
"lines": lines,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user