function enableCapture()

in sdk_contrib/fetch/lib/fetch_p.js [68:173]


function enableCapture(baseFetchFunction, requestClass, downstreamXRayEnabled, subsegmentCallback) {

  const overridenFetchAsync = async (...args) => {
    const thisDownstreamXRayEnabled = !!downstreamXRayEnabled;
    const thisSubsegmentCallback = subsegmentCallback;
    // Standardize request information
    const request = typeof args[0] === 'object' ?
      args[0] :
      new requestClass(...args);

    // Facilitate the addition of Segment information via the request arguments
    const params = args.length > 1 ? args[1] : {};

    // Short circuit if the HTTP is already being captured
    if (request.headers.has('X-Amzn-Trace-Id')) {
      return await baseFetchFunction(...args);
    }

    const url = new URL(request.url);
    const isAutomaticMode = AWSXRay.isAutomaticMode();

    const parent = AWSXRay.resolveSegment(AWSXRay.resolveManualSegmentParams(params));
    const hostname = url.hostname || url.host || 'Unknown host';

    if (!parent) {
      let output = '[ host: ' + hostname +
        (request.method ? (', method: ' + request.method) : '') +
        ', path: ' + url.pathname + ' ]';

      if (isAutomaticMode) {
        getLogger().info('RequestInit for request ' + output +
          ' is missing the sub/segment context for automatic mode. Ignoring.');
      } else {
        getLogger().info('RequestInit for request ' + output +
          ' requires a segment object on the options params as "XRaySegment" for tracing in manual mode. Ignoring.');
      }

      // Options are not modified, only parsed for logging. We can pass in the original arguments.
      return await baseFetchFunction(...args);
    }

    let subsegment;
    if (parent.notTraced) {
      subsegment = parent.addNewSubsegmentWithoutSampling(hostname);
    } else {
      subsegment = parent.addNewSubsegment(hostname);
    }

    subsegment.namespace = 'remote';

    if (!parent.noOp) {
      request.headers.set('X-Amzn-Trace-Id',
        'Root=' + (parent.segment ? parent.segment : parent).trace_id +
        ';Parent=' + subsegment.id +
        ';Sampled=' + (subsegment.notTraced ? '0' : '1'));
    }

    // Set up fetch call and capture any thrown errors
    const capturedFetch = async () => {
      const requestClone = request.clone();
      let response;
      try {
        response = await baseFetchFunction(requestClone);

        if (thisSubsegmentCallback) {
          thisSubsegmentCallback(subsegment, requestClone, response);
        }

        const statusCode = response.status;
        if (statusCode === 429) {
          subsegment.addThrottleFlag();
        }

        const cause = utils.getCauseTypeFromHttpStatus(statusCode);
        if (cause) {
          subsegment[cause] = true;
        }

        subsegment.addFetchRequestData(requestClone, response, thisDownstreamXRayEnabled);
        subsegment.close();
        return response;
      } catch (e) {
        if (thisSubsegmentCallback) {
          thisSubsegmentCallback(subsegment, requestClone, response, e);
        }
        const madeItToDownstream = (e.code !== 'ECONNREFUSED');
        subsegment.addErrorFlag();
        subsegment.addFetchRequestData(requestClone, response, madeItToDownstream && thisDownstreamXRayEnabled);
        subsegment.close(e);
        throw (e);
      }
    };

    if (isAutomaticMode) {
      const session = AWSXRay.getNamespace();
      return await session.runPromise(async () => {
        AWSXRay.setSegment(subsegment);
        return await capturedFetch();
      });
    } else {
      return await capturedFetch();
    }
  };

  return overridenFetchAsync;
}