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

     六、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"
        }
      }
    复制代码

     

  • 相关阅读:
    7 种提升 Spring Boot 吞吐量神技
    Spring boot原理
    群面的技巧
    m3u8文件格式讲解,Python解析m3u8文件,并获取在线地址
    MySQL更新锁表超时 Lock wait timeout exceeded
    centos 使用docker安装mysql
    Product 1 Modulo N(数论,1600)
    Visual Studio 2017附加依赖项
    GDB的TUI模式(文本界面)
    【three.js】结合vue进行开发第一个3d页面
  • 原文地址:https://www.cnblogs.com/China-Mr-zhong/p/16420357.html