普通日志收集 主进程 log4js 下载依赖
1 npm install log4js --save
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 const log4js = require ('log4js' );log4js.configure ({ appenders : { myLogFile : { type : "dateFile" , filename : './logs/mylog' , pattern : "yyyy-MM-dd-hh.log" , alwaysIncludePattern : true , compress : false , encoding : 'utf-8' , maxLogSize : 1024 * 1024 }, 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窗口中显示日志
1 log4js.getLogger ('myLogConsole' );
正式部署后改为
1 log4js.getLogger ('myLogFile' );
使用
1 2 const logger = require ('./assets/js/MyLog' ).logger ;logger.info ("app init" );
logger对象暴露到全局(main.js)
注意
使用Electron和Webpack结合的时候,建议日志在main.js中引用,页面中通过ipc方式进行调用。
工具类MyLog.js我是配置在assets/js/MyLog.js。
package.json中配置build下的files配置。
package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 { "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日志记录工具
首先我们安装依赖:
1 npm i electron-log --save
在项目里面引入依赖项:
1 2 3 4 5 6 7 8 9 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;
然后在我们的主线程加入以下代码:
1 2 3 zlog.info ('这是个提示日志' ); zlog.warn ('这是个警告日志' ); zlog.error ('这是个错误日志' );
electron-log supports the following log levels:
1 error, warn, info, verbose, debug, silly
以上代码通过不同级别记录日志,默认情况下会在控制台打印出和保存到本地文件,
日志默认保存在app.getPath('userData')目录下的log.log文件中,
这个时候你会发现日志的时间和日志级别,日志内容都记录下来了,有这些信息我们就可以更好的跟踪bug等信息了。当然这个依赖不止这些功能:
我们可以设置log路径和文件名:
1 zlog.transports .file .resolvePath = () => path.join (filepath, filename);
我们可以格式化日志内容:
1 zlog.transports .file .format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}'
也可以通过log.transports.file.level和log.transports.console.level来分别设置日志输出目标和日志输出等级。
如果想禁止Console中输出可以设置对应项为false
1 2 zlog.transports .file .level = true ; zlog.transports .console .level = false ;
虽然有了这些日志信息,但是都在不同用户的电脑上,我们可以开发一个程序,在适当的时候把用户日志传送到web服务器上去,这样让我们更好的跟踪!
渲染进程 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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}
页面中引用
1 2 import {logger} from "./assets/js/mylog" ;logger.info ("登录初始化" );
主进程网络日志 Electron有主进程和渲染进程,一般呢我们通过渲染进程的控制台network就可以看到程序发起的网络请求。但是使用这个方法呢会有三个问题:
无法监控主进程发起的网络请求;
Electron呢可能会有多个窗口,不同的窗口发起不同的请求可能存在关联关系,就需要联合监控,就非常麻烦。
无法精确的分析某个时段的网络请求。
为了弥补这方面的不足,Electron提供了netLog模块,允许开发人员通过编程的方式记录网络请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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
1 2 3 4 5 6 7 8 9 10 const {crashReporter} = require ('electron' )crashReporter.start ({ productName :'myblog' , companyName :'psvmc' , submitURL :'https://www.psvmc.cn' , uploadToServer :false }) console .info (crashReporter.getCrashesDirectory ());
可以调用以下方法模拟崩溃
官方说可以设置崩溃日志的目录,但是我这里设置无效
1 2 3 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#%E4%BA%8B%E4%BB%B6-render-process-gone
代码
1 2 3 4 5 const { app } = require ('electron' )app.on ('child-process-gone' , (event, details ) => { console .log (details); })
崩毁重启
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 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 (); } }