<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
.net core 自帶一個基礎的logger框架Microsoft.Extensions.Logging。
微軟預設實現了Microsoft.Extensions.Logging.Console.dll。控制檯的紀錄檔輸出和Microsoft.Extensions.Logging.Debug.dll偵錯輸出。
下面我們寫一個我們自己的本地檔案輸出模組demo,簡單理解一下自帶的這個logger系統。
logger框架主要幾個類:LoggerFactory,Logger,LoggerProvider。
看名字就很好理解,都不需要解釋。
實現我們自己的file logger只需要實現logger,loggerProvider即可。
loggerFactory.AddFile(this.Configuration.GetSection("FileLogging"));
為LoggerFactory擴張一個方法,提供增加紀錄檔寫檔案方式的入口。相關的設定來自appsettings.json
public static class FileLoggerExtensions { //add 紀錄檔檔案建立規則,分割規則,格式化規則,過濾規則 to appsettings.json public static ILoggerFactory AddFile(this ILoggerFactory factory, IConfiguration configuration) { return AddFile(factory, new FileLoggerSettings(configuration)); } public static ILoggerFactory AddFile(this ILoggerFactory factory, FileLoggerSettings fileLoggerSettings) { factory.AddProvider(new FileLoggerProvider(fileLoggerSettings)); return factory; } }
public class FileLoggerProvider : ILoggerProvider, Idisposable
關鍵方法CreateLogger,建立真正寫紀錄檔的logger。對當前的logger可以做適當的快取,設定logger
public class FileLoggerProvider : ILoggerProvider, IDisposable { FileLoggerSettings _configuration; readonly ConcurrentDictionary<string, InitLoggerModel> _loggerKeys = new ConcurrentDictionary<string, InitLoggerModel>(); readonly ConcurrentDictionary<string, FileLogger> _loggers = new ConcurrentDictionary<string, FileLogger>(); public FileLoggerProvider(FileLoggerSettings configuration) { _configuration = configuration; _configuration.ChangeToken.RegisterChangeCallback(p => { //appsettings.json changed. reload settings. _configuration.Reload(); //update loggers settings form new settings foreach (var item in this._loggers.Values) { InitLoggerModel model = new InitLoggerModel(); InitLoggerSettings(item.Name, model); InitLogger(model, item); } }, null); } public ILogger CreateLogger(string categoryName) { var loggerKey = this._loggerKeys.GetOrAdd(categoryName, p => { InitLoggerModel model = new InitLoggerModel(); InitLoggerSettings(categoryName, model); return model; }); var key = loggerKey.FileDiretoryPath + loggerKey.FileNameTemplate; return this._loggers.GetOrAdd(key, p => { var logger = new FileLogger(categoryName); InitLogger(loggerKey, logger); return logger; }); } private static void InitLogger(InitLoggerModel model, FileLogger logger) { logger.FileNameTemplate = model.FileNameTemplate; logger.FileDiretoryPath = model.FileDiretoryPath; logger.MinLevel = model.MinLevel; } class InitLoggerModel { public LogLevel MinLevel { get; set; } public string FileDiretoryPath { get; set; } public string FileNameTemplate { get; set; } public override int GetHashCode() { return this.MinLevel.GetHashCode() + this.FileDiretoryPath.GetHashCode() + this.FileNameTemplate.GetHashCode(); } public override bool Equals(object obj) { var b = obj as InitLoggerModel; if (b == null) return false; return this.MinLevel == b.MinLevel && this.FileDiretoryPath == b.FileDiretoryPath && this.FileNameTemplate == b.FileNameTemplate; } } private void InitLoggerSettings(string categoryName, InitLoggerModel model) { model.MinLevel = LogLevel.Debug; var keys = this.GetKeys(categoryName); foreach (var item in keys) { var switchV = _configuration.GetSwitch(item); if (switchV.Item1) { model.MinLevel = switchV.Item2; break; } } model.FileDiretoryPath = this._configuration.DefaultPath; foreach (var item in keys) { var switchV = _configuration.GetDiretoryPath(item); if (switchV.Item1) { model.FileDiretoryPath = switchV.Item2; break; } } model.FileNameTemplate = this._configuration.DefaultFileName; foreach (var item in keys) { var switchV = _configuration.GetFileName(item); if (switchV.Item1) { model.FileNameTemplate = switchV.Item2; break; } } } IEnumerable<string> GetKeys(string categoryName) { while (!String.IsNullOrEmpty(categoryName)) { // a.b.c //--result // a.b.c,a.b,a,Default yield return categoryName; var last = categoryName.LastIndexOf('.'); if (last <= 0) { yield return "Default"; yield break; } System.Diagnostics.Debug.WriteLine(categoryName + "--" + last); categoryName = categoryName.Substring(0, last); } yield break; } public void Dispose() { } }
public class FileLogger : Ilogger
public class FileLogger : ILogger { static protected string delimiter = new string(new char[] { (char)1 }); public FileLogger(string categoryName) { this.Name = categoryName; } class Disposable : IDisposable { public void Dispose() { } } Disposable _DisposableInstance = new Disposable(); public IDisposable BeginScope<TState>(TState state) { return _DisposableInstance; } public bool IsEnabled(LogLevel logLevel) { return this.MinLevel <= logLevel; } public void Reload() { _Expires = true; } public string Name { get; private set; } public LogLevel MinLevel { get; set; } public string FileDiretoryPath { get; set; } public string FileNameTemplate { get; set; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (!this.IsEnabled(logLevel)) return; var msg = formatter(state, exception); this.Write(logLevel, eventId, msg, exception); } void Write(LogLevel logLevel, EventId eventId, string message, Exception ex) { EnsureInitFile(); //TODO 提高效率 佇列寫!!! var log = String.Concat(DateTime.Now.ToString("HH:mm:ss"), '[', logLevel.ToString(), ']', '[', Thread.CurrentThread.ManagedThreadId.ToString(), ',', eventId.Id.ToString(), ',', eventId.Name, ']', delimiter, message, delimiter, ex?.ToString()); lock (this) { this._sw.WriteLine(log); } } bool _Expires = true; string _FileName; protected StreamWriter _sw; void EnsureInitFile() { if (CheckNeedCreateNewFile()) { lock (this) { if (CheckNeedCreateNewFile()) { InitFile(); _Expires = false; } } } } bool CheckNeedCreateNewFile() { if (_Expires) { return true; } //TODO 使用 RollingType判斷是否需要建立檔案。提高效率!!! if (_FileName != DateTime.Now.ToString(this.FileNameTemplate)) { return true; } return false; } void InitFile() { if (!Directory.Exists(this.FileDiretoryPath)) { Directory.CreateDirectory(this.FileDiretoryPath); } var path = ""; int i = 0; do { _FileName = DateTime.Now.ToString(this.FileNameTemplate); path = Path.Combine(this.FileDiretoryPath, _FileName + "_" + i + ".log"); i++; } while (System.IO.File.Exists(path)); var oldsw = _sw; _sw = new StreamWriter(new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read), Encoding.UTF8); _sw.AutoFlush = true; if (oldsw != null) { try { _sw.Flush(); _sw.Dispose(); } catch { } } } }
到此這篇關於.Net Core使用Logger實現log寫入本地檔案系統的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45