Skip to content

Commit a74536b

Browse files
authored
feat: support max-buffer-size for AWSLogs driver (#26396)
When mode is set to `non-blocking`, logs are stored in a buffer. The setting `max-buffer-size` controls the size of this buffer. Being able to set this buffer is very important, the larger the buffer, the less likely there is to be log loss. Recently I performed benchmarking of `non-blocking` mode, and found that the default buffer size is not sufficient to prevent log loss: moby/moby#45999 We're planning to run an education campaign to ensure ECS customers understand the risk with the default `blocking` mode, and the risk with `non-blocking` mode with the default buffer size. Therefore, we need folks to be able to control this setting in their CDK. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 9753039 commit a74536b

File tree

6 files changed

+65
-4
lines changed

6 files changed

+65
-4
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.template.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,9 @@
955955
"awslogs-stream-prefix": "firelens",
956956
"awslogs-region": {
957957
"Ref": "AWS::Region"
958-
}
958+
},
959+
"mode": "non-blocking",
960+
"max-buffer-size": "26214400b"
959961
}
960962
},
961963
"MemoryReservation": 50,

packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/tree.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,9 @@
15261526
"awslogs-stream-prefix": "firelens",
15271527
"awslogs-region": {
15281528
"Ref": "AWS::Region"
1529-
}
1529+
},
1530+
"mode": "non-blocking",
1531+
"max-buffer-size": "26214400b"
15301532
}
15311533
},
15321534
"firelensConfiguration": {

packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ taskDefinition.addFirelensLogRouter('log_router', {
3131
configFileType: ecs.FirelensConfigFileType.S3,
3232
},
3333
},
34-
logging: new ecs.AwsLogDriver({ streamPrefix: 'firelens' }),
34+
logging: new ecs.AwsLogDriver({
35+
streamPrefix: 'firelens',
36+
mode: ecs.AwsLogDriverMode.NON_BLOCKING,
37+
maxBufferSize: cdk.Size.mebibytes(25),
38+
}),
3539
memoryReservationMiB: 50,
3640
});
3741

packages/aws-cdk-lib/aws-ecs/README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,11 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef');
966966
taskDefinition.addContainer('TheContainer', {
967967
image: ecs.ContainerImage.fromRegistry('example-image'),
968968
memoryLimitMiB: 256,
969-
logging: ecs.LogDrivers.awsLogs({ streamPrefix: 'EventDemo' }),
969+
logging: ecs.LogDrivers.awsLogs({
970+
streamPrefix: 'EventDemo',
971+
mode: ecs.AwsLogDriverMode.NON_BLOCKING,
972+
maxBufferSize: Size.mebibytes(25),
973+
}),
970974
});
971975
```
972976

packages/aws-cdk-lib/aws-ecs/lib/log-drivers/aws-log-driver.ts

+20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Construct } from 'constructs';
22
import { LogDriver, LogDriverConfig } from './log-driver';
33
import { removeEmpty } from './utils';
44
import * as logs from '../../../aws-logs';
5+
import { Size, SizeRoundingBehavior } from '../../../core';
56
import { ContainerDefinition } from '../container-definition';
67

78
/**
@@ -82,6 +83,16 @@ export interface AwsLogDriverProps {
8283
* @default - AwsLogDriverMode.BLOCKING
8384
*/
8485
readonly mode?: AwsLogDriverMode;
86+
87+
/**
88+
* When AwsLogDriverMode.NON_BLOCKING is configured, this parameter
89+
* controls the size of the non-blocking buffer used to temporarily
90+
* store messages. This parameter is not valid with
91+
* AwsLogDriverMode.BLOCKING.
92+
*
93+
* @default - 1 megabyte if driver mode is non-blocking, otherwise this property is not set
94+
*/
95+
readonly maxBufferSize?: Size;
8596
}
8697

8798
/**
@@ -106,6 +117,10 @@ export class AwsLogDriver extends LogDriver {
106117
if (props.logGroup && props.logRetention) {
107118
throw new Error('Cannot specify both `logGroup` and `logRetentionDays`.');
108119
}
120+
121+
if (props.maxBufferSize && props.mode !== AwsLogDriverMode.NON_BLOCKING) {
122+
throw new Error('Cannot specify `maxBufferSize` when the driver mode is blocking');
123+
}
109124
}
110125

111126
/**
@@ -116,6 +131,10 @@ export class AwsLogDriver extends LogDriver {
116131
retention: this.props.logRetention || Infinity,
117132
});
118133

134+
const maxBufferSize = this.props.maxBufferSize
135+
? `${this.props.maxBufferSize.toBytes({ rounding: SizeRoundingBehavior.FLOOR })}b`
136+
: undefined;
137+
119138
this.logGroup.grantWrite(containerDefinition.taskDefinition.obtainExecutionRole());
120139

121140
return {
@@ -127,6 +146,7 @@ export class AwsLogDriver extends LogDriver {
127146
'awslogs-datetime-format': this.props.datetimeFormat,
128147
'awslogs-multiline-pattern': this.props.multilinePattern,
129148
'mode': this.props.mode,
149+
'max-buffer-size': maxBufferSize,
130150
}),
131151
};
132152
}

packages/aws-cdk-lib/aws-ecs/test/aws-log-driver.test.ts

+29
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('aws log driver', () => {
2424
multilinePattern: 'pattern',
2525
streamPrefix: 'hello',
2626
mode: ecs.AwsLogDriverMode.NON_BLOCKING,
27+
maxBufferSize: cdk.Size.mebibytes(25),
2728
}),
2829
});
2930

@@ -44,6 +45,7 @@ describe('aws log driver', () => {
4445
'awslogs-datetime-format': 'format',
4546
'awslogs-multiline-pattern': 'pattern',
4647
'mode': 'non-blocking',
48+
'max-buffer-size': '26214400b',
4749
},
4850
},
4951
}),
@@ -146,6 +148,33 @@ describe('aws log driver', () => {
146148

147149
});
148150

151+
test('throws error when specifying maxBufferSize and blocking mode', () => {
152+
// GIVEN
153+
const logGroup = new logs.LogGroup(stack, 'LogGroup');
154+
155+
// THEN
156+
expect(() => new ecs.AwsLogDriver({
157+
logGroup,
158+
streamPrefix: 'hello',
159+
mode: ecs.AwsLogDriverMode.BLOCKING,
160+
maxBufferSize: cdk.Size.mebibytes(25),
161+
})).toThrow(/.*maxBufferSize.*/);
162+
163+
});
164+
165+
test('throws error when specifying maxBufferSize and default settings', () => {
166+
// GIVEN
167+
const logGroup = new logs.LogGroup(stack, 'LogGroup');
168+
169+
// THEN
170+
expect(() => new ecs.AwsLogDriver({
171+
logGroup,
172+
streamPrefix: 'hello',
173+
maxBufferSize: cdk.Size.mebibytes(25),
174+
})).toThrow(/.*maxBufferSize.*/);
175+
176+
});
177+
149178
test('allows cross-region log group', () => {
150179
// GIVEN
151180
const logGroupRegion = 'asghard';

0 commit comments

Comments
 (0)