| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- using System;
- using System.IO;
- using System.Text;
- using NLog;
- using NLog.Config;
- using NLog.Targets;
- namespace TeamAAS.Logging
- {
- /// <summary>
- /// NLog 统一接入点:全应用只此一份 NLog 配置,挂两个文件目标——
- /// 公共日志(Common):路径由 CommonPattern 解析(年/日期滚动),AppLogger 与插件 1/2 级日志共用;
- /// 任务日志(Task):路径由 TaskPattern 解析,流程名/任务名由每条日志的事件属性带入。
- /// 单文件大小归档(ArchiveAboveSize)与保留天数自动删除(MaxArchiveDays)均由 NLog 原生完成。
- /// 行格式由调用侧拼好后以 ${message} 原样写入。
- /// </summary>
- internal static class NLogHub
- {
- /// <summary>公共日志器名(AppLogger + 插件 1/2 级共用)。</summary>
- public const string CommonLoggerName = "TeamAAS.Common";
- /// <summary>任务日志器名(插件 3/4 级用)。</summary>
- public const string TaskLoggerName = "TeamAAS.Task";
- /// <summary>流程名事件属性名(TaskPattern 中的 {flow})。</summary>
- public const string FlowPropertyName = "flow";
- /// <summary>任务名事件属性名(TaskPattern 中的 {task})。</summary>
- public const string TaskPropertyName = "task";
- private static readonly object Gate = new object();
- private static PluginLogConfig _config;
- private static string _appliedSignature;
- /// <summary>下发日志配置(启动加载/保存系统配置时调用),配置变化时重建 NLog 目标。</summary>
- public static void Configure(PluginLogConfig config)
- {
- lock (Gate)
- {
- _config = config ?? new PluginLogConfig();
- _appliedSignature = null; // 强制下次 Apply 重建
- }
- Apply();
- }
- /// <summary>确保 NLog 配置已就绪(未下发时用默认配置);配置未变则幂等返回。</summary>
- public static void Apply()
- {
- lock (Gate)
- {
- var cfg = _config ?? (_config = new PluginLogConfig());
- var signature = BuildSignature(cfg);
- if (signature == _appliedSignature && LogManager.Configuration != null)
- return;
- var rootDir = ResolveRoot(cfg.RootPath);
- var commonFileName = Path.Combine(rootDir, ToLayout(cfg.CommonPattern, @"{year}\{time}.log"));
- var taskFileName = Path.Combine(rootDir, ToLayout(cfg.TaskPattern, @"{flow}\{task}\{year}\{time}.log"));
- long maxBytes = cfg.MaxFileMB > 0 ? (long)cfg.MaxFileMB * 1024 * 1024 : 0;
- int maxDays = cfg.RetentionDays > 0 ? cfg.RetentionDays : 0;
- var nlogCfg = new LoggingConfiguration();
- var commonTarget = MakeTarget("common", commonFileName, maxBytes, maxDays);
- var taskTarget = MakeTarget("task", taskFileName, maxBytes, maxDays);
- nlogCfg.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, commonTarget, CommonLoggerName);
- nlogCfg.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, taskTarget, TaskLoggerName);
- LogManager.Configuration = nlogCfg;
- _appliedSignature = signature;
- }
- }
- /// <summary>构造一个文件目标:日期滚动 + 超大小归档 + 超保留天数自动删除。</summary>
- private static FileTarget MakeTarget(string name, string fileName, long maxBytes, int maxDays)
- => new FileTarget(name)
- {
- FileName = fileName,
- Layout = "${message}",
- Encoding = Encoding.UTF8,
- KeepFileOpen = false,
- ConcurrentWrites = true,
- ArchiveAboveSize = maxBytes, // 0=不按大小归档
- ArchiveNumbering = ArchiveNumberingMode.Rolling,
- MaxArchiveFiles = 0, // 不按份数限制
- MaxArchiveDays = maxDays // 0=不按天数删除
- };
- /// <summary>公共日志器(AppLogger + 插件 1/2 级)。</summary>
- public static Logger Common => LogManager.GetLogger(CommonLoggerName);
- /// <summary>任务日志器(插件 3/4 级)。</summary>
- public static Logger Task => LogManager.GetLogger(TaskLoggerName);
- /// <summary>解析日志根目录:绝对路径直接用,相对路径拼到程序目录下。</summary>
- private static string ResolveRoot(string root)
- => Path.IsPathRooted(root ?? "")
- ? root
- : Path.Combine(TeamAAS.PathHelper.Root, string.IsNullOrWhiteSpace(root) ? "Logs" : root);
- /// <summary>把路径公式里的占位符转为 NLog 布局渲染器(日期/事件属性),交由 NLog 自行滚动与归档。</summary>
- private static string ToLayout(string pattern, string fallback)
- {
- if (string.IsNullOrWhiteSpace(pattern)) pattern = fallback;
- return pattern
- .Replace("{year}", "${date:format=yyyy}")
- .Replace("{month}", "${date:format=MM}")
- .Replace("{day}", "${date:format=dd}")
- .Replace("{time}", "${date:format=yyyy-MM-dd}")
- .Replace("{timestamp}", "${date:format=yyyyMMdd_HHmmss}")
- .Replace("{flow}", "${event-properties:item=" + FlowPropertyName + ":whenEmpty=_}")
- .Replace("{task}", "${event-properties:item=" + TaskPropertyName + ":whenEmpty=_}");
- }
- /// <summary>配置指纹:任一关键字段变化则重建 NLog 配置。</summary>
- private static string BuildSignature(PluginLogConfig c)
- => string.Join("|", c.RootPath, c.CommonPattern, c.TaskPattern, c.MaxFileMB, c.RetentionDays);
- }
- }
|