You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Npgsql按PostgreSQL存储过程的日志级别输出日志?

让Npgsql按PostgreSQL存储过程定义的级别输出日志

默认情况下,Npgsql会把PostgreSQL存储过程里的RAISE NOTICE/INFO/WARNING这类通知全当成Debug级别输出到.NET日志系统——这是它默认的日志处理逻辑导致的。要实现按存储过程定义的级别输出,你需要自定义日志处理逻辑,把PostgreSQL的通知级别映射到对应的.NET LogLevel。

步骤1:实现自定义Npgsql日志类

写一个自定义日志类,实现INpgsqlLogger接口,在Log方法里完成PostgreSQL级别到.NET日志级别的映射:

Imports Microsoft.Extensions.Logging
Imports Npgsql.Logging

Public Class CustomNpgsqlLogger
    Implements INpgsqlLogger

    Private ReadOnly _logger As ILogger
    Private ReadOnly _categoryName As String

    Public Sub New(logger As ILogger, categoryName As String)
        _logger = logger
        _categoryName = categoryName
    End Sub

    Public Sub Log(level As NpgsqlLogLevel, msg As String, exception As Exception, parameters As Object()) Implements INpgsqlLogger.Log
        ' 把PostgreSQL日志级别映射到.NET对应的LogLevel
        Dim netLevel As LogLevel = level switch {
            NpgsqlLogLevel.Debug => LogLevel.Debug,
            NpgsqlLogLevel.Info => LogLevel.Information,
            NpgsqlLogLevel.Warn => LogLevel.Warning,
            NpgsqlLogLevel.Error => LogLevel.Error,
            NpgsqlLogLevel.Fatal => LogLevel.Critical,
            _ => LogLevel.Debug
        }

        ' 提取RAISE语句的纯消息内容(去掉默认的"Received notice: "前缀)
        If msg.StartsWith("Received notice: ") Then
            Dim noticeMsg = msg.Substring("Received notice: ".Length)
            _logger.Log(netLevel, exception, noticeMsg, parameters)
        Else
            _logger.Log(netLevel, exception, msg, parameters)
        End If
    End Sub

    Public Function IsEnabled(level As NpgsqlLogLevel) As Boolean Implements INpgsqlLogger.IsEnabled
        ' 判断当前级别是否需要输出
        Dim netLevel As LogLevel = level switch {
            NpgsqlLogLevel.Debug => LogLevel.Debug,
            NpgsqlLogLevel.Info => LogLevel.Information,
            NpgsqlLogLevel.Warn => LogLevel.Warning,
            NpgsqlLogLevel.Error => LogLevel.Error,
            NpgsqlLogLevel.Fatal => LogLevel.Critical,
            _ => LogLevel.Debug
        }
        Return _logger.IsEnabled(netLevel)
    End Function
End Class

步骤2:实现自定义日志工厂

再写一个日志工厂类,用来生成上面的自定义日志实例:

Imports Microsoft.Extensions.Logging
Imports Npgsql.Logging

Public Class CustomNpgsqlLoggerFactory
    Implements INpgsqlLoggerFactory

    Private ReadOnly _factory As ILoggerFactory

    Public Sub New(factory As ILoggerFactory)
        _factory = factory
    End Sub

    Public Function CreateLogger(name As String) As INpgsqlLogger Implements INpgsqlLoggerFactory.CreateLogger
        Dim logger = _factory.CreateLogger(name)
        Return New CustomNpgsqlLogger(logger, name)
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        ' 按需释放资源
    End Sub
End Class

步骤3:替换日志初始化代码

把原来的Npgsql日志初始化代码换成自定义的版本:

' 初始化.NET原生日志工厂
Dim varloggerFactory = LoggerFactory.Create(Function(builder)
                                                builder.AddConsole()
                                                       .SetMinimumLevel(LogLevel.Debug) ' 确保包含你需要的最低级别
                                            End Function)

' 启用自定义Npgsql日志逻辑
NpgsqlLoggingConfiguration.InitializeLogging(New CustomNpgsqlLoggerFactory(varloggerFactory))

效果验证

现在执行存储过程里的RAISE语句,日志会按对应级别输出:

  • RAISE INFO 'This is info!' → 输出info:级别日志
  • RAISE DEBUG 'This is debug!' → 输出dbug:级别日志
  • RAISE WARNING 'This is warning!' → 输出warn:级别日志
  • RAISE NOTICE 'DOES THIS SHOW UP IN THE TEXT?' → PostgreSQL的NOTICE默认对应Npgsql的Info级别,所以会输出info:级别(如果要单独调整NOTICE的级别,可在CustomNpgsqlLogger的Log方法里单独判断处理)
  • RAISE EXCEPTION 'This is an error message' → 依然按Error级别输出

补充说明

如果需要更精准地处理PostgreSQL通知(比如直接获取通知的原始级别),可以监听Npgsql连接的Notification事件,这种方式能拿到NotificationEventArgs里的Severity属性,直接对应PostgreSQL的级别,再手动输出对应级别的日志。不过上面的自定义日志方式已经能满足大部分场景需求。

内容的提问来源于stack exchange,提问作者dusty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:05:40