.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

.Net Core Logger 实现log写入本地文件系统的更多相关文章

  1. HTML5之本地文件系统API - File System API

    HTML5之本地文件系统API - File System API 新的HTML5标准给我们带来了大量的新特性和惊喜,例如,画图的画布Canvas,多媒体的audio和video等等.除了上面我们提到 ...

  2. React Native之本地文件系统访问组件react-native-fs的介绍与使用

    React Native之本地文件系统访问组件react-native-fs的介绍与使用 一,需求分析 1,需要将图片保存到本地相册: 2,需要创建文件,并对其进行读写 删除操作. 二,简单介绍 re ...

  3. [开源类库/项目] android保存崩溃时的错误信息log至本地【源码+jar包+使用说...

    不知大家是否经常遇到这种情况:自己的项目有时会在没有连接到电脑时发生崩溃,好不容易发现的bug结果连接到电脑时又复现不出来了:又或者自己写的一个功能在开机启动时产生小bug导致崩溃,而刚启动的机器想让 ...

  4. OC 将NSString写入本地文件

    最近在公司偶尔遇到一些不经常复现的bug,为了调试,只好把关键值记录到本地文件中,在遇到问题时,调出本地文件查看一下就可以很方便的知道是不是代码逻辑的错误或者问题考虑不够周全了. 废话不多说,流程在代 ...

  5. 数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下

    数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下 作者:Eric 微信:loveoracle11g 1.创建pfile文件 # su - ora11g # cd $ORAC ...

  6. 【翻译自mos文章】将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边

    将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边 參考原文: How To Extract Datapump File From ASM Diskgroup To Local Files ...

  7. OSSFS将OSS bucket 挂载到本地文件系统及注意事项

    OSSFS将OSS bucket 挂载到本地文件系统及注意事项 下载ossfs安装包 wget http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/as ...

  8. 解决从linux本地文件系统上传文件到HDFS时的权限问题

    当使用 hadoop fs -put localfile /user/xxx 时提示: put: Permission denied: user=root, access=WRITE, inode=& ...

  9. QTreeWidget实现动态加载本地文件系统

    QT之前没有接触过,之所以做这个也是被临时拉去GoldenFarm组去做渲染的客户端:还别说,虽说是第一次,做出来的这个东西倒是挺让我满意的.先说一下具体需求,然后再上图吧: 渲染时在选择场景文件时, ...

随机推荐

  1. C# webform上传图片并生成缩略图

    其实里面写的很乱,包括修改文件名什么的都没有仔细去写,主要是想记录下缩略图生成的几种方式 ,大家明白就好! void UpImgs() { if (FileUpload1.HasFile) { str ...

  2. 网站美化常见CSS

    伴随网络时代日新月异的发展,用户不仅仅满足于软件系统的功能需求,对软件系统的页面显示效果以及交互模式的要求也逐渐提高.尤其是展示性质的平台页面对于界面美化效果要求更高,有一句话说的好:Html是结构, ...

  3. 成就PHP高手的五个必由之路

    亲们,此文时转载过来的,不是原创!特此说明一下 原文名称:5 ways to be a better php developer原文链接:http://www.developertutorials.c ...

  4. C/C++内存泄漏及检测

    参考 http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html

  5. 《分布式事务解决之道》沙龙ppt共享

    大型分布式系统往往由很多“微服务”组成,而不同的微服务往往又连接着不同的数据库,在看似常用的功能背后,可能又需要横跨不同的“微服务”和“数据库”才能实现.那么如何才能保证系统事务的一致性呢?这也同时是 ...

  6. js操作table表格导出数据到excel方法

    js导出excel资料很少,网上也找了很多,基本都不能用,要么只能是IE用,还必须要权限,这是非常不好的.后来到github上找到table2excel.js,虽然可以用,但仍然对IE支持不够,也算不 ...

  7. 性能卓越的js模板引擎--artTemplate

    artTemplate能够将数据与View视图的分离,充分利用 javascript 引擎特性,使得其性能无论在前端还是后端都有极其出色的表现. 在 chrome 下渲染效率测试中分别是知名引擎 Mu ...

  8. 关于IOS中safari下的select下拉菜单,文字过长不换行的问题

    今天遇到下图这种问题,文字过长,显示不全.折腾了老半天,在网上搜了半天也找不到解决方案. 于是问了下同事,同事提到了<optgroup>,这个标签厉害. <optgroup> ...

  9. ng-option指令使用记录,设置默认值需要注意

    ng-options一般有以下用法: 数组作为数据源: label for value in array select as label for value in array label group ...

  10. Dynamic CRM 查询实体记录 被共享给了 哪个用户

    --客户表名"new_customer" SELECT u.FullName AS 被共享人,a.new_name AS 客户名称,sup.SystemUserid AS 共享人I ...