Skip to content

Commit d8b65ca

Browse files
committed
feat(appsync): implements configuration that utilizes enhanced metrics for data source and resolver
1 parent d62f669 commit d8b65ca

13 files changed

+228
-9
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,22 @@ const api = new appsync.GraphqlApi(this, 'OwnerContact', {
937937

938938
Enables and controls the enhanced metrics feature. Enhanced metrics emit granular data on API usage and performance such as AppSync request and error counts, latency, and cache hits/misses. All enhanced metric data is sent to your CloudWatch account, and you can configure the types of data that will be sent.
939939

940+
```ts
941+
const schema = new appsync.SchemaFile({ filePath: 'mySchemaFile' })
942+
new appsync.GraphqlApi(this, 'api', {
943+
name: 'myApi',
944+
definition: appsync.Definition.fromSchema(schema),
945+
enhancedMetricsConfig: {
946+
dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.FULL_REQUEST_DATA_SOURCE_METRICS,
947+
operationLevelMetricsEnabled: true,
948+
resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior. dataSourceLevelMetricsBehavior: appsync.DataSourceLevelMetricsBehavior.FULL_REQUEST_RESOLVER_METRICS,
949+
,
950+
},
951+
});
952+
```
953+
954+
If you wish to enable enhanced monitoring only for subset of data sources or resolvers you are use following configuration
955+
940956
```ts
941957
const schema = new appsync.SchemaFile({ filePath: 'mySchemaFile' })
942958
new appsync.GraphqlApi(this, 'api', {
@@ -948,6 +964,16 @@ new appsync.GraphqlApi(this, 'api', {
948964
resolverLevelMetricsBehavior: appsync.ResolverLevelMetricsBehavior.PER_RESOLVER_METRICS,
949965
},
950966
});
967+
968+
const noneDS = api.addNoneDataSource('none', {
969+
enhancedMetricsEnabled: true,
970+
});
971+
972+
noneDS.createResolver('noneResolver', {
973+
typeName: 'Mutation',
974+
fieldName: 'addDemoMetricsConfig',
975+
enhancedMetricsEnabled: true,
976+
});
951977
```
952978

953979
## Events

packages/aws-cdk-lib/aws-appsync/lib/data-source.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ export interface BaseDataSourceProps {
3434
* @default - None
3535
*/
3636
readonly description?: string;
37+
38+
/**
39+
* the whether to enable enhanced metrics of the data source
40+
* Value will be ignored, if `enhancedMetricsConfig.dataSourceLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_DATA_SOURCE_METRICS`
41+
*
42+
* @default - Enhance metrics are disabled
43+
*/
44+
readonly enhancedMetricsEnabled?: boolean;
3745
}
3846

3947
/**
@@ -128,11 +136,14 @@ export abstract class BaseDataSource extends Construct {
128136
// Replace unsupported characters from DataSource name. The only allowed pattern is: {[_A-Za-z][_0-9A-Za-z]*}
129137
const name = (props.name ?? id);
130138
const supportedName = Token.isUnresolved(name) ? name : name.replace(/[\W]+/g, '');
139+
const metricsConfig = props.enhancedMetricsEnabled === undefined ? undefined
140+
: (props.enhancedMetricsEnabled ? 'ENABLED': 'DISABLED');
131141
this.ds = new CfnDataSource(this, 'Resource', {
132142
apiId: props.api.apiId,
133143
name: supportedName,
134144
description: props.description,
135145
serviceRoleArn: this.serviceRole?.roleArn,
146+
metricsConfig: metricsConfig,
136147
...extended,
137148
});
138149
this.name = supportedName;

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ export interface DataSourceOptions {
3737
* @default - No description
3838
*/
3939
readonly description?: string;
40+
41+
/**
42+
* The whether to enable enhanced metrics of the data source
43+
* Value will be ignored, if `enhancedMetricsConfig.dataSourceLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_DATA_SOURCE_METRICS`
44+
*
45+
* @default - Enhance metrics are disabled
46+
*/
47+
readonly enhancedMetricsEnabled?: boolean;
4048
}
4149

4250
/**
@@ -377,6 +385,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
377385
api: this,
378386
name: options?.name,
379387
description: options?.description,
388+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
380389
});
381390
}
382391

@@ -393,6 +402,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
393402
table,
394403
name: options?.name,
395404
description: options?.description,
405+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
396406
});
397407
}
398408

@@ -409,6 +419,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
409419
endpoint,
410420
name: options?.name,
411421
description: options?.description,
422+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
412423
authorizationConfig: options?.authorizationConfig,
413424
});
414425
}
@@ -426,6 +437,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
426437
lambdaFunction,
427438
name: options?.name,
428439
description: options?.description,
440+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
429441
});
430442
}
431443

@@ -448,6 +460,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
448460
api: this,
449461
name: options?.name,
450462
description: options?.description,
463+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
451464
serverlessCluster,
452465
secretStore,
453466
databaseName,
@@ -473,6 +486,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
473486
api: this,
474487
name: options?.name,
475488
description: options?.description,
489+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
476490
serverlessCluster,
477491
secretStore,
478492
databaseName,
@@ -492,6 +506,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
492506
api: this,
493507
name: options?.name,
494508
description: options?.description,
509+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
495510
domain,
496511
});
497512
}
@@ -508,6 +523,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
508523
eventBus,
509524
name: options?.name,
510525
description: options?.description,
526+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
511527
});
512528
}
513529

@@ -523,6 +539,7 @@ export abstract class GraphqlApiBase extends Resource implements IGraphqlApi {
523539
api: this,
524540
name: options?.name,
525541
description: options?.description,
542+
enhancedMetricsEnabled: options?.enhancedMetricsEnabled,
526543
domain,
527544
});
528545
}

packages/aws-cdk-lib/aws-appsync/lib/resolver.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ export interface BaseResolverProps {
6666
* @default - no code is used
6767
*/
6868
readonly code?: Code;
69+
70+
/**
71+
* The whether to enable enhanced metrics
72+
* Value will be ignored, if `enhancedMetricsConfig.resolverLevelMetricsBehavior` on AppSync GraphqlApi construct is set to `FULL_REQUEST_RESOLVER_METRICS`
73+
*
74+
* @default - Enhance metrics are disabled
75+
*/
76+
readonly enhancedMetricsEnabled?: boolean;
6977
}
7078

7179
/**
@@ -133,6 +141,8 @@ export class Resolver extends Construct {
133141
}
134142

135143
const code = props.code?.bind(this);
144+
const metricsConfig = props.enhancedMetricsEnabled === undefined ? undefined
145+
: (props.enhancedMetricsEnabled ? 'ENABLED': 'DISABLED');
136146
this.resolver = new CfnResolver(this, 'Resource', {
137147
apiId: props.api.apiId,
138148
typeName: props.typeName,
@@ -147,6 +157,7 @@ export class Resolver extends Construct {
147157
responseMappingTemplate: props.responseMappingTemplate ? props.responseMappingTemplate.renderTemplate() : undefined,
148158
cachingConfig: this.createCachingConfig(props.cachingConfig),
149159
maxBatchSize: props.maxBatchSize,
160+
metricsConfig: metricsConfig,
150161
});
151162
props.api.addSchemaDependency(this.resolver);
152163
if (props.dataSource) {

packages/aws-cdk-lib/aws-appsync/test/appsync-dynamodb.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { Template } from '../../assertions';
2+
import { Match, Template } from '../../assertions';
33
import * as db from '../../aws-dynamodb';
44
import * as cdk from '../../core';
55
import * as appsync from '../lib';
@@ -71,6 +71,23 @@ describe('DynamoDb Data Source configuration', () => {
7171
});
7272
});
7373

74+
test.each([
75+
[true, 'ENABLED'],
76+
[false, 'DISABLED'],
77+
[undefined, Match.absent()],
78+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
79+
// WHEN
80+
api.addDynamoDbDataSource('ds', table, {
81+
enhancedMetricsEnabled: enhancedMetricsEnabled,
82+
});
83+
84+
// THEN
85+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
86+
Type: 'AMAZON_DYNAMODB',
87+
MetricsConfig: metricsConfig,
88+
});
89+
});
90+
7491
test('appsync errors when creating multiple dynamo db data sources with no configuration', () => {
7592
// THEN
7693
expect(() => {

packages/aws-cdk-lib/aws-appsync/test/appsync-elasticsearch.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as path from 'path';
22
import { describeDeprecated } from '@aws-cdk/cdk-build-tools';
3-
import { Template } from '../../assertions';
3+
import { Match, Template } from '../../assertions';
44
import * as es from '../../aws-elasticsearch';
55
import * as cdk from '../../core';
66
import * as appsync from '../lib';
@@ -109,6 +109,23 @@ describeDeprecated('Appsync Elasticsearch integration', () => {
109109
});
110110
});
111111

112+
test.each([
113+
[true, 'ENABLED'],
114+
[false, 'DISABLED'],
115+
[undefined, Match.absent()],
116+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
117+
// WHEN
118+
api.addElasticsearchDataSource('ds', domain, {
119+
enhancedMetricsEnabled: enhancedMetricsEnabled,
120+
});
121+
122+
// THEN
123+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
124+
Type: 'AMAZON_ELASTICSEARCH',
125+
MetricsConfig: metricsConfig,
126+
});
127+
});
128+
112129
test('appsync errors when creating multiple elasticsearch data sources with no configuration', () => {
113130
// WHEN
114131
const when = () => {

packages/aws-cdk-lib/aws-appsync/test/appsync-eventbridge.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { Template } from '../../assertions';
2+
import { Match, Template } from '../../assertions';
33
import * as eventBridge from '../../aws-events';
44
import * as cdk from '../../core';
55
import * as appsync from '../lib';
@@ -88,6 +88,23 @@ describe('EventBridge Data Source Configuration', () => {
8888
});
8989
});
9090

91+
test.each([
92+
[true, 'ENABLED'],
93+
[false, 'DISABLED'],
94+
[undefined, Match.absent()],
95+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
96+
// WHEN
97+
api.addEventBridgeDataSource('ds', eventBus, {
98+
enhancedMetricsEnabled: enhancedMetricsEnabled,
99+
});
100+
101+
// THEN
102+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
103+
Type: 'AMAZON_EVENTBRIDGE',
104+
MetricsConfig: metricsConfig,
105+
});
106+
});
107+
91108
test('An error occurs when creating multiple EventBridge data sources with the same name', () => {
92109
// WHEN
93110
const when = () => {

packages/aws-cdk-lib/aws-appsync/test/appsync-http.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { Template } from '../../assertions';
2+
import { Match, Template } from '../../assertions';
33
import * as sfn from '../../aws-stepfunctions';
44
import * as cdk from '../../core';
55
import * as appsync from '../lib';
@@ -57,6 +57,23 @@ describe('Http Data Source configuration', () => {
5757
});
5858
});
5959

60+
test.each([
61+
[true, 'ENABLED'],
62+
[false, 'DISABLED'],
63+
[undefined, Match.absent()],
64+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
65+
// WHEN
66+
api.addHttpDataSource('ds', endpoint, {
67+
enhancedMetricsEnabled: enhancedMetricsEnabled,
68+
});
69+
70+
// THEN
71+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
72+
Type: 'HTTP',
73+
MetricsConfig: metricsConfig,
74+
});
75+
});
76+
6077
test('appsync configures name, authorizationConfig correctly', () => {
6178
// WHEN
6279
api.addHttpDataSource('ds', endpoint, {

packages/aws-cdk-lib/aws-appsync/test/appsync-lambda.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { Template } from '../../assertions';
2+
import { Match, Template } from '../../assertions';
33
import * as lambda from '../../aws-lambda';
44
import * as cdk from '../../core';
55
import * as appsync from '../lib';
@@ -65,6 +65,23 @@ describe('Lambda Data Source configuration', () => {
6565
});
6666
});
6767

68+
test.each([
69+
[true, 'ENABLED'],
70+
[false, 'DISABLED'],
71+
[undefined, Match.absent()],
72+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
73+
// WHEN
74+
api.addLambdaDataSource('ds', func, {
75+
enhancedMetricsEnabled: enhancedMetricsEnabled,
76+
});
77+
78+
// THEN
79+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
80+
Type: 'AWS_LAMBDA',
81+
MetricsConfig: metricsConfig,
82+
});
83+
});
84+
6885
test('appsync sanitized datasource name from unsupported characters', () => {
6986
const badCharacters = [...'!@#$%^&*()+-=[]{}\\|;:\'",<>?/'];
7087

packages/aws-cdk-lib/aws-appsync/test/appsync-none.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from 'path';
2-
import { Template } from '../../assertions';
2+
import { Match, Template } from '../../assertions';
33
import * as cdk from '../../core';
44
import * as appsync from '../lib';
55

@@ -82,6 +82,23 @@ describe('None Data Source configuration', () => {
8282
});
8383
});
8484

85+
test.each([
86+
[true, 'ENABLED'],
87+
[false, 'DISABLED'],
88+
[undefined, Match.absent()],
89+
])('appsync configures metrics config correctly to set %s', (enhancedMetricsEnabled, metricsConfig) => {
90+
// WHEN
91+
api.addNoneDataSource('ds', {
92+
enhancedMetricsEnabled: enhancedMetricsEnabled,
93+
});
94+
95+
// THEN
96+
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::DataSource', {
97+
Type: 'NONE',
98+
MetricsConfig: metricsConfig,
99+
});
100+
});
101+
85102
test('appsync errors when creating multiple none data sources with no configuration', () => {
86103
// THEN
87104
expect(() => {

0 commit comments

Comments
 (0)