diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-01-12 13:30:46 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-01-15 13:32:09 +0100 |
| commit | fd02a14f3fad35f49cfd7b9deb3aae02fcf9dda2 (patch) | |
| tree | 1515c4cef215db8bc1487c50ccf30de06182eff3 /gui/src/main | |
| parent | e0e9fe815b047fbc75e3bf01eea95133ae7c035f (diff) | |
| download | mullvadvpn-fd02a14f3fad35f49cfd7b9deb3aae02fcf9dda2.tar.xz mullvadvpn-fd02a14f3fad35f49cfd7b9deb3aae02fcf9dda2.zip | |
Implement logging functionality
Diffstat (limited to 'gui/src/main')
| -rw-r--r-- | gui/src/main/logging.ts | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/gui/src/main/logging.ts b/gui/src/main/logging.ts new file mode 100644 index 0000000000..fb21c54b48 --- /dev/null +++ b/gui/src/main/logging.ts @@ -0,0 +1,103 @@ +import { app } from 'electron'; +import fs from 'fs'; +import path from 'path'; +import { IpcMainEventChannel } from '../shared/ipc-event-channel'; +import { LogLevel, ILogInput, ILogOutput } from '../shared/logging-types'; + +export const OLD_LOG_FILES = ['frontend-renderer.log']; + +export class FileOutput implements ILogOutput { + private fileDescriptor?: number; + + constructor(public level: LogLevel, private filePath: string) { + try { + this.fileDescriptor = fs.openSync(filePath, fs.constants.O_CREAT | fs.constants.O_WRONLY); + } catch (e) { + console.error(`Failed to open ${this.filePath}`); + } + } + + public dispose() { + if (this.fileDescriptor) { + try { + fs.closeSync(this.fileDescriptor); + } catch (e) { + console.error(`Failed to close ${this.filePath}`); + } + } + } + + public write(_level: LogLevel, message: string) { + if (this.fileDescriptor) { + fs.write(this.fileDescriptor, `${message}\n`, (err) => { + if (err) { + console.error(`Failed to log to ${this.filePath}`); + } + }); + } + } +} + +export class IpcInput implements ILogInput { + public on(handler: (level: LogLevel, message: string) => void) { + IpcMainEventChannel.logging.handleLog(({ level, message }) => handler(level, message)); + } +} + +export function getMainLogPath() { + return path.join(getLogDirectoryDir(), 'main.log'); +} + +export function getRendererLogPath() { + return path.join(getLogDirectoryDir(), 'renderer.log'); +} + +export function createLoggingDirectory(): void { + try { + fs.mkdirSync(getLogDirectoryDir(), { recursive: true }); + } catch (e) { + console.error('Failed to create logging directory'); + } +} + +// When cleaning up old log files they are first backed up and the next time removed. +export function cleanUpLogDirectory(fileNames: string[]): void { + fileNames.forEach((fileName) => { + const filePath = path.join(getLogDirectoryDir(), fileName); + rotateOrDeleteFile(filePath); + }); +} + +export function backupLogFile(filePath: string): boolean { + const backupFilePath = getBackupFilePath(filePath); + try { + fs.accessSync(filePath); + fs.renameSync(filePath, backupFilePath); + return true; + } catch (e) { + console.error(`Failed to backup ${filePath}`); + return false; + } +} + +export function rotateOrDeleteFile(filePath: string): void { + if (!backupLogFile(filePath)) { + const backupFilePath = getBackupFilePath(filePath); + try { + fs.accessSync(backupFilePath); + fs.unlinkSync(backupFilePath); + } catch (e) { + console.error(`Failed to delete ${filePath}`); + } + } +} + +function getBackupFilePath(filePath: string): string { + const parsedPath = path.parse(filePath); + parsedPath.base = parsedPath.name + '.old' + parsedPath.ext; + return path.normalize(path.format(parsedPath)); +} + +function getLogDirectoryDir() { + return app.getPath('logs'); +} |
