3

原生实现.NET 5.0+ 自定义日志 - China-Mr-zhong

 1 year ago
source link: https://www.cnblogs.com/China-Mr-zhong/p/16420357.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

原生实现.NET 5.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();//添加文件日志

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK