Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions observability-events-otel-collector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,17 @@ EOF

### AWS CloudWatch Logs

Credentials come from the standard AWS chain (IRSA on EKS):
Compatible with `observability-logs-aws-cloudwatch` when the adapter chart is
installed with `events.enabled=true`. The adapter setup job creates the events
log group with retention; the collector only needs permission to create streams
and publish log events. Credentials come from the standard AWS chain (IRSA on
EKS):

```yaml
exporters:
awscloudwatchlogs:
region: "us-east-1"
log_group_name: "/openchoreo/k8s-events"
log_group_name: "/aws/containerinsights/events"
log_stream_name: "events"
pipelineExporters:
- awscloudwatchlogs
Expand Down
7 changes: 7 additions & 0 deletions observability-logs-aws-cloudwatch/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ CFG_DIR := internal/api
OAPI_CODEGEN_VERSION ?= v2.5.1
# Pinned to an immutable commit SHA so `make openapi-codegen` is reproducible.
# Bump the SHA when the upstream spec changes.
#
# NOTE: the events API (`POST /api/v1/events/query`, EventsQueryRequest/Response,
# EventEntry) must be present in this upstream spec before regenerating. Until that
# lands upstream, the generated `internal/api/gen/*` was produced from the local
# TASKS/logs-event-publishing/openapi.yaml — regenerating against a spec that lacks
# the events path will strip the events code and break the build. Override with e.g.
# `make openapi-codegen SPEC=../TASKS/logs-event-publishing/openapi.yaml` in the meantime.
SPEC := https://raw.githubusercontent.com/openchoreo/openchoreo/main/openapi/observability-logs-adapter-api.yaml

.PHONY: oapi-codegen-install openapi-codegen unit-test
Expand Down
242 changes: 212 additions & 30 deletions observability-logs-aws-cloudwatch/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion observability-logs-aws-cloudwatch/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.1
0.3.0
16 changes: 16 additions & 0 deletions observability-logs-aws-cloudwatch/helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,24 @@ AWS region sourced from the upstream subchart values block.
Resolved application log group name for the adapter and setup Job.
*/}}
{{- define "logs-aws-cloudwatch.logGroupName" -}}
{{- if .Values.global.applicationLogGroupName -}}
{{- .Values.global.applicationLogGroupName -}}
{{- else -}}
{{- printf "%s/application" (include "logs-aws-cloudwatch.logGroupPrefix" .) -}}
{{- end -}}
{{- end -}}

{{/*
Log group where the observability-events-otel-collector ships enriched Kubernetes
events. Mirrors the application log group under the shared prefix.
*/}}
{{- define "logs-aws-cloudwatch.eventsLogGroupName" -}}
{{- if .Values.events.logGroupName -}}
{{- .Values.events.logGroupName -}}
{{- else -}}
{{- printf "%s/events" (include "logs-aws-cloudwatch.logGroupPrefix" .) -}}
{{- end -}}
{{- end -}}

{{/*
Validate required values and fail fast with a readable message.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ data:
AWS_REGION: {{ include "logs-aws-cloudwatch.region" . | quote }}
LOG_GROUP_PREFIX: {{ include "logs-aws-cloudwatch.logGroupPrefix" . | quote }}
LOG_GROUP_NAME: {{ include "logs-aws-cloudwatch.logGroupName" . | quote }}
EVENTS_LOG_GROUP_NAME: {{ include "logs-aws-cloudwatch.eventsLogGroupName" . | quote }}
QUERY_TIMEOUT_SECONDS: {{ .Values.adapter.queryTimeoutSeconds | quote }}
QUERY_POLL_MILLISECONDS: {{ .Values.adapter.queryPollMilliseconds | quote }}
LOG_LEVEL: {{ .Values.adapter.logLevel | quote }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,16 @@ spec:
value: {{ include "logs-aws-cloudwatch.region" . | quote }}
- name: LOG_GROUP_PREFIX
value: {{ include "logs-aws-cloudwatch.logGroupPrefix" . | quote }}
- name: LOG_GROUP_NAME
value: {{ include "logs-aws-cloudwatch.logGroupName" . | quote }}
- name: RETENTION_DAYS
value: {{ .Values.containerLogs.retentionDays | quote }}
- name: EVENTS_PROVISION_LOG_GROUP
value: {{ .Values.events.provisionLogGroup | quote }}
- name: EVENTS_LOG_GROUP_NAME
value: {{ include "logs-aws-cloudwatch.eventsLogGroupName" . | quote }}
- name: EVENTS_RETENTION_DAYS
value: {{ .Values.events.retentionDays | quote }}
{{- if .Values.awsCredentials.name }}
envFrom:
- secretRef:
Expand Down
21 changes: 19 additions & 2 deletions observability-logs-aws-cloudwatch/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Job. The application log group resolves to `<global.logGroupPrefix>/application`.
global:
logGroupPrefix: "/aws/containerinsights"
# Optional exact application log group name. When empty, the chart uses
# `<global.logGroupPrefix>/application`.
applicationLogGroupName: ""

# AWS authentication mode. Defaults to **EKS Pod Identity / IRSA / EC2
# instance-profile** — the AWS SDK default credentials chain picks them up
Expand All @@ -26,6 +29,20 @@ awsCredentials:
containerLogs:
retentionDays: 7

# Kubernetes event support. Events are an optional, opt-in capability: they are
# ingested by the separate `observability-events-otel-collector` chart (deployed
# with its `awscloudwatchlogs` exporter pointed at the events log group below).
# The adapter always serves `POST /api/v1/events/query`. This flag only governs
# whether the setup Job provisions the events log group + retention.
events:
provisionLogGroup: true
# Optional exact events log group name. When empty, the chart uses
# `<global.logGroupPrefix>/events`.
logGroupName: ""
# Retention for the events log group. Sparser and longer-lived than container
# logs; must be one of CloudWatch's allowed values (see containerLogs above).
retentionDays: 30

# ---------------------------------------------------------------------------
# amazon-cloudwatch-observability dependency
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -148,7 +165,7 @@ amazon-cloudwatch-observability:
Name cloudwatch_logs
Match application.*
region ${AWS_REGION}
log_group_name {{ .Values.global.logGroupPrefix | default "/aws/containerinsights" | trimSuffix "/" }}/application
log_group_name {{ if .Values.global.applicationLogGroupName }}{{ .Values.global.applicationLogGroupName }}{{ else }}{{ .Values.global.logGroupPrefix | default "/aws/containerinsights" | trimSuffix "/" }}/application{{ end }}
log_stream_prefix ${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
Expand Down Expand Up @@ -216,7 +233,7 @@ amazon-cloudwatch-observability:
Name cloudwatch_logs
Match application.*
region ${AWS_REGION}
log_group_name {{ .Values.global.logGroupPrefix | default "/aws/containerinsights" | trimSuffix "/" }}/application
log_group_name {{ if .Values.global.applicationLogGroupName }}{{ .Values.global.applicationLogGroupName }}{{ else }}{{ .Values.global.logGroupPrefix | default "/aws/containerinsights" | trimSuffix "/" }}/application{{ end }}
log_stream_prefix ${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
Expand Down
49 changes: 35 additions & 14 deletions observability-logs-aws-cloudwatch/init/setup-cloudwatch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,52 @@ set -euo pipefail

AWS_REGION="${AWS_REGION:?AWS_REGION is required}"
LOG_GROUP_PREFIX="${LOG_GROUP_PREFIX:-/aws/containerinsights}"
LOG_GROUP_NAME="${LOG_GROUP_NAME:-}"
RETENTION_DAYS="${RETENTION_DAYS:-7}"
EVENTS_PROVISION_LOG_GROUP="${EVENTS_PROVISION_LOG_GROUP:-${EVENTS_ENABLED:-false}}"
EVENTS_LOG_GROUP_NAME="${EVENTS_LOG_GROUP_NAME:-}"
EVENTS_RETENTION_DAYS="${EVENTS_RETENTION_DAYS:-30}"

# CloudWatch's PutRetentionPolicy only accepts this fixed set of values; any
# other number is rejected by the API mid-run, leaving log groups created but
# unconfigured. Fail fast with a clearer message instead.
case " 1 3 5 7 14 30 60 90 120 150 180 365 400 545 731 1096 1827 2192 2557 2922 3288 3653 " in
*" ${RETENTION_DAYS} "*) ;;
*)
echo "RETENTION_DAYS=${RETENTION_DAYS} is not a valid CloudWatch retention." >&2
echo "Allowed: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653" >&2
exit 1
;;
esac
validate_retention() {
case " 1 3 5 7 14 30 60 90 120 150 180 365 400 545 731 1096 1827 2192 2557 2922 3288 3653 " in
*" ${1} "*) ;;
*)
echo "Retention '${1}' is not a valid CloudWatch retention." >&2
echo "Allowed: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653" >&2
exit 1
;;
esac
}

validate_retention "${RETENTION_DAYS}"

# Strip any trailing slash so joining the segments stays predictable.
LOG_GROUP_PREFIX="${LOG_GROUP_PREFIX%/}"
LOG_GROUP_NAME="${LOG_GROUP_NAME:-${LOG_GROUP_PREFIX}/application}"
EVENTS_LOG_GROUP_NAME="${EVENTS_LOG_GROUP_NAME:-${LOG_GROUP_PREFIX}/events}"

# Each entry is "<log-group-name> <retention-days>". The application log group is
# always provisioned; the events log group is opt-in
# (events.provisionLogGroup) and gets its own, typically longer, retention.
LOG_GROUPS=(
"${LOG_GROUP_PREFIX}/application"
"${LOG_GROUP_NAME} ${RETENTION_DAYS}"
)

echo "Ensuring CloudWatch log groups exist in region ${AWS_REGION} with ${RETENTION_DAYS}-day retention"
if [ "${EVENTS_PROVISION_LOG_GROUP}" = "true" ]; then
validate_retention "${EVENTS_RETENTION_DAYS}"
LOG_GROUPS+=("${EVENTS_LOG_GROUP_NAME} ${EVENTS_RETENTION_DAYS}")
fi

echo "Ensuring CloudWatch log groups exist in region ${AWS_REGION}"

for group in "${LOG_GROUPS[@]}"; do
echo "Ensuring log group: ${group}"
for entry in "${LOG_GROUPS[@]}"; do
# Split "<group> <retention>" into its two fields.
group="${entry%% *}"
retention="${entry##* }"
echo "Ensuring log group: ${group} (retention ${retention}d)"

# Attempt creation directly and key off the API's own "already exists" error.
# This avoids a describe→create TOCTOU race and stops a real failure
Expand All @@ -55,11 +76,11 @@ for group in "${LOG_GROUPS[@]}"; do
exit "${create_status}"
fi

echo "Setting retention on ${group} to ${RETENTION_DAYS} days"
echo "Setting retention on ${group} to ${retention} days"
aws logs put-retention-policy \
--region "${AWS_REGION}" \
--log-group-name "${group}" \
--retention-in-days "${RETENTION_DAYS}"
--retention-in-days "${retention}"
done

echo "CloudWatch log groups are ready"
Loading
Loading