C#-关于日志的功能扩展
目录
一、日志Sink(接收器)
二、Trace追踪实现日志
三、日志滚动
一、日志Sink(接收器)
安装NuGet包:Serilog
Sink有很多种,这里介绍两种:
Console接收器(安装Serilog.Sinks.Console);
File接收器(安装Serilog.Sinks.File);
MinimumLevel:最小记录级别
rollingInterval:生成日志文件周期
outputTemplate:输出日志模板
继承ILogEventSink接口实现 Emit:当Sink器接收到新日志时触发
通过该接口将接收器接收的日志添加进内部日志集合
将该接口实现类实例化对象通过WriteTo.Sink(myEventSink)与Logger绑定
实现 ILogEventSink接口示例:
public List<string> Logs = new List<string>();
private readonly ITextFormatter _formatter=
new MessageTemplateTextFormatter("Message:{Message} [{Level}] Location:{FilePath}[{LineNumber}]");
public void Emit(LogEvent logEvent)
{
if (logEvent != null)
{
var textWriter=new StringWriter();
_formatter.Format(logEvent, textWriter);
Logs.Add(textWriter.ToString());
}
}
Main程序:
MyEventSink myEventSink = new MyEventSink();
string path = "Logs\\Error\\.txt";
string outputTemplate = "{NewLine}Date: {Timestamp:yyyy-MM-dd HH:mm:ss.fff}\tLevel: {Level}\tCallName: {SourceContext}->{MemberName}"
+ "{NewLine}Path: {FilePath}[{LineNumber}]"
+ "{NewLine}Message: {Message}";
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()//记录相关上下文信息
.MinimumLevel.Debug()
.WriteTo.Sink(myEventSink)
.WriteTo.Logger(log => log.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error)
.WriteTo.File(path, rollingInterval: RollingInterval.Day, outputTemplate: outputTemplate))
.WriteTo.Console()
.CreateLogger();
Log.Warning("*****************Warning***************");
Log.Logger.Information("*******************Info****************");
Log.Logger.CallError<Test>("#####################Error##################");
foreach (string str in myEventSink.Logs)
{
Console.WriteLine(str);
}
static class LogExtension
{
public static void CallError<T>(this ILogger logger, string message,
[CallerMemberName] string meberName = "",
[CallerFilePath] string filepath = "",
[CallerLineNumber] int lineNum = 0)
=> logger.ForContext<T>()
.ForContext("MemberName", meberName)
.ForContext("FilePath", filepath)
.ForContext("LineNumber", lineNum)
.Error(message);
public static void CallError<T>(this ILogger logger, Exception e, string message,
[CallerMemberName] string meberName = "",
[CallerFilePath] string filepath = "",
[CallerLineNumber] int lineNum = 0)
=> logger.ForContext<T>()
.ForContext("MemberName", meberName)
.ForContext("FilePath", filepath)
.ForContext("LineNumber", lineNum)
.Error(e, message);
}
二、Trace追踪实现日志
继承抽象类TraceListener,重写方法TraceEvent
注意:添加监听对象Trace.Listeners.Add(this);
public override void TraceEvent(TraceEventCache? eventCache, string source, TraceEventType eventType, int id, string? message)
{
switch (eventType)
{
case TraceEventType.Error:
Log.Logger.CallError<MyTraceListen>(message);
break;
case TraceEventType.Warning:
Log.Logger.Warning(message);
break;
case TraceEventType.Information:
Log.Logger.Information(message);
break;
default:
break;
}
}
三、日志滚动
通过ObservableCollection类的CollectionChanged事件实现日志自动滚动到底部:
集合改变触发事件,更改附加属性AutoScroll值,值更改触发CallBack将日志滚动到底部;
注意:MouseEnter与MouseLeave两事件的响应原因:查看日志时,防止日志自动滚动到底部;
<DataGrid attach:ScrollHelper.AutoScroll="{Binding AutoScroll}"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
ItemsSource="{Binding LogService.Logs}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MouseEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Time}" Header="时间" />
<DataGridTextColumn Binding="{Binding Lev}" Header="级别" />
<DataGridTextColumn Binding="{Binding Message}" Header="信息">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
<Setter Property="TextBlock.TextAlignment" Value="Left" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Lev}" Value="Error">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Lev}" Value="Warn">
<Setter Property="Foreground" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
public LogService LogService { get; set; }=LogService.GetInstance();
private bool _autoScroll;
public bool AutoScroll
{
get { return _autoScroll; }
set => SetProperty(ref _autoScroll, value);
}
[RelayCommand]
public void MouseEnter()
{
LogService._logs.CollectionChanged -= Scroll;
}
[RelayCommand]
public void MouseLeave()
{
LogService._logs.CollectionChanged += Scroll;
}
private void Scroll(object sender, NotifyCollectionChangedEventArgs e)
{
AutoScroll = !AutoScroll;
}
public MainWinViewModel()
{
LogService.OpenListen();
LogService._logs.CollectionChanged += Scroll;
}