Skip to content

Logging

Foundry Connect writes its application log as structured JSON, one object per line. This page describes what the log contains, how to configure it, and what it deliberately does not do.

The log line

Every line is a single JSON object:

{"level":"info","time":1786619775084,"service":"web","app_service":"web","component":"business/run/run.ts","correlation_id":"3f7a1c2e-8b04-4d1a-9f65-2c0d5e7a1b93","user_id":42,"runId":12195,"attempt":1,"msg":"run launched"}
Field Meaning
level debug, info, audit, warn, or error
time milliseconds since the epoch, UTC
service, app_service the service that emitted the line, from APP_NAME, which defaults to web
component the source module, so a line can be traced to the code that wrote it
correlation_id ties every line produced by one API call together. See below
user_id the acting user, when the line was emitted during an authenticated request
msg the human readable message. It is a fixed string, so lines can be grouped

Any remaining fields are context the call site supplied, such as runId and attempt above. Values are structured fields rather than text interpolated into the message, so they can be filtered on directly.

Correlation id

Each incoming API request is assigned a correlation_id, and every line emitted while handling that request carries it, including work that continues asynchronously. To follow one request end to end, filter on that single value.

If the request already carries an x-request-id header, that value is reused, so a proxy such as nginx can originate the identifier at the edge and one id then covers every hop. The response always echoes the id back in its own x-request-id header.

An inbound value is accepted only when it is at most 128 characters and made of letters, digits, dots, underscores, or hyphens. Anything else is ignored and Foundry Connect generates its own id. This is deliberate: the header is supplied by the caller, and an unbounded or specially crafted value would otherwise appear on every line of that request.

Configuration

Setting Default Purpose
LOG_LEVEL debug Lowest level that is written. Accepts debug, info, audit, error
LOG_FORMAT json in production, pretty elsewhere json for machine readable output, pretty for human readable output during development
LOG_DIR /var/log/viafoundry Directory the log file is written to
LOG_FILE_NAME viafoundry Base name of the log file
LOG_AUTO_ROTATE true Roll the file daily and compress what rolls off
LOG_MAX_FILES_DAYS 14d How long rotated files are kept

LOG_LEVEL accepts four values and warn is not among them, even though lines are emitted at warn. The levels rank debug, info, audit, warn, error, and setting LOG_LEVEL keeps everything at that rank and above. Setting it to audit therefore still records warnings and errors, while dropping debug and info.

The default of debug is verbose for a production deployment. Set LOG_LEVEL=info or higher there unless you are actively diagnosing something.

The LOG_DIR and LOG_FILE_NAME defaults still carry the product's former name. That is deliberate and must not be tidied up: those paths are the writable bind mount target in every compose file, no deployment sets them in its own environment file, and a renamed default directory is not writable by the non-root runtime user, which crash loops the backend at startup. A new install that wants a different path can set LOG_DIR explicitly.

Output goes to standard output and, in production, to a file in LOG_DIR as well. Container deployments usually collect standard output; the file exists for on-prem operators who read it directly on the host.

With LOG_AUTO_ROTATE enabled the file is <LOG_FILE_NAME>-YYYY-MM-DD.log and older days are compressed to .log.gz. With it disabled the file is <LOG_FILE_NAME>.log and grows without bound, so an external rotation mechanism becomes your responsibility.

What this does not do

State these plainly when planning around them.

  • There is no central log store. Lines are written to standard output and to the local file. Shipping them somewhere searchable, and any retention policy beyond the file rotation above, is the operating organization's responsibility.
  • This is not an audit trail of record changes. The log records what the application did, not a tamper evident history of who changed which record and when. Lines at the audit level are operational events in the same stream as everything else, subject to the same rotation, and they can be lost when a file rolls off. Do not rely on them as a record of truth.
  • Retention is not enforced by the product. LOG_MAX_FILES_DAYS governs rotated files on one host. Nothing verifies that a policy is met, and nothing prevents a line being deleted.
  • Frontend errors are not included. Only backend activity reaches this log today.