.Net Core Logger 实现log写入本地文件系统
.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写入本地文件系统的更多相关文章
- HTML5之本地文件系统API - File System API
HTML5之本地文件系统API - File System API 新的HTML5标准给我们带来了大量的新特性和惊喜,例如,画图的画布Canvas,多媒体的audio和video等等.除了上面我们提到 ...
- React Native之本地文件系统访问组件react-native-fs的介绍与使用
React Native之本地文件系统访问组件react-native-fs的介绍与使用 一,需求分析 1,需要将图片保存到本地相册: 2,需要创建文件,并对其进行读写 删除操作. 二,简单介绍 re ...
- [开源类库/项目] android保存崩溃时的错误信息log至本地【源码+jar包+使用说...
不知大家是否经常遇到这种情况:自己的项目有时会在没有连接到电脑时发生崩溃,好不容易发现的bug结果连接到电脑时又复现不出来了:又或者自己写的一个功能在开机启动时产生小bug导致崩溃,而刚启动的机器想让 ...
- OC 将NSString写入本地文件
最近在公司偶尔遇到一些不经常复现的bug,为了调试,只好把关键值记录到本地文件中,在遇到问题时,调出本地文件查看一下就可以很方便的知道是不是代码逻辑的错误或者问题考虑不够周全了. 废话不多说,流程在代 ...
- 数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下
数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下 作者:Eric 微信:loveoracle11g 1.创建pfile文件 # su - ora11g # cd $ORAC ...
- 【翻译自mos文章】将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边
将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边 參考原文: How To Extract Datapump File From ASM Diskgroup To Local Files ...
- OSSFS将OSS bucket 挂载到本地文件系统及注意事项
OSSFS将OSS bucket 挂载到本地文件系统及注意事项 下载ossfs安装包 wget http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/as ...
- 解决从linux本地文件系统上传文件到HDFS时的权限问题
当使用 hadoop fs -put localfile /user/xxx 时提示: put: Permission denied: user=root, access=WRITE, inode=& ...
- QTreeWidget实现动态加载本地文件系统
QT之前没有接触过,之所以做这个也是被临时拉去GoldenFarm组去做渲染的客户端:还别说,虽说是第一次,做出来的这个东西倒是挺让我满意的.先说一下具体需求,然后再上图吧: 渲染时在选择场景文件时, ...
随机推荐
- WPF入门:数据绑定
上一篇我们将XAML大概做了个了解 ,这篇将继续学习WPF数据绑定的相关内容 数据源与控件的Binding Binding作为数据传送UI的通道,通过INotityPropertyChanged接口的 ...
- C++ 最小化到托盘
#define WM_SHOWTASK (WM_USER + 1) void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID &a ...
- python学习笔记- 多线程(1)
学习多线程首先先要理解线程和进程的关系. 进程 计算机的程序是储存在磁盘中的可执行的二进制文件,执行时把这些二进制文件加载到内存中,操作系统调用并交给处理器执行对应操作,进程是程序的一次执行过程,这是 ...
- java web学习总结(二十三) -------------------编写自己的JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- QT数据库连接的几个重要函数的使用及注意事项(原创)
注:在这里数据库对象等同于数据库连接对象,也就是QSqlDatabase类的对象 QSqlDatabase QSqlDatabase::addDatabase((const QString & ...
- iOS中NSLog输出格式大全
iOS开发中的输出格式大全: %@ 对象 %d, %i 整数%u 无符整形%f ...
- android Intent介绍
Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 ...
- android Service介绍
一.简介 android中service(服务)运行于后台,没有界面.和其他组件一样,service也运行在主线程中,因此不能用它来做耗时的请求或者动作.可以在服务中开启线程,在线程中做耗时操作.可以 ...
- Swift3 - String 字符串、Array 数组、Dictionary 字典的使用
Swift相关知识,本随笔为 字符串.数组.字典的简单使用,有理解.使用错误的地方望能指正. ///************************************************** ...
- android ImageLoader 混淆加载drawable出现黑色图片的解决方案
在网上找了很久,没有找到.后来看了源码才知道... 多线程异步加载和显示图片(图片来源于网络.sd卡.assets文件夹,drawable文件夹(不能加载9patch),新增加载视频缩略图) Stri ...