.Net Core Logger 实现log写入本地文件系统
.net core 自带一个基础的logger框架Microsoft.Extensions.Logging。
微软默认实现了Microsoft.Extensions.Logging.Console.dll。控制台的日志输出和Microsoft.Extensions.Logging.Debug.dll调试输出。
下面我们写一个我们自己的本地文件输出模块demo,简单理解一下自带的这个logger系统。
logger框架主要几个类:LoggerFactory,Logger,LoggerProvider。
看名字就很好理解,都不需要解释。
实现我们自己的file logger只需要实现logger,loggerProvider即可。
第一步:入口。
loggerFactory.AddFile(this.Configuration.GetSection("FileLogging"));
为LoggerFactory扩张一个方法,提供增加日志写文件方式的入口。相关的配置来自appsettings.json
1 public static class FileLoggerExtensions
2 {
3 //add 日志文件创建规则,分割规则,格式化规则,过滤规则 to appsettings.json
4 public static ILoggerFactory AddFile(this ILoggerFactory factory, IConfiguration configuration)
5 {
6 return AddFile(factory, new FileLoggerSettings(configuration));
7 }
8 public static ILoggerFactory AddFile(this ILoggerFactory factory, FileLoggerSettings fileLoggerSettings)
9 {
10 factory.AddProvider(new FileLoggerProvider(fileLoggerSettings));
11 return factory;
12 }
13 }
第二步:实现我们的logger提供程序,实现ILoggerProvider接口
public class FileLoggerProvider : ILoggerProvider, Idisposable
关键方法CreateLogger,创建真正写日志的logger。对当前的logger可以做适当的缓存,配置logger
1 public class FileLoggerProvider : ILoggerProvider, IDisposable
2 {
3 FileLoggerSettings _configuration;
4 readonly ConcurrentDictionary<string, InitLoggerModel> _loggerKeys = new ConcurrentDictionary<string, InitLoggerModel>();
5 readonly ConcurrentDictionary<string, FileLogger> _loggers = new ConcurrentDictionary<string, FileLogger>();
6
7 public FileLoggerProvider(FileLoggerSettings configuration)
8 {
9 _configuration = configuration;
10 _configuration.ChangeToken.RegisterChangeCallback(p =>
11 {
12 //appsettings.json changed. reload settings.
13 _configuration.Reload();
14
15 //update loggers settings form new settings
16 foreach (var item in this._loggers.Values)
17 {
18 InitLoggerModel model = new InitLoggerModel();
19 InitLoggerSettings(item.Name, model);
20 InitLogger(model, item);
21 }
22
23 }, null);
24 }
25 public ILogger CreateLogger(string categoryName)
26 {
27 var loggerKey = this._loggerKeys.GetOrAdd(categoryName, p =>
28 {
29 InitLoggerModel model = new InitLoggerModel();
30 InitLoggerSettings(categoryName, model);
31 return model;
32 });
33 var key = loggerKey.FileDiretoryPath + loggerKey.FileNameTemplate;
34 return this._loggers.GetOrAdd(key, p =>
35 {
36 var logger = new FileLogger(categoryName);
37 InitLogger(loggerKey, logger);
38 return logger;
39 });
40 }
41
42 private static void InitLogger(InitLoggerModel model, FileLogger logger)
43 {
44 logger.FileNameTemplate = model.FileNameTemplate;
45 logger.FileDiretoryPath = model.FileDiretoryPath;
46 logger.MinLevel = model.MinLevel;
47 }
48
49 class InitLoggerModel
50 {
51 public LogLevel MinLevel { get; set; }
52 public string FileDiretoryPath { get; set; }
53 public string FileNameTemplate { get; set; }
54
55 public override int GetHashCode()
56 {
57 return this.MinLevel.GetHashCode() + this.FileDiretoryPath.GetHashCode() + this.FileNameTemplate.GetHashCode();
58 }
59 public override bool Equals(object obj)
60 {
61 var b = obj as InitLoggerModel;
62 if (b == null)
63 return false;
64 return this.MinLevel == b.MinLevel && this.FileDiretoryPath == b.FileDiretoryPath && this.FileNameTemplate == b.FileNameTemplate;
65 }
66
67 }
68 private void InitLoggerSettings(string categoryName, InitLoggerModel model)
69 {
70 model.MinLevel = LogLevel.Debug;
71 var keys = this.GetKeys(categoryName);
72 foreach (var item in keys)
73 {
74 var switchV = _configuration.GetSwitch(item);
75 if (switchV.Item1)
76 {
77 model.MinLevel = switchV.Item2;
78 break;
79 }
80 }
81 model.FileDiretoryPath = this._configuration.DefaultPath;
82 foreach (var item in keys)
83 {
84 var switchV = _configuration.GetDiretoryPath(item);
85 if (switchV.Item1)
86 {
87 model.FileDiretoryPath = switchV.Item2;
88 break;
89 }
90 }
91 model.FileNameTemplate = this._configuration.DefaultFileName;
92 foreach (var item in keys)
93 {
94 var switchV = _configuration.GetFileName(item);
95 if (switchV.Item1)
96 {
97 model.FileNameTemplate = switchV.Item2;
98 break;
99 }
100 }
101 }
102
103 IEnumerable<string> GetKeys(string categoryName)
104 {
105 while (!String.IsNullOrEmpty(categoryName))
106 {
107 // a.b.c
108 //--result
109 // a.b.c,a.b,a,Default
110 yield return categoryName;
111 var last = categoryName.LastIndexOf('.');
112 if (last <= 0)
113 {
114 yield return "Default";
115 yield break;
116 }
117 System.Diagnostics.Debug.WriteLine(categoryName + "--" + last);
118 categoryName = categoryName.Substring(0, last);
119 }
120 yield break;
121
122 }
123 public void Dispose()
124 {
125 }
126 }
第三步:实现我们的logger,实现ILogger接口。真正将log写入file
public class FileLogger : Ilogger
1 public class FileLogger : ILogger
2 {
3 static protected string delimiter = new string(new char[] { (char)1 });
4 public FileLogger(string categoryName)
5 {
6 this.Name = categoryName;
7 }
8 class Disposable : IDisposable
9 {
10 public void Dispose()
11 {
12 }
13 }
14 Disposable _DisposableInstance = new Disposable();
15 public IDisposable BeginScope<TState>(TState state)
16 {
17 return _DisposableInstance;
18 }
19 public bool IsEnabled(LogLevel logLevel)
20 {
21 return this.MinLevel <= logLevel;
22 }
23 public void Reload()
24 {
25 _Expires = true;
26 }
27
28 public string Name { get; private set; }
29
30 public LogLevel MinLevel { get; set; }
31 public string FileDiretoryPath { get; set; }
32 public string FileNameTemplate { get; set; }
33 public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
34 {
35 if (!this.IsEnabled(logLevel))
36 return;
37 var msg = formatter(state, exception);
38 this.Write(logLevel, eventId, msg, exception);
39 }
40 void Write(LogLevel logLevel, EventId eventId, string message, Exception ex)
41 {
42 EnsureInitFile();
43
44 //TODO 提高效率 队列写!!!
45 var log = String.Concat(DateTime.Now.ToString("HH:mm:ss"), '[', logLevel.ToString(), ']', '[',
46 Thread.CurrentThread.ManagedThreadId.ToString(), ',', eventId.Id.ToString(), ',', eventId.Name, ']',
47 delimiter, message, delimiter, ex?.ToString());
48 lock (this)
49 {
50 this._sw.WriteLine(log);
51 }
52 }
53
54 bool _Expires = true;
55 string _FileName;
56 protected StreamWriter _sw;
57 void EnsureInitFile()
58 {
59 if (CheckNeedCreateNewFile())
60 {
61 lock (this)
62 {
63 if (CheckNeedCreateNewFile())
64 {
65 InitFile();
66 _Expires = false;
67 }
68 }
69 }
70 }
71 bool CheckNeedCreateNewFile()
72 {
73 if (_Expires)
74 {
75 return true;
76 }
77 //TODO 使用 RollingType判断是否需要创建文件。提高效率!!!
78 if (_FileName != DateTime.Now.ToString(this.FileNameTemplate))
79 {
80 return true;
81 }
82 return false;
83 }
84 void InitFile()
85 {
86 if (!Directory.Exists(this.FileDiretoryPath))
87 {
88 Directory.CreateDirectory(this.FileDiretoryPath);
89 }
90 var path = "";
91 int i = 0;
92 do
93 {
94 _FileName = DateTime.Now.ToString(this.FileNameTemplate);
95 path = Path.Combine(this.FileDiretoryPath, _FileName + "_" + i + ".log");
96 i++;
97 } while (System.IO.File.Exists(path));
98 var oldsw = _sw;
99 _sw = new StreamWriter(new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read), Encoding.UTF8);
100 _sw.AutoFlush = true;
101 if (oldsw != null)
102 {
103 try
104 {
105 _sw.Flush();
106 _sw.Dispose();
107 }
108 catch
109 {
110 }
111 }
112 }
113 }
代码:https://github.com/czd890/NetCoreWebApp
本文来自博客园,作者:{春光牛牛,yak},转载请注明原文链接:https://www.cnblogs.com/yakniu/p/16643140.html
欢迎各位大佬们评论指正
QQ讨论群:610129902
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)