.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;
}
}

第二步:实现我们的logger提供程序,实现ILoggerProvider接口

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 <= )
{
yield return "Default";
yield break;
}
System.Diagnostics.Debug.WriteLine(categoryName + "--" + last);
categoryName = categoryName.Substring(, last);
}
yield break; }
public void Dispose()
{
}
}

第三步:实现我们的logger,实现ILogger接口。真正将log写入file

public class FileLogger : Ilogger

     public class FileLogger : ILogger
{
static protected string delimiter = new string(new char[] { (char) });
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 = ;
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
{
}
}
}
}

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

最新文章

  1. 【总结】.Net面试题集锦 (二)
  2. Mint Linux 安装 DotnetCore 遭遇无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系
  3. cocoapod-使用cocoapod安装AFNetworking3.0
  4. What is the difference between a Clustered and Non Clustered Index?
  5. How to crack interviews ...
  6. (转)C# WinForm获取当前路径汇总
  7. C# 堆和栈的区别-该文转自:http://www.itcodes.cn/746.html | 程序人生
  8. a++与=++a的区别
  9. WPF DataGrid
  10. 最全ASCLL码
  11. 「30天自制操作系统」 Stop &amp; 「OS67 」 Start
  12. SQL 用中文的拼音和笔画排序
  13. 【渗透测试】PHPCMS9.6.0 任意文件上传漏洞+修复方案
  14. [转载] Thrift-server与spring集成
  15. java基础概述
  16. MySQL 多表查询 学习与练习
  17. VSCode瞎折腾记
  18. element-ui修改全局样式且只作用于当前页面
  19. Kubernetes集群搭建之CNI-Flanneld部署篇
  20. ABP 番外篇-容器

热门文章

  1. 前端开发:Javascript中的数组,常用方法解析
  2. div+css3绘制基本图形
  3. JVM 架构解读
  4. MyBatis的一系列问题的处理(遍历Map集合和智能标签和属性和字段不一样的解决办法 和sql片段)(三)
  5. dirname 命令
  6. Linux下反弹shell的种种方式
  7. 在Visual Studio 2015 中添加SharePoint 2016 开发模板
  8. Intellij idea 和android studio 代码给混淆
  9. Resharper的配置和使用
  10. 使用bulkload向hbase中批量写入数据