Electron日志管理:应用运行日志记录与分析

Electron日志管理:应用运行日志记录与分析

【免费下载链接】electron 使用Electron构建跨平台桌面应用程序,支持JavaScript、HTML和CSS 【免费下载链接】electron 项目地址: https://gitcode.com/GitHub_Trending/el/electron

概述

在Electron应用开发过程中,有效的日志管理是确保应用稳定性和可维护性的关键。Electron提供了多种日志记录机制,从简单的控制台输出到高级的网络日志记录,帮助开发者监控应用运行状态、调试问题并分析性能瓶颈。

内置日志机制

1. 控制台日志

最基本的日志方式是通过console对象:

// 主进程日志
console.log('主进程启动');
console.error('发生错误');
console.warn('警告信息');

// 渲染进程日志
console.log('渲染进程初始化完成');

2. 启用详细日志记录

Electron支持通过命令行参数启用详细日志:

# 启用标准错误输出日志
electron --enable-logging

# 将日志输出到文件
electron --enable-logging=file

# 指定日志文件路径
electron --enable-logging --log-file=/path/to/log.txt

# 设置日志级别
electron --enable-logging --log-level=1

3. 环境变量控制

# 通过环境变量启用日志
ELECTRON_ENABLE_LOGGING=1 electron

# 指定日志文件
ELECTRON_ENABLE_LOGGING=1 ELECTRON_LOG_FILE=/path/to/log.txt electron

网络日志记录

Electron提供了专门的NetLog API用于记录网络活动:

const { session } = require('electron');

// 创建网络日志实例
const netLog = session.defaultSession.netLog;

// 开始记录网络日志
async function startNetLogging() {
  try {
    await netLog.startLogging('/path/to/netlog.json', {
      captureMode: 'default', // default, includeSensitive, everything
      maxFileSize: 10485760   // 10MB
    });
    console.log('网络日志记录已启动');
  } catch (error) {
    console.error('启动网络日志失败:', error);
  }
}

// 停止记录
async function stopNetLogging() {
  try {
    await netLog.stopLogging();
    console.log('网络日志记录已停止');
  } catch (error) {
    console.error('停止网络日志失败:', error);
  }
}

// 检查当前是否在记录
console.log('正在记录网络日志:', netLog.currentlyLogging);

多进程日志管理

主进程日志

const { app } = require('electron');
const fs = require('fs');
const path = require('path');

class MainProcessLogger {
  constructor() {
    this.logFile = path.join(app.getPath('userData'), 'main.log');
    this.setupLogging();
  }

  setupLogging() {
    // 重定向控制台输出到文件
    const logStream = fs.createWriteStream(this.logFile, { flags: 'a' });
    
    const originalLog = console.log;
    const originalError = console.error;
    
    console.log = (...args) => {
      const message = `[INFO] ${new Date().toISOString()}: ${args.join(' ')}\n`;
      logStream.write(message);
      originalLog.apply(console, args);
    };
    
    console.error = (...args) => {
      const message = `[ERROR] ${new Date().toISOString()}: ${args.join(' ')}\n`;
      logStream.write(message);
      originalError.apply(console, args);
    };
  }
}

// 初始化日志系统
new MainProcessLogger();

渲染进程日志

// preload.js
const { ipcRenderer } = require('electron');

// 重写渲染进程的console方法
const originalConsole = { ...console };

['log', 'error', 'warn', 'info', 'debug'].forEach(method => {
  console[method] = (...args) => {
    // 发送到主进程记录
    ipcRenderer.send('renderer-log', {
      level: method,
      message: args.join(' '),
      timestamp: new Date().toISOString()
    });
    
    // 保持原有功能
    originalConsole[method].apply(console, args);
  };
});

日志级别与分类

class LogLevel {
  static DEBUG = 0;
  static INFO = 1;
  static WARN = 2;
  static ERROR = 3;
}

class Logger {
  constructor(level = LogLevel.INFO) {
    this.level = level;
  }

  debug(...args) {
    if (this.level <= LogLevel.DEBUG) {
      this._log('DEBUG', args);
    }
  }

  info(...args) {
    if (this.level <= LogLevel.INFO) {
      this._log('INFO', args);
    }
  }

  warn(...args) {
    if (this.level <= LogLevel.WARN) {
      this._log('WARN', args);
    }
  }

  error(...args) {
    if (this.level <= LogLevel.ERROR) {
      this._log('ERROR', args);
    }
  }

  _log(level, args) {
    const message = `[${level}] ${new Date().toISOString()}: ${args.join(' ')}`;
    console.log(message);
  }
}

日志轮转与归档

const fs = require('fs');
const path = require('path');
const zlib = require('zlib');

class LogRotator {
  constructor(logDir, maxSize = 10485760, maxFiles = 10) {
    this.logDir = logDir;
    this.maxSize = maxSize;
    this.maxFiles = maxFiles;
  }

  rotateIfNeeded(logFile) {
    try {
      const stats = fs.statSync(logFile);
      if (stats.size > this.maxSize) {
        this.rotate(logFile);
      }
    } catch (error) {
      // 文件不存在,不需要轮转
    }
  }

  rotate(logFile) {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const rotatedFile = path.join(
      this.logDir,
      `${path.basename(logFile, '.log')}-${timestamp}.log.gz`
    );

    // 压缩并归档旧日志
    const input = fs.createReadStream(logFile);
    const output = fs.createWriteStream(rotatedFile);
    const gzip = zlib.createGzip();

    input.pipe(gzip).pipe(output).on('finish', () => {
      // 清空原日志文件
      fs.writeFileSync(logFile, '');
      this.cleanupOldFiles();
    });
  }

  cleanupOldFiles() {
    const files = fs.readdirSync(this.logDir)
      .filter(file => file.endsWith('.gz'))
      .map(file => ({
        name: file,
        time: fs.statSync(path.join(this.logDir, file)).mtime.getTime()
      }))
      .sort((a, b) => b.time - a.time);

    // 删除超出数量限制的旧文件
    if (files.length > this.maxFiles) {
      files.slice(this.maxFiles).forEach(file => {
        fs.unlinkSync(path.join(this.logDir, file.name));
      });
    }
  }
}

性能监控日志

class PerformanceMonitor {
  constructor() {
    this.metrics = new Map();
    this.startTimes = new Map();
  }

  start(metricName) {
    this.startTimes.set(metricName, process.hrtime());
  }

  end(metricName) {
    const startTime = this.startTimes.get(metricName);
    if (!startTime) return null;

    const diff = process.hrtime(startTime);
    const duration = diff[0] * 1000 + diff[1] / 1000000; // 毫秒

    this.recordMetric(metricName, duration);
    return duration;
  }

  recordMetric(metricName, value) {
    if (!this.metrics.has(metricName)) {
      this.metrics.set(metricName, []);
    }
    this.metrics.get(metricName).push(value);

    console.log(`[PERF] ${metricName}: ${value.toFixed(2)}ms`);
  }

  getSummary() {
    const summary = {};
    for (const [metricName, values] of this.metrics) {
      const sorted = values.sort((a, b) => a - b);
      summary[metricName] = {
        count: values.length,
        min: Math.min(...values),
        max: Math.max(...values),
        avg: values.reduce((a, b) => a + b, 0) / values.length,
        p95: sorted[Math.floor(sorted.length * 0.95)]
      };
    }
    return summary;
  }
}

错误追踪与报告

class ErrorTracker {
  constructor() {
    this.setupErrorHandlers();
  }

  setupErrorHandlers() {
    // 主进程错误处理
    process.on('uncaughtException', (error) => {
      this.logError('uncaughtException', error);
    });

    process.on('unhandledRejection', (reason, promise) => {
      this.logError('unhandledRejection', reason);
    });

    // 渲染进程错误处理(通过preload脚本)
  }

  logError(type, error) {
    const errorInfo = {
      timestamp: new Date().toISOString(),
      type,
      message: error.message,
      stack: error.stack,
      code: error.code
    };

    console.error(`[ERROR] ${JSON.stringify(errorInfo)}`);

    // 可以在这里添加错误上报逻辑
    this.reportError(errorInfo);
  }

  reportError(errorInfo) {
    // 发送到错误监控服务
    // fetch('https://error-reporting-service.com/api/errors', {
    //   method: 'POST',
    //   headers: { 'Content-Type': 'application/json' },
    //   body: JSON.stringify(errorInfo)
    // });
  }
}

日志分析工具集成

const { exec } = require('child_process');

class LogAnalyzer {
  static analyzeLogs(logFile, options = {}) {
    return new Promise((resolve, reject) => {
      const commands = [];

      if (options.search) {
        commands.push(`grep -n "${options.search}" "${logFile}"`);
      }

      if (options.errorOnly) {
        commands.push(`grep -n "\\[ERROR\\]" "${logFile}"`);
      }

      if (options.stats) {
        commands.push(`awk '
          /\\[ERROR\\]/ { errors++ }
          /\\[WARN\\]/ { warnings++ }
          /\\[INFO\\]/ { infos++ }
          END {
            print "Errors:", errors
            print "Warnings:", warnings
            print "Infos:", infos
            print "Total:", errors + warnings + infos
          }
        ' "${logFile}"`);
      }

      if (commands.length === 0) {
        commands.push(`cat "${logFile}"`);
      }

      exec(commands.join(' | '), (error, stdout, stderr) => {
        if (error) {
          reject(error);
        } else {
          resolve(stdout);
        }
      });
    });
  }
}

最佳实践总结

日志策略规划

mermaid

配置建议表格

环境日志级别输出目标轮转策略
开发DEBUG控制台+文件按大小(10MB)
测试INFO文件按大小(50MB)
生产WARN文件+监控服务按天+按大小

性能考量

// 避免在生产环境记录过多DEBUG日志
if (process.env.NODE_ENV !== 'production') {
  logger.debug('详细调试信息');
}

// 使用参数化日志避免不必要的字符串拼接
logger.info('用户操作: %s, 参数: %o', action, params);

// 异步日志记录避免阻塞主线程
setImmediate(() => {
  logger.info('异步日志消息');
});

通过实施这些日志管理策略,你可以构建一个健壮的Electron应用监控体系,及时发现和解决运行中的问题,提升应用质量和用户体验。

【免费下载链接】electron 使用Electron构建跨平台桌面应用程序,支持JavaScript、HTML和CSS 【免费下载链接】electron 项目地址: https://gitcode.com/GitHub_Trending/el/electron

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值