5.3. Logs and monitoring

The TOA server logs through SLF4J with Logback as the backend. The default configuration ships in logback-spring.xml (packaged inside the server jar) and writes simultaneously to:

  • stdout - so the service integrates cleanly with journalctl on Linux and the Event Viewer / NSSM logs on Windows.

  • a rotating file at ./logs/toa-server.log (relative to the working directory) - so a long-running process keeps a structured on-disk audit trail without depending on the system journal.

5.3.1. File rotation

The file appender uses Logback’s SizeAndTimeBasedRollingPolicy - it rolls when either the daily date boundary is crossed or the active file exceeds the size limit, whichever comes first. Rotated files are gzipped and named, e.g.:

toa-server.log
toa-server.log.2026-04-14.0.gz
toa-server.log.2026-04-14.1.gz
toa-server.log.2026-04-13.0.gz

Defaults:

Property

Default

logging.file.name

./logs/toa-server.log

logging.logback.rollingpolicy.max-file-size

50MB

logging.logback.rollingpolicy.total-size-cap

1GB

logging.logback.rollingpolicy.max-history

30 (days)

All four are standard Spring Boot logging properties - the server just plumbs them into the Logback rolling policy via <springProperty> substitutions, so any deployment knob that takes Spring Boot configuration (application.properties, config/toa-server.yml, JVM args -Dlogging.file.name=..., environment variables LOGGING_FILE_NAME, …) overrides them.

5.3.2. Per-package levels

The application package defaults to INFO. Bump it for troubleshooting without restarting the stack:

logging:
  level:
    root: INFO
    com.lightcomp.tahiti.office.addon: DEBUG
    # Drill into a specific subsystem if needed:
    com.lightcomp.tahiti.office.addon.damis: TRACE

Spring Boot picks up logging.level.* changes on a context refresh; for an interactive session, hitting the /actuator/loggers endpoint (when actuator is enabled) flips levels at runtime without restart.

5.3.3. Key events to look for

A failed import upload that rolls back atomically does not appear as a single log line; look for an exception traceback inside the ImportController or DomainStorage logger.

5.3.4. Disabling file logging

Set logging.file.name to an empty value, or remove it from the configuration. With no logging.file.name Spring Boot still loads logback-spring.xml but the rolling appender will fail to open the file - cleaner to drop the file appender entirely by replacing logback-spring.xml with a console-only variant, or by setting:

logging:
  file:
    name:    # explicitly empty

and accepting that the file appender is then misconfigured. For production deployments where stdout is captured by systemd, leaving logging.file.name empty is fine - the rolling appender just opens no file.

5.3.5. Health and metrics

Spring Boot Actuator ships in the server jar with a deliberately narrow exposure - only /actuator/health and /actuator/info are reachable over HTTP:

GET /actuator/health

Returns 200 {"status":"UP"} when the server is fully wired up. This is the right URL for a reverse-proxy upstream liveness probe (nginx proxy_pass, HAProxy option httpchk, AWS target group health check). Use it as /healthz behind your proxy so the actuator URL stays internal.

GET /actuator/info

Returns the Maven build-info and git commit metadata stamped into the jar at build time, e.g.:

{
  "build": {
    "artifact": "toa-server",
    "name":     "TOAServer",
    "version":  "0.9.0",
    "time":     "2026-04-15T23:14:11.443Z"
  },
  "git": {
    "branch":     "release",
    "commit": {
      "id":   "a3f0c4b...",
      "time": "2026-04-15T22:10:02Z"
    }
  },
  "java": { "version": "21.0.3", ... },
  "os":   { "name": "Linux", "version": "...", ... }
}

Useful for verifying a deployment landed cleanly without ssh-ing onto the box.

To expose more endpoints (loggers, metrics, env, …), extend management.endpoints.web.exposure.include in application.properties or config/toa-server.yml. Think carefully about the trust boundary first - some of these endpoints leak operational detail (config values, beans, environment variables) and should not be reachable from the public reverse proxy. Either bind the actuator port separately (management.server.port=8081) and firewall it, or front it with HTTP basic auth.