import { Construct } from 'constructs' ; import * as logs from "aws-cdk-lib/aws-logs" ; import * as cfnApig from "aws-cdk-lib/aws-apigatewayv2" ; import * as apig from "@aws-cdk/aws-apigatewayv2-alpha" ; import { App } from "../App" ; export interface AccessLogProps extends cfnApig . CfnStage . AccessLogSettingsProperty { retention ? : keyof typeof logs . RetentionDays ; } const defaultHttpFields = [ `"requestTime":"$context.requestTime"` , `"requestId":"$context.requestId"` , `"httpMethod":"$context.httpMethod"` , `"path":"$context.path"` , `"routeKey":"$context.routeKey"` , `"status":$context.status` , `"responseLatency":$context.responseLatency` , `"integrationRequestId":"$context.integration.requestId"` , `"integrationStatus":"$context.integration.status"` , `"integrationLatency":"$context.integration.latency"` , `"integrationServiceStatus":"$context.integration.integrationStatus"` , `"ip":"$context.identity.sourceIp"` , `"userAgent":"$context.identity.userAgent"` , `"cognitoIdentityId":"$context.identity.cognitoIdentityId"` , ] ; const defaultWebSocketFields = [ `"requestTime":"$context.requestTime"` , `"requestId":"$context.requestId"` , `"eventType":"$context.eventType"` , `"routeKey":"$context.routeKey"` , `"status":$context.status` , `"integrationRequestId":"$context.awsEndpointRequestId"` , `"integrationStatus":"$context.integrationStatus"` , `"integrationLatency":"$context.integrationLatency"` , `"integrationServiceStatus":"$context.integration.integrationStatus"` , `"ip":"$context.identity.sourceIp"` , `"userAgent":"$context.identity.userAgent"` , `"cognitoIdentityId":"$context.identity.cognitoIdentityId"` , `"connectedAt":"$context.connectedAt"` , `"connectionId":"$context.connectionId"` , ] ; export function buildAccessLogData ( scope , accessLog , apiStage , isDefaultStage ) { if ( accessLog === false ) { return ; } const isWebSocketApi = apiStage instanceof apig . WebSocketStage ; let logGroup ; let destinationArn ; if ( accessLog && ( accessLog as AccessLogProps ) . destinationArn ) { destinationArn = ( accessLog as AccessLogProps ) . destinationArn ; } else { const root = scope . node . root as App ; const apiName = root . logicalPrefixedName ( scope . node . id ) ; const logGroupName = "LogGroup" + ( isDefaultStage ? "" : apiStage . stageName ) ; const retention = ( accessLog && ( accessLog as AccessLogProps ) . retention ) || "INFINITE" ; const retentionValue = logs . RetentionDays [ retention ] ; if ( ! retentionValue ) { throw new Error ( `Invalid access log retention value "${ retention }".` ) ; } logGroup = new logs . LogGroup ( scope , logGroupName , { logGroupName : [ `/aws/vendedlogs/apis` , `/${ cleanupLogGroupName ( apiName ) }-${ apiStage . api . apiId }` , `/${ cleanupLogGroupName ( apiStage . stageName ) }` , ] . join ( "" ) , retention : retentionValue , } ) ; destinationArn = logGroup . logGroupArn ; } let format ; if ( accessLog && ( accessLog as AccessLogProps ) . format ) { format = ( accessLog as AccessLogProps ) . format ; } else if ( typeof accessLog === "string" ) { format = accessLog ; } else { format = isWebSocketApi ? "{" + defaultWebSocketFields . join ( "," ) + "}" : "{" + defaultHttpFields . join ( "," ) + "}" ; } if ( ! apiStage ?. node . defaultChild ) { throw new Error ( `Failed to define the default stage for Http API` ) ; } const cfnStage = apiStage . node . defaultChild as cfnApig . CfnStage ; cfnStage . accessLogSettings = { format , destinationArn } ; return logGroup ; } export function cleanupLogGroupName ( str ) { return str . replace ( /[^.\-_/#A-Za-z0-9]/g , "" ) ; }