function createAPMError()

in lib/errors.js [159:294]


function createAPMError(args, cb) {
  let numAsyncStepsRemaining = 0; // finish() will call cb() only when this is 0.

  const error = {
    id: args.id,
    timestamp: args.timestampUs,
  };
  if (args.traceContext) {
    error.parent_id = args.traceContext.traceparent.id;
    error.trace_id = args.traceContext.traceparent.traceId;
  }
  if (args.trans) {
    error.transaction_id = args.trans.id;
    error.transaction = {
      name: args.trans.name,
      type: args.trans.type,
      sampled: args.trans.sampled,
    };
  }
  if (args.errorContext) {
    error.context = args.errorContext;
  }

  if (args.exception) {
    // Handle an exception, i.e. `captureError(<an Error instance>, ...)`.
    const err = args.exception;
    const errMsg = String(err.message);
    error.exception = {
      message: errMsg,
      type: args.exceptionType || String(err.name),
      handled: args.handled,
    };

    if ('code' in err) {
      error.exception.code = String(err.code);
    } else {
      // To provide better grouping of mysql errors that happens after the async
      // boundery, we modify to exception type to include the custom mysql error
      // type (e.g. ER_PARSE_ERROR)
      var match = errMsg.match(MYSQL_ERROR_MSG_RE);
      if (match) {
        error.exception.code = match[1];
      }
    }

    // Optional add an alternative error message as well as the exception message.
    if (args.message && typeof args.message === 'string') {
      error.log = { message: args.message };
    }

    if (args.shouldCaptureAttributes) {
      const attrs = attributesFromErr(err);
      if (attrs) {
        error.exception.attributes = attrs;
      }
    }

    numAsyncStepsRemaining++;
    gatherStackTrace(
      args.log,
      args.exception,
      args.sourceLinesAppFrames,
      args.sourceLinesLibraryFrames,
      null, // filterCallSite
      function (_err, stacktrace) {
        // _err from gatherStackTrace is always null.

        const culprit = culpritFromStacktrace(stacktrace);
        if (culprit) {
          error.culprit = culprit;
        }
        const moduleName = _moduleNameFromFrames(stacktrace);
        if (moduleName) {
          // TODO: consider if we should include this as it's not originally what module was intended for
          error.exception.module = moduleName;
        }
        error.exception.stacktrace = stacktrace;
        finish();
      },
    );
  } else {
    // Handle a logMessage, i.e. `captureError(<not an Error instance>, ...)`.
    error.log = {};
    const msg = args.logMessage;
    if (typeof msg === 'string') {
      error.log.message = msg;
    } else if (typeof msg === 'object' && msg !== null) {
      if (msg.message) {
        error.log.message = util.format.apply(
          this,
          [msg.message].concat(msg.params),
        );
        error.log.param_message = msg.message;
      } else {
        error.log.message = util.inspect(msg);
      }
    } else {
      error.log.message = String(msg);
    }
  }

  if (args.callSiteLoc) {
    numAsyncStepsRemaining++;
    gatherStackTrace(
      args.log,
      args.callSiteLoc,
      args.sourceLinesAppFrames,
      args.sourceLinesLibraryFrames,
      null, // filterCallSite
      function (_err, stacktrace) {
        // _err from gatherStackTrace is always null.

        if (stacktrace) {
          // In case there isn't any log object, we'll make a dummy message
          // as the APM Server requires a message to be present if a
          // stacktrace also present
          if (!error.log) {
            error.log = { message: error.exception.message };
          }
          error.log.stacktrace = stacktrace;
          finish();
        }
      },
    );
  } else {
    numAsyncStepsRemaining++;
    setImmediate(finish);
  }

  function finish() {
    numAsyncStepsRemaining--;
    if (numAsyncStepsRemaining === 0) {
      cb(null, error);
    }
  }
}