本文介绍Util应用框架如何记录日志.

日志记录共分4篇,本文是正文,后续还有3篇分别介绍写入不同日志接收器的安装和配置方法.

概述

日志记录对于了解系统执行情况非常重要.

Asp.Net Core 抽象了日志基础架构,支持使用日志提供程序进行扩展,提供控制台日志等简单实现.

Serilog 是 .Net 流行的第三方日志框架,支持结构化日志,并能与 Asp.Net Core 日志集成.

Serilog 支持多种日志接收器,可以将日志发送到不同的地方.

我们可以将日志写入文本文件,但查看文本文件比较困难,文件如果很大,查找问题非常费力.

对于生产环境,我们需要包含管理界面的日志系统.

Seq 是一个日志系统,可以很好的展示结构化日志数据,并提供模糊搜索功能.

Exceptionless 是基于 Asp.Net Core 开发的日志系统.

与 Seq 相比,Exceptionless 搜索能力较弱.

Seq 和 Exceptionless 都提供了 Serilog 日志接收器,可以使用 Serilog 接入它们.

Util应用框架使用 Serilog 日志框架,同时集成了 SeqExceptionless 日志系统.

Util简化了日志配置,并对常用功能进行扩展.

日志配置

选择日志接收器

Util应用框架默认支持三种 Serilog 日志接收器:

  • 日志文件
  • Seq
  • Exceptionless

你可以从中选择一种或多种,如果都不能满足要求,你也可以引用 Serilog 支持的其它日志接收器,或自行实现.

配置日志接收器

请转到特定日志接收器章节查看配置方法.

配置日志级别

Asp.Net Core 使用日志级别表示日志的严重程度,定义如下:

  • Trace = 0
  • Debug = 1
  • Information = 2
  • Warning = 3
  • Error = 4
  • Critical = 5
  • None = 6

None不开启日志,Trace的严重程度最低,Critical的严重程度最高,需要高度关注.

可以在 appsettings.json 配置文件设置日志级别.

{
"Logging": {
"LogLevel": {
"Default": "Information"
}
}
}

Logging 配置节用于配置日志.

LogLevel 为所有日志提供程序配置日志级别.

Default 为所有日志类别设置默认的日志级别.

上面的配置将默认日志级别设置为 Information.

意味着只输出日志级别等于或大于 Information 的日志.

现在 Trace 和 Debug 两个级别的日志被禁用了.

可以为特定日志类别设置日志级别.

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
}
}
}

配置增加了 Microsoft 日志类别,并设置为 Debug 日志级别.

日志类别用来给日志分类,一般使用带命名空间的类名作为日志类别.

日志类别支持模糊匹配, Microsoft 日志类别不仅匹配 Microsoft ,而且还能匹配以 Microsoft 开头的所有日志类别,比如 Microsoft.AspNetCore .

Serilog 的日志级别

Serilog 定义了自己的日志级别,不支持上面介绍的标准配置方式.

Exceptionless 也是如此.

使用第三方框架的日志级别会导致复杂性.

Util应用框架扩展了 Serilog 和 Exceptionless 的日志级别配置,允许以统一的标准方式进行配置.

记录日志

.Net 提供了标准的日志记录接口 Microsoft.Extensions.Logging.ILogger.

你可以使用 ILogger 记录日志.

Util应用框架还提供了一个 Util.Logging.ILog 接口.

当你需要写入很长的日志时,可能需要使用 StringBuilder 拼接日志内容.

ILog 提供了一种更简单的方式写入长内容日志.

使用 ILogger 记录日志

ILogger 支持泛型参数, 用来指定日志类别,使用带命名空间的类名作为日志类别.

namespace Demo;

public class DemoController : WebApiControllerBase {
public DemoController( ILogger<DemoController> logger ) {
logger.LogDebug( "Util" );
}
}

示例在控制器构造方法注入 ILogger<DemoController> ,日志类别为 Demo.DemoController .

ILogger 扩展了一些以 Log 开头的方法,比如 LogDebug,表示写入日志级别为 Debug 的消息.

logger.LogDebug( "Util" ) 以 Debug 日志级别写入消息'Util'.

使用 ILog 记录日志

Util应用框架定义了 ILog 接口.

ILog 是对 ILogger 接口的简单包装, 对日志内容的设置进行了扩展.

ILog 也使用泛型参数来指定日志类别.

使用 ILog 完成上面相同的示例.

public class DemoController : WebApiControllerBase {
public DemoController( ILog<DemoController> log ) {
log.Message( "Util" ).LogDebug();
}
}

Message 是 ILog 定义的方法, 用来设置日志消息,可以多次调用它拼接内容.

当你需要写比较长的日志内容, ILog 可以帮你拼接内容,这样省去了定义 StringBuilder 的麻烦.

可以在 ILog 添加自定义扩展方法来设置内容, Util应用框架内置了一些设置日志消息的扩展方法, 比如 AppendLine.

public class DemoController : WebApiControllerBase {
public DemoController( ILog<DemoController> log ) {
log.AppendLine( "内容1" )
.AppendLine( "内容2" )
.LogDebug();
}
}

你可以定义自己的扩展方法,以更加语义化的方式记录日志.

范例:

public class DemoController : WebApiControllerBase {
public DemoController( ILog<DemoController> log ) {
log.Caption( "标题" )
.Content( "内容" )
.Sql( "Sql" )
.LogDebug();
}
}

ILog 与 ILogger 比较:

ILog 更擅长记录内容很长的日志.

ILog 是有状态服务,不能在多个线程共享使用.

可以使用 ILog 记录业务日志,其它场景应使用 ILogger.

结构化日志支持

Serilog 日志框架对结构化日志提供了支持.

结构化日志使用特定语法的消息模板日志格式,可以从日志文本中提取搜索元素.

结构化日志的优势主要体现在日志系统对日志消息的展示和搜索方式上.

不同的日志系统对结构化日志的展示方式和搜索能力不同.

请参考 Seq 和 Exceptionless 的 结构化日志支持 小节.

日志操作上下文

记录日志时,我们除了需要记录业务内容,还需要知道一些额外的信息,比如操作用户是谁.

我们希望记录日志时仅设置业务内容,这些额外的信息最好能自动记录.

Util应用框架通过日志上下文自动设置这些额外信息.

  • UserId 设置当前操作用户标识

  • Application 设置当前应用程序名称.

  • Environment 设置当前环境名称.

  • TraceId 设置跟踪号.

  • Stopwatch 设置计时器,用于记录请求执行花了多长时间.

在 Asp.Net Core 环境, 日志上下文由日志上下文中间件 Util.Applications.Logging.LogContextMiddleware 创建.

无需手工添加日志上下文中间件,只要引用 Util.Application.WebApi 类库, 就会自动添加到中间件管道.

对于 Web 请求, 跟踪号是一个重要的信息,可以通过查询跟踪号,将相关的请求日志全部查出来.

另外, Exceptionless 会自动收集很多系统信息.

源码解析

ILog 日志操作

ILog 日志操作接口提供链式调用方式设置日志内容.

  • Message 方法设置日志消息.

  • Property 方法设置扩展属性.

  • State 设置日志参数对象.

Log 开头的日志记录方法,将日志操作委托给 ILogger 相关方法.

/// <summary>
/// 日志操作
/// </summary>
/// <typeparam name="TCategoryName">日志类别</typeparam>
public interface ILog<out TCategoryName> : ILog {
} /// <summary>
/// 日志操作
/// </summary>
public interface ILog {
/// <summary>
/// 设置日志事件标识
/// </summary>
/// <param name="eventId">日志事件标识</param>
ILog EventId( EventId eventId );
/// <summary>
/// 设置异常
/// </summary>
/// <param name="exception">异常</param>
ILog Exception( Exception exception );
/// <summary>
/// 设置自定义扩展属性
/// </summary>
/// <param name="propertyName">属性名</param>
/// <param name="propertyValue">属性值</param>
ILog Property( string propertyName, string propertyValue );
/// <summary>
/// 设置日志状态对象
/// </summary>
/// <param name="state">状态对象</param>
ILog State( object state );
/// <summary>
/// 设置日志消息
/// </summary>
/// <param name="message">日志消息</param>
/// <param name="args">日志消息参数</param>
ILog Message( string message, params object[] args );
/// <summary>
/// 是否启用
/// </summary>
/// <param name="logLevel">日志级别</param>
bool IsEnabled( LogLevel logLevel );
/// <summary>
/// 开启日志范围
/// </summary>
/// <typeparam name="TState">日志状态类型</typeparam>
/// <param name="state">日志状态</param>
IDisposable BeginScope<TState>( TState state );
/// <summary>
/// 写跟踪日志
/// </summary>
ILog LogTrace();
/// <summary>
/// 写调试日志
/// </summary>
ILog LogDebug();
/// <summary>
/// 写信息日志
/// </summary>
ILog LogInformation();
/// <summary>
/// 写警告日志
/// </summary>
ILog LogWarning();
/// <summary>
/// 写错误日志
/// </summary>
ILog LogError();
/// <summary>
/// 写致命日志
/// </summary>
ILog LogCritical();
}

ILogExtensions 日志操作扩展

Util应用框架内置了几个日志操作扩展方法,你可以定义自己的扩展方法,以方便内容设置.

/// <summary>
/// 日志操作扩展
/// </summary>
public static class ILogExtensions {
/// <summary>
/// 添加消息
/// </summary>
/// <param name="log">配置项</param>
/// <param name="message">消息</param>
/// <param name="args">日志消息参数</param>
public static ILog Append( this ILog log,string message, params object[] args ) {
log.CheckNull( nameof( log ) );
log.Message( message, args );
return log;
} /// <summary>
/// 当条件为true添加消息
/// </summary>
/// <param name="log">配置项</param>
/// <param name="message">消息</param>
/// <param name="condition">条件,值为true则添加消息</param>
/// <param name="args">日志消息参数</param>
public static ILog AppendIf( this ILog log, string message,bool condition, params object[] args ) {
log.CheckNull( nameof( log ) );
if ( condition )
log.Message( message, args );
return log;
} /// <summary>
/// 添加消息并换行
/// </summary>
/// <param name="log">配置项</param>
/// <param name="message">消息</param>
/// <param name="args">日志消息参数</param>
public static ILog AppendLine( this ILog log, string message, params object[] args ) {
log.CheckNull( nameof( log ) );
log.Message( message, args );
log.Message( Environment.NewLine );
return log;
} /// <summary>
/// 当条件为true添加消息并换行
/// </summary>
/// <param name="log">配置项</param>
/// <param name="message">消息</param>
/// <param name="condition">条件,值为true则添加消息</param>
/// <param name="args">日志消息参数</param>
public static ILog AppendLineIf( this ILog log, string message, bool condition, params object[] args ) {
log.CheckNull( nameof( log ) );
if ( condition ) {
log.Message( message, args );
log.Message( Environment.NewLine );
}
return log;
} /// <summary>
/// 消息换行
/// </summary>
/// <param name="log">配置项</param>
public static ILog Line( this ILog log ) {
log.CheckNull( nameof(log) );
log.Message( Environment.NewLine );
return log;
}
}

LogContext 日志上下文

通过日志上下文自动记录重要的额外信息.

/// <summary>
/// 日志上下文
/// </summary>
public class LogContext {
/// <summary>
/// 初始化日志上下文
/// </summary>
public LogContext() {
Data = new Dictionary<string, object>();
} /// <summary>
/// 计时器
/// </summary>
public Stopwatch Stopwatch { get; set; }
/// <summary>
/// 跟踪标识
/// </summary>
public string TraceId { get; set; }
/// <summary>
/// 用户标识
/// </summary>
public string UserId { get; set; }
/// <summary>
/// 应用程序
/// </summary>
public string Application { get; set; }
/// <summary>
/// 执行环境
/// </summary>
public string Environment { get; set; }
/// <summary>
/// 扩展数据
/// </summary>
public IDictionary<string, object> Data { get; }
}

LogContextMiddleware 日志上下文中间件

日志上下文中间件创建日志上下文,并添加到 HttpContext 对象的 Items .

/// <summary>
/// 日志上下文中间件
/// </summary>
public class LogContextMiddleware {
/// <summary>
/// 下个中间件
/// </summary>
private readonly RequestDelegate _next; /// <summary>
/// 初始化日志上下文中间件
/// </summary>
/// <param name="next">下个中间件</param>
public LogContextMiddleware( RequestDelegate next ) {
_next = next;
} /// <summary>
/// 执行中间件
/// </summary>
/// <param name="context">Http上下文</param>
public async Task Invoke( HttpContext context ) {
var traceId = context.Request.Headers["x-correlation-id"].SafeString();
if ( traceId.IsEmpty() )
traceId = context.TraceIdentifier;
var session = context.RequestServices.GetService<Util.Sessions.ISession>();
var environment = context.RequestServices.GetService<IWebHostEnvironment>();
var logContext = new LogContext {
Stopwatch = Stopwatch.StartNew(),
TraceId = traceId,
UserId = session?.UserId,
Application = environment?.ApplicationName,
Environment = environment?.EnvironmentName
};
context.Items[LogContextAccessor.LogContextKey] = logContext;
await _next( context );
}
}

ILogContextAccessor 日志上下文访问器

日志上下文访问器从 HttpContext.Items 获取日志上下文.

/// <summary>
/// 日志上下文访问器
/// </summary>
public interface ILogContextAccessor {
/// <summary>
/// 日志上下文
/// </summary>
LogContext Context { get; set; }
} /// <summary>
/// 日志上下文访问器
/// </summary>
public class LogContextAccessor : ILogContextAccessor {
/// <summary>
/// 日志上下文键名
/// </summary>
public const string LogContextKey = "Util.Logging.LogContext"; /// <summary>
/// 日志上下文
/// </summary>
public LogContext Context {
get => Util.Helpers.Convert.To<LogContext>( Web.HttpContext.Items[LogContextKey] );
set => Web.HttpContext.Items[LogContextKey] = value;
}
}

LogContextEnricher 日志上下文扩展

Serilog 提供 ILogEventEnricher 接口用于设置扩展属性.

LogContextEnricher 使用 Ioc.Create 方法获取依赖服务 ILogContextAccessor.

这是因为不能使用依赖注入,它要求实现类必须是无参构造函数.

Ioc.Create 在 Asp.Net Core 环境获取依赖服务是安全的,但在其它环境则可能获取失败.

如果获取日志上下文失败,也不会对功能造成影响,只是丢失了一些上下文信息.

/// <summary>
/// 日志上下文扩展属性
/// </summary>
public class LogContextEnricher : ILogEventEnricher {
/// <summary>
/// 扩展属性
/// </summary>
/// <param name="logEvent">日志事件</param>
/// <param name="propertyFactory">日志事件属性工厂</param>
public void Enrich( LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
var accessor = Ioc.Create<ILogContextAccessor>();
if ( accessor == null )
return;
var context = accessor.Context;
if ( context == null )
return;
if ( logEvent == null )
return;
if ( propertyFactory == null )
return;
RemoveProperties( logEvent );
AddDuration( context,logEvent, propertyFactory );
AddTraceId( context, logEvent, propertyFactory );
AddUserId( context, logEvent, propertyFactory );
AddApplication( context, logEvent, propertyFactory );
AddEnvironment( context, logEvent, propertyFactory );
AddData( context, logEvent, propertyFactory );
} /// <summary>
/// 移除默认设置的部分属性
/// </summary>
private void RemoveProperties( LogEvent logEvent ) {
logEvent.RemovePropertyIfPresent( "ActionId" );
logEvent.RemovePropertyIfPresent( "ActionName" );
logEvent.RemovePropertyIfPresent( "RequestId" );
logEvent.RemovePropertyIfPresent( "RequestPath" );
logEvent.RemovePropertyIfPresent( "ConnectionId" );
} /// <summary>
/// 添加执行持续时间
/// </summary>
private void AddDuration( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context?.Stopwatch == null )
return;
var property = propertyFactory.CreateProperty( "Duration", context.Stopwatch.Elapsed.Description() );
logEvent.AddOrUpdateProperty( property );
} /// <summary>
/// 添加跟踪号
/// </summary>
private void AddTraceId( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context == null || context.TraceId.IsEmpty() )
return;
var property = propertyFactory.CreateProperty( "TraceId", context.TraceId );
logEvent.AddOrUpdateProperty( property );
} /// <summary>
/// 添加用户标识
/// </summary>
private void AddUserId( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context == null || context.UserId.IsEmpty() )
return;
var property = propertyFactory.CreateProperty( "UserId", context.UserId );
logEvent.AddOrUpdateProperty( property );
} /// <summary>
/// 添加应用程序
/// </summary>
private void AddApplication( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context == null || context.Application.IsEmpty() )
return;
var property = propertyFactory.CreateProperty( "Application", context.Application );
logEvent.AddOrUpdateProperty( property );
} /// <summary>
/// 添加执行环境
/// </summary>
private void AddEnvironment( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context == null || context.Environment.IsEmpty() )
return;
var property = propertyFactory.CreateProperty( "Environment", context.Environment );
logEvent.AddOrUpdateProperty( property );
} /// <summary>
/// 添加扩展数据
/// </summary>
private void AddData( LogContext context, LogEvent logEvent, ILogEventPropertyFactory propertyFactory ) {
if ( context?.Data == null || context.Data.Count == 0 )
return;
foreach ( var item in context.Data ) {
var property = propertyFactory.CreateProperty( item.Key, item.Value );
logEvent.AddOrUpdateProperty( property );
}
}
}

LoggerEnrichmentConfigurationExtensions

将 LogContextEnricher 扩展到 LoggerEnrichmentConfiguration 上.

/// <summary>
/// Serilog扩展属性配置扩展
/// </summary>
public static class LoggerEnrichmentConfigurationExtensions {
/// <summary>
/// 添加日志上下文扩展属性
/// </summary>
/// <param name="source">日志扩展配置</param>
public static LoggerConfiguration WithLogContext( this LoggerEnrichmentConfiguration source ) {
source.CheckNull( nameof( source ) );
return source.With<LogContextEnricher>();
} /// <summary>
/// 添加日志级别扩展属性
/// </summary>
/// <param name="source">日志扩展配置</param>
public static LoggerConfiguration WithLogLevel( this LoggerEnrichmentConfiguration source ) {
source.CheckNull( nameof( source ) );
return source.With<LogLevelEnricher>();
}
}

AddSerilog 配置方法

AddSerilog 配置方法封装了 Serilog 的配置.

  • 配置 ILog 接口服务依赖.

  • 将 Asp.Net Core 日志级别转换为 Serilog 日志级别.

  • 设置日志上下文扩展.

/// <summary>
/// Serilog日志操作扩展
/// </summary>
public static class AppBuilderExtensions {
/// <summary>
/// 配置Serilog日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
public static IAppBuilder AddSerilog( this IAppBuilder builder ) {
return builder.AddSerilog( false );
} /// <summary>
/// 配置Serilog日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="isClearProviders">是否清除默认设置的日志提供程序</param>
public static IAppBuilder AddSerilog( this IAppBuilder builder, bool isClearProviders ) {
return builder.AddSerilog( options => {
options.IsClearProviders = isClearProviders;
} );
} /// <summary>
/// 配置Serilog日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="appName">应用程序名称</param>
public static IAppBuilder AddSerilog( this IAppBuilder builder, string appName ) {
return builder.AddSerilog( options => {
options.Application = appName;
} );
} /// <summary>
/// 配置Serilog日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="setupAction">日志配置操作</param>
public static IAppBuilder AddSerilog( this IAppBuilder builder, Action<LogOptions> setupAction ) {
builder.CheckNull( nameof( builder ) );
var options = new LogOptions();
setupAction?.Invoke( options );
builder.Host.ConfigureServices( ( context, services ) => {
services.AddSingleton<ILogFactory, LogFactory>();
services.AddTransient( typeof( ILog<> ), typeof( Log<> ) );
services.AddTransient( typeof( ILog ), t => t.GetService<ILogFactory>()?.CreateLog( "default" ) ?? NullLog.Instance );
var configuration = context.Configuration;
services.AddLogging( loggingBuilder => {
if ( options.IsClearProviders )
loggingBuilder.ClearProviders();
SerilogLog.Logger = new LoggerConfiguration()
.Enrich.WithProperty( "Application", options.Application )
.Enrich.FromLogContext()
.Enrich.WithLogLevel()
.Enrich.WithLogContext()
.ReadFrom.Configuration( configuration )
.ConfigLogLevel( configuration )
.CreateLogger();
loggingBuilder.AddSerilog();
} );
} );
return builder;
}
}

AddExceptionless 配置方法

AddExceptionless 配置方法封装了 Serilog 和 Exceptionless 的配置.

  • 配置 ILog 接口服务依赖.

  • 将 Asp.Net Core 日志级别转换为 Exceptionless 日志级别.

  • 设置日志上下文扩展.

/// <summary>
/// Exceptionless日志操作扩展
/// </summary>
public static class AppBuilderExtensions {
/// <summary>
/// 配置Exceptionless日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="isClearProviders">是否清除默认设置的日志提供程序</param>
public static IAppBuilder AddExceptionless( this IAppBuilder builder, bool isClearProviders = false ) {
return builder.AddExceptionless( null, isClearProviders );
} /// <summary>
/// 配置Exceptionless日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="appName">应用程序名称</param>
public static IAppBuilder AddExceptionless( this IAppBuilder builder, string appName ) {
return builder.AddExceptionless( null, appName );
} /// <summary>
/// 配置Exceptionless日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="configAction">Exceptionless日志配置操作</param>
/// <param name="isClearProviders">是否清除默认设置的日志提供程序</param>
public static IAppBuilder AddExceptionless( this IAppBuilder builder, Action<ExceptionlessConfiguration> configAction, bool isClearProviders = false ) {
return builder.AddExceptionless( configAction, t => t.IsClearProviders = isClearProviders );
} /// <summary>
/// 配置Exceptionless日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="configAction">Exceptionless日志配置操作</param>
/// <param name="appName">应用程序名称</param>
public static IAppBuilder AddExceptionless( this IAppBuilder builder, Action<ExceptionlessConfiguration> configAction, string appName ) {
return builder.AddExceptionless( configAction, t => t.Application = appName );
} /// <summary>
/// 配置Exceptionless日志操作
/// </summary>
/// <param name="builder">应用生成器</param>
/// <param name="configAction">Exceptionless日志配置操作</param>
/// <param name="setupAction">日志配置</param>
public static IAppBuilder AddExceptionless( this IAppBuilder builder, Action<ExceptionlessConfiguration> configAction, Action<LogOptions> setupAction ) {
builder.CheckNull( nameof( builder ) );
var options = new LogOptions();
setupAction?.Invoke( options );
builder.Host.ConfigureServices( ( context, services ) => {
services.AddSingleton<ILogFactory, LogFactory>();
services.AddTransient( typeof( ILog<> ), typeof( Log<> ) );
services.AddTransient( typeof( ILog ), t => t.GetService<ILogFactory>()?.CreateLog( "default" ) ?? NullLog.Instance );
var configuration = context.Configuration;
services.AddLogging( loggingBuilder => {
if ( options.IsClearProviders )
loggingBuilder.ClearProviders();
ConfigExceptionless( configAction, configuration );
SerilogLog.Logger = new LoggerConfiguration()
.Enrich.WithProperty( "Application", options.Application )
.Enrich.FromLogContext()
.Enrich.WithLogLevel()
.Enrich.WithLogContext()
.WriteTo.Exceptionless()
.ReadFrom.Configuration( configuration )
.ConfigLogLevel( configuration )
.CreateLogger();
loggingBuilder.AddSerilog();
} );
} );
return builder;
} /// <summary>
/// 配置Exceptionless
/// </summary>
private static void ConfigExceptionless( Action<ExceptionlessConfiguration> configAction, IConfiguration configuration ) {
ExceptionlessClient.Default.Startup();
if ( configAction != null ) {
configAction( ExceptionlessClient.Default.Configuration );
ConfigLogLevel( configuration, ExceptionlessClient.Default.Configuration );
return;
}
ExceptionlessClient.Default.Configuration.ReadFromConfiguration( configuration );
ConfigLogLevel( configuration, ExceptionlessClient.Default.Configuration );
} /// <summary>
/// 配置日志级别
/// </summary>
private static void ConfigLogLevel( IConfiguration configuration, ExceptionlessConfiguration options ) {
var section = configuration.GetSection( "Logging:LogLevel" );
foreach ( var item in section.GetChildren() ) {
if ( item.Key == "Default" ) {
options.Settings.Add( "@@log:*", GetLogLevel( item.Value ) );
continue;
}
options.Settings.Add( $"@@log:{item.Key}*", GetLogLevel( item.Value ) );
}
} /// <summary>
/// 获取日志级别
/// </summary>
private static string GetLogLevel( string logLevel ) {
switch ( logLevel.ToUpperInvariant() ) {
case "TRACE":
return "Trace";
case "DEBUG":
return "Debug";
case "INFORMATION":
return "Info";
case "ERROR":
return "Error";
case "CRITICAL":
return "Fatal";
case "NONE":
return "Off";
default:
return "Warn";
}
}
}

Util应用框架基础(六) - 日志记录(一) - 正文的更多相关文章

  1. 从零开始编写自己的C#框架(20)——框架异常处理及日志记录

    最近很忙,杂事也多,所以开发本框架也是断断续续的,终于在前两天将前面设定的功能都基本完成了,剩下一些小功能遗漏的以后发现再补上.接下来的章节主要都是讲解在本框架的基础上进行开发的小巧. 本框架主要有四 ...

  2. [编程基础] Python日志记录库logging总结

    Python日志记录教程展示了如何使用日志记录模块在Python中进行日志记录. 文章目录 1 介绍 1.1 背景 1.2 Python日志记录模块 1.3 根记录器 2 Python logging ...

  3. Gin 框架 - 使用 logrus 进行日志记录

    目录 概述 日志格式 Logrus 使用 推荐阅读 概述 上篇文章分享了 Gin 框架的路由配置,这篇文章分享日志记录. 查了很多资料,Go 的日志记录用的最多的还是 github.com/sirup ...

  4. PHP框架中的日志系统

    现在在一家公司做PHP后台开发程序猿(我们组没有前端,做活动时会做前端的东西),刚开始到公司的时候花2个周赶出了一个前端加后台的活动(记得当时做不出来周末加了两天班...),到现在过去4个多月了,可以 ...

  5. Asp.Net Core 2.0 项目实战(9) 日志记录,基于Nlog或Microsoft.Extensions.Logging的实现及调用实例

    本文目录 1. Net下日志记录 2. NLog的使用     2.1 添加nuget引用NLog.Web.AspNetCore     2.2 配置文件设置     2.3 依赖配置及调用     ...

  6. 清晰梳理最全日志框架关系与日志配置-SpringBoot 2.7.2 实战基础

    优雅哥 SpringBoot 2.7.2 实战基础 - 07 - 日志配置 Java 中日志相关的 jar 包非常多,log4j.log4j2.commons-logging.logback.slf4 ...

  7. 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)

    前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...

  8. 《手把手教你》系列基础篇(八十四)-java+ selenium自动化测试-框架设计基础-TestNG日志-上篇(详解教程)

    1.简介 TestNG还为我们提供了测试的记录功能-日志.例如,在运行测试用例期间,用户希望在控制台中记录一些信息.信息可以是任何细节取决于目的.牢记我们正在使用Selenium进行测试,我们需要有助 ...

  9. Web APi之异常处理(Exception)以及日志记录(NLog)(十六)

    前言 上一篇文章我们介绍了关于日志记录用的是Log4net,确实也很挺强大,但是别忘了我们.NET有专属于我们的日志框架,那就是NLog,相对于Log4net而言,NLog可以说也是一个很好的记录日志 ...

  10. 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大

    讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1.功能太少:2.效率低下:3.线程锁bug等等等各种莫名其妙的bug一直都没解决. 其实最重要的是log4j的作者自己也放弃了l ...

随机推荐

  1. 王道oj/problem13(用递归数楼梯)

    网址:http://oj.lgwenda.com/problem/13 思路:用递归写step(int n):return step(n-1)+step(n-2); 停止条件是:n=1为1:n=2为2 ...

  2. CSS3属性 2D转换

    * { margin: 0; padding: 0 } table { border-spacing: 0; border-collapse: collapse; margin: 10px auto ...

  3. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-11-playwright操作iframe-上篇

    1.简介 原估计宏哥这里就不对iframe这个知识点做介绍和讲解了,因为前边的窗口切换就为这种网页处理提供了思路,另一个原因就是虽然iframe很强大,但是现在很少有网站用它了.但是还是有小伙伴或者童 ...

  4. LeetCode 周赛上分之旅 #40 结合特征压缩的数位 DP 问题

    ️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...

  5. 拼多多根据ID取商品详情 API 返回值说明

    ​ item_get-根据ID取商品详情 注册开通 pinduoduo.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) se ...

  6. 每日一库:pprof简介

    pprof简介 pprof是Go语言的一个性能分析库,它可以帮助开发者找出程序中的性能瓶颈.pprof提供了CPU分析.内存分析.阻塞分析等多种性能分析功能. 以下是pprof的主要特性: CPU分析 ...

  7. Python/Java/Php/C#/Go/C/C++这几个主力语言,谁到底真的不行

    1.前言 阿里最近又进行了史诗级的大裁员,IT行业肉眼可见的持续性衰退与没落.当潮水退却,才能看出谁在裸泳.作为当今计算机编程界的几大主力语言,谁才真正的裸泳者呢? 2.描述 1.Python: Py ...

  8. 二叉搜索树(Binary Search Tree,BST)

    二叉搜索树(Binary Search Tree,BST) 二叉搜索树(Binary Search Tree),也称二叉查找树或二叉排序树,是一种特殊的二叉树,它满足以下性质 对于二叉搜索树的每个节点 ...

  9. Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例

    Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例 点击封面跳转到Unity国际版下载页面 简介 在Unity中, ...

  10. SpringCloud搭建保姆级教程

    一.搭建服务注册与发现中⼼ 使⽤Spring Cloud Netflix 中的 Eureka 搭建服务注册与发现中⼼ 1.创建SpringBoot应用添加依赖 1.spring web 2.eurek ...