如何让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
相关产品推荐
相关产品推荐

