Logs
Trinium writes plain text to standard output and Docker does the rest, so your own collector ships the logs and Trinium never holds a monitoring key.
Reading them
docker compose logs -f trinium
That is the whole of it. Trinium writes plain text, one line per event, meant to be read by a person with no tooling at all:
2026-10-26 18:39:45Z INFO trinium::audit: audit action="instance.started" actor_name=system actor_kind="System" object_kind="instance" outcome="Success" 2026-10-26 18:40:44Z INFO trinium::runs: run finished status=Succeeded environment=Production kind=Live trigger=Schedule version=12 seconds=93 warnings=0 completed_at=2026-10-26T18:40:44Z run_id=01a17983-d1d9-71e0-a549-0e71e319aa08 pipeline="Daily orders"
Each line is a UTC timestamp, the level, the component that emitted it, and the message with any values attached as name=value. Anything logged while a pipeline is running also carries that run: run{run_id=… pipeline_id=…}:, so grep for one run id and you get everything about it together: staging, the worker and the notification.
There is no other format and nothing to configure. Color codes are never written, so the output is the same in a terminal, in a file, and in your monitoring system.
Log files are capped at 10 MB × 5 files per service, in compose.yaml. You do not need to configure anything, and no log will fill your disk.
Sending them to your monitoring system
Trinium never connects to a monitoring service. It writes to standard output and Docker does the rest, so no API key or endpoint is ever stored in Trinium, and this works the same whether you are on the internet or air-gapped.
Recommended: run your vendor's agent alongside Trinium. Datadog, Elastic (Filebeat), Splunk, Grafana Alloy, Fluent Bit and Vector all read container logs off the host. Create a file called compose.override.yaml beside your compose.yaml. Docker Compose loads it automatically, so docker compose up -d stays exactly the same command, and an upgrade will never overwrite it:
# compose.override.yaml — yours, not ours. Example: Datadog.
services:
datadog:
image: gcr.io/datadoghq/agent:7
environment:
DD_API_KEY: ${DD_API_KEY}
DD_LOGS_ENABLED: "true"
DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: "true"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
restart: unless-stoppedThe agent reads the logs; it does not replace them, so docker compose logs keeps working and the size cap still applies.
Advanced: change the log driver instead. Docker can ship logs directly to syslog, Splunk, Fluentd, Graylog or CloudWatch with no agent. Again in compose.override.yaml:
services:
trinium:
logging:
driver: syslog
options:
syslog-address: "tcp://siem.example.com:514"This turns off docker compose logs. That command only works with the json-file, local and journald drivers, so with any other driver you lose local log viewing, and so do we if you ask us for support. Prefer the agent above unless your policy forbids running one.
Alerting on run outcomes
Every pipeline run and every flow run writes exactly one line when it finishes, whatever ended it: it succeeded, it failed, someone cancelled it, it reached its time limit, a scheduled run could not start, or the server running it stopped. The line uses the target trinium::runs and appears within about ten seconds of the run ending:
2026-10-26 18:40:55Z WARN trinium::runs: run finished status=Failed environment=Production kind=Live trigger=Schedule version=12 seconds=1 warnings=0 completed_at=2026-10-26T18:40:46Z run_id=01a17983-d9b8-7ad3-8809-28074dc77f83 pipeline="Daily orders" error="Node 'Load' failed: ..." 2026-10-26 18:40:55Z INFO trinium::runs: flow run finished status=Succeeded environment=Production trigger=Schedule seconds=1840 completed_at=2026-10-26T18:40:51Z flow_run_id=01a17983-e1a4-78d3-b010-694476557b30 flow="Nightly load"
| Field | What it holds |
|---|---|
status | Succeeded, Failed or Cancelled. A failed run is logged as WARN, every other outcome as INFO. |
environment | Staging or Production. |
kind | Live, or Test for a Test run. Pipeline runs only. |
trigger | Manual, Schedule or Flow (a pipeline run started by a flow). |
version | The version a Live run ran. Absent on a Test run. |
seconds | How long it ran. Absent when it never started. |
warnings | How many warnings it wrote. |
completed_at | When it ended, in UTC. |
run_id / flow_run_id | The run, as the Runs page and the API name it. |
pipeline / flow | The name, in quotes. |
values | The text parameter values it ran with, such as region = US. |
error | Why it failed or stopped, in quotes, on the same line even when the message has several lines. |
A field with nothing to report is left out rather than written empty. Like the audit feed, this line cannot be switched off by a log-level setting.
Email, Slack and Discord notifications cover scheduled runs and flows. This line covers every run, including runs started by hand and the pipeline runs inside a flow, so it is the one to build a monitor on. Runs that ended more than an hour before Trinium could write their line (while it was stopped, or before a restore) are not written, so a restart never replays old history into your monitor.
To alert on a failed run, match the two words trinium::runs and status=Failed:
- Amazon CloudWatch: with the lines in a log group (the CloudWatch agent, or Docker's
awslogsdriver), create a metric filter with the pattern"trinium::runs" "status=Failed", then an alarm on that metric that notifies an SNS topic. - Azure Monitor: with the lines in a Log Analytics workspace (the Azure Monitor Agent's text log collection, or Fluent Bit), create a log search alert rule on a query such as
TriniumLogs_CL | where RawData has "trinium::runs" and RawData has "status=Failed". - Datadog: a log monitor on the query
"trinium::runs" "status=Failed". To filter and chart by pipeline or environment, add a Grok parser to the log pipeline with the rulerun %{data::keyvalue}. - Splunk: fields written as
name=valueare extracted automatically at search time, so"trinium::runs" status=Failedfinds them. - Vector: the transform below turns every line into named fields. It is what we tested the line against.
transforms:
trinium_runs:
type: remap
inputs: [trinium]
source: |
parsed, err = parse_regex(.message, r'^(?P<ts>\S+ \S+)\s+(?P<level>[A-Z]+) (?P<target>\S+): (?P<event>run finished|flow run finished) (?P<kv>.*)$')
if err == null {
. = merge(parsed, parse_key_value!(parsed.kv))
del(.kv)
}The audit feed
Every action that changes something (sign-ins and failed sign-ins, role changes, connection and pipeline edits, backups taken and downloaded, settings changes) is written to the audit trail, which Enterprise shows under Settings → Audit, and is also emitted on the log stream under the target trinium::audit. That is what to point at a SIEM:
docker compose logs trinium | grep trinium::audit
Each line names the action, who did it, what it was done to, and whether it succeeded, failed or was refused. Secrets are never included: a changed password or key is recorded as the fact that it changed, never as a value.
Two things worth knowing. The audit feed cannot be switched off by a log-level setting, so it keeps flowing even while you are debugging something else. And it is a copy: the trail in the database remains the record of truth, so if your collector is down for an hour you have lost nothing: every entry is still there, and on Enterprise Settings → Audit shows them and exports them as CSV.