Skip to main content

Using winston with electron

· 3 min read

Electron logs to stdout by default, so when you build a production app, those logs will not be saved anywhere. However winston opens up a whole plethora of options.

First install deps:

yarn add winston electron-is-dev
// logger.js

import winston from 'winston';
import util from 'util';
import isDev from 'electron-is-dev';
import { app } from 'electron';
import { join } from 'path';

// https://github.com/winstonjs/winston/issues/1427
const combineMessageAndSplat = () => ({
transform(info) {
const { [Symbol.for('splat')]: args = [], message } = info;
// eslint-disable-next-line no-param-reassign
info.message = util.format(message, ...args);
return info;
},
});

const createLogger = () => winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
combineMessageAndSplat(),
winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`),
),
});

const logDirPath = isDev ? '.' : app.getPath('userData');

const logger = createLogger();
logger.add(new winston.transports.File({ level: 'debug', filename: join(logDirPath, 'app.log'), options: { flags: 'a' } }));
if (isDev) logger.add(new winston.transports.Console());

export default logger;

⚠️ This assumes you're transpiling ESM, because Electron does not yet support ESM. Tip: You can use build-electron for this.

Then use your logger:

import logger from './logger.js';

logger.error('Some error happened', err);

This will make your app log to Library/Application\ Support/Your app/app.log (on MacOS, and accordingly on other platforms). When running in development it will still log to your console.

Example outputs:

logger.info({ someObj: 1 });
2022-09-04T14:28:09.278Z info: { someObj: 1 }

.

logger.info('test', 1, 'a', { b: 2, c: 3 });
2022-09-04T14:28:09.281Z info: test 1 a { b: 2, c: 3 }

.

logger.info('string');
2022-09-04T14:28:09.281Z info: string

.

logger.info({ a: 1, b: [{ c: [1] }] });
2022-09-04T14:28:09.281Z info: { a: 1, b: [ { c: [Array] } ] }

.

logger.info('1', '2', { a: 1 });
2022-09-04T14:28:09.281Z info: 1 2 { a: 1 }

.

logger.info([{}, '']);
2022-09-04T14:28:09.281Z info: [ {}, '' ]

.

logger.error(new Error('test1'), { additional: 'data' }, 'hmm');
2022-09-04T14:28:09.282Z error: Error: test1
at Object.<anonymous> (app.js:39:14)
at Module._compile (internal/modules/cjs/loader.js:968:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10)
at Module.load (internal/modules/cjs/loader.js:816:32)
at Module._load (internal/modules/cjs/loader.js:728:14)
at Function.Module._load (electron/js2c/asar.js:748:26)
at Module.require (internal/modules/cjs/loader.js:853:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (electron.js:9:16)
at Module._compile (internal/modules/cjs/loader.js:968:30) { additional: 'data' } hmm

.

logger.error('error occurred', new Error('test2'), { additional: 'data' }, 'hmm');
2022-09-04T14:28:09.283Z error: error occurred test2 Error: test2
at Object.<anonymous> (app.js:40:32)
at Module._compile (internal/modules/cjs/loader.js:968:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10)
at Module.load (internal/modules/cjs/loader.js:816:32)
at Module._load (internal/modules/cjs/loader.js:728:14)
at Function.Module._load (electron/js2c/asar.js:748:26)
at Module.require (internal/modules/cjs/loader.js:853:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (electron.js:9:16)
at Module._compile (internal/modules/cjs/loader.js:968:30) { additional: 'data' } hmm