Skip to content

Add journald log collection support for CloudWatch Agent#2121

Open
Paamicky wants to merge 25 commits into
mainfrom
mcommey/journald-logs-support
Open

Add journald log collection support for CloudWatch Agent#2121
Paamicky wants to merge 25 commits into
mainfrom
mcommey/journald-logs-support

Conversation

@Paamicky
Copy link
Copy Markdown
Contributor

@Paamicky Paamicky commented May 13, 2026

Description of the issue

Modern Linux distributions (AL2023) use systemd-journald as the sole logging system, dropping rsyslog by default. Customers on AL2023 have no /var/log/messages to tail. This feature adds native systemd-journald log collection to the CloudWatch Agent by integrating the upstream OpenTelemetry journald receiver. This fills that gap.

Description of changes

  • Config translator - Maps customer JSON config (units, priority, matches, filters) to OTel journald receiver config. Follows the same pattern as existing CWAgent translators (windows event logs, log files).
  • Pipeline translator - Creates one OTel pipeline per collect_list entry with independent receiver, filter processor, batch processor, and exporter. Each entry routes to its own CloudWatch log group/stream.
  • Filter processor - Implements regex-based include/exclude filtering using the OTel filter processor with OTTL expressions.
  • File storage extension - Persists journald cursor to /opt/aws/amazon-cloudwatch-agent/logs/state/ for state management across agent restarts. No log duplication or loss on restart.
  • JSON schema validation - Adds units, priority, matches, filters field definitions with type/length constraints and additionalProperties: false.
  • Agent health - Adds journald feature flag to the user-agent string for adoption metrics tracking.
  • Config wizard- Interactive journald configuration with prompts for units, priority, matches, and regex filters.
  • Sample configs and translation tests — journaldlogs_units, journaldlogs_priority, journaldlogs_matches, journaldlogs_filters with generated .conf and .yaml snapshots.

Config Example:

    "agent": {
      "debug": true
    },
    "logs": {
      "logs_collected": {
        "journald": {
          "collect_list": [
	    {
              "log_group_name": "journald-all-logs",
              "log_stream_name": "{instance_id}",
              "retention_in_days": 1
            },
            {
              "log_group_name": "journald-units-test",
              "log_stream_name": "{instance_id}",
              "units": ["sshd"],
              "retention_in_days": 1
            },
	    {
              "log_group_name": "journald-priority-info",
              "log_stream_name": "{instance_id}",
              "priority": "info",
              "retention_in_days": 1
            },
            {
              "log_group_name": "journald-priority-err",
              "log_stream_name": "{instance_id}",
              "priority": "err",
              "retention_in_days": 1
            },
            {
              "log_group_name": "journald-matches-test",
              "log_stream_name": "{instance_id}",
              "matches": [{"_UID": "0"}],
              "retention_in_days": 1
            },
            {
              "log_group_name": "journald-filter-test",
              "log_stream_name": "{instance_id}",
              "filters": [
                {"type": "include", "expression": ".*CODE_FILE.*"}
              ],
              "retention_in_days": 1
            }
          ]
        }
      }
    }
  }

License

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Tests

  • TestJournaldUnitsLogs - validates only entries from configured unit appear in CloudWatch
  • TestJournaldPriorityLogs - validates only entries at err priority and above appear
  • TestJournaldMatchesLogs - validates only entries matching _UID=0 appear
  • TestJournaldRegexLogs - validates only entries matching include regex appear
  • TestJournaldLogState - validates no duplicates or missing logs across agent restart (cursor persistence)
  • All tests run on AL2 and AL2023
  • Integration test: feature_linux_fournald_log_test: https://github.com/aws/amazon-cloudwatch-agent/actions/runs/25865272301

EKS and some other flakey test are failing on main, team is try to resolve it.

Requirements

Integration test and SElinux Policy update PR's needs to be merged before this PR
Integration test: aws/amazon-cloudwatch-agent-test#695
SElinux Policy Update: aws/amazon-cloudwatch-agent-selinux#9


Integration Tests

To run integration tests against this PR, add the ready for testing label.

@Paamicky Paamicky requested review from dricross and sky333999 May 13, 2026 14:13
@Paamicky Paamicky added the ready for testing Indicates this PR is ready for integration tests to run label May 13, 2026
@Paamicky Paamicky force-pushed the mcommey/journald-logs-support branch 2 times, most recently from 3fa27e5 to fb1113c Compare May 14, 2026 02:20
@Paamicky Paamicky force-pushed the mcommey/journald-logs-support branch from fb1113c to a21f5de Compare May 14, 2026 02:34
@Paamicky Paamicky marked this pull request as ready for review May 14, 2026 13:22
@Paamicky Paamicky requested a review from a team as a code owner May 14, 2026 13:22
@Paamicky Paamicky requested a review from JayPolanco May 14, 2026 13:27
@Paamicky Paamicky requested a review from okankoAMZ May 14, 2026 13:27

const (
var (
KeyDelimiter = otelconfmap.KeyDelimiter
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to change this from const to var?

var _ common.ComponentTranslator = (*translator)(nil)

// StorageID is the component.ID for the file_storage/journald extension, exported for use by the receiver.
var StorageID component.ID
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The receiver reads filestorage.StorageID (a global var set as a side effect of NewTranslator()). If build() order ever changes or the receiver is tested in isolation, this silently becomes component.ID{}. No other extension/receiver pair communicates via a global var. Can we expose a pure function instead?

func StorageComponentID() component.ID {
    return component.NewIDWithName(filestorage.NewFactory().Type(), "journald")
}

"description": "Array of systemd units to read from",
"items": {
"type": "string",
"maxLength": 256
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minItems and uniqueItems are array keywords, they're silently ignored on "type": "string". This means no validation on priority values. Can we use an "enum" like event_levels in logsWindowsEventsDefinition does?

"enum": ["emerg", "alert", "crit", "err", "warning", "notice", "info", "debug", "0", "1", "2", "3", "4", "5", "6", "7"]

}
}

// Set AWS session configuration
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sets cfg.Region, cfg.Profile, etc. directly, but the existing awscloudwatchlogs exporter (same config type) uses cfg.AWSSessionSettings.*. Could this cause different credential resolution behavior? Should match translator/translate/otel/exporter/awscloudwatchlogs/translator.go.

"collect_list"
]
},
"logsJournaldDefinition": {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log_group_name isn't required here, but both logsWindowsEventsDefinition and logsFilesDefinition require their key field. A customer who omits it silently gets all logs routed to a shared "journald-logs" group. Should we add "required": ["log_group_name"]?

@Paamicky Paamicky force-pushed the mcommey/journald-logs-support branch from eb180a4 to 91c2b7f Compare May 22, 2026 04:14
@Paamicky Paamicky force-pushed the mcommey/journald-logs-support branch from 91c2b7f to da333e1 Compare May 22, 2026 05:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for testing Indicates this PR is ready for integration tests to run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants