aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-30 02:37:44 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-30 02:55:08 +0100
commit7db370fb877bfaa7bc7cd57764895fb4ab6d493c (patch)
treec1559d49a3343e3cc59c795a3f3cb781e36d7667
parentbuild: Switch to esbuild (diff)
downloadsophie-7db370fb877bfaa7bc7cd57764895fb4ab6d493c.tar.gz
sophie-7db370fb877bfaa7bc7cd57764895fb4ab6d493c.tar.zst
sophie-7db370fb877bfaa7bc7cd57764895fb4ab6d493c.zip
refactor: Improve logging
-rw-r--r--packages/main/package.json1
-rw-r--r--packages/main/src/controllers/config.ts32
-rw-r--r--packages/main/src/controllers/nativeTheme.ts10
-rw-r--r--packages/main/src/services/ConfigPersistenceService.ts39
-rw-r--r--packages/main/src/utils/logging.ts31
-rw-r--r--packages/renderer/src/index.tsx1
-rw-r--r--yarn.lock8
7 files changed, 79 insertions, 43 deletions
diff --git a/packages/main/package.json b/packages/main/package.json
index 76eff8e..a1af489 100644
--- a/packages/main/package.json
+++ b/packages/main/package.json
@@ -11,6 +11,7 @@
11 "dependencies": { 11 "dependencies": {
12 "@sophie/service-shared": "workspace:*", 12 "@sophie/service-shared": "workspace:*",
13 "@sophie/shared": "workspace:*", 13 "@sophie/shared": "workspace:*",
14 "chalk": "^5.0.0",
14 "electron": "16.0.5", 15 "electron": "16.0.5",
15 "json5": "^2.2.0", 16 "json5": "^2.2.0",
16 "lodash-es": "^4.17.21", 17 "lodash-es": "^4.17.21",
diff --git a/packages/main/src/controllers/config.ts b/packages/main/src/controllers/config.ts
index f2467c7..600a142 100644
--- a/packages/main/src/controllers/config.ts
+++ b/packages/main/src/controllers/config.ts
@@ -28,17 +28,16 @@ import { Disposer, getLogger } from '../utils';
28 28
29const DEFAULT_CONFIG_DEBOUNCE_TIME = ms('1s'); 29const DEFAULT_CONFIG_DEBOUNCE_TIME = ms('1s');
30 30
31const logger = getLogger('controller:config'); 31const log = getLogger('config');
32 32
33export async function initConfig( 33export async function initConfig(
34 config: Config, 34 config: Config,
35 persistenceService: ConfigPersistenceService, 35 persistenceService: ConfigPersistenceService,
36 debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME, 36 debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME,
37): Promise<Disposer> { 37): Promise<Disposer> {
38 logger.debug('Initializing controller'); 38 log.trace('Initializing config controller');
39 39
40 let lastSnapshotOnDisk: ConfigSnapshotOut | null = null; 40 let lastSnapshotOnDisk: ConfigSnapshotOut | null = null;
41 let writingConfig: boolean = false;
42 41
43 async function readConfig(): Promise<boolean> { 42 async function readConfig(): Promise<boolean> {
44 const result = await persistenceService.readConfig(); 43 const result = await persistenceService.readConfig();
@@ -46,9 +45,8 @@ export async function initConfig(
46 try { 45 try {
47 applySnapshot(config, result.data); 46 applySnapshot(config, result.data);
48 lastSnapshotOnDisk = getSnapshot(config); 47 lastSnapshotOnDisk = getSnapshot(config);
49 logger.debug('Loaded config');
50 } catch (err) { 48 } catch (err) {
51 logger.error('Failed to read config', result.data, err); 49 log.error('Failed to apply config snapshot', result.data, err);
52 } 50 }
53 } 51 }
54 return result.found; 52 return result.found;
@@ -56,23 +54,17 @@ export async function initConfig(
56 54
57 async function writeConfig(): Promise<void> { 55 async function writeConfig(): Promise<void> {
58 const snapshot = getSnapshot(config); 56 const snapshot = getSnapshot(config);
59 writingConfig = true; 57 await persistenceService.writeConfig(snapshot);
60 try { 58 lastSnapshotOnDisk = snapshot;
61 await persistenceService.writeConfig(snapshot);
62 lastSnapshotOnDisk = snapshot;
63 logger.debug('Wrote config');
64 } finally {
65 writingConfig = false;
66 }
67 } 59 }
68 60
69 if (!await readConfig()) { 61 if (!await readConfig()) {
70 logger.info('Config file was not found'); 62 log.info('Config file was not found');
71 try { 63 try {
72 await writeConfig(); 64 await writeConfig();
73 logger.info('Created config file'); 65 log.info('Created config file');
74 } catch (err) { 66 } catch (err) {
75 logger.error('Failed to initialize config'); 67 log.error('Failed to initialize config', err);
76 } 68 }
77 } 69 }
78 70
@@ -80,19 +72,17 @@ export async function initConfig(
80 // We can compare snapshots by reference, since it is only recreated on store changes. 72 // We can compare snapshots by reference, since it is only recreated on store changes.
81 if (lastSnapshotOnDisk !== snapshot) { 73 if (lastSnapshotOnDisk !== snapshot) {
82 writeConfig().catch((err) => { 74 writeConfig().catch((err) => {
83 logger.error('Failed to write config on config change', err); 75 log.error('Failed to write config on config change', err);
84 }) 76 })
85 } 77 }
86 }, debounceTime)); 78 }, debounceTime));
87 79
88 const disposeWatcher = persistenceService.watchConfig(async () => { 80 const disposeWatcher = persistenceService.watchConfig(async () => {
89 if (!writingConfig) { 81 await readConfig();
90 await readConfig();
91 }
92 }, debounceTime); 82 }, debounceTime);
93 83
94 return () => { 84 return () => {
95 logger.debug('Disposing controller'); 85 log.trace('Disposing config controller');
96 disposeWatcher(); 86 disposeWatcher();
97 disposeOnSnapshot(); 87 disposeOnSnapshot();
98 }; 88 };
diff --git a/packages/main/src/controllers/nativeTheme.ts b/packages/main/src/controllers/nativeTheme.ts
index 9f9bc21..9edb4e8 100644
--- a/packages/main/src/controllers/nativeTheme.ts
+++ b/packages/main/src/controllers/nativeTheme.ts
@@ -24,25 +24,25 @@ import { autorun } from 'mobx';
24import type { MainStore } from '../stores/MainStore'; 24import type { MainStore } from '../stores/MainStore';
25import { Disposer, getLogger } from '../utils'; 25import { Disposer, getLogger } from '../utils';
26 26
27const logger = getLogger('controller:nativeTheme'); 27const log = getLogger('nativeTheme');
28 28
29export function initNativeTheme(store: MainStore): Disposer { 29export function initNativeTheme(store: MainStore): Disposer {
30 logger.debug('Initializing controller'); 30 log.trace('Initializing nativeTheme controller');
31 31
32 const disposeThemeSourceReaction = autorun(() => { 32 const disposeThemeSourceReaction = autorun(() => {
33 nativeTheme.themeSource = store.config.themeSource; 33 nativeTheme.themeSource = store.config.themeSource;
34 logger.debug('Set theme source:', store.config.themeSource); 34 log.debug('Set theme source:', store.config.themeSource);
35 }); 35 });
36 36
37 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors); 37 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors);
38 const shouldUseDarkColorsListener = () => { 38 const shouldUseDarkColorsListener = () => {
39 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors); 39 store.setShouldUseDarkColors(nativeTheme.shouldUseDarkColors);
40 logger.debug('Set should use dark colors:', nativeTheme.shouldUseDarkColors); 40 log.debug('Set should use dark colors:', nativeTheme.shouldUseDarkColors);
41 }; 41 };
42 nativeTheme.on('updated', shouldUseDarkColorsListener); 42 nativeTheme.on('updated', shouldUseDarkColorsListener);
43 43
44 return () => { 44 return () => {
45 logger.debug('Disposing controller'); 45 log.trace('Disposing nativeTheme controller');
46 nativeTheme.off('updated', shouldUseDarkColorsListener); 46 nativeTheme.off('updated', shouldUseDarkColorsListener);
47 disposeThemeSourceReaction(); 47 disposeThemeSourceReaction();
48 }; 48 };
diff --git a/packages/main/src/services/ConfigPersistenceService.ts b/packages/main/src/services/ConfigPersistenceService.ts
index ee5eb9f..b2109f6 100644
--- a/packages/main/src/services/ConfigPersistenceService.ts
+++ b/packages/main/src/services/ConfigPersistenceService.ts
@@ -24,13 +24,17 @@ import throttle from 'lodash-es/throttle';
24import { join } from 'path'; 24import { join } from 'path';
25 25
26import type { ConfigSnapshotOut } from '../stores/Config'; 26import type { ConfigSnapshotOut } from '../stores/Config';
27import { Disposer } from '../utils'; 27import { Disposer, getLogger } from '../utils';
28
29const log = getLogger('configPersistence');
28 30
29export type ReadConfigResult = { found: true; data: unknown; } | { found: false; }; 31export type ReadConfigResult = { found: true; data: unknown; } | { found: false; };
30 32
31export class ConfigPersistenceService { 33export class ConfigPersistenceService {
32 private readonly configFilePath: string; 34 private readonly configFilePath: string;
33 35
36 private writingConfig = false;
37
34 private timeLastWritten: Date | null = null; 38 private timeLastWritten: Date | null = null;
35 39
36 constructor( 40 constructor(
@@ -47,10 +51,12 @@ export class ConfigPersistenceService {
47 configStr = await readFile(this.configFilePath, 'utf8'); 51 configStr = await readFile(this.configFilePath, 'utf8');
48 } catch (err) { 52 } catch (err) {
49 if ((err as NodeJS.ErrnoException).code === 'ENOENT') { 53 if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
54 log.debug('Config file', this.configFilePath, 'was not found');
50 return { found: false }; 55 return { found: false };
51 } 56 }
52 throw err; 57 throw err;
53 } 58 }
59 log.info('Read config file', this.configFilePath);
54 return { 60 return {
55 found: true, 61 found: true,
56 data: JSON5.parse(configStr), 62 data: JSON5.parse(configStr),
@@ -61,24 +67,42 @@ export class ConfigPersistenceService {
61 const configJson = JSON5.stringify(configSnapshot, { 67 const configJson = JSON5.stringify(configSnapshot, {
62 space: 2, 68 space: 2,
63 }); 69 });
64 await writeFile(this.configFilePath, configJson, 'utf8'); 70 this.writingConfig = true;
65 const stats = await stat(this.configFilePath); 71 try {
66 this.timeLastWritten = stats.mtime; 72 await writeFile(this.configFilePath, configJson, 'utf8');
73 const { mtime } = await stat(this.configFilePath);
74 log.trace('Config file', this.configFilePath, 'last written at', mtime);
75 this.timeLastWritten = mtime;
76 } finally {
77 this.writingConfig = false;
78 }
79 log.info('Wrote config file', this.configFilePath);
67 } 80 }
68 81
69 watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer { 82 watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer {
83 log.debug('Installing watcher for', this.userDataDir);
84
70 const configChanged = throttle(async () => { 85 const configChanged = throttle(async () => {
71 let mtime: Date; 86 let mtime: Date;
72 try { 87 try {
73 const stats = await stat(this.configFilePath); 88 const stats = await stat(this.configFilePath);
74 mtime = stats.mtime; 89 mtime = stats.mtime;
90 log.trace('Config file last modified at', mtime);
75 } catch (err) { 91 } catch (err) {
76 if ((err as NodeJS.ErrnoException).code === 'ENOENT') { 92 if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
93 log.debug('Config file', this.configFilePath, 'was deleted after being changed');
77 return; 94 return;
78 } 95 }
79 throw err; 96 throw err;
80 } 97 }
81 if (this.timeLastWritten === null || mtime > this.timeLastWritten) { 98 if (!this.writingConfig
99 && (this.timeLastWritten === null || mtime > this.timeLastWritten)) {
100 log.debug(
101 'Found a config file modified at',
102 mtime,
103 'whish is newer than last written',
104 this.timeLastWritten,
105 );
82 return callback(); 106 return callback();
83 } 107 }
84 }, throttleMs); 108 }, throttleMs);
@@ -96,6 +120,9 @@ export class ConfigPersistenceService {
96 } 120 }
97 }); 121 });
98 122
99 return () => watcher.close(); 123 return () => {
124 log.trace('Removing watcher for', this.configFilePath);
125 watcher.close();
126 };
100 } 127 }
101} 128}
diff --git a/packages/main/src/utils/logging.ts b/packages/main/src/utils/logging.ts
index 5cb5d21..6c4cba2 100644
--- a/packages/main/src/utils/logging.ts
+++ b/packages/main/src/utils/logging.ts
@@ -18,28 +18,37 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import chalk, { ChalkInstance } from 'chalk';
21import loglevel, { Logger } from 'loglevel'; 22import loglevel, { Logger } from 'loglevel';
22import prefix from 'loglevel-plugin-prefix'; 23import prefix from 'loglevel-plugin-prefix';
23 24
24const isDevelopment = import.meta.env.MODE === 'development'; 25if (import.meta.env.DEV) {
26 loglevel.setLevel('debug');
27} else {
28 loglevel.setLevel('info');
29}
30
31const COLORS: Partial<Record<string, ChalkInstance>> = {
32 TRACE: chalk.magenta,
33 DEBUG: chalk.cyan,
34 INFO: chalk.blue,
35 WARN: chalk.yellow,
36 ERROR: chalk.red,
37 CRITICAL: chalk.red,
38};
25 39
26if (isDevelopment) { 40function getColor(level: string): ChalkInstance {
27 loglevel.enableAll(); 41 return COLORS[level] ?? chalk.gray;
28} 42}
29 43
30prefix.reg(loglevel); 44prefix.reg(loglevel);
31prefix.apply(loglevel, { 45prefix.apply(loglevel, {
32 format(level, name, timestamp) { 46 format(level, name, timestamp) {
33 let shortName = 'global'; 47 const levelColor = getColor(level);
34 if (name !== undefined) { 48 return `${chalk.gray(`[${timestamp}]`)} ${levelColor(level)} ${chalk.green(`${name}:`)}`;
35 const nameSegments = name.split(':');
36 const lastSegment = nameSegments.pop();
37 shortName = [...nameSegments.map((segment) => segment[0]), lastSegment].join(':');
38 }
39 return `[${timestamp}] ${level} (${shortName})`;
40 }, 49 },
41}); 50});
42 51
43export function getLogger(loggerName: string): Logger { 52export function getLogger(loggerName: string): Logger {
44 return loglevel.getLogger(`sophie:${loggerName}`); 53 return loglevel.getLogger(loggerName);
45} 54}
diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx
index befb823..5e943b3 100644
--- a/packages/renderer/src/index.tsx
+++ b/packages/renderer/src/index.tsx
@@ -36,6 +36,7 @@ const isDevelopment = import.meta.env.MODE === 'development';
36 36
37if (isDevelopment) { 37if (isDevelopment) {
38 hotReloadServices(); 38 hotReloadServices();
39 document.title = `[dev] ${document.title}`;
39} 40}
40 41
41const store = createAndConnectRendererStore(window.sophieRenderer); 42const store = createAndConnectRendererStore(window.sophieRenderer);
diff --git a/yarn.lock b/yarn.lock
index 8d6a6dd..3275576 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1203,6 +1203,7 @@ __metadata:
1203 "@types/lodash-es": ^4.17.5 1203 "@types/lodash-es": ^4.17.5
1204 "@types/ms": ^0.7.31 1204 "@types/ms": ^0.7.31
1205 "@types/node": ^17.0.5 1205 "@types/node": ^17.0.5
1206 chalk: ^5.0.0
1206 electron: 16.0.5 1207 electron: 16.0.5
1207 electron-devtools-installer: ^3.2.0 1208 electron-devtools-installer: ^3.2.0
1208 esbuild: ^0.14.9 1209 esbuild: ^0.14.9
@@ -2353,6 +2354,13 @@ __metadata:
2353 languageName: node 2354 languageName: node
2354 linkType: hard 2355 linkType: hard
2355 2356
2357"chalk@npm:^5.0.0":
2358 version: 5.0.0
2359 resolution: "chalk@npm:5.0.0"
2360 checksum: 6eba7c518b9aa5fe882ae6d14a1ffa58c418d72a3faa7f72af56641f1bbef51b645fca1d6e05d42357b7d3c846cd504c0b7b64d12309cdd07867e3b4411e0d01
2361 languageName: node
2362 linkType: hard
2363
2356"char-regex@npm:^1.0.2": 2364"char-regex@npm:^1.0.2":
2357 version: 1.0.2 2365 version: 1.0.2
2358 resolution: "char-regex@npm:1.0.2" 2366 resolution: "char-regex@npm:1.0.2"