原生实现.NET5.0+ 自定义日志


一、定义一个静态类 声明一个 ReaderWriterLockSlim 对象 用于并发控制

 1     /// <summary>
 2     /// IO锁
 3     /// </summary>
 4     public static class Lock
 5     {
 6 
 7         /// <summary>
 8         /// 文件读写锁
 9         /// </summary>
10         public static readonly ReaderWriterLockSlim _fileLockSlim = null;
11 
12         /// <summary>
13         /// 构造方法
14         /// </summary>
15         static Lock()
16         {
17             _fileLockSlim = new ReaderWriterLockSlim();
18         }
19     }

二、实现ILoggerProvider 接口

 1     /// <summary>
 2     /// 文件记录器提供商
 3     /// </summary>
 4     public class FileLoggerProvider : ILoggerProvider
 5     {
 6 
 7         /// <summary>
 8         /// 配置
 9         /// </summary>
10         private readonly IConfiguration _configuration;
11 
12         /// <summary>
13         /// 日志对象缓存
14         /// </summary>
15         private readonly ConcurrentDictionary<string, FileLogger> _loggers = new ConcurrentDictionary<string, FileLogger>();
16 
17         /// <summary>
18         /// 构造方法
19         /// </summary>
20         /// <param name="configuration">配置</param>
21         public FileLoggerProvider(IConfiguration configuration)
22         {
23             _configuration = configuration;
24         }
25 
26         /// <summary>
27         /// 创建记录器
28         /// </summary>
29         /// <param name="categoryName">类别名称</param>
30         /// <returns></returns>
31         public ILogger CreateLogger(string categoryName)
32         {
33             return _loggers.GetOrAdd(categoryName, k =>
34             {
35                 return new FileLogger(_configuration, k);
36             });
37         }
38 
39         /// <summary>
40         /// 释放方法
41         /// </summary>
42         public void Dispose()
43         {
44             _loggers.Clear();
45             GC.SuppressFinalize(this);
46         }
47     }

三、实现 ILogger 接口

  1 /// <summary>
2     /// 文件记录器
3     /// </summary>
4     public class FileLogger : ILogger
5     {
6 
7         /// <summary>
8         /// 配置
9         /// </summary>
10         private readonly IConfiguration _configuration;
11 
12         /// <summary>
13         /// 类别名称
14         /// </summary>
15         private readonly string _categoryName;
16 
17         /// <summary>
18         /// 构造方法
19         /// </summary>
20         /// <param name="configuration">配置</param>
21         /// <param name="categoryName">类别名称</param>
22         public FileLogger(IConfiguration configuration, string categoryName)
23         {
24             _configuration = configuration;
25             _categoryName = categoryName;
26         }
27 
28         /// <summary>
29         /// 开始范围
30         /// </summary>
31         /// <typeparam name="TState">状态类型</typeparam>
32         /// <param name="state">状态</param>
33         /// <returns></returns>
34         public IDisposable BeginScope<TState>(TState state)
35         {
36             return null;
37         }
38 
39         /// <summary>
40         /// 是否使用
41         /// </summary>
42         /// <param name="logLevel">日志级别</param>
43         /// <returns></returns>
44         public bool IsEnabled(LogLevel logLevel)
45         {
46             var list = new List<IConfigurationSection>();
47             list.AddRange(_configuration.GetSection("Logging:LogLevel").GetChildren());
48             list.AddRange(_configuration.GetSection("Logging:FileLog:LogLevel").GetChildren());
49 
50             var category = list.LastOrDefault(f => _categoryName.StartsWith(f.Key));
51 
52             if (category == null)
53             {
54                 category = list.LastOrDefault(f => f.Key == "Default");
55             }
56 
57             if (category != null && Enum.TryParse(typeof(LogLevel), category.Value, out var level))
58             {
59                 return (int)(LogLevel)level <= (int)logLevel;
60             }
61             return 2 <= (int)logLevel;
62         }
63 
64         /// <summary>
65         /// 日志
66         /// </summary>
67         /// <typeparam name="TState">状态类型</typeparam>
68         /// <param name="logLevel">日志级别</param>
69         /// <param name="eventId">事件ID</param>
70         /// <param name="state">状态</param>
71         /// <param name="exception">异常</param>
72         /// <param name="formatter">格式化委托</param>
73         public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
74         {
75             if (IsEnabled(logLevel))
76             {
77                 try
78                 {
79                     Lock._fileLockSlim.EnterWriteLock();
80                     var baseDirectory = _configuration.GetSection("Logging:FileLog:BaseDirectory").Value;
81                     var fileName = _configuration.GetSection("Logging:FileLog:FileName").Value;
82                     var extensionName = _configuration.GetSection("Logging:FileLog:ExtensionName").Value;
83 
84                     var directory = Path.Combine(AppContext.BaseDirectory, string.IsNullOrWhiteSpace(baseDirectory) ? "app_log" : baseDirectory);
85 
86                     directory = Path.Combine(directory, logLevel.ToString());//拼接子目录
87 
88                     if (!Directory.Exists(directory))
89                     {
90                         Directory.CreateDirectory(directory);
91                     }
92                     if (string.IsNullOrWhiteSpace(fileName))
93                     {
94                         fileName = DateTime.Now.ToString("yyyy-MM-dd");
95                     }
96                     else
97                     {
98                         fileName = DateTime.Now.ToString(fileName);
99                     }
100                     extensionName = string.IsNullOrWhiteSpace(extensionName) ? ".log" : extensionName;
101 
102                     var path = Path.Combine(directory, $"{fileName}{extensionName}");
103                     var flag = true;
104                     if (File.Exists(path))
105                     {
106                         var maxSize = _configuration.GetSection("Logging:FileLog:MaxFileSize").Value;
107                         var fileInfo = new FileInfo(path);
108                         flag = fileInfo.Length / 1024.00 > (string.IsNullOrWhiteSpace(maxSize) ? 2048.00 : Convert.ToDouble(maxSize));
109                     }
110 
111                     var streamWrite = flag ? File.CreateText(path) : File.AppendText(path);
112                     var dateTimeFormart = _configuration.GetSection("Logging:FileLog:DateTimeFormat").Value;
113 
114                     var logTime = DateTime.Now.ToString((string.IsNullOrWhiteSpace(dateTimeFormart) ? "yyyy-MM-dd HH:mm:ss.fff" : dateTimeFormart));
115                     var message = formatter(state, exception);
116 
117                     var stackTrace = exception?.StackTrace;
118 
119                     var template = _configuration.GetSection("Logging:FileLog:Template").Value;
120 
121                     if (string.IsNullOrWhiteSpace(template))
122                     {
123                         streamWrite.WriteLine($"日志时间:{logTime}  类别名称:{_categoryName}[{eventId.Id}]  日志级别:{logLevel}  消息:{message}");
124 
125                         if (!string.IsNullOrWhiteSpace(stackTrace))
126                         {
127                             streamWrite.WriteLine(stackTrace);
128                         }
129                     }
130                     else
131                     {
132                         template = template.Replace("{logTime}", logTime, StringComparison.OrdinalIgnoreCase);
133                         template = template.Replace("{catetoryName}", _categoryName, StringComparison.OrdinalIgnoreCase);
134                         template = template.Replace("{eventId}", eventId.Id.ToString(), StringComparison.OrdinalIgnoreCase);
135                         template = template.Replace("{eventName}", eventId.Name, StringComparison.OrdinalIgnoreCase);
136                         template = template.Replace("{logLevel}", logLevel.ToString(), StringComparison.OrdinalIgnoreCase);
137                         template = template.Replace("{message}", message, StringComparison.OrdinalIgnoreCase);
138                         template = template.Replace("{stackTrace}", stackTrace, StringComparison.OrdinalIgnoreCase);
139                         template = template.Trim();
140                         streamWrite.WriteLine(template);
141                     }
142 
143                     streamWrite.WriteLine();
144                     streamWrite.Close();
145 
146                     var directoryInfo = new DirectoryInfo(directory);
147                     var fileInfos = directoryInfo.GetFiles();
148                     var fileCount = Convert.ToInt32(_configuration.GetSection("Logging:FileLog:MaxFileCount").Value);
149                     if (fileInfos.Length > fileCount && fileCount > 0)
150                     {
151                         var removeFileInfo = fileInfos.OrderBy(o => o.CreationTime).ThenBy(o => o.LastWriteTime).SkipLast(fileCount);
152                         foreach (var item in removeFileInfo)
153                         {
154                             File.Delete(item.FullName);
155                         }
156                     }
157                 }
158                 catch (Exception ex)
159                 {
160                     Console.WriteLine($"写入文件日志异常:{ex.Message}");
161                     Console.WriteLine(ex.StackTrace);
162                 }
163                 finally
164                 {
165                     Lock._fileLockSlim.ExitWriteLock();
166                 }
167             }
168         }
169     }

四、创建一个静态类增加一个扩展方法 注册服务 

 1 /// <summary>
2     /// 日志生成器扩展类
3     /// </summary>
4     public static class ILoggingBuilderExtensions
5     {
6 
7         /// <summary>
8         /// 添加文件日志
9         /// </summary>
10         /// <param name="loggingBuilder">日志构建</param>
11         public static ILoggingBuilder AddFileLog(this ILoggingBuilder loggingBuilder)
12         {
13             loggingBuilder.Services.AddSingleton<FileLoggerProvider>();
14             var sevices = loggingBuilder.Services.BuildServiceProvider();
15             return loggingBuilder.AddProvider(sevices.GetService<FileLoggerProvider>());
16         }
17 
18     }

五、使用方式 .NET6.0为例

var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddFileLog();//添加文件日志

 

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/270614.html

(0)
上一篇 2022年6月28日
下一篇 2022年6月28日

相关推荐

发表回复

登录后才能评论