Client.prototype._fetchApmServerVersion = function()

in lib/apm-client/http-apm-client/index.js [1483:1581]


Client.prototype._fetchApmServerVersion = function () {
  const setVerUnknownAndNotify = (errmsg) => {
    this._apmServerVersion = null; // means "unknown version"
    this._resetEncodedMetadata();
    if (isLambdaExecutionEnvironment) {
      // In a Lambda environment, where the process can be frozen, it is not
      // unusual for this request to hit an error. As long as APM Server version
      // fetching is not critical to tracing of Lambda invocations, then it is
      // preferable to not add an error message to the users log.
      this._log.debug('verfetch: ' + errmsg);
    } else {
      this.emit('request-error', new Error(errmsg));
    }
  };
  const headers = getHeaders(this._conf);
  // Explicitly do *not* pass in `this._agent` -- the keep-alive http.Agent
  // used for intake requests -- because the socket.ref() handling in
  // `Client#_ref()` conflicts with the socket.unref() below.
  const reqOpts = getBasicRequestOptions('GET', '/', headers, this._conf);
  reqOpts.timeout = 30000;

  const req = this._transportGet(reqOpts, (res) => {
    res.on('error', (err) => {
      // Not sure this event can ever be emitted, but just in case
      res.destroy(err);
    });

    if (res.statusCode !== 200) {
      res.resume();
      setVerUnknownAndNotify(
        `unexpected status from APM Server information endpoint: ${res.statusCode}`,
      );
      return;
    }

    const chunks = [];
    res.on('data', (chunk) => {
      chunks.push(chunk);
    });
    res.on('end', () => {
      if (chunks.length === 0) {
        setVerUnknownAndNotify(
          'APM Server information endpoint returned no body, often this indicates authentication ("apiKey" or "secretToken") is incorrect',
        );
        return;
      }

      let serverInfo;
      try {
        serverInfo = JSON.parse(Buffer.concat(chunks));
      } catch (parseErr) {
        setVerUnknownAndNotify(
          `could not parse APM Server information endpoint body: ${parseErr.message}`,
        );
        return;
      }

      if (serverInfo) {
        // APM Server 7.0.0 dropped the "ok"-level in the info endpoint body.
        const verStr = serverInfo.ok
          ? serverInfo.ok.version
          : serverInfo.version;
        try {
          this._apmServerVersion = new semver.SemVer(verStr);
        } catch (verErr) {
          setVerUnknownAndNotify(
            `could not parse APM Server version "${verStr}": ${verErr.message}`,
          );
          return;
        }
        this._resetEncodedMetadata();
        this._log.debug(
          { apmServerVersion: verStr },
          'fetched APM Server version',
        );
      } else {
        setVerUnknownAndNotify(
          `could not determine APM Server version from information endpoint body: ${JSON.stringify(
            serverInfo,
          )}`,
        );
      }
    });
  });

  req.on('socket', (socket) => {
    // Unref our socket to ensure this request does not keep the process alive.
    socket.unref();
  });
  req.on('timeout', () => {
    this._log.trace('_fetchApmServerVersion timeout');
    req.destroy(
      new Error(`timeout (${reqOpts.timeout}ms) fetching APM Server version`),
    );
  });
  req.on('error', (err) => {
    setVerUnknownAndNotify(`error fetching APM Server version: ${err.message}`);
  });
};