Logging
Purpose: Log usefully in AEM: logger configuration, per-package levels, and what belongs at each level.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Daily |
| Ops engineers | Log routing |
Mechanics
SLF4J everywhere: private static final Logger LOG = LoggerFactory.getLogger(PlanCardModel.class); Logs land in crx-quickstart/logs/error.log by default; Sling log configs (OSGi configs) route packages to files and set levels per environment.
# ui.config: org.apache.sling.commons.log.LogManager.factory.config~phi.cfg.json
{
"org.apache.sling.commons.log.names": ["com.academy.phi"],
"org.apache.sling.commons.log.file": "logs/phi.log",
"org.apache.sling.commons.log.level": "info"
}
Per run mode: debug in dev, info in stage, warn+ in prod for your packages.
Level discipline
| Level | Belongs there |
|---|---|
| ERROR | Broken functionality needing action; always with the exception object |
| WARN | Degraded/unexpected but self-healing (missing optional config, retry succeeded) |
| INFO | Lifecycle landmarks (sync started/finished, N items) — low volume |
| DEBUG | Diagnosis detail — safe to enable in prod briefly without flooding |
Rules
- Never log PII or secrets — plan-holder data in the PHI example is exactly what must not appear (PII handling).
- No log-and-rethrow (double logging); log where handled.
- Parameterised messages (
LOG.info("Synced {} plans", count)) — no string concatenation. - Temporarily raise a logger's level via /system/console/slinglog on a live instance for diagnosis; revert after.
- Request-correlate integration logs (pass/generate a correlation ID) — future you in an incident will be grateful.