Skip to content

Support JSON log output and make it the production default #3304

Description

@petersutter

/area logging
/area security
/kind enhancement

What would you like to be added:

JSON log output for the backend (one object per line), used by default in production. The Gardener logging guidelines define json as the default format for production and text for development.

  • Add a JSON format to @gardener-dashboard/logger, using the record shape from the guidelines ({"level":"info","ts":"…","msg":"…"}). Because the whole record is JSON-encoded, line breaks and control characters in values are escaped in one place, and multi-line content stays inside its record.
  • Honor the logFormat setting (json or text). Default to json in production (the container image sets NODE_ENV=production) and to text for local development.
  • Switch logFormat: text to json in the Helm chart and in gardener-operator (pkg/component/gardener/dashboard/configmap.go). Since the backend ignores logFormat today, the order of these changes doesn't matter.
  • Keep text for local development, and document that it doesn't protect against the problems listed below.

Notes:

  • The global logger is created on import and configured afterwards by backend/lib/logger, which is how logLevel is applied today. If the format can be switched on the same instance, shared packages using globalLogger need no changes.
  • Morgan passes finished access log lines to the logger, with its field values already escaped. Putting such a line into msg escapes them again (a " becomes \\\"). Building the access log record from the request and response avoids this; the existing URL redaction must be kept. The record also needs a regular level instead of the current http method.
  • Logger#inspect always sets colors: true, but JSON output must not contain color codes.
  • If arguments become separate fields instead of being formatted into msg: JSON.stringify turns an Error into {} and throws on circular structures and BigInt values. Logging must never throw.

Why is this needed:

The backend only writes human-readable text lines (<timestamp> <level>: <message>) and fills in printf-style arguments with util.format. The chart and gardener-operator set logFormat: text, but the backend never reads that setting. In production, this has several downsides:

  • Values from outside the dashboard, such as HTTP requests or responses from upstream APIs, are written as they are. A line break in such a value creates what looks like a separate log record. Terminal escape sequences are passed on to anyone who reads the logs in a terminal.
  • A single record can span several lines, for example error stacks or response bodies logged at trace level. Container logs are line-based, so log pipelines treat these lines as unrelated entries.
  • Nothing is machine-readable. Level and timestamp are plain text, and the timestamp is in UTC but has no zone designator. Response bodies logged at trace level contain ANSI color codes even when the output is not a terminal.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions