Skip to content
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

datadog + serverless + async_hooks not working as expected #424

Open
mjmarianetti opened this issue Oct 3, 2023 · 0 comments
Open

datadog + serverless + async_hooks not working as expected #424

mjmarianetti opened this issue Oct 3, 2023 · 0 comments
Assignees
Labels
bug Something isn't working

Comments

@mjmarianetti
Copy link

Expected Behavior

Using async_hooks to manage context inside a lambda function would allow the datadog layer to properly inject all logs with span_id and trace_id

Actual Behavior

Logs are injected with service and version but span_id and trace_id are missing.

Have a class that is used to wrap all operations for a given request and maintain context between each log. Our logger is winston

context.ts file
--------------  
class RequestContextResource extends AsyncResource {
  data: RequestContext;

  constructor() {
    super('RequestContextResource');
    this.data = {};
  }
}

export class ContextService {
  constructor() {
      this.resource = new RequestContextResource();
    }
    
  public async wrap<T>(callback: () => Promise<T>): Promise<T> {
      return new Promise<T>((resolve, reject) => {
        this.resource.runInAsyncScope(
          () => {
            callback()
              .then(result => resolve(result))
              .catch(error => reject(error))
              .finally(() => {
                // Clean up the context after the callback has completed
               this.resource.data = {};
              });
          },
          null,
          {triggerAsyncId: this.resource.asyncId},
        );
      });
    }

  public addContext(data: unknown): void {
   for (const key of Object.keys(data)) {
      if (Object.prototype.hasOwnProperty.call(data, key)) {
        this.resource.data[key] = data[key];
      }
    }
  }
  
  public debug(message) {
     winston.debug(message, this.resource.data);
  }
  
  }
  
lambda.ts file
--------------  
const context = new ContextService();
handler = return context.wrap((lambdaEvent) => {
  context.addContext({requestId: lambdaEvent.requestId})
  context.debug(`this is a log message`)
  context.addContext({userId: lambdaEvent.userId})
  context.debug(`this is another log message`)
});

Calling this function with lambdaEvent = {userId: "1234", requestId: "321321"} we would expect the following result

{
  "dd": {
      "service": "service-name",
      "version": "1.0.0",
      "trace_id":"xxxxxx", ---> this is missing in the logs
      "span_id":"xxxxxx" ---> this is missing in the logs
  },
  "level": "debug",
  "message": "this is a log message",
  "requestId": "321321"
}
{
  "dd": {
      "service": "service-name",
      "version": "1.0.0",
      "trace_id":"xxxxxx", ---> this is missing in the logs
      "span_id":"xxxxxx" ---> this is missing in the logs
  },
  "level": "debug",
  "message": "this is another log message",
  "requestId": "321321",
  "userId: "1234"
}  

Steps to Reproduce the Problem

  1. Wrap the lambda handler with a function that allow you to add context to your requests
  2. Call the lambda handler
  3. Expect to have span_id and trace_id being injected in cloudwatch log output from the lambda function.

Extra information:

  • The above approach works just fine for docker containers using it with this configuration
import tracer from 'dd-trace';
tracer.init({
  service: 'service_name',
  logInjection: true,
});
  • This started happening when we migrated from cls_hooked to async_hooks for performance

Specifications

  • Datadog Lambda Layer version: 95
  • Node version: 16.x
  • datadog-lambda-js: 7.97.0
  • dd-trace: 4.16.0

serverless.yml


plugins:
- serverless-plugin-datadog
- serverless-webpack
- ...
webpack:   
  packagerOptions:
    scripts:
      # optional, only needed when they are included as transitive dependencies
      - rm -rf node_modules/datadog-lambda-js node_modules/dd-trace
  includeModules:
    forceExclude:
      - aws-sdk
      - dd-trace
      - datadog-lambda-js
  packager: 'npm'
...
  datadog:
    addExtension: false
    flushMetricsToLogs: true
    enableXrayTracing: false
    enableDDTracing: true
    enableTags: true
    forwarderArn: arn:aws:lambda:xxxxxxxxxxx

Stacktrace

@duncanista duncanista added the bug Something isn't working label Feb 5, 2024
@duncanista duncanista self-assigned this Sep 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants