当前位置 : 主页 > 编程语言 > 其它开发 >

原生实现.NET 5.0+ 自定义日志

来源:互联网 收集:自由互联 发布时间:2022-06-29
一、定义一个静态类 声明一个ReaderWriterLockSlim 对象 用于并发控制 1 /// summary 2 /// IO锁 3 /// /summary 4 public static class Lock 5 { 6 7 /// summary 8 /// 文件读写锁 9 /// /summary 10 public static readonly Re

一、定义一个静态类 声明一个 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();//添加文件日志

 六、json文件配置格式 原生格式  一如既往喜欢微软原生实现的方式

"Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
    },
    "FileLog": {
      "LogLevel": {
        "Default": "Information"
      },
      "BaseDirectory": "app_log",
      "FileName": "yyyy-MM-dd",
      "ExtensionName": ".log",
      "Template": "LogTime:{LogTime}  CatetoryName:{CatetoryName}  LogLevel:{LogLevel}\r\n{Message}\r\n{StackTrace}\r\n",
      "MaxFileCount": 10,
      "MaxFileSize": 2048,
      "DateTimeFormat": "yyyy-MM-dd HH:mm:ss.fff"
    }
  }

 

网友评论