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.
Enable JSON logging with the --json-logs runtime option.
Log Severity Levels
| Severity | Meaning | Typical events |
|---|---|---|
INFO | Startup information, such as starting the scanner or initializing metrics, and scaling lifecycle events. | Workload successfully scaled up or down; downscaler starting configurations. |
WARN | An unexpected or recoverable condition, such as an indeterminate scaling period or a retry after a workload conflict. | Incomplete scaling time; workload conflict retry. |
ERROR | An operation failed, such as parsing configuration, reading a workload, or applying a scaling change. | Failed scaling operation; invalid configuration or annotation. |
DEBUG | Detailed 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.
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.)
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:
| Field | Type | Meaning |
|---|---|---|
time | string | RFC3339 timestamp generated by the JSON log handler. |
severity | string | Log severity: DEBUG, INFO, WARN, or ERROR. |
msg | string | Human-readable event description. |
workload | string | Workload name, when the record is associated with a workload. |
namespace | string | Kubernetes namespace of the workload. |
kind | string | Kubernetes resource kind, such as Deployment or StatefulSet. |
scalingAction | string | Selected scaling state, such as ScalingUp, ScalingDown, ScalingIgnore, or ScalingNone. |
decisionScope | string | Scope that supplied the scaling decision or exclusion; runtime filters use ScopeCli or ScopeEnvironment when the exact source is not retained. |
decisionValue | boolean or string | Value that caused the decision, for example true or a formatted time span. |
upscaleOnExclusion | boolean | Present 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
excludeorexclude-untilsetting configured in the workload scope logsdecisionScope: "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
- Enable JSON output with
--json-logs. - Enable detailed records with
--debugwhen the issue involves scope parsing or a scaling decision. - Filter by
namespace,workload, andkindbefore inspecting the message text. - Check
scalingActionto determine whether the workload was scaled, skipped, excluded, or left unchanged. - Check
decisionScope,decisionValue, orupscaleOnExclusionto understand why the action was selected. - For failed operations, filter
severity == "ERROR"and inspect theerrorfield.