如何修改ServiceStack JsonApiClient的默认日志行为?
解决ServiceStack JsonApiClient将4xx状态码记录为错误日志的问题
要调整JsonApiClient对4xx状态码的日志级别,核心是拦截或覆盖其默认的日志判断逻辑,以下是几种可行方案:
方案1:自定义ILogger实现状态码感知的日志级别转换
通过包装默认的ILogger,在日志记录时根据状态码动态调整级别,将4xx请求转为警告级别,5xx及其他错误保留错误级别:
// 自定义Logger,根据状态码调整日志级别 public class StatusCodeAwareLogger : ILogger { private readonly ILogger _innerLogger; public StatusCodeAwareLogger(ILogger innerLogger) => _innerLogger = innerLogger; public IDisposable BeginScope<TState>(TState state) => _innerLogger.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => _innerLogger.IsEnabled(logLevel); public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { var logMessage = formatter(state, exception); // 检测日志内容中的4xx状态码 bool isClientError = logMessage.Contains("400") || logMessage.Contains("401") || logMessage.Contains("403") || logMessage.Contains("404"); if (logLevel == LogLevel.Error && isClientError) { // 将4xx错误日志转为警告级别 _innerLogger.Log(LogLevel.Warning, eventId, state, exception, formatter); } else { // 其他情况保留原日志级别 _innerLogger.Log(logLevel, eventId, state, exception, formatter); } } } // 自定义LoggerFactory包装器 public class StatusCodeAwareLoggerFactory : ILoggerFactory { private readonly ILoggerFactory _innerFactory; public StatusCodeAwareLoggerFactory(ILoggerFactory innerFactory) => _innerFactory = innerFactory; public void AddProvider(ILoggerProvider provider) => _innerFactory.AddProvider(provider); public ILogger CreateLogger(string categoryName) => new StatusCodeAwareLogger(_innerFactory.CreateLogger(categoryName)); }
使用方式
创建JsonApiClient时传入自定义LoggerFactory:
var defaultFactory = LoggerFactory.Create(builder => builder.AddConsole()); var client = new JsonApiClient("http://localhost:8080") { LoggerFactory = new StatusCodeAwareLoggerFactory(defaultFactory) };
方案2:继承JsonApiClient重写SendAsync方法
通过继承JsonApiClient,重写核心请求方法,自定义异常和响应的日志逻辑:
public class CustomJsonApiClient : JsonApiClient { public CustomJsonApiClient(string baseUri) : base(baseUri) {} protected override async Task<TResponse> SendAsync<TResponse>(HttpMethod httpMethod, string relativeOrAbsoluteUrl, object request, CancellationToken token = default) { try { var response = await base.SendAsync<TResponse>(httpMethod, relativeOrAbsoluteUrl, request, token); // 处理返回带状态码的响应(实现IHasStatusCode的情况) if (response is IHasStatusCode hasStatusCode && hasStatusCode.StatusCode >= 400 && hasStatusCode.StatusCode < 500) { Logger.LogWarning("SendAsync: {StatusCode} {StatusDescription}", hasStatusCode.StatusCode, HttpStatusCode.GetName((HttpStatusCode)hasStatusCode.StatusCode)); } return response; } catch (WebServiceException ex) { // 处理请求抛出的异常 if (ex.StatusCode >= 400 && ex.StatusCode < 500) { Logger.LogWarning("SendAsync: {Status} {StatusCode} - {Message}", ex.Status, ex.StatusCode, ex.Message); } else { Logger.LogError(ex, "SendAsync: {Status} {StatusCode}", ex.Status, ex.StatusCode); } throw; } } }
使用方式
直接实例化自定义客户端:
var client = new CustomJsonApiClient("http://localhost:8080");
方案3:通过日志过滤规则屏蔽4xx错误日志(快速临时方案)
如果只是想临时屏蔽4xx的错误日志,可通过日志框架的过滤规则实现(以Microsoft.Extensions.Logging为例):
var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole() .AddFilter("ServiceStack.JsonApiClient", (logLevel, _, state, __) => { if (logLevel == LogLevel.Error) { var message = state.ToString(); // 排除包含4xx状态码的错误日志 return !(message.Contains("400") || message.Contains("401") || message.Contains("403") || message.Contains("404")); } return true; }); }); var client = new JsonApiClient("http://localhost:8080") { LoggerFactory = loggerFactory };
注意:此方案会直接过滤掉4xx的错误日志,无法转为警告级别,适合临时场景。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

