普通日志收集
主进程
log4js
下载依赖
代码语言:javascript复制npm install log4js --save
工具类
代码语言:javascript复制const log4js = require('log4js');
log4js.configure({
appenders: {
myLogFile: {
type: "dateFile",
filename: './logs/mylog',//您要写入日志文件的路径及文件名前缀
pattern: "yyyy-MM-dd-hh.log",//(可选,默认为.yyyy-MM-dd) - 文件名后缀。格式:.yyyy-MM-dd-hh:mm:ss.log
alwaysIncludePattern: true,//(默认为false) - 将模式包含在当前日志文件的名称以及备份中
compress: false,//(默认为false) - 在滚动期间压缩备份文件(备份文件将具有.gz扩展名)
encoding: 'utf-8',//default "utf-8",文件的编码
maxLogSize: 1024 * 1024 // 1M 文件最大存储空间,当文件内容超过文件存储空间会自动生成一个文件xxx.log.1的序列自增长的文件
},
myLogConsole: {
type: 'console'
}
},
categories: {
default: {
appenders: ['myLogFile', 'myLogConsole'],
level: log4js.levels.ALL
},
myLogFile: {
appenders: ['myLogFile'],
level: log4js.levels.ALL
},
myLogConsole: {
appenders: ['myLogConsole'],
level: log4js.levels.ALL
}
}
});
let log = log4js.getLogger('myLogFile');
module.exports.logger = log;
开发时在Console窗口中显示日志
代码语言:javascript复制log4js.getLogger('myLogConsole');
正式部署后改为
代码语言:javascript复制log4js.getLogger('myLogFile');
使用
代码语言:javascript复制const logger = require('./assets/js/MyLog').logger;
logger.info("app init");
logger对象暴露到全局(main.js)
代码语言:javascript复制global.zlog = logger;
注意
使用Electron和Webpack结合的时候,建议日志在
main.js
中引用,页面中通过ipc方式进行调用。 工具类MyLog.js
我是配置在assets/js/MyLog.js
。 package.json中配置build下的files配置。
package.json
代码语言:javascript复制{
"name": "xhlive",
"productName": "我的博客",
"version": "1.3.6",
"description": "",
"main": "main.js",
"build": {
"asar": true,
"files": [
"build/*",
"main.js",
"*.html",
"image",
"assets",
"app.ico",
"node_modules/**/*"
],
"appId": "cn.psvmc.myblog",
"win": {
"icon": "app.ico",
"target": [
"zip"
]
},
"nsis": {
"oneClick": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"installerIcon": "app.ico",
"uninstallerIcon": "app.ico",
"installerHeaderIcon": "app.ico",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"license": "LICENSE.txt"
},
"extraResources": [
],
"mac": {
"hardenedRuntime": false
}
},
"scripts": {
"start": "webpack --mode development && cross-env ELECTRON_DISABLE_SECURITY_WARNINGS=true electron .",
"webpack": "webpack --mode development",
"dist": "webpack --mode development && electron-builder --win --ia32",
"dist_dir": "webpack --mode development && electron-builder --dir --win --ia32"
},
"devDependencies": {
},
"dependencies": {
}
}
Electron-log(推荐)
Electron-log日志记录工具
首先我们安装依赖:
代码语言:javascript复制npm i electron-log --save
在项目里面引入依赖项:
代码语言:javascript复制const zlog = require('electron-log');
let filepath = path.join(app.getPath("documents"), 'xhlive/logs/');
let nowdate = new Date();
let nowdate_str = nowdate.getFullYear() "_" (nowdate.getMonth() 1) "_" nowdate.getDate() "_" nowdate.getHours();
let filename = "mylog_" nowdate_str ".log";
zlog.transports.file.resolvePath = () => path.join(filepath, filename);
zlog.transports.file.level = true;
zlog.transports.console.level = false;
global.zlog = zlog;
然后在我们的主线程加入以下代码:
代码语言:javascript复制zlog.info('这是个提示日志');
zlog.warn('这是个警告日志');
zlog.error('这是个错误日志');
electron-log supports the following log levels:
代码语言:javascript复制error, warn, info, verbose, debug, silly
以上代码通过不同级别记录日志,默认情况下会在控制台打印出和保存到本地文件,
日志默认保存在app.getPath('userData')
目录下的log.log
文件中,
这个时候你会发现日志的时间和日志级别,日志内容都记录下来了,有这些信息我们就可以更好的跟踪bug等信息了。当然这个依赖不止这些功能:
我们可以设置log路径和文件名:
代码语言:javascript复制zlog.transports.file.resolvePath = () => path.join(filepath, filename);
我们可以格式化日志内容:
代码语言:javascript复制zlog.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}'
也可以通过log.transports.file.level
和log.transports.console.level
来分别设置日志输出目标和日志输出等级。
如果想禁止Console中输出可以设置对应项为false
代码语言:javascript复制zlog.transports.file.level = true;
zlog.transports.console.level = false;
虽然有了这些日志信息,但是都在不同用户的电脑上,我们可以开发一个程序,在适当的时候把用户日志传送到web服务器上去,这样让我们更好的跟踪!
渲染进程
工具类
代码语言:javascript复制const remote = window.require("electron").remote;
const app = remote.app;
let zlog = remote.getGlobal('zlog');
const isDevelopment = !app.isPackaged;
window.zlog = zlog;
function get_log_func(m_args) {
let temp_arr = [];
for (let m_arg of m_args) {
if (m_arg) {
if (m_arg instanceof Object) {
temp_arr.push(JSON.stringify(m_arg));
} else {
temp_arr.push(m_arg);
}
}
}
return temp_arr.join(" | ");
}
let logger = {
log: function (...args) {
if (zlog) {
zlog.info(get_log_func(args));
}
if (isDevelopment) {
console.log(...args)
}
},
info: function (...args) {
if (zlog) {
zlog.info(get_log_func(args));
}
if (isDevelopment) {
console.info(...args)
}
},
warn: function (...args) {
if (zlog) {
zlog.warn(get_log_func(args));
}
if (isDevelopment) {
console.warn(...args)
}
},
error: function (...args) {
if (zlog) {
zlog.error(get_log_func(args));
}
if (isDevelopment) {
console.error(...args)
}
},
}
export {logger}
页面中引用
代码语言:javascript复制import {logger} from "./assets/js/mylog";
logger.info("登录初始化");
主进程网络日志
Electron有主进程和渲染进程,一般呢我们通过渲染进程的控制台network就可以看到程序发起的网络请求。但是使用这个方法呢会有三个问题:
- 无法监控主进程发起的网络请求;
- Electron呢可能会有多个窗口,不同的窗口发起不同的请求可能存在关联关系,就需要联合监控,就非常麻烦。
- 无法精确的分析某个时段的网络请求。
为了弥补这方面的不足,Electron提供了netLog模块,允许开发人员通过编程的方式记录网络请求。
代码语言:javascript复制const { remote } = require('electron')
let filepath = path.join(app.getPath("documents"), 'xhlive/logs/');
let nowdate = new Date();
let nowdate_str = nowdate.getFullYear() "_" (nowdate.getMonth() 1) "_" nowdate.getDate() "_" nowdate.getHours();
let filename = "mynet_" nowdate_str ".log";
await remote.netLog.startLogging(path.join(filepath, filename));
let ses = remote.getCurrentWebContents().session;
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.baidu.com');
xhr.onload = async () => {
log.info(xhr.responseText);
await remote.netLog.stopLogging()
}
xhr.send()
netLog模块是一个主进程模块,所以我们需要通过remote来使用他,
它的startLogging接收两个参数,第一个参数是日志文件记录的路径,也可以通过app.getPath('userData')
来指定路径,第二个参数是一个配置对象,具体参考文档。
接着我们发起一个网络请求,得到响应后,我们通过stopLogging()来停止网络监控。
tips: 低版本的Electron可以使用以下方法:
app.commandLine.appendSwitch('log-net-log', 'net-log')
,net-log为文件名称,可以自定义,文件会保存在项目根目录下,
也可以根据app.commandLine.hasSwitch('log-net-log')
查看网络日志开关是否被打开,返回true
或false
崩溃日志收集
官方文档:https://www.electronjs.org/docs/api/crash-reporter#crashreporter
代码语言:javascript复制const {crashReporter} = require('electron')
crashReporter.start({
productName:'myblog',
companyName:'psvmc',
submitURL:'https://www.psvmc.cn',
uploadToServer:false
})
console.info(crashReporter.getCrashesDirectory());
可以调用以下方法模拟崩溃
代码语言:javascript复制process.crash()
官方说可以设置崩溃日志的目录,但是我这里设置无效
代码语言:javascript复制let logpath = path.resolve(app.getPath("documents") '/myblog/logs/');
console.info(logpath);
app.setPath('crashDumps', logpath)
官方说的设置uploadToServer:false
,就不需要设置submitURL
,但是实际测试并非如此。
另外这种方法生成的错误日志也没法通过文本文档查看,所以我就没有使用。
但是我们可以监听事件child-process-gone
https://www.electronjs.org/docs/api/app#事件-render-process-gone
代码
代码语言:javascript复制const { app } = require('electron')
app.on('child-process-gone', (event, details) => {
console.log(details);
})
崩毁重启
代码语言:javascript复制import { BrowserWindow, app, dialog} from 'electron';
const mainWindow = BrowserWindow.fromId(global.mainId);
mainWindow.webContents.on('crashed', () => {
const options = {
type: 'error',
title: '进程崩溃了',
message: '这个进程已经崩溃.',
buttons: ['重载', '退出'],
};
recordCrash().then(() => {
dialog.showMessageBox(options, (index) => {
if (index === 0) reloadWindow(mainWindow);
else app.quit();
});
}).catch((e) => {
console.log('err', e);
});
})
function recordCrash() {
return new Promise(resolve => {
// 崩溃日志请求成功....
resolve();
})
}
function reloadWindow(mainWin) {
if (mainWin.isDestroyed()) {
app.relaunch();
app.exit(0);
} else {
BrowserWindow.getAllWindows().forEach((w) => {
if (w.id !== mainWin.id) w.destroy();
});
mainWin.reload();
}
}