{% extends "base.html" %} {% block title %}Logs · {{ site.title }}{% endblock %} {% block content %}

Application logs

{% if available %} {% endif %}
{% if not available %}

No log files found. File logging is written by configure_logging(log_dir=...); once it runs, records show up here.

{% else %}
{% if entries %}
{% for entry in entries %} {% set traceback = entry.get("exception") %} {% set ctx = [] %} {% for key in context_keys %} {% if entry.get(key) is not none %}{% set _ = ctx.append((key, entry.get(key))) %}{% endif %} {% endfor %} {% endfor %}
Timestamp Level Logger Message
{{ entry.get("timestamp", "") }} {% set level = (entry.get("level", "") or "")|lower %} {{ entry.get("level", "—") }} {{ entry.get("logger", entry.get("name", "—")) }} {% if traceback %} {# The whole record is the toggle: clicking anywhere on the message reveals the traceback. Collapsed by default so a page of 500s stays scannable, and pure
/ so it works with the admin shipping no JavaScript. #}
{{ entry.get("message", "") }} {% if ctx %}
    {% for key, value in ctx %}
  • {{ key }} {{ value }}
  • {% endfor %}
{% endif %} Traceback
{{ traceback }}
{% else %} {{ entry.get("message", "") }} {% if ctx %}
    {% for key, value in ctx %}
  • {{ key }} {{ value }}
  • {% endfor %}
{% endif %} {% endif %}
{% if pagination.page > 1 %} « Prev {% endif %} Page {{ pagination.page }} of {{ pagination.pages }} ({{ pagination.total }} records) {% if pagination.page < pagination.pages %} Next » {% endif %}

An export covers every record matching the current filter, newest first, up to {{ export_max }} — not just this page. Markdown wraps each traceback in a fenced block so it survives a paste into an issue; JSON ships the records verbatim.

{% else %}

No records match the current filter.

{% endif %} {% endif %}
{% endblock %}