Skip to main content
Version: 1.4.0

Logs

GoKubeDownscaler writes operational information to standard output using Go's structured slog logger. Logs can be emitted as human-readable text or as one JSON object per line. JSON logs are recommended for production deployments because they can be parsed and queried reliably by Kubernetes logging systems.

Log Output Formats​

Text Logs​

Text logs are the default. They are convenient when running the component locally or reading logs directly in a terminal.

JSON Logs​

With JSON logging enabled, every record is emitted as a single JSON object. A typical record has this shape:

{
"time": "2026-09-14T12:34:56.789Z",
"severity": "INFO",
"msg": "successfully processed workload state",
"workload": "checkout",
"namespace": "production",
"kind": "Deployment",
"scalingAction": "ScalingDown",
"decisionScope": "ScopeWorkload",
"decisionValue": "[09:00-18:00]"
}

The severity field is used instead of the default slog field name level which is a standard for logging systems, in particular Google Cloud Platform's Cloud Logging.

info

Enable JSON logging with the --json-logs runtime option.

Log Severity Levels​

SeverityMeaningTypical events
INFOStartup information, such as starting the scanner or initializing metrics, and scaling lifecycle events.Workload successfully scaled up or down; downscaler starting configurations.
WARNAn unexpected or recoverable condition, such as an indeterminate scaling period or a retry after a workload conflict.Incomplete scaling time; workload conflict retry.
ERRORAn operation failed, such as parsing configuration, reading a workload, or applying a scaling change.Failed scaling operation; invalid configuration or annotation.
DEBUGDetailed scan and decision information intended for troubleshooting.Excluded or skipped workload; scope evaluation and scan details.

INFO, WARN, and ERROR logs are enabled by default. DEBUG logs are enabled when the --debug option is set. Dry-run mode enables debug logging by default so that potential scaling decisions can be inspected.

warning

DEBUG level is very verbose and is not recommended for normal production operation, this could generate a large volume of logs that can result in increased storage and ingestion costs. (Especially if you are using a cloud provider logging solution to store your logs.)

tip

Use --json-logs --debug while investigating a workload. Use --json-logs without --debug in normal production operation to keep the log volume lower while retaining structured warnings and errors.

Common Fields​

The following fields identify the workload and the scaling decision:

FieldTypeMeaning
timestringRFC3339 timestamp generated by the JSON log handler.
severitystringLog severity: DEBUG, INFO, WARN, or ERROR.
msgstringHuman-readable event description.
workloadstringWorkload name, when the record is associated with a workload.
namespacestringKubernetes namespace of the workload.
kindstringKubernetes resource kind, such as Deployment or StatefulSet.
scalingActionstringSelected scaling state, such as ScalingUp, ScalingDown, ScalingIgnore, or ScalingNone.
decisionScopestringScope that supplied the scaling decision or exclusion; runtime filters use ScopeCli or ScopeEnvironment when the exact source is not retained.
decisionValueboolean or stringValue that caused the decision, for example true or a formatted time span.
upscaleOnExclusionbooleanPresent instead of decisionValue when an excluded workload is explicitly upscaled.

Scaling Actions​

Common outcomes include:

  • scalingExcluded: the workload is excluded from scaling by a matching scope.
  • scalingGracePeriod: the workload is still within its configured grace period.
  • ScalingNone: no scope supplied a scaling configuration.
  • ScalingIgnore: a matching scope explicitly prevents scaling.
  • ScalingIncomplete: the configured times cannot currently be evaluated.
  • ScalingDown: the workload is downscaled.
  • ScalingUp: the workload is upscaled.

This is an example of a debug log indicating that a workload was excluded from scaling:

{
"severity": "DEBUG",
"msg": "workload is excluded, skipping",
"workload": "batch-worker",
"namespace": "production",
"kind": "Deployment",
"scalingAction": "scalingExcluded",
"decisionScope": "ScopeWorkload"
}

For exclusions that happen before a scaling decision exists, decisionScope identifies the governing scope when one exists:

  • Grace-period exclusion: a grace period configured in the namespace scope logs decisionScope: "ScopeNamespace".
  • Scope exclusion: an exclude or exclude-until setting configured in the workload scope logs decisionScope: "ScopeWorkload".
  • Initial filter exclusion: a label, namespace, or workload-name filter runs before scope evaluation and logs decisionScope: "ScopeCli or ScopeEnvironment", because those filters can be configured through CLI flags or environment variables.
  • External scaling exclusion: automatic external-scaling detection has no configuration scope and logs decisionScope: "ScopeNone".

Grace-period exclusions use the scope that configured the grace period, scope-based exclusions use the scope that excluded the workload, and runtime filter exclusions use decisionScope: "ScopeCli or ScopeEnvironment".

Kubernetes Logs​

When the container writes JSON to standard output, Kubernetes preserves each JSON record as the container log message. A collector such as Loki, Fluent Bit, Fluentd, or Elasticsearch should parse the message as JSON and index selected fields such as severity, msg, workload, namespace, kind, and scalingAction. You can also choose to store the entire JSON record in a single field for later parsing and better analysis.

Querying JSON Logs​

Because each record is a complete JSON object, fields can be selected without parsing the message text.

jq​

Filter all downscaling records from a local log file:

jq 'select(.scalingAction == "ScalingDown")' kubedownscaler.log

Show errors for one workload:

jq 'select(.severity == "ERROR" and .workload == "checkout")' kubedownscaler.log

Print a compact decision summary:

jq -r '[.time, .namespace, .kind, .workload, .scalingAction, (.decisionScope // "-")] | @tsv' kubedownscaler.log

Loki / LogQL​

Select logs from a Kubernetes container and parse their JSON fields:

{app="gokubedownscaler"} | json | scalingAction="ScalingDown"

Find scaling errors:

{app="gokubedownscaler"} | json | severity="ERROR" | workload != ""

CloudWatch Logs Insights​

When JSON logs are delivered to Amazon CloudWatch Logs, CloudWatch Logs Insights can query the structured fields directly. Select the log group containing the GoKubeDownscaler container logs and run one of these queries.

Find recent downscaling events:

fields @timestamp, namespace, kind, workload, scalingAction, decisionScope
| filter scalingAction = "ScalingDown"
| sort @timestamp desc
| limit 100

Find errors for a specific workload:

fields @timestamp, severity, msg, error, namespace, workload
| filter severity = "ERROR"
| filter namespace = "production" and workload = "checkout"
| sort @timestamp desc
| limit 100

Count scaling actions by namespace and action:

stats count(*) as total by namespace, scalingAction
| sort total desc

Google Cloud Logging​

In Google Cloud Logging, use the Logs Explorer query language to filter structured Kubernetes container logs. The exact resource.type can vary with the deployment; k8s_container is the usual value for logs collected from a Kubernetes container.

Find downscaling events in a Kubernetes cluster:

resource.type="k8s_container"
jsonPayload.scalingAction="ScalingDown"
jsonPayload.namespace="production"

Find errors for one workload:

resource.type="k8s_container"
severity>=ERROR
jsonPayload.workload="checkout"
jsonPayload.namespace="production"

Find all scaling actions for a workload and order them by time in Logs Explorer:

resource.type="k8s_container"
jsonPayload.workload="checkout"
jsonPayload.scalingAction:*

If the collector maps the application severity field into Cloud Logging's reserved top-level severity field, use severity>=ERROR as shown above. Otherwise, query the original JSON field with jsonPayload.severity="ERROR".

Troubleshooting Workflow​

  1. Enable JSON output with --json-logs.
  2. Enable detailed records with --debug when the issue involves scope parsing or a scaling decision.
  3. Filter by namespace, workload, and kind before inspecting the message text.
  4. Check scalingAction to determine whether the workload was scaled, skipped, excluded, or left unchanged.
  5. Check decisionScope, decisionValue, or upscaleOnExclusion to understand why the action was selected.
  6. For failed operations, filter severity == "ERROR" and inspect the error field.