在 Electron 中用 electron-log 记录日志:完整指南(含代码示例、常用配置与注意事项)
electron-log 是一款轻量、常用且专为 Electron(也支持 Node)设计的日志库 —— 支持多进程(main/renderer)、输出到控制台和文件、可自定义格式与自定义 transport(扩展器)。这篇文章把你可能需要知道的基本用法、常用配置项(文件位置 / 文件名 / 格式 / 轮转)和实战注意事项都讲清楚。
1. 安装与快速开始
# npm
npm install electron-log
# 或者 yarn
yarn add electron-log
主进程(main)中最简单的使用:
// main.js (Electron main process)
const log = require('electron-log');
log.info('App starting...');
log.warn('something might be wrong');
log.error(new Error('error'));
渲染进程(renderer)中使用(推荐通过 electron-log/renderer):
// renderer.js
import log from 'electron-log/renderer';
log.info('Hello from renderer');
小提示:
electron-log也导出了electron-log/node入口用于纯 Node 环境。
2. 常用 API(方法 & 等级)
日志方法同 console 风格,可用的方法与等级有:
log.error(...)、log.warn(...)、log.info(...)、log.verbose(...)、log.debug(...)、log.silly(...)
electron-log 支持的级别:error, warn, info, verbose, debug, silly。你可以按等级控制哪些日志被最终输出(transport 的 level 配置)。
3. 默认输出位置(文件路径)——重要事实
默认情况下(不同平台)electron-log 会把日志写到平台合适的位置,例如:
- macOS:
~/Library/Logs/{app name}/main.log - Linux:
~/.config/{app name}/logs/main.log(或~/.config/{app name}/log.log的变体,视版本) - Windows:
%USERPROFILE%\AppData\Roaming\{app name}\logs\main.log(或类似路径)
4. 进程与 transport:console / file / rendererConsole(工作机制)
electron-log 默认启用几个 transport(输出目标):
- console transport:在主进程打印到 Node 的
console,在渲染进程打印到 DevTools 控制台。 - file transport:把格式化后的日志写入磁盘文件(上文提到的位置)。
- rendererConsole / ipc 逻辑:在渲染进程写日志时,日志可以通过 IPC 发送给主进程,由主进程写入文件;也可以直接在渲染进程记录到文件(但通常推荐由主进程统一写文件以避免文件竞争)。
5. 常用配置项
你可以在程序启动时配置 log 对象的 transports、format、level 等。
// main.js
const log = require('electron-log');
const path = require('path');
const { app } = require('electron');
// 初始化(可选)
log.transports.file.level = 'info'; // 文件最低记录级别
log.transports.console.level = 'debug'; // 控制台显示级别
log.transports.rendererConsole.level = false; // 禁用 rendererConsole transport
// 自定义文件名或位置(方法一:resolvePathFn)
log.transports.file.resolvePathFn = () => path.join(app.getPath('userData'), 'my-logs', 'app.log');
// 自定义输出格式(占位符:{h}/{i}/{s}/{d}/{m}/{y}/{processType}/{text} 等)
log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}] [{processType}] {text}';
// 获取当前日志文件路径(运行在主进程)
const fileInfo = log.transports.file.getFile(); // 返回 {path, size, name, ...}
console.log('log file path:', fileInfo.path);
字段说明(重点)
log.transports.file.level:设置写文件的最小级别,低于此级别的日志不会写文件(false表示禁用)。log.transports.console.level:控制台输出级别(主进程在 stdout,渲染在 DevTools)。log.transports.file.resolvePath(或老版本resolvePathFn):一个函数,返回要写入的日志文件的完整路径(字符串)。用它来自定义日志放到app.getPath('userData')等安全目录中。log.transports.file.format:自定义格式字符串(默认包含时间 / 进程类型 / 文本),格式化语法见源码/README(常用占位符如{h}{i}{s}{d}{m}{y}{processType}{text})。
6. 获取或打开当前日志文件(方便“打开日志”按钮)
主进程可以获取实际写入的文件信息,然后用 Electron 的 shell.openPath() 打开目录或文件:
const { shell } = require('electron');
const file = log.transports.file.getFile(); // { path, size, ... }
console.log('current log file:', file.path);
shell.openPath(path.dirname(file.path)); // 打开包含日志的文件夹
注意:
getFile()需要在主进程调用(它才能访问实际写入文件的 transport 实例)。有社区讨论与建议也指出这一点是查找日志文件路径的可靠办法。
7. 文件轮转(rotation)、大小与数量控制(实践建议)
electron-log 的 file transport 在实现里含有对 maxSize (或类似字段)的支持,并会在超出大小时备份已有日志(例如添加时间戳后缀)。不过社区 issue 提醒在高并发/多进程同时写同一文件时,轮转可能出现边界情况或“超出 maxSize” 的时刻性差异(这是文件系统与并发写入的常见问题)。实践建议:
- 推荐由主进程统一写文件(renderer 写日志通过 IPC 发给主进程),避免多个进程直接写到同一文件导致竞争。
- 如果需要严格的轮转与更高级策略,考虑把
electron-log的 file transport 替换为或包装第三方成熟的轮转库(如file-stream-rotator)或把日志上报到集中化服务(Sentry / Datadog / Elastic)。
8. 在主/渲染/预加载脚本中的推荐实践(实战)
在主进程统一初始化(推荐)
在 main 中初始化 electron-log,并把 level/format/resolvePath 等配置好。渲染进程通过 electron-log/renderer(内部会把日志通过 IPC 发给主进程)或通过自定义 IPC 转发给主进程记录到文件。
// main.js
const { app, BrowserWindow } = require('electron');
const log = require('electron-log');
const path = require('path');
app.on('ready', () => {
// 确保 app.name 和 app.getPath 已准备好
log.transports.file.level = 'info';
log.transports.file.resolvePath = () => path.join(app.getPath('userData'), 'logs', 'main.log');
log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}] [{processType}] {text}';
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
win.loadURL('file://' + __dirname + '/index.html');
log.info('Main process started');
});
// preload.js (可选)
const log = require('electron-log/renderer'); // 或 require('electron-log').renderer
window.log = log; // 小心把它暴露给渲染(只在你信任页面时)
<!-- renderer.js -->
window.log.info('renderer ready');
// 或者直接 import log from 'electron-log/renderer'
为什么推荐主进程统一写文件?
- 主进程是单实例:可以避免多个渲染进程并发写同一文件产生的竞争 / 损坏 / 轮转问题。
- 渲染进程更容易开关(窗口关闭),集中化便于管理日志级别 / 上传。
9. 常见注意事项与陷阱(实战经验)
- 主进程 vs 渲染进程写文件:尽量让主进程写文件,渲染进程通过 IPC 发消息(内置
rendererConsoletransport 已实现该逻辑)。多 renderer 直接写同一文件会有并发/轮转问题。 - 生产环境默认行为:在较新的版本或打包环境中,renderer 的 console transport 可能默认被禁用或等级不同(请在生产构建中检查并显式设置
level)。有的项目需要在生产也记录某些级别的日志(例如error)。 - 日志文件大小与轮转:内置轮转逻辑存在,但在极端并发场景或跨进程写入场景下要小心,必要时用更成熟的轮转方案或把日志集中化。
- 不要把敏感信息写日志:日志可能被用户或运维读取,避免记录密码、密钥、PII。
- 使用
getFile()获取文件信息:用log.transports.file.getFile()在主进程定位或打开日志文件夹是最可靠方法。
10. 完整示例:生产就绪的日志初始化(示范)
// logger.js (main process)
const log = require('electron-log');
const path = require('path');
const { app } = require('electron');
function initLogger() {
// levels
log.transports.console.level = process.env.NODE_ENV === 'development' ? 'debug' : 'warn';
log.transports.file.level = 'info';
// put logs under userData/logs/
const logsDir = path.join(app.getPath('userData'), 'logs');
log.transports.file.resolvePath = () => path.join(logsDir, `${app.name || 'app'}-main.log`);
// format: 2025-10-21 15:00:00 [main] message
log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}] [{processType}] {text}';
log.transports.console.format = '[{h}:{i}:{s}] [{processType}] {text}';
return log;
}
module.exports = initLogger;
在 main 中调用:
const initLogger = require('./logger');
const log = initLogger();
log.info('App initialized');
1363

被折叠的 条评论
为什么被折叠?



