分享 NET 5.x 自定义文件日志实现 原汁原味
下面直接贴出实现代码
FileLoggerProvider
/// <summary>
/// 文件记录器提供商
/// </summary>
public class FileLoggerProvider : ILoggerProvider
{ /// <summary>
/// 配置
/// </summary>
private readonly IConfiguration configuration; /// <summary>
/// 构造方法
/// </summary>
/// <param name="configuration">配置</param>
public FileLoggerProvider(IConfiguration configuration)
{
this.configuration = configuration;
} /// <summary>
/// 创建记录器
/// </summary>
/// <param name="categoryName">类别名称</param>
/// <returns></returns>
public ILogger CreateLogger(string categoryName)
{
return new FileLogger(configuration, categoryName);
} /// <summary>
/// 释放方法
/// </summary>
public void Dispose()
{
}
}
Lock
/// <summary>
/// IO锁
/// </summary>
public static class Lock
{ /// <summary>
/// 文件读写锁
/// </summary>
public static readonly ReaderWriterLockSlim fileLockSlim = null; ///// <summary>
///// 数据库读写锁
///// </summary>
//public static readonly ReaderWriterLockSlim dbLockSlim = null; /// <summary>
/// 构造方法
/// </summary>
static Lock()
{
fileLockSlim = new ReaderWriterLockSlim();
//dbLockSlim = new ReaderWriterLockSlim();
}
}
FileLogger
/// <summary>
/// 文件记录器
/// </summary>
public class FileLogger : ILogger
{ /// <summary>
/// 配置
/// </summary>
private readonly IConfiguration configuration; /// <summary>
/// 类别名称
/// </summary>
private readonly string categoryName; /// <summary>
/// 构造方法
/// </summary>
/// <param name="configuration">配置</param>
/// <param name="categoryName">类别名称</param>
public FileLogger(IConfiguration configuration, string categoryName)
{
this.configuration = configuration;
this.categoryName = categoryName;
} /// <summary>
/// 开始范围
/// </summary>
/// <typeparam name="TState">状态类型</typeparam>
/// <param name="state">状态</param>
/// <returns></returns>
public IDisposable BeginScope<TState>(TState state)
{
return null;
} /// <summary>
/// 是否使用
/// </summary>
/// <param name="logLevel">日志级别</param>
/// <returns></returns>
public bool IsEnabled(LogLevel logLevel)
{
var list = new List<IConfigurationSection>();
list.AddRange(configuration.GetSection("Logging:LogLevel").GetChildren());
list.AddRange(configuration.GetSection("Logging:FileLog:LogLevel").GetChildren()); var category = list.LastOrDefault(f => this.categoryName.StartsWith(f.Key)); if (category == null)
{
category = list.LastOrDefault(f => f.Key == "Default");
} if (category != null && Enum.TryParse(typeof(LogLevel), category.Value, out var level))
{
return (int)(LogLevel)level <= (int)logLevel;
}
return 2 <= (int)logLevel;
} /// <summary>
/// 日志
/// </summary>
/// <typeparam name="TState">状态类型</typeparam>
/// <param name="logLevel">日志级别</param>
/// <param name="eventId">事件ID</param>
/// <param name="state">状态</param>
/// <param name="exception">异常</param>
/// <param name="formatter">格式化委托</param>
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
try
{
Lock.fileLockSlim.EnterWriteLock();
var baseDirectory = configuration.GetSection("Logging:FileLog:BaseDirectory").Value;
var fileName = configuration.GetSection("Logging:FileLog:FileName").Value;
var extensionName = configuration.GetSection("Logging:FileLog:ExtensionName").Value; var directory = Path.Combine(AppContext.BaseDirectory, string.IsNullOrWhiteSpace(baseDirectory) ? "app_log" : baseDirectory); if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (string.IsNullOrWhiteSpace(fileName))
{
fileName = DateTime.Now.ToString("yyyy-MM-dd");
}
else
{
fileName = DateTime.Now.ToString(fileName);
}
extensionName = string.IsNullOrWhiteSpace(extensionName) ? ".log" : extensionName; var path = Path.Combine(directory, $"{fileName}{extensionName}");
var flag = true;
if (File.Exists(path))
{
var maxSize = configuration.GetSection("Logging:FileLog:MaxFileSize").Value;
var fileInfo = new FileInfo(path);
flag = fileInfo.Length / 1024.00 > (string.IsNullOrWhiteSpace(maxSize) ? 2048.00 : Convert.ToDouble(maxSize));
} var streamWrite = flag ? File.CreateText(path) : File.AppendText(path);
var dateTimeFormart = configuration.GetSection("Logging:FileLog:DateTimeFormat").Value; var logTime = DateTime.Now.ToString((string.IsNullOrWhiteSpace(dateTimeFormart) ? "yyyy-MM-dd HH:mm:ss.fff" : dateTimeFormart));
var message = formatter(state, exception); var stackTrace = exception?.StackTrace; var template = configuration.GetSection("Logging:FileLog:Template").Value; if (string.IsNullOrWhiteSpace(template))
{
streamWrite.WriteLine($"日志时间:{logTime} 类别名称:{categoryName} 日志级别:{logLevel} 消息:{message}"); if (!string.IsNullOrWhiteSpace(stackTrace))
{
streamWrite.WriteLine(stackTrace);
}
}
else
{
template = template.Replace("{logTime}", logTime, StringComparison.OrdinalIgnoreCase);
template = template.Replace("{catetoryName}", categoryName, StringComparison.OrdinalIgnoreCase);
template = template.Replace("{eventId}", eventId.Id.ToString(), StringComparison.OrdinalIgnoreCase);
template = template.Replace("{eventName}", eventId.Name, StringComparison.OrdinalIgnoreCase);
template = template.Replace("{logLevel}", logLevel.ToString(), StringComparison.OrdinalIgnoreCase);
template = template.Replace("{message}", message, StringComparison.OrdinalIgnoreCase);
template = template.Replace("{stackTrace}", stackTrace, StringComparison.OrdinalIgnoreCase);
template = template.Trim();
streamWrite.WriteLine(template);
} streamWrite.WriteLine();
streamWrite.Close(); var directoryInfo = new DirectoryInfo(directory);
var fileInfos = directoryInfo.GetFiles();
var fileCount = Convert.ToInt32(configuration.GetSection("Logging:FileLog:MaxFileCount").Value);
if (fileInfos.Length > fileCount && fileCount > 0)
{
var removeFileInfo = fileInfos.OrderBy(o => o.CreationTime).ThenBy(o => o.LastWriteTime).SkipLast(fileCount);
foreach (var item in removeFileInfo)
{
File.Delete(item.FullName);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"写入文件日志异常:{ex.Message}");
Console.WriteLine(ex.StackTrace);
}
finally
{
Lock.fileLockSlim.ExitWriteLock();
}
}
}
}
ILoggingBuilderExtensions
/// <summary>
/// 日志构造扩展类
/// </summary>
public static class ILoggingBuilderExtensions
{ /// <summary>
/// 添加文件日志
/// </summary>
/// <param name="loggingBuilder">日志构建</param>
public static ILoggingBuilder AddFileLog(this ILoggingBuilder loggingBuilder)
{
loggingBuilder.Services.AddSingleton<FileLoggerProvider>();
var sevices = loggingBuilder.Services.BuildServiceProvider();
return loggingBuilder.AddProvider(sevices.GetService<FileLoggerProvider>());
} }
Json配置格式示例
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
},
"FileLog": {
"LogLevel": {
"Default": "Information"
},
"BaseDirectory": "app_log",
"FileName": "yyyy-MM-dd",
"ExtensionName": ".log",
"Template": "LogTime:{LogTime} CatetoryName:{CatetoryName} LogLevel:{LogLevel}\r\n{Message}\r\n{StackTrace}\r\n",
"MaxFileCount": 10,
"MaxFileSize": 2048,
"DateTimeFormat": "yyyy-MM-dd HH:mm:ss.fff"
}
}
}
分享 NET 5.x 自定义文件日志实现 原汁原味的更多相关文章
- (Unity)Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进展混淆,避免被反编译
Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进行混淆,避免被反编译. 1.打开VS,博主所用版本是Visual Studio 2013. 2.新建一个VC项目 ...
- log4j.xml配置,包含自定义log4j日志级别及输出日志到不同文件
一.配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configura ...
- 【分享】我们用了不到200行代码实现的文件日志系统,极佳的IO性能和高并发支持,附压力测试数据
很多项目都配置了日志记录的功能,但是,却只有很少的项目组会经常去看日志.原因就是日志文件生成规则设置不合理,将严重的错误日志跟普通的错误日志混在一起,分析起来很麻烦. 其实,我们想要的一个日志系统核心 ...
- 【腾讯Bugly干货分享】微信mars 的高性能日志模块 xlog
本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/581c2c46bef1702a2db3ae53 Dev Club 是一个交流移动 ...
- 简单的php自定义错误日志
平时经常看php的错误日志,很少有机会去自己动手写日志,看了王健的<最佳日志实践>觉得写一个清晰明了,结构分明的日志还是非常有必要的. 在写日志前,我们问问自己:为什么我们有时要记录自定义 ...
- 自定义log4j日志级别
转载自: http://blog.csdn.net/seven_cm/article/details/26849821 自定义log4j日志级别 参考了网上资料:http://www.360doc. ...
- 装饰者模式的学习(c#) EF SaveChanges() 报错(转载) C# 四舍五入 保留两位小数(转载) DataGridView样式生成器使用说明 MSSQL如何将查询结果拼接成字符串 快递查询 C# 通过smtp直接发送邮件 C# 带参访问接口,WebClient方式 C# 发送手机短信 文件 日志 写入 与读取
装饰者模式的学习(c#) 案例转自https://www.cnblogs.com/stonefeng/p/5679638.html //主体基类 using System;using System.C ...
- DJANGO-天天生鲜项目从0到1-005-FastDFS与Nginx打造自定义文件存储系统
本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...
- (16)-Python3之--自定义logging日志模块
1.自定义的日志模块如下: import logging from logging.handlers import TimedRotatingFileHandler import datetime f ...
随机推荐
- 实战!spring Boot security+JWT 前后端分离架构认证登录!
大家好,我是不才陈某~ 认证.授权是实战项目中必不可少的部分,而Spring Security则将作为首选安全组件,因此陈某新开了 <Spring Security 进阶> 这个专栏,写一 ...
- 洛谷 P3688 - [ZJOI2017]树状数组(二维线段树+标记永久化)
题面传送门 首先学过树状数组的应该都知道,将树状数组方向写反等价于前缀和 \(\to\) 后缀和,因此题目中伪代码的区间求和实质上是 \(sum[l-1...n]-sum[r...n]=sum[l-1 ...
- map与unordered_map区别及使用
需要引入的头文件不同map: #include <map>unordered_map: #include <unordered_map> 内部实现机理不同map: map内部实 ...
- 【Plink】Error: Multiple instances of '_' in sample ID.?
目录 前言 原因 解决方法 方法一:修改样本名 方法二:修改--id-delim 方法三:加入--double_id或--const-fid参数 前言 将vcf转化为plink格式时,命令如下: pl ...
- 对于vue项目更新迭代导致上传至服务器后出现Loading chunk {n} failed和Unexpected token <的解决方式
相信大家对于vue项目的维护与更新中会遇见很多问题,其中有两种情况最为常见. 一种是Loading chunk {n} failed,这种情况出现的原因是vue页面更新上传至服务器后,由于vue默认打 ...
- day32 HTML
day32 HTML 什么是前端 只要是跟用户打交道的界面都可以称之为前端 # eg:电脑界面, 手机界面,平板界面, 什么是后端? eg:python, java,php,go, 不跟用户直接打交道 ...
- flink-----实时项目---day04-------1. 案例:统计点击、参与某个活动的人数和次数 2. 活动指标多维度统计(自定义redisSink)
1. 案例 用户ID,活动ID,时间,事件类型,省份 u001,A1,2019-09-02 10:10:11,1,北京市 u001,A1,2019-09-02 14:10:11,1,北京市 u001, ...
- MyBatis Collection小记—— 关联查询、递归查询、多字段关联
经常会用到mybatis的Collection标签来做级联查询或递归查询,现通过一个伪例来简单的说明一下使用中的关键点: 首先先列出三个表,给出一个场景: 1,角色表 t_role( id,name ...
- MapStruct对象转换
第一次看到 MapStruct 的时候, 我个人非常的开心.因为其跟我内心里面的想法不谋而合. 1 MapStruct 是什么? 1.1 JavaBean 的困扰 对于代码中 JavaBean之间的转 ...
- Linux学习 - 文件包处理命令
一.搜索文件find find [搜索范围] [匹配条件] (1) -name(名字查找) <1> find /etc -name init 查找/etc下以 "in ...