Skip to content

Lambda : Unreadable HTTP body sent when using pg.Pool() and the AWS SAM CLI #2575

@jlvoiseux

Description

@jlvoiseux

Bug description

When running an APM-instrumented Lambda function and querying a Postgres instance using pg.Pool (example), the agent sends an HTTP request to the Lambda extension whose body is unreadable by the extension.

Afterwards, no data is sent to the APM server, and subsequent invocations of the Lambda function are interrupted.

Sample execution logs

First invocation (unreadable body)

opbeans-lambda_1  | 2022/02/15 17:06:47 Received event: {
opbeans-lambda_1  |     "eventType": "INVOKE",
opbeans-lambda_1  |     "deadlineMs": 1644944817828,
opbeans-lambda_1  |     "requestId": "0ca8d962-201b-4e94-a4b5-0585b955004e",
opbeans-lambda_1  |     "invokedFunctionArn": "arn:aws:lambda:us-east-1:012345678912:function:OpbeansLambdaItemsPool",
opbeans-lambda_1  |     "tracing": {
opbeans-lambda_1  |             "type": "",
opbeans-lambda_1  |             "value": ""
opbeans-lambda_1  |     }
opbeans-lambda_1  | }
opbeans-lambda_1  | 2022/02/15 17:06:47 Checking for agent data
opbeans-lambda_1  | 2022/02/15 17:06:47 No agent data on buffer
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:47.894Z","log":{"logger":"elastic-apm-node"},"awsRequestId":"0ca8d962-201b-4e94-a4b5-0585b955004e","ecs":{"version":"1.6.0"},"message":"lambda: fn start"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:47.895Z","log":{"logger":"elastic-apm-node"},"awsRequestId":"0ca8d962-201b-4e94-a4b5-0585b955004e","ecs":{"version":"1.6.0"},"message":"lambda: setExtraMetadata"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:47.907Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","_encodedMetadata":"{\"metadata\":{\"service\":{\"name\":\"OpbeansLambdaItemsPool\",\"environment\":\"development\",\"runtime\":{\"name\":\"AWS_Lambda_nodejs14.x\",\"version\":\"14.18.3\"},\"language\":{\"name\":\"javascript\"},\"agent\":{\"name\":\"nodejs\",\"version\":\"3.29.0\"},\"version\":\"$LATEST\",\"id\":\"arn:aws:lambda:us-east-1:012345678912:function:OpbeansLambdaItemsPool\",\"framework\":{\"name\":\"AWS Lambda\"},\"node\":{\"configured_name\":\"$LATEST\"}},\"process\":{\"pid\":29,\"ppid\":1,\"title\":\"/var/lang/bin/node\",\"argv\":[\"/var/lang/bin/node\",\"/var/runtime/index.js\"]},\"system\":{\"hostname\":\"0d992400a1e7\",\"architecture\":\"x64\",\"platform\":\"linux\",\"container\":{\"id\":\"0d992400a1e7b07ad4b9f4989dbb8ab8e562e1cedf6a542f54563b42a8a5ac55\"}},\"cloud\":{\"provider\":\"aws\",\"region\":\"us-east-1\",\"service\":{\"name\":\"lambda\"},\"account\":{\"id\":\"012345678912\"}}}}\n","ecs":{"version":"1.6.0"},"message":"_resetEncodedMetadata"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:47.908Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","ecs":{"version":"1.6.0"},"message":"uncorked (expectExtraMetadata)"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.924Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"start trace {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"unnamed\",\"type\":\"lambda\",\"subtype\":null,\"action\":null}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.926Z","log":{"logger":"elastic-apm-node"},"ctxmgr":"AsyncHooksRunContextManager( RC(Trans(0b0492, OpbeansLambdaItemsPool)) )","ecs":{"version":"1.6.0"},"message":"supersedeWithTransRunContext()"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.928Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"setting transaction name {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"OpbeansLambdaItemsPool\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.928Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"setting transaction result {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"result\":\"success\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.930Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"setting transaction name {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"GET OpbeansLambdaItemsPool\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:47.978Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","apmServerVersion":"7.16.3","ecs":{"version":"1.6.0"},"message":"fetched APM Server version"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.481Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"intercepted call to pg.Client.prototype.query"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.488Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"start span {\"span\":\"1336391f1f7fb3bc\",\"parent\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"SQL\",\"type\":\"db\",\"subtype\":\"postgresql\",\"action\":\"query\"}"}
postgres_1        | 2022-02-15 17:06:48.499 UTC [481] LOG:  statement: CREATE TABLE IF NOT EXISTS products (Id SERIAL PRIMARY KEY, Name varchar(255) NOT NULL, Description varchar(255) NOT NULL)
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.509Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"intercepted end of pg.Client.prototype.query"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.511Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"ended span {\"span\":\"1336391f1f7fb3bc\",\"parent\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"CREATE TABLE IF\",\"type\":\"db\",\"subtype\":\"postgresql\",\"action\":\"query\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.530Z","log":{"logger":"elastic-apm-node"},"ctxmgr":"AsyncHooksRunContextManager( RC(Trans(0b0492, GET OpbeansLambdaItemsPool)), RC(Trans(0b0492, GET OpbeansLambdaItemsPool)), RC(Trans(0b0492, GET OpbeansLambdaItemsPool)) )","ecs":{"version":"1.6.0"},"message":"addEndedSpan(CREATE TABLE IF)"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.532Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"encoding span {\"span\":\"1336391f1f7fb3bc\",\"parent\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"name\":\"CREATE TABLE IF\",\"type\":\"db\"}"}
opbeans-lambda_1  | 2022-02-15T17:06:48.542Z    0ca8d962-201b-4e94-a4b5-0585b955004e    INFO    Table created
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:48.555Z","log":{"logger":"elastic-apm-node"},"awsRequestId":"0ca8d962-201b-4e94-a4b5-0585b955004e","ecs":{"version":"1.6.0"},"message":"lambda: fn end"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.556Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"setting transaction result {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"result\":\"HTTP 2xx\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.558Z","log":{"logger":"elastic-apm-node"},"ctxmgr":"AsyncHooksRunContextManager( RC() )","ecs":{"version":"1.6.0"},"message":"addEndedTransaction(GET OpbeansLambdaItemsPool)"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.562Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"sending transaction {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\"}"}
opbeans-lambda_1  | {"log.level":"debug","@timestamp":"2022-02-15T17:06:48.566Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"ended transaction {\"trans\":\"0b0492f19ef7c917\",\"trace\":\"8f687dc4c7633f5d6db2afceb4fa67db\",\"type\":\"request\",\"result\":\"HTTP 2xx\",\"name\":\"GET OpbeansLambdaItemsPool\"}"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:48.605Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","reqId":"b0e4485922badf64df394dd84273ad8c","ecs":{"version":"1.6.0"},"message":"intake request start"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:48.615Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","fullTimeMs":22.875,"numEvents":1,"numBytes":683,"ecs":{"version":"1.6.0"},"message":"_write: encode object"}
opbeans-lambda_1  | {"log.level":"trace","@timestamp":"2022-02-15T17:06:48.619Z","log":{"logger":"elastic-apm-node"},"event.module":"apmclient","reqId":"b0e4485922badf64df394dd84273ad8c","ecs":{"version":"1.6.0"},"message":"intakeReq \"socket\": unref it"}
opbeans-lambda_1  | 2022/02/15 17:06:49 Could not read bytes from agent request body 
opbeans-lambda_1  | 2022-02-15 17:06:49,172 | Unable to find Click Context for getting session_id.
opbeans-lambda_1  | 2022-02-15 17:06:49,172 | Invalid lambda response received: Lambda response must be valid json
opbeans-lambda_1  | 2022-02-15 17:06:49 172.21.0.1 - - [15/Feb/2022 17:06:49] "GET /itemsPool HTTP/1.1" 502 -
opbeans-lambda_1  | 2022-02-15 17:06:49 172.21.0.1 - - [15/Feb/2022 17:06:49] "GET /favicon.ico HTTP/1.1" 403 -
opbeans-lambda_1  | 2022/02/15 17:06:57 Time expired waiting for agent signal or runtimeDone event
opbeans-lambda_1  | 2022/02/15 17:06:57 Checking for agent data
opbeans-lambda_1  | 2022/02/15 17:06:57 No agent data on buffer
opbeans-lambda_1  | 2022/02/15 17:06:57 funcDone signal received, not processing any more log events
opbeans-lambda_1  | 2022/02/15 17:06:57 funcDone signal received, not processing any more agent data
opbeans-lambda_1  | 2022/02/15 17:06:57 Waiting for next event...

Second invocation (the Lambda function seems to be interrupted)

opbeans-lambda_1  | 2022-02-15 17:19:59,705 | Constructed String representation of Event to invoke Lambda. Event: {"body": null, "headers": {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8", "Cache-Control": "max-age=0", "Connection": "keep-alive", "Host": "0.0.0.0:3000", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", "X-Forwarded-Port": "3000", "X-Forwarded-Proto": "http"}, "httpMethod": "GET", "isBase64Encoded": false, "multiValueHeaders": {"Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Accept-Encoding": ["gzip, deflate"], "Accept-Language": ["en-GB,en-US;q=0.9,en;q=0.8"], "Cache-Control": ["max-age=0"], "Connection": ["keep-alive"], "Host": ["0.0.0.0:3000"], "Upgrade-Insecure-Requests": ["1"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36"], "X-Forwarded-Port": ["3000"], "X-Forwarded-Proto": ["http"]}, "multiValueQueryStringParameters": null, "path": "/itemsPool", "pathParameters": null, "queryStringParameters": null, "requestContext": {"accountId": "123456789012", "apiId": "1234567890", "domainName": "0.0.0.0:3000", "extendedRequestId": null, "httpMethod": "GET", "identity": {"accountId": null, "apiKey": null, "caller": null, "cognitoAuthenticationProvider": null, "cognitoAuthenticationType": null, "cognitoIdentityPoolId": null, "sourceIp": "172.21.0.1", "user": null, "userAgent": "Custom User Agent String", "userArn": null}, "path": "/itemsPool", "protocol": "HTTP/1.1", "requestId": "3ef1043b-987e-4579-b61c-10956dd16b37", "requestTime": "15/Feb/2022:17:05:16 +0000", "requestTimeEpoch": 1644944716, "resourceId": "123456", "resourcePath": "/itemsPool", "stage": "Prod"}, "resource": "/itemsPool", "stageVariables": null, "version": "1.0"}
opbeans-lambda_1  | 2022-02-15 17:19:59,706 | Found one Lambda function with name 'OpbeansLambdaItemsPool'
opbeans-lambda_1  | 2022-02-15 17:19:59,706 | Invoking src/itemsPool.itemsPool (nodejs14.x)
opbeans-lambda_1  | 2022-02-15 17:19:59,706 | Environment variables overrides data is standard format
opbeans-lambda_1  | 2022-02-15 17:19:59,706 | Loading AWS credentials from session with profile 'None'
opbeans-lambda_1  | 2022-02-15 17:20:01,734 | Resolving code path. Cwd=/Users/jlvoiseux/Documents/github/apm/sandbox/opbeans-lambda/nodejs, CodeUri=/Users/jlvoiseux/Documents/github/apm/sandbox/opbeans-lambda/nodejs/.aws-sam/build/OpbeansLambdaItemsPool
opbeans-lambda_1  | 2022-02-15 17:20:01,734 | Resolved absolute path to code is /Users/jlvoiseux/Documents/github/apm/sandbox/opbeans-lambda/nodejs/.aws-sam/build/OpbeansLambdaItemsPool
opbeans-lambda_1  | 2022-02-15 17:20:01,739 | Reuse the created warm container for Lambda function 'OpbeansLambdaItemsPool'
opbeans-lambda_1  | 2022-02-15 17:20:01,744 | Lambda function 'OpbeansLambdaItemsPool' is already running
opbeans-lambda_1  | 2022-02-15 17:20:01,745 | Starting a timer for 10 seconds for function 'OpbeansLambdaItemsPool'
opbeans-lambda_1  | START RequestId: d5c34398-2c78-440d-9de2-4c2f1e983224 Version: $LATEST
opbeans-lambda_1  | END RequestId: d5c34398-2c78-440d-9de2-4c2f1e983224
 opbeans-lambda_1  | REPORT RequestId: d5c34398-2c78-440d-9de2-4c2f1e983224      Duration: 5.77 ms       Billed Duration: 6 ms   Memory Size: 128 MB     Max Memory Used: 128 MB 
opbeans-lambda_1  | 2022-02-15 17:20:01,779 | Invalid lambda response received: Lambda response must be valid json
opbeans-lambda_1  | 2022-02-15 17:20:01 172.21.0.1 - - [15/Feb/2022 17:20:01] "GET /itemsPool HTTP/1.1" 502 -
opbeans-lambda_1  | 2022-02-15 17:20:01 172.21.0.1 - - [15/Feb/2022 17:20:01] "GET /favicon.ico HTTP/1.1" 403 -
opbeans-lambda_1  | 2022/02/15 17:20:01 Received event: {
opbeans-lambda_1  |     "eventType": "INVOKE",
opbeans-lambda_1  |     "deadlineMs": 1644945611768,
opbeans-lambda_1  |     "requestId": "d5c34398-2c78-440d-9de2-4c2f1e983224",
opbeans-lambda_1  |     "invokedFunctionArn": "arn:aws:lambda:us-east-1:012345678912:function:OpbeansLambdaItemsPool",
opbeans-lambda_1  |     "tracing": {
opbeans-lambda_1  |             "type": "",
opbeans-lambda_1  |             "value": ""
opbeans-lambda_1  |     }
opbeans-lambda_1  | }
opbeans-lambda_1  | 2022/02/15 17:20:01 Checking for agent data
opbeans-lambda_1  | 2022/02/15 17:20:01 No agent data on buffer

To Reproduce

This behavior can be reproduced by running the Opbeans Lambda demo and accessing the localhost:3000/itemsPool endpoint. Else, one needs to setup a Postgres database, write, build and execute a function dedicated to querying it with the AWS SAM CLI.

Expected behavior

The expected behavior is to send a transaction containing a span corresponding to the database interaction, similar to what happens here :
image

Environment (please complete the following information)

How are you starting the agent? (please tick one of the boxes)

  • Calling agent.start() directly (e.g. require('elastic-apm-node').start(...))
  • Requiring elastic-apm-node/start from within the source code
  • Starting node with -r elastic-apm-node/start

Additional context

  • Agent config options

    Click to expand
    ELASTIC_APM_CENTRAL_CONFIG: false
    ELASTIC_APM_CLOUD_PROVIDER: none
    ELASTIC_APM_SERVER_URL: http://localhost:8200
    ELASTIC_APM_LOG_LEVEL: trace
    
  • package.json dependencies:

    Click to expand
    "dependencies": {
    "elastic-apm-node": "^3.27.0",
    "pg": "^8.7.1",
    "axios" : "^0.25.0"
    }
    

Metadata

Metadata

Assignees

Labels

agent-nodejsMake available for APM Agents project planning.bug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions