目录
一、日志Sink(接收器)
安装NuGet包:Serilog
Sink有很多种,这里介绍两种:
Console接收器(安装Serilog.Sinks.Console);
File接收器(安装Serilog.Sinks.File);
MinimumLevel:最小记录级别rollingInterval:生成日志文件周期
outputTemplate:输出日志模板
继承ILogEventSink接口实现 Emit:当Sink器接收到新日志时触发通过该接口将接收器接收的日志添加进内部日志集合
将该接口实现类实例化对象通过WriteTo.Sink(myEventSink)与Logger绑定
实现 ILogEventSink接口示例:
cs
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程序:
cs
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);
}
cs
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);
cs
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两事件的响应原因:查看日志时,防止日志自动滚动到底部;
XML
<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>
cs
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;
}