function wrapQuery()

in lib/instrumentation/modules/mysql.js [109:199]


  function wrapQuery(original) {
    return function wrappedQuery(sql, values, cb) {
      agent.logger.debug('intercepted call to mysql %s.query', objType);

      var span = ins.createSpan(null, 'db', 'mysql', 'query', {
        exitSpan: true,
      });
      if (!span) {
        return original.apply(this, arguments);
      }

      var hasCallback = false;
      var sqlStr;

      if (this[symbols.knexStackObj]) {
        span.customStackTrace(this[symbols.knexStackObj]);
        this[symbols.knexStackObj] = null;
      }

      const wrapCallback = function (origCallback) {
        hasCallback = true;
        return ins.bindFunction(function wrappedCallback(_err) {
          span.end();
          return origCallback.apply(this, arguments);
        });
      };

      switch (typeof sql) {
        case 'string':
          sqlStr = sql;
          break;
        case 'object':
          if (typeof sql._callback === 'function') {
            sql._callback = wrapCallback(sql._callback);
          }
          sqlStr = sql.sql;
          break;
        case 'function':
          arguments[0] = wrapCallback(sql);
          break;
      }

      if (sqlStr) {
        agent.logger.debug({ sql: sqlStr }, 'extracted sql from mysql query');
        span.setDbContext({
          statement: sqlStr,
          type: 'sql',
          user,
          instance: database,
        });
        span.name = sqlSummary(sqlStr);
      }
      span._setDestinationContext(getDBDestination(host, port));

      if (typeof values === 'function') {
        arguments[1] = wrapCallback(values);
      } else if (typeof cb === 'function') {
        arguments[2] = wrapCallback(cb);
      }

      const spanRunContext = ins.currRunContext().enterSpan(span);
      const result = ins.withRunContext(
        spanRunContext,
        original,
        this,
        ...arguments,
      );

      if (!hasCallback && result instanceof EventEmitter) {
        // Wrap `result.emit` instead of `result.once('error', ...)` to avoid
        // changing app behaviour by possibly setting the only 'error' handler.
        shimmer.wrap(result, 'emit', function (origEmit) {
          return function wrappedEmit(event, data) {
            // The 'mysql' module emits 'end' even after an 'error' event.
            switch (event) {
              case 'error':
                break;
              case 'end':
                span.end();
                break;
            }
            return origEmit.apply(this, arguments);
          };
        });
        // Ensure event handlers execute in the caller run context.
        ins.bindEmitter(result);
      }

      return result;
    };
  }