如何包装sails-mongo db方法进行性能分析?

时间:2016-09-13 04:14:35

标签: sails.js sails-mongo

我正在尝试使用miniprofiler设置一个sails hook来帮助配置mongo的用法。我正在努力如何在执行配置文件的函数中包装db方法。我试图通过用户钩子来做到这一点:

setupMiniprofilerMongo(req, res, next) {
  const adapter = sails.hooks.orm.datastores.default.adapter;
  const adapterPrototype = Object.getPrototypeOf(adapter);
  const originalMethod = adapter.adapter.find;
  methodPrototype.find = function profiledMongoCommand(connectionName, collectionName, options, cb) {
    sails.log.info(`${collectionName}.find`);
    return originalMethod.call(adapter, connectionName, collectionName, options, cb);
  };
}

这会导致抛出以下错误:

TypeError: Cannot read property 'collections' of undefined
    at Object.module.exports.adapter.find (/Users/jgeurts/dev/platform/node_modules/sails-mongo/lib/adapter.js:349:40)
    at Object.profiledMongoCommand [as find] (/Users/jgeurts/dev/platform/config/http.js:234:37)

任何帮助将不胜感激。我试图将方法包装在mongodb包上,但这似乎也不起作用。 :/

1 个答案:

答案 0 :(得分:1)

我通过包装水线查询方法得到了这个。但是,还有改进的余地。

setupMiniprofilerWaterline(req, res, next) {
  const dbOperations = [
    'count',
    'create',
    'createEach',
    'define',
    'describe',
    'destroy',
    'drop',
    'find',
    'join',
    //        'native',
    //        'registerConnection',
    'update',
  ];

  const waterlineMethodByModels = {};
  const miniprofilerWaterline = () => {
    return {
      name: 'mongodb',
      handler(req, res, next) {

        if (!req.miniprofiler || !req.miniprofiler.enabled) {
          return next();
        }

        const profiler = req.miniprofiler;

        for (const modelName of _.keys(sails.models)) {
          for (const dbOperation of dbOperations) {
            const model = sails.models[modelName];
            if (!model[dbOperation]) {
              continue;
            }

            if (!waterlineMethodByModels[modelName]) {
              waterlineMethodByModels[modelName] = {};
            }

            // Prevent wrapping a method more than once
            if (waterlineMethodByModels[modelName][dbOperation]) {
              continue;
            }

            waterlineMethodByModels[modelName][dbOperation] = true;

            const originalMethod = model[dbOperation];

            model[dbOperation] = function profiledMongoCommand(...args) {
              const query = args && args.length ? args[0] : '';
              const lastArg = args && args.length ? args[args.length - 1] : null;
              const modelAndMethod = `${modelName}.${dbOperation}`;

              if (lastArg && typeof lastArg === 'function') {
                sails.log.debug(`mongo::${modelAndMethod}  - ${JSON.stringify(query)}`);
                const callback = args.pop();

                const timing = profiler.startTimeQuery('mongodb', query ? JSON.stringify(query || '') : '');
                // In general, the callstack is kind of useless to us for these profiles
                // The model/db method is more useful in the miniprofiler UI
                timing.callStack = `\n\nMethod: ${modelAndMethod}`;

                return originalMethod.call(this, ...args, function profiledResult(...results) {
                  profiler.stopTimeQuery(timing);
                  callback(...results);
                });
              }

              const methodResult = originalMethod.call(this, ...args);
              const methodResultPrototype = Object.getPrototypeOf(methodResult);
              const isDeferred = !!methodResultPrototype.exec;
              // If methodResult is a Deferred object type, then the query method will be profiled above when the deferred is executed (with a callback)
              // So we only care to log this if the methodResult is not a deferred object
              if (!isDeferred) {
                sails.log.warn(`Was not able to profile mongo::${modelAndMethod}. Maybe its a promise? query: ${JSON.stringify(query)}`);
              }

              return methodResult;
            };
          }
        }

        next();
      },
    };
  };

  miniprofiler.express.for(miniprofilerWaterline())(req, res, next);
},

如果您想在自己的项目中贡献/使用

,则代码可以miniprofiler-waterline获得