Skip to content

Commit

Permalink
#115 - Turn on API Gateway Access Logs
Browse files Browse the repository at this point in the history
  • Loading branch information
formkiqMike committed Feb 17, 2023
1 parent e51b2ba commit e66cb72
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,21 @@ Conditions:
- Condition: HasTypesenseApiKey

Resources:


DocumentsApiRequestsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${DocumentsApiRequests}"
RetentionInDays: 90
Tags:
- Key: "Application"
Value:
Fn::Sub: "FormKiQ ${FormKiQType}"
- Key: "AppEnvironment"
Value:
Fn::Sub: "${AppEnvironment}"

DocumentsApiRequests:
Type: AWS::Serverless::Function
DependsOn:
Expand Down Expand Up @@ -197,6 +211,20 @@ Resources:
Ref: DocumentsApiRequests
Principal: apigateway.amazonaws.com

DocumentsStageAccessLogs:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 90
LogGroupName:
Fn::Sub: "/${AWS::StackName}/APIDocumentsHttpAccessLogs"

IamDocumentsStageAccessLogs:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 90
LogGroupName:
Fn::Sub: "/${AWS::StackName}/APIDocumentsIamAccessLogs"

DocumentsStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
Expand All @@ -206,6 +234,12 @@ Resources:
Description:
Fn::Sub: "Documents API ${AppEnvironment}"
StageName: "$default"
AccessLogSettings:
DestinationArn:
Fn::GetAtt:
- DocumentsStageAccessLogs
- Arn
Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "integrationStatus": $context.integrationStatus, "integrationLatency": $context.integrationLatency, "responseLength":"$context.responseLength" }'

IamDocumentsStage:
Type: AWS::ApiGatewayV2::Stage
Expand All @@ -216,7 +250,31 @@ Resources:
Description:
Fn::Sub: "Documents IAM API ${AppEnvironment}"
StageName: "$default"
AccessLogSettings:
DestinationArn:
Fn::GetAtt:
- IamDocumentsStageAccessLogs
- Arn
Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "integrationStatus": $context.integrationStatus, "integrationLatency": $context.integrationLatency, "responseLength":"$context.responseLength" }'


DocumentsHttpApiIdParameter:
Type: AWS::SSM::Parameter
Properties:
Description: "The ID for the API endpoint that uses Cognito authorization"
Name:
Fn::Sub: "/formkiq/${AppEnvironment}/api/DocumentsHttpId"
Type: String
Value:
Ref: DocumentsHttpApi
Tags:
Application:
Fn::Sub: "FormKiQ ${FormKiQType}"
AppEnvironment:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

DocumentsHttpApiUrlParameter:
Type: AWS::SSM::Parameter
Properties:
Expand Down Expand Up @@ -363,6 +421,7 @@ Resources:
- sns:Publish
Resource:
- Fn::Sub: "{{resolve:ssm:/formkiq/${AppEnvironment}/sns/DocumentEventArn}}"

DocumentsIamApiUrlParameter:
Type: AWS::SSM::Parameter
Properties:
Expand All @@ -379,6 +438,23 @@ Resources:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

DocumentsIamApiIdParameter:
Type: AWS::SSM::Parameter
Properties:
Description: "The ID for the API endpoint that uses IAM authorization"
Name:
Fn::Sub: "/formkiq/${AppEnvironment}/api/DocumentsIamId"
Type: String
Value:
Ref: DocumentsIamApi
Tags:
Application:
Fn::Sub: "FormKiQ ${FormKiQType}"
AppEnvironment:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

DocumentsApiRequestsParameter:
Type: AWS::SSM::Parameter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ protected DocumentActionsProcessor(final Map<String, String> map, final Region a
SsmService ssmService = new SsmServiceCache(ssm, cacheTime, TimeUnit.MINUTES);

String typeSenseHost =
ssmService.getParameterValue("/formkiq/" + appEnvironment + "/typesense/ApiEndpoint");
ssmService.getParameterValue("/formkiq/" + appEnvironment + "/api/TypesenseEndpoint");
String typeSenseApiKey =
ssmService.getParameterValue("/formkiq/" + appEnvironment + "/typesense/ApiKey");

Expand Down
42 changes: 40 additions & 2 deletions lambda-s3/src/main/resources/cloudformation/template-sar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,30 @@ Resources:
Value:
Fn::Sub: "${AWS::StackName}"

DocumentActionsProcessorParameter:
Type: AWS::SSM::Parameter
Properties:
Description: "Lambda function to process Document Actions requests"
Name:
Fn::Sub: "/formkiq/${AppEnvironment}/lambda/DocumentActionsProcessor"
Type: String
Value:
Ref: DocumentActionsProcessor
Tags:
Application:
Fn::Sub: "FormKiQ ${FormKiQType}"
AppEnvironment:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

DocumentActionsProcessorLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${DocumentActionsProcessor}"
RetentionInDays: 90

DocumentActionsProcessor:
Type: AWS::Serverless::Function
DependsOn:
Expand Down Expand Up @@ -247,7 +271,14 @@ Resources:
- DocumentActionsQueue
- Arn
BatchSize: 10


StagingS3CreateLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${StagingS3Create}"
RetentionInDays: 90

StagingS3Create:
Type: AWS::Serverless::Function
DependsOn:
Expand Down Expand Up @@ -325,7 +356,14 @@ Resources:
- ''
- - 'arn:aws:s3:::'
- Fn::Sub: "formkiq-${FormKiQType}-${AppEnvironment}-staging-${AWS::AccountId}"


DocumentsS3UpdateLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${DocumentsS3Update}"
RetentionInDays: 90

DocumentsS3Update:
Type: AWS::Serverless::Function
DependsOn:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public static void beforeClass() throws Exception {
ssmService.putParameter("/formkiq/" + APP_ENVIRONMENT + "/s3/OcrBucket", BUCKET_NAME);

String typeSenseHost = "http://localhost:" + TypeSenseExtension.getMappedPort();
ssmService.putParameter("/formkiq/" + APP_ENVIRONMENT + "/typesense/ApiEndpoint",
ssmService.putParameter("/formkiq/" + APP_ENVIRONMENT + "/api/TypesenseEndpoint",
typeSenseHost);
ssmService.putParameter("/formkiq/" + APP_ENVIRONMENT + "/typesense/ApiKey", API_KEY);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ Conditions:
- Condition: CreateResources

Resources:

TypesenseProcessorLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${TypesenseProcessor}"
RetentionInDays: 90

TypesenseProcessor:
Type: AWS::Serverless::Function
Expand Down Expand Up @@ -170,7 +177,7 @@ Resources:
Properties:
Description: "Typesense API Endpoint"
Name:
Fn::Sub: "/formkiq/${AppEnvironment}/typesense/ApiEndpoint"
Fn::Sub: "/formkiq/${AppEnvironment}/api/TypesenseEndpoint"
Type: String
Value:
Fn::If:
Expand All @@ -187,6 +194,29 @@ Resources:
StackName:
Fn::Sub: "${AWS::StackName}"

TypesenseApiIdParameter:
Type: AWS::SSM::Parameter
Condition: CreateResources
Properties:
Description: "Typesense API ID"
Name:
Fn::Sub: "/formkiq/${AppEnvironment}/api/TypesenseApiId"
Type: String
Value:
Fn::If:
- CreateResources
- Fn::GetAtt:
- ApiGateway
- ApiId
- ""
Tags:
Application:
Fn::Sub: "FormKiQ ${FormKiQType}"
AppEnvironment:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

TypesenseLambdaRole:
Type: AWS::IAM::Role
Condition: CreateResources
Expand Down Expand Up @@ -466,6 +496,7 @@ Resources:
ProtocolType: HTTP
Name:
Fn::Sub: "${AWS::StackName} Typesense - ${AppEnvironment}"
Description: "FormKiQ Typesense API"

Integration:
Type: AWS::ApiGatewayV2::Integration
Expand All @@ -485,6 +516,13 @@ Resources:
- Arn
PayloadFormatVersion: "1.0"

StageAccessLogs:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 90
LogGroupName:
Fn::Sub: "/${AWS::StackName}/APITypeSenseAccessLogs"

Stage:
Type: AWS::ApiGatewayV2::Stage
Condition: CreateResources
Expand All @@ -493,6 +531,12 @@ Resources:
Ref: ApiGateway
StageName: $default
AutoDeploy: true
AccessLogSettings:
DestinationArn:
Fn::GetAtt:
- StageAccessLogs
- Arn
Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "integrationStatus": $context.integrationStatus, "integrationLatency": $context.integrationLatency, "responseLength":"$context.responseLength" }'

Route:
Type: AWS::ApiGatewayV2::Route
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ Resources:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"


EmailNotifyLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${EmailNotify}"
RetentionInDays: 90

EmailNotify:
Type: AWS::Serverless::Function
DependsOn:
Expand Down
20 changes: 20 additions & 0 deletions src/main/resources/cloudformation/monitoring.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: FormKiQ Monitoring

Resources:

ApplicationDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName:
Fn::Sub: "${AWS::StackName}-dashboard"
DashboardBody:
Fn::Sub: '{"widgets":[{"height":6,"width":6,"y":6,"x":0,"type":"metric","properties":{"metrics":[["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/TypesenseProcessor}}"],[".","Errors",".","."],[".","Throttles",".","."],[".","Duration",".",".",{"stat":"Average"}],[".","ConcurrentExecutions",".",".",{"stat":"Maximum"}]],"view":"timeSeries","region":"${AWS::Region}","stacked":false,"title":"TypesenseProcessorLambda","period":60,"stat":"Sum"}},{"height":6,"width":6,"y":6,"x":12,"type":"metric","properties":{"metrics":[["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/DocumentsUpdateObject}}"],[".","Errors",".","."],[".","Throttles",".","."],[".","Duration",".",".",{"stat":"Average"}],[".","ConcurrentExecutions",".",".",{"stat":"Maximum"}]],"view":"timeSeries","region":"${AWS::Region}","stacked":false,"title":"DocumentsS3UpdateLambda","period":60,"stat":"Sum"}},{"height":6,"width":6,"y":6,"x":18,"type":"metric","properties":{"metrics":[["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/StagingCreateObject}}"],[".","Errors",".","."],[".","Throttles",".","."],[".","Duration",".",".",{"stat":"Average"}],[".","ConcurrentExecutions",".",".",{"stat":"Maximum"}]],"view":"timeSeries","region":"${AWS::Region}","stacked":false,"title":"DocumentS3CreateLambda","period":60,"stat":"Sum"}},{"height":6,"width":6,"y":6,"x":6,"type":"metric","properties":{"metrics":[["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/DocumentActionsProcessor}}"],[".","Errors",".","."],[".","Throttles",".","."],[".","Duration",".",".",{"stat":"Average"}],[".","ConcurrentExecutions",".",".",{"stat":"Maximum"}]],"view":"timeSeries","region":"${AWS::Region}","stacked":false,"title":"DocumentActionsProcessorLambda","period":60,"stat":"Sum"}},{"height":6,"width":6,"y":12,"x":0,"type":"metric","properties":{"metrics":[["AWS/ApiGateway","4xx","ApiId","{{resolve:ssm:/formkiq/${AppEnvironment}/api/DocumentsHttpId}}",{"yAxis":"right"}],[".","5xx",".",".",{"yAxis":"right"}],[".","DataProcessed",".",".",{"yAxis":"left"}],[".","Count",".",".",{"label":"Count","yAxis":"right"}],[".","IntegrationLatency",".",".",{"stat":"Average"}],[".","Latency",".",".",{"stat":"Average"}]],"view":"timeSeries","stacked":false,"region":"${AWS::Region}","period":60,"stat":"Sum","title":"DocumentHttp"}},{"height":6,"width":24,"y":0,"x":0,"type":"metric","properties":{"metrics":[["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/StagingCreateObject}}",{"label":"ProcessedDocuments"}],["AWS/Lambda","Invocations","FunctionName","{{resolve:ssm:/formkiq/${AppEnvironment}/lambda/TypesenseProcessor}}",{"label":"ProcessedTypesenseDocuments"}]],"view":"timeSeries","stacked":false,"title":"DocumentMetrics","region":"${AWS::Region}","period":60,"stat":"Sum"}},{"height":6,"width":6,"y":12,"x":6,"type":"metric","properties":{"metrics":[["AWS/ApiGateway","4xx","ApiId","{{resolve:ssm:/formkiq/${AppEnvironment}/api/DocumentsIamId}}",{"yAxis":"right"}],[".","5xx",".",".",{"yAxis":"right"}],[".","DataProcessed",".",".",{"yAxis":"left"}],[".","Count",".",".",{"label":"Count","yAxis":"right"}],[".","IntegrationLatency",".",".",{"stat":"Average"}],[".","Latency",".",".",{"stat":"Average"}]],"view":"timeSeries","stacked":false,"region":"${AWS::Region}","period":60,"stat":"Sum","title":"DocumentIAM"}},{"height":6,"width":6,"y":12,"x":12,"type":"metric","properties":{"metrics":[["AWS/ApiGateway","4xx","ApiId","nt5e3thcgl",{"yAxis":"right"}],[".","5xx",".",".",{"yAxis":"right"}],[".","DataProcessed",".",".",{"yAxis":"left"}],[".","Count",".",".",{"label":"Count","yAxis":"right"}],[".","IntegrationLatency",".",".",{"stat":"Average"}],[".","Latency",".",".",{"stat":"Average"}]],"view":"timeSeries","stacked":false,"region":"${AWS::Region}","period":60,"stat":"Sum","title":"CognitoAPI"}},{"height":6,"width":6,"y":12,"x":18,"type":"metric","properties":{"metrics":[["AWS/ApiGateway","4xx","ApiId","{{resolve:ssm:/formkiq/${AppEnvironment}/api/TypesenseEndpoint}}",{"yAxis":"right"}],[".","5xx",".",".",{"yAxis":"right"}],[".","DataProcessed",".",".",{"yAxis":"left"}],[".","Count",".",".",{"label":"Count","yAxis":"right"}],[".","IntegrationLatency",".",".",{"stat":"Average"}],[".","Latency",".",".",{"stat":"Average"}]],"view":"timeSeries","stacked":false,"region":"${AWS::Region}","period":60,"stat":"Sum","title":"TypesenseAPI"}}]}'

Outputs:

DashboardURL:
Description: "Dashboard URL"
Value:
Fn::Sub: "https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${ApplicationDashboard}"
13 changes: 13 additions & 0 deletions src/main/resources/cloudformation/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,19 @@ Resources:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"

Monitoring:
Type: AWS::Serverless::Application
DependsOn:
- TypeSenseService
- CoreStorage
- CoreApi
- Cognito
Properties:
Location: ./monitoring.yaml
Parameters:
AppEnvironment:
Ref: AppEnvironment

Outputs:
AppEnvironment:
Expand Down
24 changes: 22 additions & 2 deletions websocket-api/src/main/resources/cloudformation/template-sar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,14 @@ Resources:
Properties:
ApiId:
Ref: WebSocketApi


StageAccessLogs:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 90
LogGroupName:
Fn::Sub: "/${AWS::StackName}/APIWebsocketAccessLogs"

Stage:
Type: AWS::ApiGatewayV2::Stage
Properties:
Expand All @@ -109,6 +116,12 @@ Resources:
Ref: Deployment
ApiId:
Ref: WebSocketApi
AccessLogSettings:
DestinationArn:
Fn::GetAtt:
- StageAccessLogs
- Arn
Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "integrationStatus": $context.integrationStatus, "integrationLatency": $context.integrationLatency, "responseLength":"$context.responseLength" }'
Tags:
Application:
Fn::Sub: "FormKiQ ${FormKiQType}"
Expand Down Expand Up @@ -193,7 +206,14 @@ Resources:
Fn::Sub: "${AppEnvironment}"
StackName:
Fn::Sub: "${AWS::StackName}"


ApiFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName:
Fn::Sub: "/${AWS::StackName}/${ApiFunction}"
RetentionInDays: 90

ApiFunction:
Type: AWS::Serverless::Function
Properties:
Expand Down

0 comments on commit e66cb72

Please sign in to comment.