Skip to content

Commit

Permalink
Centralize log file and refactor desktop logging
Browse files Browse the repository at this point in the history
- Migrate to `electron-log` v5.X.X, centralizing log files to adhere to
  best-practices.
- Add critical event logging in the log file.
- Replace `ElectronLog` type with `LogFunctions` for better abstraction.
- Unify log handling in `desktop-runtime-error` by removing
  `renderer.log` due to `electron-log` v5 changes.
- Update and extend logger interfaces, removing 'I' prefix and adding
  common log levels to abstract `electron-log` completely.
- Move logger interfaces to the application layer as it's cross-cutting
  concern, meanwhile keeping the implementations in the infrastructure
  layer.
- Introduce `useLogger` hook for easier logging in Vue components.
- Simplify `WindowVariables` by removing nullable properties.
- Improve documentation to clearly differentiate between desktop and web
  versions, outlining specific features of each.
  • Loading branch information
undergroundwires committed Dec 2, 2023
1 parent 8f5d7ed commit 08dbfea
Show file tree
Hide file tree
Showing 40 changed files with 347 additions and 191 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@
- 🌍️ **Online**: [https://privacy.sexy](https://privacy.sexy).
- 🖥️ **Offline**: Download directly for: [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.8/privacy.sexy-Setup-0.12.8.exe), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.8/privacy.sexy-0.12.8.dmg), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.8/privacy.sexy-0.12.8.AppImage). For more options, see [here](#additional-install-options).

Online version does not require to run any software on your computer. Offline version has more functions such as running the scripts directly.
For a detailed comparison of features between the desktop and web versions of privacy.sexy, see [Desktop vs. Web Features](./docs/desktop-vs-web-features.md).

💡 You should apply your configuration from time to time (more than once). It would strengthen your privacy and security control because privacy.sexy and its scripts get better and stronger in every new version.
💡 Regularly applying your configuration with privacy.sexy is recommended, especially after each new release and major operating system updates. Each version updates scripts to enhance stability, privacy, and security.

[![privacy.sexy application](img/screenshot.png?raw=true )](https://privacy.sexy)

Expand Down
36 changes: 36 additions & 0 deletions docs/desktop-vs-web-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Desktop vs. Web Features

This table outlines the differences between the desktop and web versions of `privacy.sexy`.

| Feature | Desktop | Web |
| ------- |---------|-----|
| [Usage without installation](#usage-without-installation) | 🔴 Not available | 🟢 Available |
| [Offline usage](#offline-usage) | 🟢 Available | 🟡 Partially available |
| [Auto-updates](#auto-updates) | 🟢 Available | 🟢 Available |
| [Logging](#logging) | 🟢 Available | 🔴 Not available |
| [Script execution](#script-execution) | 🟢 Available | 🔴 Not available |

## Feature Descriptions

### Usage without installation

The web version can be used directly in a browser without any installation, whereas the desktop version requires downloading and installing the software.

> **Note for Linux:** For Linux users, privacy.sexy is available as an AppImage, which is a portable format that does not require traditional installation. This means Linux users can use the desktop version without installation, similar to the web version.
### Offline usage

Once loaded, the web version can be used offline. The desktop version inherently supports offline usage.

### Auto-updates

Both versions automatically update to ensure you have the latest features and security enhancements.

### Logging

The desktop version supports logging of activities to aid in troubleshooting. This feature is not available in the web version.

### Script execution

Direct execution of scripts is possible in the desktop version, offering a more integrated experience.
This functionality is not present in the web version due to browser limitations.
19 changes: 11 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@juggle/resize-observer": "^3.4.0",
"ace-builds": "^1.30.0",
"cross-fetch": "^4.0.0",
"electron-log": "^4.4.8",
"electron-log": "^5.0.1",
"electron-progressbar": "^2.1.0",
"electron-updater": "^6.1.4",
"file-saver": "^2.0.5",
Expand Down
6 changes: 6 additions & 0 deletions src/application/Common/Log/Logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Logger {
info(...params: unknown[]): void;
warn(...params: unknown[]): void;
error(...params: unknown[]): void;
debug(...params: unknown[]): void;
}
5 changes: 5 additions & 0 deletions src/application/Common/Log/LoggerFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Logger } from '@/application/Common/Log/Logger';

export interface LoggerFactory {
readonly logger: Logger;
}
31 changes: 23 additions & 8 deletions src/infrastructure/Log/ConsoleLogger.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import { ILogger } from './ILogger';
import { Logger } from '@/application/Common/Log/Logger';

export class ConsoleLogger implements ILogger {
constructor(private readonly consoleProxy: Partial<Console> = console) {
export class ConsoleLogger implements Logger {
constructor(private readonly consoleProxy: ConsoleLogFunctions = globalThis.console) {
if (!consoleProxy) { // do not trust strictNullChecks for global objects
throw new Error('missing console');
}
}

public info(...params: unknown[]): void {
const logFunction = this.consoleProxy?.info;
if (!logFunction) {
throw new Error('missing "info" function');
}
logFunction.call(this.consoleProxy, ...params);
this.consoleProxy.info(...params);
}

public warn(...params: unknown[]): void {
this.consoleProxy.warn(...params);
}

public error(...params: unknown[]): void {
this.consoleProxy.error(...params);
}

public debug(...params: unknown[]): void {
this.consoleProxy.debug(...params);
}
}

interface ConsoleLogFunctions extends Partial<Console> {
readonly info: Console['info'];
readonly warn: Console['warn'];
readonly error: Console['error'];
readonly debug: Console['debug'];
}
22 changes: 10 additions & 12 deletions src/infrastructure/Log/ElectronLogger.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { ElectronLog } from 'electron-log';
import { ILogger } from './ILogger';
import log from 'electron-log/main';
import { Logger } from '@/application/Common/Log/Logger';
import type { LogFunctions } from 'electron-log';

// Using plain-function rather than class so it can be used in Electron's context-bridging.
export function createElectronLogger(logger: Partial<ElectronLog>): ILogger {
if (!logger) {
throw new Error('missing logger');
}
export function createElectronLogger(logger: LogFunctions = log): Logger {
return {
info: (...params) => {
if (!logger.info) {
throw new Error('missing "info" function');
}
logger.info(...params);
},
info: (...params) => logger.info(...params),
debug: (...params) => logger.debug(...params),
warn: (...params) => logger.warn(...params),
error: (...params) => logger.error(...params),
};
}

export const ElectronLogger = createElectronLogger();
3 changes: 0 additions & 3 deletions src/infrastructure/Log/ILogger.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/infrastructure/Log/ILoggerFactory.ts

This file was deleted.

10 changes: 8 additions & 2 deletions src/infrastructure/Log/NoopLogger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { ILogger } from './ILogger';
import { Logger } from '@/application/Common/Log/Logger';

export class NoopLogger implements ILogger {
export class NoopLogger implements Logger {
public info(): void { /* NOOP */ }

public warn(): void { /* NOOP */ }

public error(): void { /* NOOP */ }

public debug(): void { /* NOOP */ }
}
18 changes: 15 additions & 3 deletions src/infrastructure/Log/WindowInjectedLogger.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Logger } from '@/application/Common/Log/Logger';
import { WindowVariables } from '../WindowVariables/WindowVariables';
import { ILogger } from './ILogger';

export class WindowInjectedLogger implements ILogger {
private readonly logger: ILogger;
export class WindowInjectedLogger implements Logger {
private readonly logger: Logger;

constructor(windowVariables: WindowVariables | undefined | null = window) {
if (!windowVariables) { // do not trust strict null checks for global objects
Expand All @@ -17,4 +17,16 @@ export class WindowInjectedLogger implements ILogger {
public info(...params: unknown[]): void {
this.logger.info(...params);
}

public warn(...params: unknown[]): void {
this.logger.warn(...params);
}

public debug(...params: unknown[]): void {
this.logger.debug(...params);
}

public error(...params: unknown[]): void {
this.logger.error(...params);
}
}
6 changes: 3 additions & 3 deletions src/infrastructure/WindowVariables/WindowVariables.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { OperatingSystem } from '@/domain/OperatingSystem';
import { ISystemOperations } from '@/infrastructure/SystemOperations/ISystemOperations';
import { ILogger } from '@/infrastructure/Log/ILogger';
import { Logger } from '@/application/Common/Log/Logger';

/* Primary entry point for platform-specific injections */
export interface WindowVariables {
readonly isDesktop?: boolean;
readonly isDesktop: boolean;
readonly system?: ISystemOperations;
readonly os?: OperatingSystem;
readonly log?: ILogger;
readonly log: Logger;
}
10 changes: 5 additions & 5 deletions src/presentation/bootstrapping/ClientLoggerFactory.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { RuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/RuntimeEnvironment';
import { IRuntimeEnvironment } from '@/infrastructure/RuntimeEnvironment/IRuntimeEnvironment';
import { ConsoleLogger } from '@/infrastructure/Log/ConsoleLogger';
import { ILogger } from '@/infrastructure/Log/ILogger';
import { ILoggerFactory } from '@/infrastructure/Log/ILoggerFactory';
import { Logger } from '@/application/Common/Log/Logger';
import { LoggerFactory } from '@/application/Common/Log/LoggerFactory';
import { NoopLogger } from '@/infrastructure/Log/NoopLogger';
import { WindowInjectedLogger } from '@/infrastructure/Log/WindowInjectedLogger';

export class ClientLoggerFactory implements ILoggerFactory {
public static readonly Current: ILoggerFactory = new ClientLoggerFactory();
export class ClientLoggerFactory implements LoggerFactory {
public static readonly Current: LoggerFactory = new ClientLoggerFactory();

public readonly logger: ILogger;
public readonly logger: Logger;

protected constructor(environment: IRuntimeEnvironment = RuntimeEnvironment.CurrentEnvironment) {
if (environment.isDesktop) {
Expand Down
5 changes: 5 additions & 0 deletions src/presentation/bootstrapping/DependencyProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@/presentation/injectionSymbols';
import { PropertyKeys } from '@/TypeHelpers';
import { useUserSelectionState } from '@/presentation/components/Shared/Hooks/UseUserSelectionState';
import { useLogger } from '@/presentation/components/Shared/Hooks/UseLogger';

export function provideDependencies(
context: IApplicationContext,
Expand Down Expand Up @@ -57,6 +58,10 @@ export function provideDependencies(
return useUserSelectionState(state, events);
},
),
useLogger: (di) => di.provide(
InjectionKeys.useLogger,
useLogger,
),
};
registerAll(Object.values(resolvers), api);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ILogger } from '@/infrastructure/Log/ILogger';
import { Logger } from '@/application/Common/Log/Logger';
import { Bootstrapper } from '../Bootstrapper';
import { ClientLoggerFactory } from '../ClientLoggerFactory';

export class AppInitializationLogger implements Bootstrapper {
constructor(
private readonly logger: ILogger = ClientLoggerFactory.Current.logger,
private readonly logger: Logger = ClientLoggerFactory.Current.logger,
) { }

public async bootstrap(): Promise<void> {
Expand Down
4 changes: 3 additions & 1 deletion src/presentation/components/DevToolkit/DevToolkit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@

<script lang="ts">
import { defineComponent } from 'vue';
import { injectKey } from '@/presentation/injectionSymbols';
import { dumpNames } from './DumpNames';
export default defineComponent({
setup() {
const { log } = injectKey((keys) => keys.useLogger);
const devActions: readonly DevAction[] = [
{
name: 'Log script/category names',
handler: async () => {
const names = await dumpNames();
console.log(names);
log.info(names);
},
},
];
Expand Down
8 changes: 8 additions & 0 deletions src/presentation/components/Shared/Hooks/UseLogger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LoggerFactory } from '@/application/Common/Log/LoggerFactory';
import { ClientLoggerFactory } from '@/presentation/bootstrapping/ClientLoggerFactory';

export function useLogger(factory: LoggerFactory = ClientLoggerFactory.Current) {
return {
log: factory.logger,
};
}
6 changes: 3 additions & 3 deletions src/presentation/electron/main/Update/AutoUpdater.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { app, dialog } from 'electron';
import { autoUpdater, UpdateInfo } from 'electron-updater';
import { ProgressInfo } from 'electron-builder';
import log from 'electron-log';
import { ElectronLogger } from '@/infrastructure/Log/ElectronLogger';
import { UpdateProgressBar } from './UpdateProgressBar';

export async function handleAutoUpdate() {
Expand All @@ -23,11 +23,11 @@ function startHandlingUpdateProgress() {
On macOS, download-progress event is not called.
So the indeterminate progress will continue until download is finished.
*/
log.debug('@download-progress@\n', progress);
ElectronLogger.debug('@download-progress@\n', progress);
progressBar.showProgress(progress);
});
autoUpdater.on('update-downloaded', async (info: UpdateInfo) => {
log.info('@update-downloaded@\n', info);
ElectronLogger.info('@update-downloaded@\n', info);
progressBar.close();
await handleUpdateDownloaded();
});
Expand Down
Loading

0 comments on commit 08dbfea

Please sign in to comment.