using System; using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Text; namespace StandardScene.Signal.Logic { /// /// 磁条交管放行留档,按车名分目录:log/mag-traffic/car{name}/release_yyyyMMdd.log /// 进程启停等写到 log/mag-traffic/_sys/sys_yyyyMMdd.log /// public static class MagTrafficFileLogger { private static readonly ConcurrentDictionary CarLocks = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private static readonly object SysLock = new object(); private static readonly char[] InvalidNameChars = Path.GetInvalidFileNameChars(); private static string _baseDirectory = "log"; private static bool _enabled = true; public static void Configure(string baseDirectory, bool enabled) { _baseDirectory = string.IsNullOrWhiteSpace(baseDirectory) ? "log" : baseDirectory.Trim(); _enabled = enabled; } public static string GetLogDirectory() { return Path.Combine(ResolveBaseDirectory(), "mag-traffic"); } /// 目录名 car{name};名称为空时回退 car{id}。 public static string GetCarFolderKey(string carName, int carId) { var safe = SanitizeName(carName); if (string.IsNullOrWhiteSpace(safe)) { safe = carId > 0 ? carId.ToString() : "unknown"; } return "car" + safe; } public static string GetCarLogDirectory(string carName, int carId = 0) { return Path.Combine(GetLogDirectory(), GetCarFolderKey(carName, carId)); } public static string GetCurrentCarLogFilePath(string carName, int carId = 0) { return Path.Combine(GetCarLogDirectory(carName, carId), $"release_{DateTime.Now:yyyyMMdd}.log"); } public static string GetCurrentSysLogFilePath() { return Path.Combine(GetLogDirectory(), "_sys", $"sys_{DateTime.Now:yyyyMMdd}.log"); } /// 按车名写入放行记录。 public static void Write(string carName, int carId, string message) { if (!_enabled || string.IsNullOrWhiteSpace(message)) { return; } var folderKey = GetCarFolderKey(carName, carId); var carLock = CarLocks.GetOrAdd(folderKey, _ => new object()); lock (carLock) { try { var directory = Path.Combine(GetLogDirectory(), folderKey); Directory.CreateDirectory(directory); var path = Path.Combine(directory, $"release_{DateTime.Now:yyyyMMdd}.log"); File.AppendAllText( path, $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {message}{Environment.NewLine}", new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } catch { } } } /// 进程启停、重载配置等非单车事件。 public static void WriteSystem(string message) { if (!_enabled || string.IsNullOrWhiteSpace(message)) { return; } lock (SysLock) { try { var path = GetCurrentSysLogFilePath(); Directory.CreateDirectory(Path.GetDirectoryName(path) ?? GetLogDirectory()); File.AppendAllText( path, $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {message}{Environment.NewLine}", new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } catch { } } } private static string SanitizeName(string name) { if (string.IsNullOrWhiteSpace(name)) { return ""; } var chars = name.Trim().Select(ch => InvalidNameChars.Contains(ch) || ch <= 31 ? '_' : ch).ToArray(); var safe = new string(chars).Trim('.', ' '); while (safe.Contains("__")) { safe = safe.Replace("__", "_"); } return safe.Length > 80 ? safe.Substring(0, 80) : safe; } private static string ResolveBaseDirectory() { return Path.IsPathRooted(_baseDirectory) ? _baseDirectory : Path.Combine(AppContext.BaseDirectory, _baseDirectory); } } }