.Net Core Logger 实现log写入本地文件系统

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: .net core 自带一个基础的logger框架Microsoft.Extensions.Logging。 微软默认实现了Microsoft.Extensions.Logging.Console.dll。

.net core 自带一个基础的logger框架Microsoft.Extensions.Logging

微软默认实现了Microsoft.Extensions.Logging.Console.dll。控制台的日志输出和Microsoft.Extensions.Logging.Debug.dll调试输出。

下面我们写一个我们自己的本地文件输出模块demo,简单理解一下自带的这个logger系统。

logger框架主要几个类:LoggerFactoryLoggerLoggerProvider

看名字就很好理解,都不需要解释。

实现我们自己的file logger只需要实现logger,loggerProvider即可。

第一步:入口。

loggerFactory.AddFile(this.Configuration.GetSection("FileLogging"));

LoggerFactory扩张一个方法,提供增加日志写文件方式的入口。相关的配置来自appsettings.json

 1     public static class FileLoggerExtensions
 2     {
 3         //add 日志文件创建规则,分割规则,格式化规则,过滤规则 to appsettings.json
 4         public static ILoggerFactory AddFile(this ILoggerFactory factory, IConfiguration configuration)
 5         {
 6             return AddFile(factory, new FileLoggerSettings(configuration));
 7         }
 8         public static ILoggerFactory AddFile(this ILoggerFactory factory, FileLoggerSettings fileLoggerSettings)
 9         {
10             factory.AddProvider(new FileLoggerProvider(fileLoggerSettings));
11             return factory;
12         }
13     }
View Code

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

public class FileLoggerProvider : ILoggerProvider, Idisposable

关键方法CreateLogger,创建真正写日志的logger。对当前的logger可以做适当的缓存,配置logger

  1     public class FileLoggerProvider : ILoggerProvider, IDisposable
  2     {
  3         FileLoggerSettings _configuration;
  4         readonly ConcurrentDictionary<string, InitLoggerModel> _loggerKeys = new ConcurrentDictionary<string, InitLoggerModel>();
  5         readonly ConcurrentDictionary<string, FileLogger> _loggers = new ConcurrentDictionary<string, FileLogger>();
  6 
  7         public FileLoggerProvider(FileLoggerSettings configuration)
  8         {
  9             _configuration = configuration;
 10             _configuration.ChangeToken.RegisterChangeCallback(p =>
 11             {
 12                 //appsettings.json changed. reload settings.
 13                 _configuration.Reload();
 14 
 15                 //update loggers settings form new settings
 16                 foreach (var item in this._loggers.Values)
 17                 {
 18                     InitLoggerModel model = new InitLoggerModel();
 19                     InitLoggerSettings(item.Name, model);
 20                     InitLogger(model, item);
 21                 }
 22 
 23             }, null);
 24         }
 25         public ILogger CreateLogger(string categoryName)
 26         {
 27             var loggerKey = this._loggerKeys.GetOrAdd(categoryName, p =>
 28              {
 29                  InitLoggerModel model = new InitLoggerModel();
 30                  InitLoggerSettings(categoryName, model);
 31                  return model;
 32              });
 33             var key = loggerKey.FileDiretoryPath + loggerKey.FileNameTemplate;
 34             return this._loggers.GetOrAdd(key, p =>
 35             {
 36                 var logger = new FileLogger(categoryName);
 37                 InitLogger(loggerKey, logger);
 38                 return logger;
 39             });
 40         }
 41 
 42         private static void InitLogger(InitLoggerModel model, FileLogger logger)
 43         {
 44             logger.FileNameTemplate = model.FileNameTemplate;
 45             logger.FileDiretoryPath = model.FileDiretoryPath;
 46             logger.MinLevel = model.MinLevel;
 47         }
 48 
 49         class InitLoggerModel
 50         {
 51             public LogLevel MinLevel { get; set; }
 52             public string FileDiretoryPath { get; set; }
 53             public string FileNameTemplate { get; set; }
 54 
 55             public override int GetHashCode()
 56             {
 57                 return this.MinLevel.GetHashCode() + this.FileDiretoryPath.GetHashCode() + this.FileNameTemplate.GetHashCode();
 58             }
 59             public override bool Equals(object obj)
 60             {
 61                 var b = obj as InitLoggerModel;
 62                 if (b == null)
 63                     return false;
 64                 return this.MinLevel == b.MinLevel && this.FileDiretoryPath == b.FileDiretoryPath && this.FileNameTemplate == b.FileNameTemplate;
 65             }
 66 
 67         }
 68         private void InitLoggerSettings(string categoryName, InitLoggerModel model)
 69         {
 70             model.MinLevel = LogLevel.Debug;
 71             var keys = this.GetKeys(categoryName);
 72             foreach (var item in keys)
 73             {
 74                 var switchV = _configuration.GetSwitch(item);
 75                 if (switchV.Item1)
 76                 {
 77                     model.MinLevel = switchV.Item2;
 78                     break;
 79                 }
 80             }
 81             model.FileDiretoryPath = this._configuration.DefaultPath;
 82             foreach (var item in keys)
 83             {
 84                 var switchV = _configuration.GetDiretoryPath(item);
 85                 if (switchV.Item1)
 86                 {
 87                     model.FileDiretoryPath = switchV.Item2;
 88                     break;
 89                 }
 90             }
 91             model.FileNameTemplate = this._configuration.DefaultFileName;
 92             foreach (var item in keys)
 93             {
 94                 var switchV = _configuration.GetFileName(item);
 95                 if (switchV.Item1)
 96                 {
 97                     model.FileNameTemplate = switchV.Item2;
 98                     break;
 99                 }
100             }
101         }
102 
103         IEnumerable<string> GetKeys(string categoryName)
104         {
105             while (!String.IsNullOrEmpty(categoryName))
106             {
107                 // a.b.c
108                 //--result
109                 // a.b.c,a.b,a,Default
110                 yield return categoryName;
111                 var last = categoryName.LastIndexOf('.');
112                 if (last <= 0)
113                 {
114                     yield return "Default";
115                     yield break;
116                 }
117                 System.Diagnostics.Debug.WriteLine(categoryName + "--" + last);
118                 categoryName = categoryName.Substring(0, last);
119             }
120             yield break;
121 
122         }
123         public void Dispose()
124         {
125         }
126     }
View Code

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

public class FileLogger : Ilogger

  1     public class FileLogger : ILogger
  2     {
  3         static protected string delimiter = new string(new char[] { (char)1 });
  4         public FileLogger(string categoryName)
  5         {
  6             this.Name = categoryName;
  7         }
  8         class Disposable : IDisposable
  9         {
 10             public void Dispose()
 11             {
 12             }
 13         }
 14         Disposable _DisposableInstance = new Disposable();
 15         public IDisposable BeginScope<TState>(TState state)
 16         {
 17             return _DisposableInstance;
 18         }
 19         public bool IsEnabled(LogLevel logLevel)
 20         {
 21             return this.MinLevel <= logLevel;
 22         }
 23         public void Reload()
 24         {
 25             _Expires = true;
 26         }
 27 
 28         public string Name { get; private set; }
 29 
 30         public LogLevel MinLevel { get; set; }
 31         public string FileDiretoryPath { get; set; }
 32         public string FileNameTemplate { get; set; }
 33         public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
 34         {
 35             if (!this.IsEnabled(logLevel))
 36                 return;
 37             var msg = formatter(state, exception);
 38             this.Write(logLevel, eventId, msg, exception);
 39         }
 40         void Write(LogLevel logLevel, EventId eventId, string message, Exception ex)
 41         {
 42             EnsureInitFile();
 43 
 44             //TODO 提高效率 队列写!!!
 45             var log = String.Concat(DateTime.Now.ToString("HH:mm:ss"), '[', logLevel.ToString(), ']', '[',
 46                   Thread.CurrentThread.ManagedThreadId.ToString(), ',', eventId.Id.ToString(), ',', eventId.Name, ']',
 47                   delimiter, message, delimiter, ex?.ToString());
 48             lock (this)
 49             {
 50                 this._sw.WriteLine(log);
 51             }
 52         }
 53 
 54         bool _Expires = true;
 55         string _FileName;
 56         protected StreamWriter _sw;
 57         void EnsureInitFile()
 58         {
 59             if (CheckNeedCreateNewFile())
 60             {
 61                 lock (this)
 62                 {
 63                     if (CheckNeedCreateNewFile())
 64                     {
 65                         InitFile();
 66                         _Expires = false;
 67                     }
 68                 }
 69             }
 70         }
 71         bool CheckNeedCreateNewFile()
 72         {
 73             if (_Expires)
 74             {
 75                 return true;
 76             }
 77             //TODO 使用 RollingType判断是否需要创建文件。提高效率!!!
 78             if (_FileName != DateTime.Now.ToString(this.FileNameTemplate))
 79             {
 80                 return true;
 81             }
 82             return false;
 83         }
 84         void InitFile()
 85         {
 86             if (!Directory.Exists(this.FileDiretoryPath))
 87             {
 88                 Directory.CreateDirectory(this.FileDiretoryPath);
 89             }
 90             var path = "";
 91             int i = 0;
 92             do
 93             {
 94                 _FileName = DateTime.Now.ToString(this.FileNameTemplate);
 95                 path = Path.Combine(this.FileDiretoryPath, _FileName + "_" + i + ".log");
 96                 i++;
 97             } while (System.IO.File.Exists(path));
 98             var oldsw = _sw;
 99             _sw = new StreamWriter(new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read), Encoding.UTF8);
100             _sw.AutoFlush = true;
101             if (oldsw != null)
102             {
103                 try
104                 {
105                     _sw.Flush();
106                     _sw.Dispose();
107                 }
108                 catch
109                 {
110                 }
111             }
112         }
113     }
View Code

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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
56 5
|
1月前
|
存储 人工智能 JSON
RAG Logger:专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、性能监控
RAG Logger 是一款专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、检索结果记录、LLM 交互记录和性能监控等功能。
64 7
RAG Logger:专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、性能监控
|
2月前
|
前端开发 C# 开发者
.NET使用Umbraco CMS快速构建一个属于自己的内容管理系统
.NET使用Umbraco CMS快速构建一个属于自己的内容管理系统
42 12
|
2月前
|
Web App开发 前端开发 调度
一款基于 .NET + Blazor 开发的智能访客管理系统
一款基于 .NET + Blazor 开发的智能访客管理系统
|
2月前
|
开发框架 JavaScript 前端开发
精选2款.NET开源的博客系统
精选2款.NET开源的博客系统
|
2月前
|
前端开发 JavaScript C#
基于.NET8+Vue3开发的权限管理&个人博客系统
基于.NET8+Vue3开发的权限管理&个人博客系统
|
2月前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
59 1
|
3月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
61 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
2月前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
48 3
|
3月前
|
开发框架 安全 Java
.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力
本文深入探讨了.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力。.NET不仅支持跨平台开发,具备出色的安全性和稳定性,还能与多种技术无缝集成,为企业级应用提供全面支持。
63 3