zoukankan      html  css  js  c++  java
  • .Net Core Logger 实现log写入本地文件系统

    .net core 自带一个基础的logger框架Microsoft.Extensions.Logging

    微软默认实现了Microsoft.Extensions.Logging.Console.dll。控制台的日志输出和Microsoft.Extensions.Logging.Debug.dll调试输出。

    下面我们写一个我们自己的本地文件输出模块demo,简单理解一下自带的这个logger系统。

    logger框架主要几个类:LoggerFactoryLoggerLoggerProvider

    看名字就很好理解,都不需要解释。

    实现我们自己的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     }
    View Code

    第二步:实现我们的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     }
    View Code

    第三步:实现我们的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     }
    View Code

    代码:https://github.com/czd890/NetCoreWebApp

  • 相关阅读:
    ubuntu sudo 号令有效处理
    shell脚本的主笔、存储、实行
    Oracle 11gR1中细粒度访谒收集处事(4)
    Solaris效力经管工具 SMF快速入门指南(1)
    Solaris 10完成宁静Kerberos身份验证(2)
    高质量C /C编程指南第2章 程序的版式
    Solaris 10下设置EJB 3.0景遇(1)
    高质量C /C编程指南序言
    Java学习之路:不走弯路,就是捷径 www.51testing.com
    两个结构体可以直接赋值吗? 回复 "JohnsonAnother" 的问题
  • 原文地址:https://www.cnblogs.com/calvinK/p/5673218.html
Copyright © 2011-2022 走看看