首页 技术 正文
技术 2022年11月18日
0 收藏 329 点赞 4,363 浏览 6740 个字

一、定义一个静态类 声明一个 ReaderWriterLockSlim 对象 用于并发控制

 1     /// <summary>
2 /// IO锁
3 /// </summary>
4 public static class Lock
5 {
6
7 /// <summary>
8 /// 文件读写锁
9 /// </summary>
10 public static readonly ReaderWriterLockSlim _fileLockSlim = null;
11
12 /// <summary>
13 /// 构造方法
14 /// </summary>
15 static Lock()
16 {
17 _fileLockSlim = new ReaderWriterLockSlim();
18 }
19 }

二、实现ILoggerProvider 接口

 1     /// <summary>
2 /// 文件记录器提供商
3 /// </summary>
4 public class FileLoggerProvider : ILoggerProvider
5 {
6
7 /// <summary>
8 /// 配置
9 /// </summary>
10 private readonly IConfiguration _configuration;
11
12 /// <summary>
13 /// 日志对象缓存
14 /// </summary>
15 private readonly ConcurrentDictionary<string, FileLogger> _loggers = new ConcurrentDictionary<string, FileLogger>();
16
17 /// <summary>
18 /// 构造方法
19 /// </summary>
20 /// <param name="configuration">配置</param>
21 public FileLoggerProvider(IConfiguration configuration)
22 {
23 _configuration = configuration;
24 }
25
26 /// <summary>
27 /// 创建记录器
28 /// </summary>
29 /// <param name="categoryName">类别名称</param>
30 /// <returns></returns>
31 public ILogger CreateLogger(string categoryName)
32 {
33 return _loggers.GetOrAdd(categoryName, k =>
34 {
35 return new FileLogger(_configuration, k);
36 });
37 }
38
39 /// <summary>
40 /// 释放方法
41 /// </summary>
42 public void Dispose()
43 {
44 _loggers.Clear();
45 GC.SuppressFinalize(this);
46 }
47 }

三、实现 ILogger 接口

  1 /// <summary>
2 /// 文件记录器
3 /// </summary>
4 public class FileLogger : ILogger
5 {
6
7 /// <summary>
8 /// 配置
9 /// </summary>
10 private readonly IConfiguration _configuration;
11
12 /// <summary>
13 /// 类别名称
14 /// </summary>
15 private readonly string _categoryName;
16
17 /// <summary>
18 /// 构造方法
19 /// </summary>
20 /// <param name="configuration">配置</param>
21 /// <param name="categoryName">类别名称</param>
22 public FileLogger(IConfiguration configuration, string categoryName)
23 {
24 _configuration = configuration;
25 _categoryName = categoryName;
26 }
27
28 /// <summary>
29 /// 开始范围
30 /// </summary>
31 /// <typeparam name="TState">状态类型</typeparam>
32 /// <param name="state">状态</param>
33 /// <returns></returns>
34 public IDisposable BeginScope<TState>(TState state)
35 {
36 return null;
37 }
38
39 /// <summary>
40 /// 是否使用
41 /// </summary>
42 /// <param name="logLevel">日志级别</param>
43 /// <returns></returns>
44 public bool IsEnabled(LogLevel logLevel)
45 {
46 var list = new List<IConfigurationSection>();
47 list.AddRange(_configuration.GetSection("Logging:LogLevel").GetChildren());
48 list.AddRange(_configuration.GetSection("Logging:FileLog:LogLevel").GetChildren());
49
50 var category = list.LastOrDefault(f => _categoryName.StartsWith(f.Key));
51
52 if (category == null)
53 {
54 category = list.LastOrDefault(f => f.Key == "Default");
55 }
56
57 if (category != null && Enum.TryParse(typeof(LogLevel), category.Value, out var level))
58 {
59 return (int)(LogLevel)level <= (int)logLevel;
60 }
61 return 2 <= (int)logLevel;
62 }
63
64 /// <summary>
65 /// 日志
66 /// </summary>
67 /// <typeparam name="TState">状态类型</typeparam>
68 /// <param name="logLevel">日志级别</param>
69 /// <param name="eventId">事件ID</param>
70 /// <param name="state">状态</param>
71 /// <param name="exception">异常</param>
72 /// <param name="formatter">格式化委托</param>
73 public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
74 {
75 if (IsEnabled(logLevel))
76 {
77 try
78 {
79 Lock._fileLockSlim.EnterWriteLock();
80 var baseDirectory = _configuration.GetSection("Logging:FileLog:BaseDirectory").Value;
81 var fileName = _configuration.GetSection("Logging:FileLog:FileName").Value;
82 var extensionName = _configuration.GetSection("Logging:FileLog:ExtensionName").Value;
83
84 var directory = Path.Combine(AppContext.BaseDirectory, string.IsNullOrWhiteSpace(baseDirectory) ? "app_log" : baseDirectory);
85
86 directory = Path.Combine(directory, logLevel.ToString());//拼接子目录
87
88 if (!Directory.Exists(directory))
89 {
90 Directory.CreateDirectory(directory);
91 }
92 if (string.IsNullOrWhiteSpace(fileName))
93 {
94 fileName = DateTime.Now.ToString("yyyy-MM-dd");
95 }
96 else
97 {
98 fileName = DateTime.Now.ToString(fileName);
99 }
100 extensionName = string.IsNullOrWhiteSpace(extensionName) ? ".log" : extensionName;
101
102 var path = Path.Combine(directory, $"{fileName}{extensionName}");
103 var flag = true;
104 if (File.Exists(path))
105 {
106 var maxSize = _configuration.GetSection("Logging:FileLog:MaxFileSize").Value;
107 var fileInfo = new FileInfo(path);
108 flag = fileInfo.Length / 1024.00 > (string.IsNullOrWhiteSpace(maxSize) ? 2048.00 : Convert.ToDouble(maxSize));
109 }
110
111 var streamWrite = flag ? File.CreateText(path) : File.AppendText(path);
112 var dateTimeFormart = _configuration.GetSection("Logging:FileLog:DateTimeFormat").Value;
113
114 var logTime = DateTime.Now.ToString((string.IsNullOrWhiteSpace(dateTimeFormart) ? "yyyy-MM-dd HH:mm:ss.fff" : dateTimeFormart));
115 var message = formatter(state, exception);
116
117 var stackTrace = exception?.StackTrace;
118
119 var template = _configuration.GetSection("Logging:FileLog:Template").Value;
120
121 if (string.IsNullOrWhiteSpace(template))
122 {
123 streamWrite.WriteLine($"日志时间:{logTime} 类别名称:{_categoryName}[{eventId.Id}] 日志级别:{logLevel} 消息:{message}");
124
125 if (!string.IsNullOrWhiteSpace(stackTrace))
126 {
127 streamWrite.WriteLine(stackTrace);
128 }
129 }
130 else
131 {
132 template = template.Replace("{logTime}", logTime, StringComparison.OrdinalIgnoreCase);
133 template = template.Replace("{catetoryName}", _categoryName, StringComparison.OrdinalIgnoreCase);
134 template = template.Replace("{eventId}", eventId.Id.ToString(), StringComparison.OrdinalIgnoreCase);
135 template = template.Replace("{eventName}", eventId.Name, StringComparison.OrdinalIgnoreCase);
136 template = template.Replace("{logLevel}", logLevel.ToString(), StringComparison.OrdinalIgnoreCase);
137 template = template.Replace("{message}", message, StringComparison.OrdinalIgnoreCase);
138 template = template.Replace("{stackTrace}", stackTrace, StringComparison.OrdinalIgnoreCase);
139 template = template.Trim();
140 streamWrite.WriteLine(template);
141 }
142
143 streamWrite.WriteLine();
144 streamWrite.Close();
145
146 var directoryInfo = new DirectoryInfo(directory);
147 var fileInfos = directoryInfo.GetFiles();
148 var fileCount = Convert.ToInt32(_configuration.GetSection("Logging:FileLog:MaxFileCount").Value);
149 if (fileInfos.Length > fileCount && fileCount > 0)
150 {
151 var removeFileInfo = fileInfos.OrderBy(o => o.CreationTime).ThenBy(o => o.LastWriteTime).SkipLast(fileCount);
152 foreach (var item in removeFileInfo)
153 {
154 File.Delete(item.FullName);
155 }
156 }
157 }
158 catch (Exception ex)
159 {
160 Console.WriteLine($"写入文件日志异常:{ex.Message}");
161 Console.WriteLine(ex.StackTrace);
162 }
163 finally
164 {
165 Lock._fileLockSlim.ExitWriteLock();
166 }
167 }
168 }
169 }

四、创建一个静态类增加一个扩展方法 注册服务

 1 /// <summary>
2 /// 日志生成器扩展类
3 /// </summary>
4 public static class ILoggingBuilderExtensions
5 {
6
7 /// <summary>
8 /// 添加文件日志
9 /// </summary>
10 /// <param name="loggingBuilder">日志构建</param>
11 public static ILoggingBuilder AddFileLog(this ILoggingBuilder loggingBuilder)
12 {
13 loggingBuilder.Services.AddSingleton<FileLoggerProvider>();
14 var sevices = loggingBuilder.Services.BuildServiceProvider();
15 return loggingBuilder.AddProvider(sevices.GetService<FileLoggerProvider>());
16 }
17
18 }

五、使用方式 .NET6.0为例

var builder = WebApplication.CreateBuilder(args);builder.Logging.AddFileLog();//添加文件日志
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,000
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,512
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,358
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,141
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,771
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,849