最近写了一个webapi 的项目,发现项目里没有写日志。导致一些问题出现后,无法定位到。所以必须添加上日志,没办法谁让我写的代码没有测试那么多,出现的情况考虑的不是那么周全。闲话不多说。下面开始
首先呢Net Core 上Logging 是由几个接口的,ILoggerFactory,ILoggerProvider,ILogger。这三个之间的关系,很多文章都说过了。我这里就不再说了。我当时记得看过这样一句话。说的是ILoggerFactory 可以生成Logger,ILoggerProvider 也可以生成Logger,但是呢,生成的东西是不一样的。ILoggerFactory 生成的ILogger 内部是根据ILoggerProvider生成的,可以说,还是ILoggerProvider 生成的Logger.
在net core 是存在ILoggerFactory的实例
的名字就是LoggerFactory ,所以我们不用去做类实现它,那么我们需要做类去实现另外的两个。下面我摘出一下我的代码。
public class CustomLoggerConfiguration
{
public int EventId { get; set; }
public LogLevel LogLevel { get; set; } = LogLevel.Information;
public string FilePath { get; set; } = Path.Combine(AppContext.BaseDirectory, "log.txt");
}
这个类是做了一下配置,主要是设置一下文件的存储路径
public class CustomLogger : ILogger
{
private readonly string _name;
private readonly CustomLoggerConfiguration _config;
public CustomLogger(string name, CustomLoggerConfiguration config) => (_name, _config) = (name, config);
public IDisposable BeginScope<TState>(TState state)
{
return default;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel == _config.LogLevel;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
if (_config.EventId == 0 || _config.EventId == eventId.Id)
{
WriteToFile($"[{eventId.Id,2}: {logLevel,-12}]");
WriteToFile($" {_name} - {formatter(state, exception)}");
}
}
public void WriteToFile(string content)
{
try
{
string logFile = _config.FilePath;
FileStream fs;
StreamWriter sw;
if (File.Exists(logFile))
fs = new FileStream(logFile, FileMode.Append, FileAccess.Write);
else
fs = new FileStream(logFile, FileMode.Create, FileAccess.Write);
sw = new StreamWriter(fs);
sw.WriteLine(content);
sw.Close();
fs.Close();
}
catch
{ }
}
}
这个类就是实现ILogger 的接口的类,主要就是实现接口,能够写入到文件中
另外的两个类,CustomLogProvider ,CustomLogExtension 是参照官方文档上抄写的
public static class CustomLogExtensions
{
public static ILoggingBuilder AddCustomLogger(this ILoggingBuilder builder, CustomLoggerConfiguration configure)
{
ILoggerProvider provider = new CustomLogProvider(configure);
builder.AddProvider(provider);
return builder;
}
public static ILoggingBuilder AddCustomLogger(
this ILoggingBuilder builder) =>
builder.AddCustomLogger(
new CustomLoggerConfiguration());
public static ILoggingBuilder AddCustomLogger(
this ILoggingBuilder builder,
Action<CustomLoggerConfiguration> configure)
{
var config = new CustomLoggerConfiguration();
configure(config);
return builder.AddCustomLogger(config);
}
}
public class CustomLogProvider : ILoggerProvider
{
private readonly CustomLoggerConfiguration _config;
private readonly ConcurrentDictionary<string, CustomLogger> _loggers =
new ConcurrentDictionary<string, CustomLogger>();
public CustomLogProvider(CustomLoggerConfiguration configure)
{
_config = configure;
}
public ILogger CreateLogger(string categoryName) =>
_loggers.GetOrAdd(categoryName, name => new CustomLogger(name, _config));
public void Dispose() => _loggers.Clear();
}
下面就是最主要的了,如何使用这些类
需要在Program.cs 这个类里面进行操作,找到方法
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(builder =>
builder.ClearProviders()
.AddProvider(
new CustomLogProvider(
new CustomLoggerConfiguration
{
LogLevel = LogLevel.Error
}))
.AddCustomLogger()
.AddCustomLogger(configuration =>
{
configuration.LogLevel = LogLevel.Warning;
}))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
注意:这里我添加了三个loggerProvider,因为我写的实现的时候,写的一个provider 只能处理一种级别的日志,从代码中可以看出来,一个是LogLevel.Error 处理错误的。一个是处理警告的,还有一个是处理Information的,应该比较容易理解
由于依赖注入的关系,我们在需要用日志的地方,在他的构造函数中,直接注入ILogger<T> 就行了,比如下面的代码
public readonly IMongoCollection<ElementDtoNew> _collection;
private readonly ILogger<ElementDtoNew> _logger;
public ElementDtoNewService(IDatabaseSettings databaseSettings,ILogger<ElementDtoNew> logger)
{
var client = new MongoClient(databaseSettings.ConnectionString);
var db = client.GetDatabase(databaseSettings.DatabaseName);
var collection = db.ListCollectionNames();
_logger = logger;
_logger.LogInformation("Hello World!");
}
这样记录就会写到你定义的位置了。
结语
写这篇文章的目的呢,其实就是让我自己记住,不要忘了,其实理解并不是很深,我好像看他的源码,我记得之前有人说,可以找到源码,但是我现在不知道在哪可以看到。