Logging & Observability¶
SentriKat writes structured logs to /var/log/sentrikat/ inside the container. Logs are split per concern so SOC2/SIEM consumers can ingest the security and audit streams independently from application noise.
Log files¶
| File | Level | Content | Retention |
|---|---|---|---|
application.log | INFO+ | App boot, scheduler ticks, Flask request handlers info/warning | 10 MB × 10 backups (~100 MB) |
error.log | ERROR | Uncaught exceptions, sanitized 500 errors, stack traces | 10 MB × 10 backups |
access.log | INFO | HTTP request access (method, path, status, IP, UA) | 20 MB × 10 backups |
security.log | WARNING+ | Auth events, license rejections, permission denials, lockouts | 10 MB × 20 backups (~200 MB) |
audit.log | INFO (JSON) | Privileged CRUD on user/role/setting/integration | 20 MB × 50 backups (~1 GB) |
ldap.log | INFO | LDAP operations (bind, search, sync, auto-provision) | 10 MB × 10 backups |
performance.log | INFO (JSON) | Slow queries (>200ms), slow endpoints | 20 MB × 10 backups |
Rotation is automatic (Python logging.handlers.RotatingFileHandler). Retention can be tuned by editing app/logging_config.py:setup_logging.
Ownership and permissions¶
All log files are owned by the sentrikat system user (UID assigned at build time — check with docker compose exec sentrikat id) inside the container. The entrypoint docker-entrypoint.sh drops privileges from root to sentrikat via gosu before starting gunicorn, so the master and all workers create files with the correct ownership.
If you ever see logs only populated with the boot lines (~6 entries in application.log, everything else 0 bytes), check ownership first:
docker exec sentrikat ls -la /var/log/sentrikat/
# Expected: every file 'sentrikat sentrikat'
# Wrong: 'root root' → privilege drop didn't happen
Mounting logs to host¶
By default /var/log/sentrikat/ is a tmpfs (in-memory) under the read-only rootfs. Logs are lost on container restart. To persist:
Option A — STORAGE_ROOT env var¶
services:
sentrikat:
environment:
STORAGE_ROOT: /data/sentrikat
volumes:
- /host/path/sentrikat-data:/data/sentrikat
The entrypoint derives LOG_DIR=$STORAGE_ROOT/logs, DATA_DIR=$STORAGE_ROOT/data, BACKUP_DIR=$STORAGE_ROOT/backups automatically. Make sure the host path is owned by the container's sentrikat UID (check with docker compose exec sentrikat id):
Option B — explicit LOG_DIR¶
If the host path can't be chowned (NFS readonly), the entrypoint falls back to /app/logs inside the container (lost on restart).
Shipping logs externally¶
Syslog forwarding¶
Elasticsearch / Kibana¶
Diagnostics — logs not populating¶
# Check ownership
docker exec sentrikat ls -la /var/log/sentrikat/
# Check line counts
docker exec sentrikat sh -c "wc -l /var/log/sentrikat/*.log"
# Confirm gunicorn workers re-initialized post_fork
docker logs sentrikat 2>&1 | grep "re-initialized DB pool + logging"
# Expected: one line per worker (typically 4-16 lines)