megahertz / electron-log

Simple logging module Electron/Node.js/NW.js application. No dependencies. No complicated configuration.
MIT License
1.32k stars 128 forks source link

TypeError with electron 17.1.0 when using electron-log in main process #391

Closed agnel-inveox closed 10 months ago

agnel-inveox commented 11 months ago

I get an error with electron 17.1.0, when using electron-log 5.0.0 in main process:

TypeError: Cannot read properties of undefined (reading 'level')
     at Function.writeFn (C:\Users\agnel.waghela\Documents\interceptor-electron\node_modules\electron-log\src\main\transports\console.js:44:51)
     at Logger.defaultLogger.processInternalErrorFn (C:\Users\agnel.waghela\Documents\interceptor-electron\node_modules\electron-log\src\main\index.js:29:36)
     at Logger.processMessage (C:\Users\agnel.waghela\Documents\interceptor-electron\node_modules\electron-log\src\core\Logger.js:171:14)
     at Logger.logData (C:\Users\agnel.waghela\Documents\interceptor-electron\node_modules\electron-log\src\core\Logger.js:124:10)
     at Logger.<computed> [as info] (C:\Users\agnel.waghela\Documents\interceptor-electron\node_modules\electron-log\src\core\Logger.js:79:37)
     at archiveLog (C:\Users\agnel.waghela\Documents\interceptor-electron\build\electron\Logger.js:104:16)
     at rotateLogFile (C:\Users\agnel.waghela\Documents\interceptor-electron\build\electron\Logger.js:176:5)
     at C:\Users\agnel.waghela\Documents\interceptor-electron\build\electron\Logger.js:360:21
     at step (C:\Users\agnel.waghela\Documents\interceptor-electron\build\electron\Logger.js:44:23)
     at Object.next (C:\Users\agnel.waghela\Documents\interceptor-electron\build\electron\Logger.js:25:53)

I've imported electron-log like this:

import * as Logger from 'electron-log';

below is partial code I'm using in a file Logger.ts

Logger.transports.file.level = 'debug';
Logger.transports.file.format = '[{iso}] [{level}] {text}';

Logger.errorHandler.startCatching();

Logger.eventLogger.events = {
  app: {
    'certificate-error': true,
    'child-process-gone': true,
    'render-process-gone': true,
    'will-finish-launching': true,
    'window-all-closed': true,
    'before-quit': true,
    'will-quit': true,
    quit: true,
    'second-instance': true,
    activate: true,
  },
  webContents: {
    crashed: true,
    'gpu-process-crashed': true,
    'did-fail-load': true,
    'did-fail-provisional-load': true,
    'plugin-crashed': true,
    'preload-error': true,
    unresponsive: true,
  },
};

Logger.eventLogger.level = 'info';

Logger.eventLogger.startLogging();

/**
 * Archive log file by renaming it to include timestamp
 *
 * @param oldLogFile Log file to be archived
 */
const archiveLog: Logger.FileTransport['archiveLogFn'] = oldLogFile => {
  const file = oldLogFile.path;
  const info = path.parse(file);
  const archiveFileName = `${info.name}-${getLogFileTimestamp()}${info.ext}`;

  try {
    renameSync(file, path.join(info.dir, archiveFileName));
    Logger.info('log file is archived as: ', archiveFileName);
  } catch (e) {
    Logger.warn('Could not rotate log', e);
  }
};

Logger.transports.file.archiveLogFn = archiveLog;

/**
 * for every log message we check if the log file
 * creation date (yyyy-mm-dd) is greater than the current date
 * then we rotate the log file
 * this ensures that log file doesn't contain log messages
 * of another day in it
 */
const rotateLogWhenDayChanges: Logger.TransformFn = ({ data, message }) => {
  /**
   * When the log entry was created
   */
  const { date: logDate } = message;

  if (logDate.setHours(0, 0, 0, 0) > getLogFileCreationTimeStamp()) {
    rotateLogFile();
  }

  return data;
};

Logger.transports.file.transforms.push(rotateLogWhenDayChanges);

/**
 * Get the log file creation timestamp i.e. birthtime
 * it is the timestamp of the log file containing
 * only the date
 *
 * @returns timestamp
 */
function getLogFileCreationTimeStamp() {
  const logFilePath = Logger.transports.file.getFile().path;
  const fileStats = statSync(logFilePath);
  // date without time
  return new Date(fileStats.birthtime).setHours(0, 0, 0, 0);
}

/**
 * Rotate log file manually
 */
export function rotateLogFile() {
  // get the file
  const logFile = Logger.transports.file.getFile();

  // archive the file manually
  archiveLog(logFile);
}

export default Logger;

I'm then importing this exported Logger in other places to log messages, which works pretty well and logs the messages in the log file. But somehow it fails with that TypeError: ... message shared at the beginning, when the rotateLogFile method is called in an async function (this functions does nothing but uploads the logs files to a server).

Any idea why all of a sudden the Logger is undefined after the file is renamed in the archiveLog method done using the renameSync statement in that method ???

the signature of that method for uploading logfiles is as follows (defined in the same Logger.ts file):

export async function archiveAndPublishLogFiles() {
   // archive the log file
  rotateLogFile();

  // upload the log file
  await uploadLogFiles();
}

/**
 * upload log files to the server
 * files are uploaded one at a time.
 */
export async function uploadLogFiles() {
  const logFiles = readUnsyncedLogFiles();

  if (logFiles.length > 0) {
    for (const file of logFiles) {
      const formData = new FormData();
      formData.append(
        'files',
        readFileSync(`${app.getPath('logs')}/${file.name}`, {
          encoding: Encodings.UTF8,
        }),
        file.name
      );

      Logger.info(`uploading ${file.name}...`);

      try {
        // upload the log files using axios post method
        const result = await axios.post(
          ...
        );

        if (result && result.status === StatusCodes.OK) {
          Logger.info(`${file.name} uploaded successfully`);
        }
      } catch (error: any) {
        Logger.error(
          `error while uploading ${file.name}`,
          error?.response?.data,
          error
        );
      }
    }
  } else {
    Logger.info('No log files to upload.');
  }
}
megahertz commented 11 months ago

Wildcard import isn't supported

agnel-inveox commented 11 months ago

Wildcard import isn't supported

ok. is this the cause of that error? because it did seem to work without any error before I introduced rotateLogWhenDayChanges.

megahertz commented 11 months ago

You should also update the lib to the latest version. A similar issue was fixed two weeks ago.

agnel-inveox commented 11 months ago

You should also update the lib to the latest version. A similar issue was fixed two weeks ago.

Makes sense. Will update the lib. and what about the best approach for importing the lib? any suggestions?

And just to confirm the latest lib is 5.0.3 as indicated on npm.

megahertz commented 11 months ago

Default export should be used.

megahertz commented 10 months ago

It should be fixed in the latest version. Let me know if you still have the issue.