『贴代码』
PasteSpider
PasteForm
精选作品
优选问答
成长笔记
【本期话题】更多
                                    我们在开发中经常遇到对方的接口请求有频率限制,比如当前接口每秒的请求不能大于100,不能大于1000,对于这样的,我们作为请求方,如何做限定?
                    
Serilog的全局处理,发生异常后,如何统一处理?只要引入一个ILogEventSink即可,一起瞧瞧去
贴代码 2025-11-11 17 0 0
在开发过程中,相信日志对于大家来说再熟悉不过了,不过我个人是不赞成到处打日志的,因为日志打得多,严重影响性能!!!那么多异常等信息,你要如何统一处理呢?

在Serilog中有这么一个东西ILogEventSink
简单意思,就是日志得一个事件!
所以我们可以通过这个事件来干点我们想要的事!

                Log.Logger = new LoggerConfiguration()
                    .ReadFrom.Configuration(Configuration)
                    .WriteTo.Sink(new SerilogCustomHandler(builder.Services), Serilog.Events.LogEventLevel.Error)
                    .Enrich.FromLogContext()
                    .CreateLogger();

直接上代码,注意看上面得SerilogCustomHandler,有没有发现我带入了一个参数builder.Services,为啥不用注入得方式呢???
这是一个坑,而且我走过了!!!
先看看SerilogCustomHandler得代码

    public class SerilogCustomHandler : ILogEventSink
    {
        /// <summary>
        /// 
        /// </summary>
        public IServiceProvider ServiceProvider { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        public SerilogCustomHandler(IServiceProvider _serviceProvider)
        {
            ServiceProvider = _serviceProvider;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logEvent"></param>
        public void Emit(LogEvent logEvent)
        {
            try
            {
                if (ServiceProvider != null)
                {
                    var _channel = ServiceProvider.GetRequiredService<ChannelHelper>();
                    Console.WriteLine($"channel is null:{(_channel == null)}!");
                }
                Console.WriteLine("--------- --  ----------- happend error wait to push!" + logEvent.MessageTemplate.ToString());
            }
            catch (Exception exl)
            {
                Console.WriteLine(exl.ToString());
            }
        }
    }

可以看到注释部分,我是想使用Channel推送出去的,这个看你的需求改成自己i想要的样子即可!

一起来看看DeepSeek如何说

你的困惑很有道理!让我用一个更直观的方式来解释这个问题。

时间线理解法

想象一下程序启动的时间线:

时间点1: Program.Main 开始执行
    ↓
时间点2: 执行 Log.Logger = new LoggerConfiguration()...
    ↓   此时创建了 SerilogCustomSink,但 ServiceProvider 还是 null!
时间点3: 构建 Host,ServiceProvider 被赋值
    ↓
时间点4: 应用程序运行

关键问题SerilogCustomSink时间点2 就被创建并”固化”在 Serilog 中,而 ServiceProvider时间点3 才被赋值。

代码演示这个时间差

public class Program
{
    public static IServiceProvider ServiceProvider { get; set; }

    public static void Main(string[] args)
    {
        Console.WriteLine("时间点1: Main开始");

        // 时间点2: 初始化Serilog
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Sink(new SerilogCustomSink(), LogEventLevel.Error)
            .CreateLogger();

        Console.WriteLine($"Serilog初始化时 ServiceProvider = {ServiceProvider}"); // null!

        // 时间点3: 构建Host
        var host = CreateHostBuilder(args).Build();
        ServiceProvider = host.Services; // 现在才有值!

        Console.WriteLine($"Host构建后 ServiceProvider = {ServiceProvider}"); // 有值了

        // 但问题是:SerilogCustomSink 早在时间点2就创建好了!
        // 它内部的 ServiceProvider 引用还是 null

        host.Run();
    }
}

public class SerilogCustomSink : ILogEventSink
{
    public SerilogCustomSink()
    {
        // 构造函数在时间点2执行,此时 ServiceProvider 是 null
        Console.WriteLine($"Sink创建时 ServiceProvider = {Program.ServiceProvider}"); // null!
    }

    public void Emit(LogEvent logEvent)
    {
        // 即使后来 ServiceProvider 有值了,但这里的引用还是创建时的状态
        Console.WriteLine($"日志输出时 ServiceProvider = {Program.ServiceProvider}");
    }
}

更直观的比喻

SerilogCustomSink 想象成一个”照片”:

// 就像拍照一样,这一刻的状态被定格了
var sink = new SerilogCustomSink(); // "拍照"时刻:ServiceProvider = null

// 后来改变了原场景
ServiceProvider = host.Services; // 改变了现实

// 但照片不会自动更新!sink 里面看到的还是拍照时的 null

解决方案的本质

不要依赖会变化的外部状态,而是通过构造函数传入确定的值!

评论列表
贴代码
0 17 0
快捷注册
用户问答更多
PasteForm,神奇了啊!都说低代码,低代码,那个是对于非开发者来说的,感觉PasteForm就是开发者的低代码啊!只要配置好Model,就有对应的CRUD操作,还带一些逻辑,和生成代码是两码事了!!!问题来了,有什么局限性,或者适用哪些场景?
07月份版本的内存占用比以前大了,也没有泄漏,啥情况?以前200MB,这个版本能到300MB
文档中的组织归属有些问题,啥时候看看,更新更新!
  • 已经升级了,主要是left join的查询的时候没有过滤,其实这个问题,多租户也是一样的!

最新动态
  • 216.****.167 正在查看 文章列表页 !
  • 216.****.167 正在查看 文章列表页 !
  • 52.****.229 正在查看 PasteTemplate和PasteBuilder的使用教程 !
  • 216.****.167 正在查看 文章列表页 !
  • 216.****.167 正在查看 文章列表页 !
  • 216.****.167 正在查看 文章列表页 !
  • 216.****.167 正在查看 PasteForm字段的属性一览(持续升级) !
  • 216.****.167 正在查看 框架PasteForm实际开发案例,支持多级对象的表单看看有多简单只要几个特性即可!(1) !
  • 216.****.167 正在查看 贴代码框架PasteForm特性介绍之markdown和richtext !
  • 216.****.167 正在查看 贴代码框架PasteForm特性介绍之file特性(上传文件) !
  • 216.****.167 正在查看 使用ABP框架不得不留意的一个工具,PasteBuilder代码生成器使用介绍,特别适用于PasteForm框架 !
欢迎加入QQ讨论群 296245685 [PasteSpider]介绍 [PasteForm]介绍 @2022-2023 PasteCode.cn 版权所有 ICP证 闽ICP备2021013869号-2