Skip to content

[apigatewayv2] Allow configuring access logging #11100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
iRoachie opened this issue Oct 25, 2020 · 21 comments · Fixed by #33977
Closed
1 task done

[apigatewayv2] Allow configuring access logging #11100

iRoachie opened this issue Oct 25, 2020 · 21 comments · Fixed by #33977
Labels
@aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1

Comments

@iRoachie
Copy link
Contributor

iRoachie commented Oct 25, 2020

Currently there's no way on the HttpApi or HttpStage construct to enable access logging as specified via https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-stage-accesslogsettings.html.

This is pretty easy to setup via sam but there's no equivalent atm for cdk.

Use Case

Enable access logs for HttpApi

Proposed Solution

  • Implement AccessLogSettings on HttpStage
  • Add logging prop to HttpApi which enables logging for all routes

I also think when the above is added to HttpApi that it should create its own log group and the permissions necessary for the HttpApi to write to it.

Other

  • 👋 I may be able to implement this feature request

This is a 🚀 Feature Request

@iRoachie iRoachie added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Oct 25, 2020
@github-actions github-actions bot added the @aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 label Oct 25, 2020
@SomayaB SomayaB added the in-progress This issue is being actively worked on. label Oct 26, 2020
@nija-at nija-at added effort/medium Medium work item – several days of effort p2 and removed needs-triage This issue or PR still needs to be triaged. labels Oct 30, 2020
@franciscoandrade82
Copy link

Hello! Do you have news on this feature? Any plans to include it in a future version?

@PeterAronZentai
Copy link

Hello would someone help formulating logging setting for HTTP API - with maybe the help of Cf* objects and the build hook I've read about?
Or is there a way to run some aws sdk commands as part of CDK provisioning code?

@iRoachie
Copy link
Contributor Author

@franciscoandrade-unit I started work on it in #11126 but I haven't finished it as yet

@ltearno
Copy link

ltearno commented Feb 19, 2021

@PeterAronZentai this page should help to formulate the cdk code to add the accesslog parameter on the underlying CfnStage resource of a Stage construct : https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_resource

Then the CfnStage has its options available (cdk: https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigatewayv2.CfnStage.html, cloudformation : https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-stage.html).

Something like this should work :

// "apigateway.defaultStage.node.defaultChild" accesses the L1 Resource in the L2 Stage
const defaultStage = apiGateway.defaultStage.node.defaultChild as apigw.CfnStage

// the L1 settings are always available because they are CloudFormation constructs and
// AWS seems to always guarantee the 1 to 1 mapping
defaultStage.accessLogSettings = {
    destinationArn: `...`,
    format: JSON.stringify({
        "requestId": "$context.requestId",
        "ip": "$context.identity.sourceIp",
        "caller": "$context.identity.caller",
        "user": "$context.identity.user",
        "requestTime": "$context.requestTime",
        "httpMethod": "$context.httpMethod",
        "resourcePath": "$context.resourcePath",
        "status": "$context.status",
        "protocol": "$context.protocol",
        "responseLength": "$context.responseLength"
    })
}

If you try it, let me know because I will need it soon ! :)

@PeterAronZentai
Copy link

PeterAronZentai commented Feb 19, 2021

@ltearno it does indeed work!

    const log = new awslog.LogGroup(this, 'log')
    const stage = backendB.defaultStage?.node.defaultChild as  apigwv2.CfnStage;
    stage.accessLogSettings = {
        destinationArn: log.logGroupArn,
        format: `$context.identity.sourceIp - - [$context.requestTime] "$context.httpMethod $context.routeKey $context.protocol" $context.status $context.responseLength $context.requestId`,
    }

Much thanks!

Also you unlocked L1 hacking for me - megathanks for that.

@ltearno
Copy link

ltearno commented Feb 25, 2021

You're welcome, thank you !

@bonoethanPFG
Copy link

Hi! Just curious if there's been any more progress made on this feature. Would love to have this available some time in the future!

@lifeofzero
Copy link

@ltearno it does indeed work!

    const log = new awslog.LogGroup(this, 'log')
    const stage = backendB.defaultStage?.node.defaultChild as  apigwv2.CfnStage;
    stage.accessLogSettings = {
        destinationArn: log.logGroupArn,
        format: `$context.identity.sourceIp - - [$context.requestTime] "$context.httpMethod $context.routeKey $context.protocol" $context.status $context.responseLength $context.requestId`,
    }

Much thanks!

Also you unlocked L1 hacking for me - megathanks for that.

@PeterAronZentai or @ltearno How were you able to apply the needed permissions for the apigwv2 to have permissions to write to the log group? I keep getting the following:

Insufficient permissions to enable logging (Service: AmazonApiGatewayV2; Status Code: 400

@jumpinjan
Copy link

I could really use this feature too. Thanks!

@lifeofzero
Copy link

@jumpinjan this is how I got it to work, if that's helpful.

    // Setup the access log for APIGWv2
    const accessLogs = new logs.LogGroup(this, 'APIGW-AccessLogs')
    const stage = httpApi.defaultStage?.node.defaultChild as apigateway.CfnStage
    stage.accessLogSettings = {
      destinationArn: accessLogs.logGroupArn,
      format: JSON.stringify({
        requestId: '$context.requestId',
        userAgent: '$context.identity.userAgent',
        sourceIp: '$context.identity.sourceIp',
        requestTime: '$context.requestTime',
        requestTimeEpoch: '$context.requestTimeEpoch',
        httpMethod: '$context.httpMethod',
        path: '$context.path',
        status: '$context.status',
        protocol: '$context.protocol',
        responseLength: '$context.responseLength',
        domainName: '$context.domainName'
      })
    }

    const role = new iam.Role(this, 'ApiGWLogWriterRole', {
      assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com')
    })

    const policy = new iam.PolicyStatement({
      actions: [
        'logs:CreateLogGroup',
        'logs:CreateLogStream',
        'logs:DescribeLogGroups',
        'logs:DescribeLogStreams',
        'logs:PutLogEvents',
        'logs:GetLogEvents',
        'logs:FilterLogEvents'
      ],
      resources: ['*']
    })

    role.addToPolicy(policy)
    accessLogs.grantWrite(role) 

@rpivo
Copy link

rpivo commented Dec 27, 2021

Going to try some solutions from this thread, but would love if this feature were built-in!

@rpivo
Copy link

rpivo commented Dec 28, 2021

@lifeofzero 's example works well -- thanks!

@atkinsonm
Copy link

atkinsonm commented Jan 14, 2022

@lifeofzero's example worked for me without the policy; the grantWrite provided logs:CreateLogStream and logs:PutLogEvents which was sufficient in my case for writing logs

(edit) it actually worked without any IAM resources at all, just the log group and the accessLogSettings. That's consistent with the documentation

@tjgurwara99
Copy link

In case anyone from Python-CDK stumbles upon this thread and is unaware of how to use the answer by @ltearno in Python, all you need to do is this

from aws_cdk import aws_logs as _logs
from aws_cdk import aws_apigatewayv2 as _apigw

class YourStack(cdk.Stack):
    def __init__(self, scope, construct_id):
        super().__init__(scope, construct_id)
        log_group = _logs.LogGroup(self, "YourAccessLogGroup", retention=_logs.RetentionDays.ONE_MONTH)
        http_api = _apigw.HttpApi(self, "SomeIdentForApi", cors_preflight=...)
        # this is where the magic happens by references
        _stage: _apigw.CfnStage = http_api.default_stage.node.default_child
        _stage.access_log_settings = _apigw.CfnStage.AccessLogSettingsProperty(
            destination_arn=log_group.log_group_arn,
            format="$context.requestId", # choose whatever format you want $context.requestId is the necessary one.
        )
        # after this just add your routes and you're good to go

@rix0rrr rix0rrr added p1 and removed p2 labels Mar 16, 2022
@PatrykMilewski
Copy link

It would be nice to include this as a core feature!

@christophercarney
Copy link

To anyone having trouble getting this to work like I did when upgrading resources -- make sure you are importing the correct CfnStage

import { CfnStage } from "aws-cdk-lib/aws-apigatewayv2";
import { CfnStage } from "aws-cdk-lib/aws-apigateway";

Are different and the latter will turn not work for access logs on your API GW v2

@tvb
Copy link

tvb commented Sep 7, 2022

        _stage: _apigw.CfnStage = http_api.default_stage.node.default_child
        _stage.access_log_settings = _apigw.CfnStage.AccessLogSettingsProperty(
            destination_arn=log_group.log_group_arn,
            format="$context.requestId", # choose whatever format you want $context.requestId is the necessary one.
        )

Hi @tjgurwara99 how to implement this when the default stage is disabled?

apigwv2.HttpApi(
            self,
...
            create_default_stage=False,
)

@tjgurwara99
Copy link

tjgurwara99 commented Sep 7, 2022

@tvb If I remember correctly, it all depends on how you handle creating a stage or whether you even create a stage. For example, you might be using add_stage method to create a custom stage or whether you have no stage at all (in which case I don't know how that works - I'm not using CDK anymore) but if you use add_stage you should be able to create the stage with CfnStage and set the AccessLogSettingsProperty.

Copy link

This issue has received a significant amount of attention so we are automatically upgrading its priority. A member of the community will see the re-prioritization and provide an update on the issue.

@azaylamba
Copy link

It is an important feature missing for WebSocket APIs.

@mergify mergify bot closed this as completed in #33977 Apr 10, 2025
mergify bot pushed a commit that referenced this issue Apr 10, 2025
### Issue # (if applicable)

Closes #11100

### Description of changes
- apigwv2 HttpStage support access logging to CloudWatch Logs https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-logging.html
- Same logic as V1 without Firehose as not supported.

### Description of how you validated changes
Unit + Integ

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 10, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
@aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1
Projects
None yet