Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Breadcrumbs & context wrapping broken with native promises #265

Closed

Description

*** Maintainer edit/resolution ***

This issue is resolved on Node.js 8.0.0, thanks to the following line item of the 8.0.0 changelog:

Native Promise instances are now Domain aware

Partial workarounds have been identified for version of Node prior to 8. Recommendation:

  • If you can, use Node.js 8 and this problem will disappear
  • If you can't use Node.js 8, use Bluebird promises instead of native promises
  • If you can't do either of those, you'll have to avoid relying on context() or wrap(); you can still use the global-scope context, which may be sufficient for certain use cases like Lambda

Original issue below:


I've been pulling my hair out trying to get breadcrumbs working in my Serverless Lambda services, but I can never seem to get it working. Like not even a little bit...

I've gone over the docs multiple times, and it seems like I'm doing everything as recommended. At this point I don't know what else to try.

Background

  • Code written in ES6
  • Built with Webpack v1 via serverless-webpack plugin
  • Compiled using babel-loader
  • Auto-breadcrumbs are disabled
  • Using latest v1.1.1 of raven-node

Example Code

Here's a simplified example of one of my functions.

// Lambda function handler
import Raven from 'raven'
Raven.config('my-dsn', { /* my config */ }).install()

import MyClass from './my-class'

export const handler = Raven.wrap((event, context, callback) => {
  new MyClass(event, callback).startDoingStuff()
})
// my-class.js
import Raven from 'raven'
import AWS from 'aws-sdk'
const ddbClient = new AWS.DynamoDB.DocumentClient()

export default class MyClass {
  constructor (event, callback) {
    this.event = event
    this.callback = callback
    Raven.setContext({ extra: this.event })
  }

  startDoingStuff () {
    Raven.captureBreadcrumb({ message: 'started doing stuff' })
    return this.doTheStuff()
      .then(this.itWorked.bind(this))
      .catch(this.itBroke.bind(this))
  }

  doTheStuff () {
    return new Promise((resolve, reject) => {
      ddbClient.query({ /* query params */ }, (error, data) => {
        if (error) {
          Raven.captureBreadcrumb({ message: 'lol nope' })
          return reject(error)
        }
        resolve(data)
      })
    })
  }

  itWorked (data) {
    this.callback(null, data)
  }

  itBroke (error) {
    Raven.captureException(error, (sentryError, eventId) => {
      this.callback(error)
    })
  }
}

Results

If something goes wrong in doTheStuff(), the events that get logged to Sentry don't have any of the extra context I tried setting in the constructor, and don't have any breadcrumbs other than the final exception...

Also, my Lambda logs on AWS are full of entries like raven@1.1.1 alert: getContext called without context; this may indicate incorrect setup - refer to docs on contexts.

So it seems like a problem with the Node.js domain API. Maybe because raven-node seems to rely on implicit binding?

I'm not really familiar with the domain API, but if a different library also tried to use domains (say maybe the AWS SDK), would changing the active domain break raven-node since it relies on domain.active.sentryContext? IDK if that's even how it works...

Anyway, is there a way to disable node domains all together and just run everything in a global context? Domains aren't really useful in an AWS Lambda environment IMO (also, they're deprecated).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions