This is a wrapper for a bunyan logger that writes log messages to a log file instead of stdout. It is useful for local development when you want to see log messages in the console but also want to save them to an easier-to-read file.

import bunyan from 'bunyan';
import fs from 'fs';
import path from 'path';
import { Writable } from 'stream';

const logFilePath = path.join(__dirname, 'logs', 'app.log');

class MsgOnlyStream extends Writable {
  _write(chunk: any, _: string, callback: (error?: Error) => void) {
    let logRecord: any;
    try {
      logRecord = JSON.parse(chunk.toString());
    } catch (error) {
      callback(error);
      return;
    }

    if (logRecord.msg) {
      console.log(logRecord.msg);
      fs.appendFileSync(logFilePath, logRecord.msg + '\n');
    }
    callback();
  }
}

export function createLocalLogger() {
  const logDir = path.dirname(logFilePath);

  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir, { recursive: true });
  }

  fs.writeFileSync(logFilePath, '');

  const logger = bunyan.createLogger({
    name: 'asset-inventory-service',
    streams: [
      {
        level: 'trace',
        stream: new MsgOnlyStream(),
      },
      {
        level: 'trace',
        stream: process.stdout,
      },
    ],
  });

  // use the same streams for child loggers
  const originalChildMethod = logger.child.bind(logger);
  logger.child = (options, simple) => {
    const childLogger = originalChildMethod(options, simple);
    childLogger.streams = (logger as any).streams; // not exposed but writable
    return childLogger;
  };

  return logger;
}