feat: implement console logger with backend integration and file logging
This commit is contained in:
56
frontend/src/lib/utils/logger-hook.ts
Normal file
56
frontend/src/lib/utils/logger-hook.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { FrontendLog } from '$lib/wailsjs/go/main/App';
|
||||||
|
|
||||||
|
function safeStringify(obj: any): string {
|
||||||
|
try {
|
||||||
|
if (typeof obj === 'object' && obj !== null) {
|
||||||
|
return JSON.stringify(obj);
|
||||||
|
}
|
||||||
|
return String(obj);
|
||||||
|
} catch (e) {
|
||||||
|
return '[Circular/Error]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupConsoleLogger() {
|
||||||
|
if ((window as any).__logger_initialized__) return;
|
||||||
|
(window as any).__logger_initialized__ = true;
|
||||||
|
|
||||||
|
const originalLog = console.log;
|
||||||
|
const originalWarn = console.warn;
|
||||||
|
const originalError = console.error;
|
||||||
|
const originalInfo = console.info;
|
||||||
|
|
||||||
|
function logToBackend(level: string, args: any[]) {
|
||||||
|
try {
|
||||||
|
// Avoid logging if wails runtime is not ready or function is missing
|
||||||
|
if (typeof FrontendLog !== 'function') return;
|
||||||
|
|
||||||
|
const message = args.map(arg => safeStringify(arg)).join(' ');
|
||||||
|
FrontendLog(level, message).catch(() => {});
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = (...args) => {
|
||||||
|
originalLog(...args);
|
||||||
|
logToBackend("INFO", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.warn = (...args) => {
|
||||||
|
originalWarn(...args);
|
||||||
|
logToBackend("WARN", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.error = (...args) => {
|
||||||
|
originalError(...args);
|
||||||
|
logToBackend("ERROR", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.info = (...args) => {
|
||||||
|
originalInfo(...args);
|
||||||
|
logToBackend("INFO", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
originalLog("Console logger hooked to Wails backend");
|
||||||
|
}
|
||||||
2
frontend/src/lib/wailsjs/go/main/App.d.ts
vendored
2
frontend/src/lib/wailsjs/go/main/App.d.ts
vendored
@@ -6,6 +6,8 @@ import {internal} from '../models';
|
|||||||
|
|
||||||
export function CheckIsDefaultEMLHandler():Promise<boolean>;
|
export function CheckIsDefaultEMLHandler():Promise<boolean>;
|
||||||
|
|
||||||
|
export function FrontendLog(arg1:string,arg2:string):Promise<void>;
|
||||||
|
|
||||||
export function GetConfig():Promise<utils.Config>;
|
export function GetConfig():Promise<utils.Config>;
|
||||||
|
|
||||||
export function GetImageViewerData():Promise<main.ImageViewerData>;
|
export function GetImageViewerData():Promise<main.ImageViewerData>;
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ export function CheckIsDefaultEMLHandler() {
|
|||||||
return window['go']['main']['App']['CheckIsDefaultEMLHandler']();
|
return window['go']['main']['App']['CheckIsDefaultEMLHandler']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function FrontendLog(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['FrontendLog'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function GetConfig() {
|
export function GetConfig() {
|
||||||
return window['go']['main']['App']['GetConfig']();
|
return window['go']['main']['App']['GetConfig']();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { setupConsoleLogger } from '$lib/utils/logger-hook';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
setupConsoleLogger();
|
||||||
const loader = document.getElementById('app-loading');
|
const loader = document.getElementById('app-loading');
|
||||||
if (loader) {
|
if (loader) {
|
||||||
loader.style.opacity = '0';
|
loader.style.opacity = '0';
|
||||||
|
|||||||
54
logger.go
54
logger.go
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -10,7 +11,47 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger = log.New(os.Stdout, "", 0)
|
var (
|
||||||
|
logger = log.New(os.Stdout, "", 0)
|
||||||
|
logFile *os.File
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitLogger initializes the logger to write to both stdout and a file in AppData
|
||||||
|
func InitLogger() error {
|
||||||
|
configDir, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
appDir := filepath.Join(configDir, "EMLy")
|
||||||
|
logsDir := filepath.Join(appDir, "logs")
|
||||||
|
|
||||||
|
if err := os.MkdirAll(logsDir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath := filepath.Join(logsDir, "app.log")
|
||||||
|
// Open file in Append mode
|
||||||
|
file, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logFile = file
|
||||||
|
|
||||||
|
// MultiWriter to write to both stdout and file
|
||||||
|
multi := io.MultiWriter(os.Stdout, file)
|
||||||
|
logger = log.New(multi, "", 0)
|
||||||
|
|
||||||
|
Log("Logger initialized. Writing to: " + logPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseLogger closes the log file
|
||||||
|
func CloseLogger() {
|
||||||
|
if logFile != nil {
|
||||||
|
logFile.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log prints a timestamped, file:line tagged log line.
|
// Log prints a timestamped, file:line tagged log line.
|
||||||
func Log(args ...any) {
|
func Log(args ...any) {
|
||||||
@@ -27,3 +68,14 @@ func Log(args ...any) {
|
|||||||
msg := fmt.Sprintln(args...)
|
msg := fmt.Sprintln(args...)
|
||||||
logger.Printf("[%s] - [%s] - [%s] - %s", date, tm, loc, strings.TrimRight(msg, "\n"))
|
logger.Printf("[%s] - [%s] - [%s] - %s", date, tm, loc, strings.TrimRight(msg, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FrontendLog allows the frontend to send logs to the backend logger
|
||||||
|
func (a *App) FrontendLog(level string, message string) {
|
||||||
|
now := time.Now()
|
||||||
|
date := now.Format("2006-01-02")
|
||||||
|
tm := now.Format("15:04:05")
|
||||||
|
|
||||||
|
// We don't use runtime.Caller here because it would point to this function
|
||||||
|
// Instead we tag it as [FRONTEND]
|
||||||
|
logger.Printf("[%s] - [%s] - [FRONTEND] - [%s] %s", date, tm, level, message)
|
||||||
|
}
|
||||||
|
|||||||
5
main.go
5
main.go
@@ -28,6 +28,11 @@ func (a *App) onSecondInstanceLaunch(secondInstanceData options.SecondInstanceDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if err := InitLogger(); err != nil {
|
||||||
|
log.Println("Error initializing logger:", err)
|
||||||
|
}
|
||||||
|
defer CloseLogger()
|
||||||
|
|
||||||
// Check for custom args
|
// Check for custom args
|
||||||
args := os.Args
|
args := os.Args
|
||||||
uniqueId := "emly-app-lock"
|
uniqueId := "emly-app-lock"
|
||||||
|
|||||||
Reference in New Issue
Block a user