mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-10-27 02:51:17 +00:00
TraceLogger now writes logs to a file in %APPDATA%\WelsonJS\Logs with a randomized suffix and process ID. If the log directory cannot be created, it falls back to the current directory. The logger also improves formatting and random suffix generation for log file names.
99 lines
3.5 KiB
C#
99 lines
3.5 KiB
C#
// TraceLogger.cs
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
|
// https://github.com/gnh1201/welsonjs
|
|
//
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace WelsonJS.Launcher
|
|
{
|
|
/// <summary>
|
|
/// File-based trace logger.
|
|
/// Writes to %APPDATA%\WelsonJS\Logs\<Namespace>.<random-6>.pid<####>.log
|
|
/// Falls back to current directory if %APPDATA%\WelsonJS\Logs cannot be created.
|
|
/// </summary>
|
|
public class TraceLogger : ICompatibleLogger
|
|
{
|
|
private static readonly string _logFilePath;
|
|
|
|
static TraceLogger()
|
|
{
|
|
try
|
|
{
|
|
string ns = typeof(TraceLogger).Namespace ?? "WelsonJS.Launcher";
|
|
string suffix = GenerateRandomSuffix(6);
|
|
int pid = Process.GetCurrentProcess().Id;
|
|
|
|
// Try %APPDATA%\WelsonJS\Logs
|
|
string baseDir;
|
|
try
|
|
{
|
|
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
|
baseDir = Path.Combine(appData, "WelsonJS", "Logs");
|
|
Directory.CreateDirectory(baseDir);
|
|
}
|
|
catch
|
|
{
|
|
// Fallback: current directory
|
|
baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
|
}
|
|
|
|
_logFilePath = Path.Combine(baseDir, $"{ns}.{suffix}.pid{pid}.log");
|
|
|
|
var fs = new FileStream(_logFilePath, FileMode.Append, FileAccess.Write, FileShare.Read);
|
|
var writer = new StreamWriter(fs) { AutoFlush = true };
|
|
|
|
if (!Trace.Listeners.OfType<TextWriterTraceListener>().Any())
|
|
{
|
|
Trace.Listeners.Add(new TextWriterTraceListener(writer)
|
|
{
|
|
Name = "FileTraceListener",
|
|
TraceOutputOptions = TraceOptions.DateTime
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Trace.Listeners.Add(new ConsoleTraceListener());
|
|
Trace.TraceWarning($"TraceLogger: failed to open log file. Using console. Error: {ex.Message}");
|
|
}
|
|
|
|
Trace.AutoFlush = true;
|
|
}
|
|
|
|
public void Info(params object[] args) => Trace.TraceInformation(Format(args));
|
|
public void Warn(params object[] args) => Trace.TraceWarning(Format(args));
|
|
public void Error(params object[] args) => Trace.TraceError(Format(args));
|
|
|
|
private static string Format(object[] args)
|
|
{
|
|
if (args == null || args.Length == 0) return string.Empty;
|
|
if (args.Length == 1) return args[0]?.ToString() ?? string.Empty;
|
|
|
|
string fmt = args[0]?.ToString() ?? string.Empty;
|
|
try { return string.Format(fmt, args.Skip(1).ToArray()); }
|
|
catch { return string.Join(" ", args.Select(a => a?.ToString() ?? "")); }
|
|
}
|
|
|
|
private static string GenerateRandomSuffix(int length)
|
|
{
|
|
char[] buf = new char[length];
|
|
byte[] rnd = new byte[length];
|
|
|
|
using (var rng = RandomNumberGenerator.Create())
|
|
{
|
|
rng.GetBytes(rnd);
|
|
}
|
|
|
|
for (int i = 0; i < length; i++)
|
|
buf[i] = (char)('a' + (rnd[i] % 26));
|
|
|
|
return new string(buf);
|
|
}
|
|
}
|
|
}
|