.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

posted @ 2016-07-15 13:08  czd890  阅读(12123)  评论(6编辑  收藏  举报