Refactor error logging

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/6/head
trivernis 2 years ago
parent 26817cfec9
commit dd6107d1fd
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,3 +1,5 @@
@import "src/colors";
::ng-deep .mat-button-wrapper > ng-icon {
font-size: 26px;
}
@ -5,3 +7,11 @@
::ng-deep ng-icon {
font-size: 24px;
}
::ng-deep .app-warn {
background-color: $warn-chill;
}
::ng-deep .app-error {
background-color: $warn;
}

@ -1,7 +1,9 @@
import {Component, OnInit} from "@angular/core";
import {RepositoryService} from "./services/repository/repository.service";
import {MatSnackBar} from "@angular/material/snack-bar";
import {ErrorBrokerService} from "./services/error-broker/error-broker.service";
import {LoggingService} from "./services/logging/logging.service";
import {LogEntry, LogLevel} from "./services/logging/LogEntry";
import {environment} from "../environments/environment";
@Component({
selector: "app-root",
@ -13,21 +15,39 @@ export class AppComponent implements OnInit {
constructor(
private snackBar: MatSnackBar,
private errorBroker: ErrorBrokerService,
private logger: LoggingService,
private repoService: RepositoryService,
) {
}
async ngOnInit() {
this.errorBroker.errorCb = (err: { message: string }) => this.showError(
err);
this.errorBroker.infoCb = (info: string) => this.showInfo(info);
this.logger.logs.subscribe(entry => {
this.logEntry(entry);
switch (entry.getLevel()) {
case LogLevel.Info:
this.showInfo(entry.getMessage());
break;
case LogLevel.Warn:
this.showWarning(entry.getMessage());
break;
case LogLevel.Error:
this.showError(entry.getMessage());
break;
}
});
await this.repoService.loadRepositories();
}
private showError(err: { message: string }) {
this.snackBar.open(err.message, undefined, {
panelClass: "warn",
private showError(err: string) {
this.snackBar.open(err, undefined, {
panelClass: "app-error",
duration: 2000,
});
}
private showWarning(err: string) {
this.snackBar.open(err, undefined, {
panelClass: "app-warn",
duration: 2000,
});
}
@ -38,4 +58,26 @@ export class AppComponent implements OnInit {
duration: 2000,
});
}
private logEntry(entry: LogEntry) {
if (!environment.production) {
switch (entry.getLevel()) {
case LogLevel.Trace:
console.trace(entry.getMessage(), entry);
break;
case LogLevel.Debug:
console.debug(entry.getMessage(), entry);
break;
case LogLevel.Info:
console.info(entry.getMessage(), entry);
break;
case LogLevel.Warn:
console.warn(entry.getMessage(), entry);
break;
}
}
if (entry.getLevel() == LogLevel.Error) {
console.error(entry.getMessage(), entry.getError(), entry);
}
}
}

@ -6,7 +6,7 @@ import {DownloadDaemonDialogComponent} from "./download-daemon-dialog/download-d
import {
AddRepositoryDialogComponent
} from "../../shared/repository/repository/add-repository-dialog/add-repository-dialog.component";
import {ErrorBrokerService} from "../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../services/logging/logging.service";
import {BehaviorSubject} from "rxjs";
import {BusyDialogComponent} from "../../shared/app-common/busy-dialog/busy-dialog.component";
import {JobService} from "../../../services/job/job.service";
@ -24,7 +24,7 @@ export class RepositoriesTabComponent implements OnInit, AfterViewInit {
public selectedRepository?: Repository;
constructor(
private errorBroker: ErrorBrokerService,
private logger: LoggingService,
private repoService: RepositoryService,
private jobService: JobService,
private stateService: StateService,
@ -60,8 +60,8 @@ export class RepositoriesTabComponent implements OnInit, AfterViewInit {
});
}
await this.selectRepository(repository, dialogContext);
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.logger.error(err);
}
}
@ -75,7 +75,7 @@ export class RepositoriesTabComponent implements OnInit, AfterViewInit {
await this.repoService.loadRepositories();
dialogContext.dialog.close(true);
} catch (err: any) {
this.errorBroker.showError(err);
this.logger.error(err);
dialogContext.message.next(
"Failed to open repository: " + err.toString());
await this.forceCloseRepository();

@ -9,7 +9,7 @@ import {BehaviorSubject} from "rxjs";
import {BusyDialogComponent} from "../../app-common/busy-dialog/busy-dialog.component";
import {ConfirmDialogComponent, ConfirmDialogData} from "../../app-common/confirm-dialog/confirm-dialog.component";
import {MatDialog, MatDialogConfig, MatDialogRef} from "@angular/material/dialog";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
type ProgressDialogContext = {
dialog: MatDialogRef<BusyDialogComponent>,
@ -22,7 +22,7 @@ type ProgressDialogContext = {
template: "<h1>Do not use</h1>",
})
export class FileActionBaseComponent {
constructor(private dialog: MatDialog, private errorBroker: ErrorBrokerService, private fileService: FileService) {
constructor(private dialog: MatDialog, private errorBroker: LoggingService, private fileService: FileService) {
}
public async copyFileContentDescriptor(file: File): Promise<void> {

@ -12,7 +12,7 @@ import {SafeResourceUrl} from "@angular/platform-browser";
import {File} from "../../../../../api/models/File";
import {FileService} from "../../../../services/file/file.service";
import {FileHelper} from "../../../../services/file/file.helper";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
import {BusyIndicatorComponent} from "../../app-common/busy-indicator/busy-indicator.component";
type ContentType = "image" | "video" | "audio" | "other";
@ -33,7 +33,7 @@ export class ContentViewerComponent implements AfterViewInit, OnChanges, OnDestr
@ViewChild(BusyIndicatorComponent) busyIndicator!: BusyIndicatorComponent;
constructor(
private errorBroker: ErrorBrokerService,
private errorBroker: LoggingService,
private fileService: FileService
) {
}
@ -70,8 +70,8 @@ export class ContentViewerComponent implements AfterViewInit, OnChanges, OnDestr
if (path) {
try {
await this.fileService.saveFile(this.file, path);
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.errorBroker.error(err);
}
}
}

@ -2,7 +2,7 @@ import {Component, EventEmitter, OnChanges, Output, SimpleChanges, ViewChild} fr
import {File} from "../../../../../api/models/File";
import {ContextMenuComponent} from "../../app-common/context-menu/context-menu.component";
import {FileService} from "../../../../services/file/file.service";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
import {MatDialog, MatDialogRef} from "@angular/material/dialog";
import {BusyDialogComponent} from "../../app-common/busy-dialog/busy-dialog.component";
import {BehaviorSubject} from "rxjs";
@ -34,7 +34,7 @@ export class FileContextMenuComponent extends FileActionBaseComponent implements
@Output() fileDeleted = new EventEmitter<File[]>();
@Output() fileStatusChange = new EventEmitter<File[]>();
constructor(fileService: FileService, errorBroker: ErrorBrokerService, dialog: MatDialog) {
constructor(fileService: FileService, errorBroker: LoggingService, dialog: MatDialog) {
super(dialog, errorBroker, fileService);
}

@ -4,7 +4,7 @@ import {FileGalleryComponent} from "./file-gallery/file-gallery.component";
import {FileGridComponent} from "./file-grid/file-grid.component";
import {FileActionBaseComponent} from "../../app-base/file-action-base/file-action-base.component";
import {MatDialog} from "@angular/material/dialog";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
import {FileService} from "../../../../services/file/file.service";
import {TabState} from "../../../../models/TabState";
@ -29,7 +29,7 @@ export class FileMultiviewComponent extends FileActionBaseComponent implements A
public selectedFiles: File[] = [];
@Input() public preselectedFile: File | undefined;
constructor(dialog: MatDialog, errorBroker: ErrorBrokerService, fileService: FileService) {
constructor(dialog: MatDialog, errorBroker: LoggingService, fileService: FileService) {
super(dialog, errorBroker, fileService);
}

@ -1,14 +1,8 @@
import {Component, Inject, ViewChild} from "@angular/core";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {
RepositoryFormComponent
} from "../repository-form/repository-form.component";
import {
RepositoryService
} from "../../../../../services/repository/repository.service";
import {
ErrorBrokerService
} from "../../../../../services/error-broker/error-broker.service";
import {RepositoryFormComponent} from "../repository-form/repository-form.component";
import {RepositoryService} from "../../../../../services/repository/repository.service";
import {LoggingService} from "../../../../../services/logging/logging.service";
@Component({
selector: "app-add-repository-dialog",
@ -21,9 +15,10 @@ export class AddRepositoryDialogComponent {
constructor(
public repoService: RepositoryService,
public errorBroker: ErrorBrokerService,
public errorBroker: LoggingService,
public dialogRef: MatDialogRef<AddRepositoryDialogComponent>,
@Inject(MAT_DIALOG_DATA) data: any) {
@Inject(MAT_DIALOG_DATA) data: any
) {
}
public async checkLocalRepoExists() {
@ -35,22 +30,23 @@ export class AddRepositoryDialogComponent {
const path = this.repositoryForm.formGroup.value.path;
try {
await this.repoService.initRepository(path);
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.errorBroker.error(err);
}
await this.checkLocalRepoExists();
}
public async addRepository() {
let {name, repositoryType, path, address} = this.repositoryForm.formGroup.value;
let { name, repositoryType, path, address } = this.repositoryForm.formGroup.value;
path = repositoryType === "local" ? path : undefined;
address = repositoryType === "remote" ? address : undefined;
try {
await this.repoService.addRepository(name, path, address,
repositoryType === "local");
repositoryType === "local"
);
this.dialogRef.close();
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.errorBroker.error(err);
}
}

@ -1,13 +1,7 @@
import {Component, Inject, ViewChild} from "@angular/core";
import {
RepositoryFormComponent
} from "../repository-form/repository-form.component";
import {
RepositoryService
} from "../../../../../services/repository/repository.service";
import {
ErrorBrokerService
} from "../../../../../services/error-broker/error-broker.service";
import {RepositoryFormComponent} from "../repository-form/repository-form.component";
import {RepositoryService} from "../../../../../services/repository/repository.service";
import {LoggingService} from "../../../../../services/logging/logging.service";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {Repository} from "../../../../../../api/models/Repository";
@ -25,9 +19,10 @@ export class EditRepositoryDialogComponent {
constructor(
public repoService: RepositoryService,
public errorBroker: ErrorBrokerService,
public errorBroker: LoggingService,
public dialogRef: MatDialogRef<EditRepositoryDialogComponent>,
@Inject(MAT_DIALOG_DATA) data: any) {
@Inject(MAT_DIALOG_DATA) data: any
) {
this.selectedRepository = data.repository;
this.originalName = this.selectedRepository.name;
}
@ -41,14 +36,14 @@ export class EditRepositoryDialogComponent {
const path = this.repositoryForm.formGroup.value.path;
try {
await this.repoService.initRepository(path);
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.errorBroker.error(err);
}
await this.checkLocalRepoExists();
}
public async addRepository() {
let {name, repositoryType, path, address} = this.repositoryForm.formGroup.value;
let { name, repositoryType, path, address } = this.repositoryForm.formGroup.value;
path = repositoryType === "local" ? path : undefined;
address = repositoryType === "remote" ? address : undefined;
@ -61,12 +56,13 @@ export class EditRepositoryDialogComponent {
await this.repoService.removeRepository(this.originalName);
}
await this.repoService.addRepository(name, path, address,
repositoryType === "local");
this.selectedRepository.update({name, local: repositoryType === "local", path, address});
repositoryType === "local"
);
this.selectedRepository.update({ name, local: repositoryType === "local", path, address });
this.dialogRef.close();
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.errorBroker.error(err);
}
}

@ -1,6 +1,6 @@
import {Component, EventEmitter, Output} from "@angular/core";
import {ImportService} from "../../../../../services/import/import.service";
import {ErrorBrokerService} from "../../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../../services/logging/logging.service";
import {AddFileOptions} from "../../../../../models/AddFileOptions";
import {File} from "../../../../../../api/models/File";
import {DialogFilter} from "@tauri-apps/api/dialog";
@ -36,7 +36,7 @@ export class FilesystemImportComponent {
public importing = false;
public importingProgress = 0;
constructor(private errorBroker: ErrorBrokerService, private importService: ImportService) {
constructor(private errorBroker: LoggingService, private importService: ImportService) {
}
public async setSelectedPaths(paths: string[]) {
@ -44,9 +44,9 @@ export class FilesystemImportComponent {
try {
this.files = await this.importService.resolvePathsToFiles(paths);
this.fileCount = this.files.length;
} catch (err) {
} catch (err: any) {
console.log(err);
this.errorBroker.showError(err);
this.errorBroker.error(err);
}
this.resolving = false;
}
@ -64,9 +64,9 @@ export class FilesystemImportComponent {
this.importOptions
);
this.fileImported.emit(resultFile);
} catch (err) {
} catch (err: any) {
console.log(err);
this.errorBroker.showError(err);
this.errorBroker.error(err);
}
count++;
this.importingProgress = (count / this.fileCount) * 100;

@ -12,7 +12,7 @@ import {
import {SortKey} from "../../../../models/SortKey";
import {MatDialog} from "@angular/material/dialog";
import {SortDialogComponent} from "./sort-dialog/sort-dialog.component";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
import {FilterDialogComponent} from "./filter-dialog/filter-dialog.component";
import {Tag} from "../../../../../api/models/Tag";
import {clipboard} from "@tauri-apps/api";
@ -57,7 +57,7 @@ export class FileSearchComponent implements AfterViewChecked, OnInit {
private needsScroll = false;
constructor(
private errorBroker: ErrorBrokerService,
private logger: LoggingService,
public dialog: MatDialog
) {
this.assignDisplayedFilters();
@ -85,8 +85,8 @@ export class FileSearchComponent implements AfterViewChecked, OnInit {
this.searchStartEvent.emit();
try {
await this.state.findFiles();
} catch (err) {
this.errorBroker.showError(err);
} catch (err: any) {
this.logger.error(err);
}
this.searchEndEvent.emit();
}

@ -13,7 +13,7 @@ import {File} from "../../../../../api/models/File";
import {Tag} from "../../../../../api/models/Tag";
import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling";
import {TagService} from "../../../../services/tag/tag.service";
import {ErrorBrokerService} from "../../../../services/error-broker/error-broker.service";
import {LoggingService} from "../../../../services/logging/logging.service";
import {BusyIndicatorComponent} from "../../app-common/busy-indicator/busy-indicator.component";
@Component({
@ -36,7 +36,7 @@ export class TagEditComponent implements AfterViewInit, OnChanges {
private fileTags: { [key: number]: Tag[] } = {};
constructor(
private errorBroker: ErrorBrokerService,
private errorBroker: LoggingService,
private tagService: TagService,
) {
}
@ -180,7 +180,7 @@ export class TagEditComponent implements AfterViewInit, OnChanges {
try {
return cb();
} catch (err: any) {
this.errorBroker.showError(err);
this.errorBroker.error(err);
return undefined;
}
} else {

@ -1,53 +0,0 @@
import {Injectable} from "@angular/core";
import {listen} from "@tauri-apps/api/event";
@Injectable({
providedIn: "root"
})
export class ErrorBrokerService {
errorCb: Function | undefined;
infoCb: Function | undefined;
constructor() {
this.registerListener().catch(err => console.error(err));
}
async registerListener() {
const _unlisten = await listen("error", event => {
const payload: any = event.payload;
if (payload.message) {
this.showError(payload);
} else {
this.showError(payload.toString());
}
});
}
async try<T>(fn: () => Promise<T>): Promise<T | undefined> {
try {
return await fn();
} catch (err) {
this.showError(err);
return;
}
}
showInfo(info: string) {
console.log(info);
if (this.infoCb) {
this.infoCb(info);
}
}
showError(error: { message: string } | any) {
console.error(error);
if (this.errorCb) {
if (!error.message) {
this.errorCb({ message: error });
} else {
this.errorCb({ ...error });
}
}
}
}

@ -0,0 +1,24 @@
export enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
export class LogEntry {
constructor(private message: string, private level: LogLevel, private error?: Error) {
}
public getMessage(): string {
return this.message;
}
public getLevel(): LogLevel {
return this.level;
}
public getError(): Error | undefined {
return this.error;
}
}

@ -1,13 +1,13 @@
import {TestBed} from "@angular/core/testing";
import {ErrorBrokerService} from "./error-broker.service";
import {LoggingService} from "./logging.service";
describe("ErrorBrokerService", () => {
let service: ErrorBrokerService;
let service: LoggingService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ErrorBrokerService);
service = TestBed.inject(LoggingService);
});
it("should be created", () => {

@ -0,0 +1,60 @@
import {Injectable} from "@angular/core";
import {listen} from "@tauri-apps/api/event";
import {BehaviorSubject} from "rxjs";
import {LogEntry, LogLevel} from "./LogEntry";
@Injectable({
providedIn: "root"
})
export class LoggingService {
logs = new BehaviorSubject<LogEntry>(new LogEntry("Log initialized", LogLevel.Trace));
constructor() {
this.registerListener().catch(err => console.error(err));
}
async registerListener() {
const _unlisten = await listen("error", event => {
const payload: any = event.payload;
if (payload.message) {
this.error(payload);
} else {
this.error(payload.toString());
}
});
}
async try<T>(fn: () => Promise<T>): Promise<T | undefined> {
try {
return await fn();
} catch (err: any) {
this.error(err);
return;
}
}
trace(message: string) {
this.log(LogLevel.Trace, message);
}
debug(message: string) {
this.log(LogLevel.Debug, message);
}
info(message: string) {
this.log(LogLevel.Info, message);
}
warn(message: string) {
this.log(LogLevel.Warn, message);
}
error(error: Error, message?: string) {
this.log(LogLevel.Error, message ?? error.message ?? error.toString(), error);
}
public log(level: LogLevel, message: string, error?: Error) {
this.logs.next(new LogEntry(message, level, error));
}
}

@ -3,7 +3,7 @@ import {Repository} from "../../../api/models/Repository";
import {BehaviorSubject} from "rxjs";
import {listen} from "@tauri-apps/api/event";
import {Info} from "../../models/Info";
import {ErrorBrokerService} from "../error-broker/error-broker.service";
import {LoggingService} from "../logging/logging.service";
import {RepositoryMetadata} from "../../models/RepositoryMetadata";
import {MediarepoApi} from "../../../api/Api";
import {mapMany, mapNew, mapOptional,} from "../../../api/models/adaptors";
@ -17,7 +17,7 @@ export class RepositoryService {
public selectedRepository = new BehaviorSubject<Repository | undefined>(
undefined);
constructor(private errorBroker: ErrorBrokerService) {
constructor(private errorBroker: LoggingService) {
this.registerListener().catch(err => console.error(err));
}
@ -25,7 +25,7 @@ export class RepositoryService {
async registerListener() {
await listen("info", (event: { payload: Info }) => {
const message = `Connected to ${event.payload.name}, Version: ${event.payload.version}`;
this.errorBroker.showInfo(message);
this.errorBroker.info(message);
});
}
@ -68,7 +68,7 @@ export class RepositoryService {
console.warn(err);
}
}
await MediarepoApi.selectRepository({name: repo.name});
await MediarepoApi.selectRepository({ name: repo.name });
}
/**
@ -98,7 +98,7 @@ export class RepositoryService {
* @returns {Promise<void>}
*/
public async addRepository(name: string, path: string | undefined, address: string | undefined, local: boolean) {
let repos = await MediarepoApi.addRepository({name, path, address, local}).then(mapMany(mapNew(Repository)));
let repos = await MediarepoApi.addRepository({ name, path, address, local }).then(mapMany(mapNew(Repository)));
this.repositories.next(repos);
}
@ -108,7 +108,7 @@ export class RepositoryService {
* @returns {Promise<boolean>}
*/
public async checkDaemonRunning(address: string): Promise<boolean> {
return MediarepoApi.checkDaemonRunning({address});
return MediarepoApi.checkDaemonRunning({ address });
}
/**
@ -117,7 +117,7 @@ export class RepositoryService {
* @returns {Promise<boolean>}
*/
public async checkLocalRepositoryExists(path: string): Promise<boolean> {
return await MediarepoApi.checkLocalRepositoryExists({path});
return await MediarepoApi.checkLocalRepositoryExists({ path });
}
/**
@ -126,7 +126,7 @@ export class RepositoryService {
* @returns {Promise<void>}
*/
public async removeRepository(name: string): Promise<void> {
await MediarepoApi.removeRepository({name});
await MediarepoApi.removeRepository({ name });
await this.loadRepositories();
}
@ -136,7 +136,7 @@ export class RepositoryService {
* @returns {Promise<void>}
*/
public async deleteRepository(name: string): Promise<void> {
await MediarepoApi.deleteRepository({name});
await MediarepoApi.deleteRepository({ name });
await this.removeRepository(name);
}
@ -146,7 +146,7 @@ export class RepositoryService {
* @returns {Promise<void>}
*/
public async startDaemon(repoPath: string): Promise<void> {
return MediarepoApi.startDaemon({repoPath});
return MediarepoApi.startDaemon({ repoPath });
}
/**
@ -155,7 +155,7 @@ export class RepositoryService {
* @returns {Promise<void>}
*/
public async initRepository(repoPath: string): Promise<void> {
return MediarepoApi.initRepository({repoPath});
return MediarepoApi.initRepository({ repoPath });
}
/**
@ -172,7 +172,7 @@ export class RepositoryService {
* @param sizeType
*/
public async getSize(sizeType: SizeType): Promise<SizeMetadata> {
return MediarepoApi.getSize({sizeType});
return MediarepoApi.getSize({ sizeType });
}
async loadSelectedRepository() {

@ -13,6 +13,10 @@ $primary-darker-30: darken($primary, 30%);
$accent: mat.get-color-from-palette($accent-pallette, 'text');
$accent-lighter-10: lighten($accent, 10%);
$warn: mat.get-color-from-palette($warn-palette);
$warn-lighter: lighten($warn, 10%);
$warn-chill: #fcd349;
$text: #FFF;
$text-darker-10: darken($text, 10%);

Loading…
Cancel
Save