写具体Log信息的是实现接口 IConsole 的 LogConsole 类
public interface IConsole
{
ConsoleColor BackgroundColor { get; set; }
ConsoleColor ForegroundColor { get; set; }
void WriteLine(string format, params object[] args);
}
WriteLine 的具体实现:
public class LogConsole : IConsole
{
public void WriteLine(string format, params object[] args)
{
System.Console.Error.WriteLine(format, args);
}
}
这里为什么要用 Console.Error 而不用标准的 Console.Out 呢?
我的理解为:当用户设置Console.Out 的时候 不影响 Console.Error: 使得程序更加的灵活,更改Console.Error 的情况极少。 参考下面的代码:
try {
writer = new StreamWriter(args[1]);
Console.SetOut(writer);
Console.SetIn(new StreamReader(args[0]));
}
catch(IOException e) {
TextWriter errorWriter = Console.Error;
errorWriter.WriteLine(e.Message);
}
ConsoleLogger 的构造函数中有个参数 : Func<string, LogLevel, bool> filter
这个参数主要用来判断是否启用了某一等级的日志 参考下面的代码:
public bool IsEnabled(LogLevel logLevel)
{
return _filter(_name, logLevel);
}
具体的 filter 例子如: (category, logLevel) => logLevel >= LogLevel.Verbose; 当错误等级大于 Verbose 才记录日志。
SetConsoleColor 方法根据不同的日志等级 设置不用的前后背景色:
case LogLevel.Critical:
Console.BackgroundColor = ConsoleColor.Red;
Console.ForegroundColor = ConsoleColor.White;
break;
case LogLevel.Error:
Console.ForegroundColor = ConsoleColor.Red;
break;
case LogLevel.Warning:
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case LogLevel.Information:
Console.ForegroundColor = ConsoleColor.White;
break;
case LogLevel.Verbose:
default:
Console.ForegroundColor = ConsoleColor.Gray;
break;
在调用此方法前:前后背景色会进行初始化:所以后面的几个不设置背景色:
var originalForegroundColor = Console.ForegroundColor; // save current colors
var originalBackgroundColor = Console.BackgroundColor;
var severity = logLevel.ToString().ToUpperInvariant();
SetConsoleColor(logLevel);
再看方法:FormatLoggerStructure(StringBuilder builder, ILoggerStructure structure, int level, bool bullet)
structure 首先执行 if (structure.Message != null) { builder.Append(structure.Message);}
然后判断 Values if (values == null){ return; }
foreach (var kvp in values) // kvp KeyValuePair<stirng,object>
{
这里的object 可以是 IEnumerable 则循环遍历
可以是 ILoggerStructure 则递归调用
否则: builder.Append(kvp.Key) .Append(": ").Append(kvp.Value);
}
level 表示前面会输出 level * 2 - 1 个空格。
bullet 是否多输出一个短横“-”;
public IDisposable BeginScope(object state) { return null; }
最后看一下Write方法:
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
最终记录日志的代码为: WriteLine("[{0}:{1}] {2}", severity, _name, message);
其中 severity=logLevel.ToString().ToUpperInvariant();
_name 是构造函数中的名字。
message 的内容与 state exception formattter 有关。
看源码发现 这里面 eventId 没有用到.
首先 如果 state 是 ILoggerStructure 并且 !=null. message = builder.ToString(); 这里的builder 是 FormatLoggerStructure 中的builder.
if (exception != null) { message += Environment.NewLine + exception;}
不是 ILoggerStructure 的情况:
else if (formatter != null)
{
message = formatter(state, exception); // 调用方传递的 formatter
}
else
{
message = LogFormatter.Formatter(state, exception); //系统提供的 state+ 换行 + e.ToString()
}
最后 : WriteLine("[{0}:{1}] {2}", severity, _name, message);
浙公网安备 33010602011771号