Add sync history backend

This commit is contained in:
Andras Schmelczer 2024-12-20 16:15:48 +00:00
parent 4a4d8c6d1a
commit f552ac4abc
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
3 changed files with 179 additions and 12 deletions

View file

@ -0,0 +1,77 @@
import { Notice } from "obsidian";
export enum LogLevel {
DEBUG = "DEBUG",
INFO = "INFO",
WARNING = "WARNING",
ERROR = "ERROR",
}
class LogLine {
public constructor(public level: LogLevel, public message: string) {}
public toString(): string {
return `${this.formatLevel()}: ${this.message}`;
}
private formatLevel(): string {
switch (this.level) {
case LogLevel.DEBUG:
return "DEBUG";
case LogLevel.INFO:
return "INFO";
case LogLevel.WARNING:
return "WARNING";
case LogLevel.ERROR:
return "ERROR";
default:
return "UNKNOWN";
}
}
}
export class Logger {
private static readonly MAX_MESSAGES = 1000;
private static instance: Logger | null = null;
private readonly messages: LogLine[] = [];
private constructor() {} // eslint-disable-line @typescript-eslint/no-empty-function
public static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
public debug(message: string): void {
this.pushMessage(message, LogLevel.DEBUG);
}
public info(message: string): void {
this.pushMessage(message, LogLevel.INFO);
}
public warn(message: string): void {
this.pushMessage(message, LogLevel.WARNING);
}
public error(message: string): void {
this.pushMessage(message, LogLevel.ERROR);
new Notice(message, 5000);
}
public getMessages(mininumSeverity: LogLevel): LogLine[] {
return this.messages.filter(
(message) => message.level >= mininumSeverity
);
}
private pushMessage(message: string, level: LogLevel): void {
this.messages.push(new LogLine(level, message));
if (this.messages.length > Logger.MAX_MESSAGES) {
this.messages.shift();
}
}
}

View file

@ -0,0 +1,94 @@
import type { RelativePath } from "src/database/document-metadata";
import { Logger } from "./logger";
export interface CommonHistoryEntry {
status: SyncStatus;
relativePath: RelativePath;
message: string;
type?: SyncType;
source?: SyncSource;
}
export enum SyncType {
CREATE = "CREATE",
UPDATE = "UPDATE",
DELETE = "DELETE",
}
export enum SyncSource {
PUSH = "PUSH",
PULL = "PULL",
}
export enum SyncStatus {
NO_OP = "NO_OP",
SUCCESS = "SUCCESS",
ERROR = "ERROR",
}
export type HistoryEntry = CommonHistoryEntry & { timestamp: Date };
export interface HistoryStats {
success: number;
error: number;
}
export class SyncHistory {
private static readonly MAX_ENTRIES = 1000;
private entries: HistoryEntry[] = [];
private readonly requestCountListeners: ((status: HistoryStats) => void)[] =
[];
private status: HistoryStats = {
success: 0,
error: 0,
};
public getMessages(): HistoryEntry[] {
return this.entries;
}
public reset(): void {
this.entries = [];
this.status = {
success: 0,
error: 0,
};
this.requestCountListeners.forEach((listener) => {
listener(this.status);
});
}
public addSyncHistoryStatsChangeListener(
listener: (status: HistoryStats) => void
): void {
this.requestCountListeners.push(listener);
listener({ ...this.status });
}
public addHistoryEntry(entry: CommonHistoryEntry): void {
const historyEntry = {
...entry,
timestamp: new Date(),
};
this.entries.push(historyEntry);
if (entry.status === SyncStatus.SUCCESS) {
this.status.success++;
Logger.getInstance().info(`Synced file: ${entry.relativePath}`);
} else if (entry.status === SyncStatus.ERROR) {
this.status.error++;
Logger.getInstance().error(
`Error syncing file: ${entry.relativePath} - ${entry.message}`
);
}
this.requestCountListeners.forEach((listener) => {
listener(this.status);
});
if (this.entries.length > SyncHistory.MAX_ENTRIES) {
this.entries.shift();
}
}
}

View file

@ -1,21 +1,17 @@
import { Plugin } from "obsidian";
import { RequestCountStatus, SyncService } from "src/services/sync-service";
import type { Plugin } from "obsidian";
import type { HistoryStats, SyncHistory } from "src/tracing/sync-history";
export class StatusBar {
private statusBarItem: HTMLElement;
private readonly statusBarItem: HTMLElement;
public constructor(plugin: Plugin, service: SyncService) {
public constructor(plugin: Plugin, history: SyncHistory) {
this.statusBarItem = plugin.addStatusBarItem();
service.addRequestCountChangeListener((status) =>
this.updateStatus(status)
history.addSyncHistoryStatsChangeListener((status) =>
{ this.updateStatus(status); }
);
}
private updateStatus({
waiting,
success,
failure,
}: RequestCountStatus): void {
this.statusBarItem.setText(`${waiting} 🔄 ${success}${failure}`);
private updateStatus({ success, error }: HistoryStats): void {
this.statusBarItem.setText(`${success}${error}`);
}
}