阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 调试与日志记录技巧

调试与日志记录技巧

作者:陈川 阅读数:21607人阅读 分类: MongoDB

调试与日志记录技巧

调试和日志记录是开发过程中不可或缺的部分,尤其是在使用 Mongoose 进行 MongoDB 操作时。合理的调试和日志记录能帮助快速定位问题,提高开发效率。以下是一些实用的技巧和示例。

启用 Mongoose 调试模式

Mongoose 内置了调试功能,可以通过设置 debug 选项来启用。启用后,Mongoose 会输出所有执行的查询和操作到控制台。

const mongoose = require('mongoose');
mongoose.set('debug', true);

// 连接数据库
mongoose.connect('mongodb://localhost:27017/test', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

启用调试模式后,控制台会输出类似以下内容:

Mongoose: users.insertOne({ name: 'John', age: 30, _id: ObjectId("..."), __v: 0 })

自定义日志输出

如果默认的调试输出不够详细,可以通过监听 Mongoose 的 debug 事件来自定义日志输出。

mongoose.set('debug', function(collectionName, method, query, doc) {
  console.log(`Mongoose: ${collectionName}.${method}`, JSON.stringify(query), doc);
});

这样可以根据需要格式化日志,例如添加时间戳或过滤特定操作。

使用中间件记录操作日志

Mongoose 的中间件(pre/post hooks)可以用来记录模型的操作日志。例如,在保存文档前后记录日志:

const userSchema = new mongoose.Schema({
  name: String,
  age: Number,
});

userSchema.pre('save', function(next) {
  console.log(`About to save user: ${this.name}`);
  next();
});

userSchema.post('save', function(doc) {
  console.log(`User saved: ${doc.name}`);
});

const User = mongoose.model('User', userSchema);

记录查询执行时间

对于性能敏感的查询,可以记录查询的执行时间,帮助优化性能。

const start = Date.now();
User.find({ age: { $gt: 25 } })
  .then(users => {
    const duration = Date.now() - start;
    console.log(`Query took ${duration}ms`);
    console.log(users);
  })
  .catch(err => console.error(err));

使用 Winston 或 Morgan 记录日志

对于生产环境,可以使用专业的日志库如 Winston 或 Morgan 来记录 Mongoose 的操作日志。

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'mongoose.log' }),
  ],
});

mongoose.set('debug', function(collectionName, method, query, doc) {
  logger.info(`Mongoose: ${collectionName}.${method}`, { query, doc });
});

错误日志记录

Mongoose 操作中的错误需要妥善记录,以便后续排查。可以在 Promise 的 catch 块或 try-catch 中记录错误。

User.findById('someId')
  .then(user => {
    if (!user) {
      throw new Error('User not found');
    }
    console.log(user);
  })
  .catch(err => {
    logger.error('Error fetching user', { error: err.message });
  });

使用 Mongoose 的日志级别

Mongoose 的 debug 选项支持传入一个函数,可以根据操作类型(如 query、update、delete)设置不同的日志级别。

mongoose.set('debug', function(collectionName, method, query, doc, options) {
  const level = method === 'delete' ? 'warn' : 'info';
  logger.log(level, `Mongoose: ${collectionName}.${method}`, { query, doc });
});

记录慢查询

可以通过中间件或全局设置记录执行时间过长的查询。

const slowQueryThreshold = 100; // 100ms

mongoose.set('debug', function(collectionName, method, query, doc, options) {
  const start = Date.now();
  return function() {
    const duration = Date.now() - start;
    if (duration > slowQueryThreshold) {
      logger.warn(`Slow query: ${collectionName}.${method} took ${duration}ms`, { query });
    }
  };
});

结合 Sentry 或类似工具

对于生产环境,可以将 Mongoose 的错误日志集成到 Sentry 等错误监控工具中。

const Sentry = require('@sentry/node');

User.findById('invalidId')
  .then(user => console.log(user))
  .catch(err => {
    Sentry.captureException(err);
    logger.error('Error in User.findById', { error: err.message });
  });

日志过滤与脱敏

记录日志时需要注意敏感信息(如密码)的脱敏处理。

mongoose.set('debug', function(collectionName, method, query, doc) {
  const sanitizedQuery = JSON.parse(JSON.stringify(query));
  if (sanitizedQuery.password) {
    sanitizedQuery.password = '***';
  }
  logger.info(`Mongoose: ${collectionName}.${method}`, { query: sanitizedQuery });
});

使用环境变量控制日志级别

根据环境(开发、测试、生产)动态调整日志级别。

const isProduction = process.env.NODE_ENV === 'production';

mongoose.set('debug', isProduction ? false : true);

记录连接状态

Mongoose 的连接事件(如 connected、disconnected)也可以记录到日志中。

mongoose.connection.on('connected', () => {
  logger.info('Mongoose connected to MongoDB');
});

mongoose.connection.on('error', err => {
  logger.error('Mongoose connection error', { error: err.message });
});

mongoose.connection.on('disconnected', () => {
  logger.warn('Mongoose disconnected from MongoDB');
});

使用 Mongoose 的 lean() 调试查询

lean() 可以跳过 Mongoose 的文档转换,直接返回纯 JavaScript 对象。这在调试查询性能时很有用。

User.find({ age: { $gt: 25 } })
  .lean()
  .then(users => {
    console.log('Lean query result:', users);
  })
  .catch(err => console.error(err));

记录批量操作

对于批量操作(如 insertMany、updateMany),可以记录操作影响的文档数量。

User.insertMany([{ name: 'Alice' }, { name: 'Bob' }])
  .then(docs => {
    logger.info(`Inserted ${docs.length} users`);
  })
  .catch(err => logger.error('Error in insertMany', { error: err.message }));

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌