Skip to content

Commit 6512acb

Browse files
authored
Merge branch 'main' into add-warning-on-vpcsubnets-without-vpc
2 parents 131d9ea + a2bb263 commit 6512acb

15 files changed

Lines changed: 2326 additions & 2 deletions

File tree

packages/@aws-cdk/aws-appsync/README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,29 @@ new route53.CnameRecord(this, `CnameApiRecord`, {
334334
});
335335
```
336336

337+
## Log Group
338+
339+
AppSync automatically create a log group with the name `/aws/appsync/apis/<graphql_api_id>` upon deployment with
340+
log data set to never expire. If you want to set a different expiration period, use the `logConfig.retention` property.
341+
342+
To obtain the GraphQL API's log group as a `logs.ILogGroup` use the `logGroup` property of the
343+
`GraphqlApi` construct.
344+
345+
```ts
346+
import * as logs from '@aws-cdk/aws-logs';
347+
348+
const logConfig: appsync.LogConfig = {
349+
retention: logs.RetentionDays.ONE_WEEK,
350+
};
351+
352+
new appsync.GraphqlApi(this, 'api', {
353+
authorizationConfig: {},
354+
name: 'myApi',
355+
schema: appsync.Schema.fromAsset(path.join(__dirname, 'myApi.graphql')),
356+
logConfig,
357+
});
358+
```
359+
337360
## Schema
338361

339362
Every GraphQL Api needs a schema to define the Api. CDK offers `appsync.Schema`
@@ -427,7 +450,7 @@ new appsync.GraphqlApi(this, 'api', {
427450
defaultAuthorization: {
428451
authorizationType: appsync.AuthorizationType.LAMBDA,
429452
lambdaAuthorizerConfig: {
430-
handler: authFunction,
453+
handler: authFunction,
431454
// can also specify `resultsCacheTtl` and `validationRegex`.
432455
},
433456
},

packages/@aws-cdk/aws-appsync/lib/graphqlapi.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ICertificate } from '@aws-cdk/aws-certificatemanager';
22
import { IUserPool } from '@aws-cdk/aws-cognito';
33
import { ManagedPolicy, Role, IRole, ServicePrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam';
44
import { IFunction } from '@aws-cdk/aws-lambda';
5+
import { ILogGroup, LogGroup, LogRetention, RetentionDays } from '@aws-cdk/aws-logs';
56
import { ArnFormat, CfnResource, Duration, Expiration, IResolvable, Stack } from '@aws-cdk/core';
67
import { Construct } from 'constructs';
78
import { CfnApiKey, CfnGraphQLApi, CfnGraphQLSchema, CfnDomainName, CfnDomainNameApiAssociation } from './appsync.generated';
@@ -248,6 +249,16 @@ export interface LogConfig {
248249
* @default - None
249250
*/
250251
readonly role?: IRole;
252+
253+
/**
254+
* The number of days log events are kept in CloudWatch Logs.
255+
* By default AppSync keeps the logs infinitely. When updating this property,
256+
* unsetting it doesn't remove the log retention policy.
257+
* To remove the retention policy, set the value to `INFINITE`
258+
*
259+
* @default RetentionDays.INFINITE
260+
*/
261+
readonly retention?: RetentionDays
251262
}
252263

253264
/**
@@ -459,6 +470,11 @@ export class GraphqlApi extends GraphqlApiBase {
459470
*/
460471
public readonly apiKey?: string;
461472

473+
/**
474+
* the CloudWatch Log Group for this API
475+
*/
476+
public readonly logGroup: ILogGroup;
477+
462478
private schemaResource: CfnGraphQLSchema;
463479
private api: CfnGraphQLApi;
464480
private apiKeyResource?: CfnApiKey;
@@ -527,6 +543,16 @@ export class GraphqlApi extends GraphqlApiBase {
527543
});
528544
}
529545

546+
const logGroupName = `/aws/appsync/apis/${this.apiId}`;
547+
548+
this.logGroup = LogGroup.fromLogGroupName(this, 'LogGroup', logGroupName);
549+
550+
if (props.logConfig?.retention) {
551+
new LogRetention(this, 'LogRetention', {
552+
logGroupName: this.logGroup.logGroupName,
553+
retention: props.logConfig.retention,
554+
});
555+
};
530556
}
531557

532558
/**
@@ -620,10 +646,11 @@ export class GraphqlApi extends GraphqlApiBase {
620646
ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSAppSyncPushToCloudWatchLogs'),
621647
],
622648
}).roleArn;
649+
const fieldLogLevel: FieldLogLevel = config.fieldLogLevel ?? FieldLogLevel.NONE;
623650
return {
624651
cloudWatchLogsRoleArn: logsRoleArn,
625652
excludeVerboseContent: config.excludeVerboseContent,
626-
fieldLogLevel: config.fieldLogLevel,
653+
fieldLogLevel: fieldLogLevel,
627654
};
628655
}
629656

packages/@aws-cdk/aws-appsync/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"@aws-cdk/aws-stepfunctions": "0.0.0",
8585
"@aws-cdk/cdk-build-tools": "0.0.0",
8686
"@aws-cdk/integ-runner": "0.0.0",
87+
"@aws-cdk/integ-tests": "0.0.0",
8788
"@aws-cdk/cfn2ts": "0.0.0",
8889
"@aws-cdk/pkglint": "0.0.0",
8990
"@types/jest": "^27.5.2",
@@ -97,6 +98,7 @@
9798
"@aws-cdk/aws-elasticsearch": "0.0.0",
9899
"@aws-cdk/aws-iam": "0.0.0",
99100
"@aws-cdk/aws-lambda": "0.0.0",
101+
"@aws-cdk/aws-logs": "0.0.0",
100102
"@aws-cdk/aws-opensearchservice": "0.0.0",
101103
"@aws-cdk/aws-rds": "0.0.0",
102104
"@aws-cdk/aws-s3-assets": "0.0.0",
@@ -113,6 +115,7 @@
113115
"@aws-cdk/aws-elasticsearch": "0.0.0",
114116
"@aws-cdk/aws-iam": "0.0.0",
115117
"@aws-cdk/aws-lambda": "0.0.0",
118+
"@aws-cdk/aws-logs": "0.0.0",
116119
"@aws-cdk/aws-opensearchservice": "0.0.0",
117120
"@aws-cdk/aws-rds": "0.0.0",
118121
"@aws-cdk/aws-s3-assets": "0.0.0",

packages/@aws-cdk/aws-appsync/test/appsync.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from 'path';
22
import { Template } from '@aws-cdk/assertions';
33
import { Certificate } from '@aws-cdk/aws-certificatemanager';
44
import * as iam from '@aws-cdk/aws-iam';
5+
import * as logs from '@aws-cdk/aws-logs';
56
import * as cdk from '@aws-cdk/core';
67
import * as appsync from '../lib';
78

@@ -191,3 +192,49 @@ test('appsync GraphqlApi should be configured with custom domain when specified'
191192
DomainName: domainName,
192193
});
193194
});
195+
196+
test('log retention should be configured with given retention time when specified', () => {
197+
// GIVEN
198+
const retentionTime = logs.RetentionDays.ONE_WEEK;
199+
200+
// WHEN
201+
new appsync.GraphqlApi(stack, 'log-retention', {
202+
authorizationConfig: {},
203+
name: 'log-retention',
204+
schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')),
205+
logConfig: {
206+
retention: retentionTime,
207+
},
208+
});
209+
210+
// THEN
211+
Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', {
212+
LogGroupName: {
213+
'Fn::Join': [
214+
'',
215+
[
216+
'/aws/appsync/apis/',
217+
{
218+
'Fn::GetAtt': [
219+
'logretentionB69DFB48',
220+
'ApiId',
221+
],
222+
},
223+
],
224+
],
225+
},
226+
RetentionInDays: 7,
227+
});
228+
});
229+
230+
test('log retention should not appear when no retention time is specified', () => {
231+
// WHEN
232+
new appsync.GraphqlApi(stack, 'no-log-retention', {
233+
authorizationConfig: {},
234+
name: 'no-log-retention',
235+
schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.test.graphql')),
236+
});
237+
238+
// THEN
239+
Template.fromStack(stack).resourceCountIs('Custom::LogRetention', 0);
240+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { join } from 'path';
2+
import { RetentionDays } from '@aws-cdk/aws-logs';
3+
import { App, Stack } from '@aws-cdk/core';
4+
import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests';
5+
import { GraphqlApi, LogConfig, Schema } from '../lib';
6+
7+
const app = new App();
8+
const stack = new Stack(app, 'AppSyncIntegLogRetention');
9+
10+
11+
const retentionTime = RetentionDays.ONE_WEEK;
12+
const logConfig: LogConfig = {
13+
retention: retentionTime,
14+
};
15+
16+
const api = new GraphqlApi(stack, 'GraphqlApi', {
17+
authorizationConfig: {},
18+
name: 'IntegLogRetention',
19+
schema: Schema.fromAsset(join(__dirname, 'appsync.test.graphql')),
20+
logConfig,
21+
});
22+
23+
const integ = new IntegTest(app, 'Integ', { testCases: [stack] });
24+
25+
const describe = integ.assertions.awsApiCall('CloudWatchLogs',
26+
'describeLogGroups',
27+
{
28+
logGroupNamePrefix: api.logGroup.logGroupName,
29+
});
30+
31+
describe.expect(ExpectedResult.objectLike({
32+
logGroups: [
33+
{
34+
logGroupName: api.logGroup.logGroupName,
35+
retentionInDays: retentionTime,
36+
},
37+
],
38+
}));
39+
40+
app.synth();

0 commit comments

Comments
 (0)