aws / aws/aws-cdk

(aws-events-targets): LogGroupTargetInput.fromObjectV2 doesn't support mixing static and dynamic fields in message

Open
#35,683 1 comment 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-events-targets effort/medium feature-request p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the feature

When using `CloudWatchLogGroup` as an EventBridge rule target with `LogGroupTargetInput.fromObjectV2()`, there's no way to create structured log messages that mix static string values with dynamic `EventField.fromPath()` values. This limitation makes it difficult to add context (like log levels or static messages) to events being logged.

### Use Case

I should be able to create structured log messages that include both:
- Static fields like `"level": "ERROR"`
- Dynamic fields from the event like `EventField.fromPath("$.detail.taskArn")`

Something like:
```typescript
LogGroupTargetInput.fromObjectV2({
timestamp: EventField.fromPath("$.time"),
message: {
level: "ERROR", // Static field
message: "Task failed", // Static field
taskArn: EventField.fromPath("$.detail.taskArn"), // Dynamic field
clusterArn: EventField.fromPath("$.detail.clusterArn"), // Dynamic field
}
})
```

However, today, the `LogGroupTargetInputOptions` interface only supports two fields:
```typescript
export interface LogGroupTargetInputOptions {
readonly timestamp?: any;
readonly message?: any;
}
```

This means:
1. The `message` field must be a flat string or single `EventField`, not a structured object
2. There's no way to add additional fields at the top level (like `level`)
3. The validation in `CloudWatchLogGroup` enforces exactly `{timestamp, message}` format

You can see this with this simple repro:

```typescript
import { Rule, EventField } from 'aws-cdk-lib/aws-events';
import { CloudWatchLogGroup, LogGroupTargetInput } from 'aws-cdk-lib/aws-events-targets';
import * as logs from 'aws-cdk-lib/aws-logs';

const rule = new Rule(this, 'MyRule', {
eventPattern: {
source: ['aws.ecs'],
detailType: ['ECS Task State Change'],
},
});

const logGroup = new logs.LogGroup(this, 'MyLogGroup');

// This doesn't work - can't add 'level' or mix static/dynamic in message
rule.addTarget(new CloudWatchLogGroup(logGroup, {
logEvent: LogGroupTargetInput.fromObjectV2({
timestamp: EventField.fromPath("$.time"),
message: // ??? No good option here for structured logging
}),
}));
```

**Attempted workarounds:**
1. Using `JSON.stringify()` - doesn't work because `EventField` objects don't serialize
2. Using array `.join("")` - doesn't work because `EventField` objects can't be concatenated
3. Using template literals - doesn't work because `EventField` objects aren't strings
4. Using the deprecated `event` property with `RuleTargetInput.fromObject()` - gets validation errors

### Proposed Solution

Option 1: Extend `LogGroupTargetInputOptions` to support structured messages:
```typescript
export interface LogGroupTargetInputOptions {
readonly timestamp?: any;
readonly message?: any;
readonly additionalFields?: Record; // NEW
}
```

Option 2: Allow `message` to be an object with mixed static/dynamic fields, similar to how `RuleTargetInput.fromObject()` works:
```typescript
LogGroupTargetInput.fromObjectV2({
timestamp: EventField.fromPath("$.time"),
message: {
level: "ERROR",
taskArn: EventField.fromPath("$.detail.taskArn"),
}
})
```

Option 3: Relax the validation in `CloudWatchLogGroup.validateInputTemplate()` to allow additional fields beyond just `timestamp` and `message`.

### Other Information

## Workaround

Currently, the only way to achieve this is to create a custom class that extends `LogGroupTargetInput` and bypasses CDK validation:

```typescript
class CustomLogGroupTargetInput extends LogGroupTargetInput {
constructor(
private readonly inputPathsMap: Record,
private readonly inputTemplate: string,
) {
super();
}

bind(_rule: IRule): RuleTargetInputProperties {
return {
inputPathsMap: this.inputPathsMap,
inputTemplate: this.inputTemplate,
};
}
}

// Usage:
rule.addTarget(
new CloudWatchLogGroup(logGroup, {
logEvent: new CustomLogGroupTargetInput(
{
"detail-taskArn": "$.detail.taskArn",
"time": "$.time",
},
'{"timestamp":

This works but bypasses type safety and CDK's abstraction.

### Acknowledgements

- [ ] I may be able to implement this feature request
- [ ] This feature might incur a breaking change

### AWS CDK Library version (aws-cdk-lib)

2.199.0

### AWS CDK CLI version

2.1007.0 (build d3f6c3c)

### Environment details (OS name and version, etc.)

MacOS

Contributor guide

Open the contributing guide

Research direction

Start by tracing LogGroupTargetInput.fromObjectV2(), LogGroupTargetInputOptions, and CloudWatchLogGroup.validateInputTemplate() to understand the current timestamp/message shape and EventField handling. Resolve which proposed API shape is intended, then verify that mixed static and dynamic structured messages are accepted and rendered correctly without bypassing validation.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.