【问题标题】:Nlog Doesn't Work Correctly In Dotnetty HandlerNlog 在 Dotnetty 处理程序中无法正常工作
【发布时间】:2019-12-31 04:33:34
【问题描述】:

我编写了一个 Dotnetty 服务器并使用 Nlog 作为日志框架。每个连接都有自己的 ID,我想将此 ID 与其他数据(消息、日期时间等)一起记录到 Sql。由于 Dotnetty 通过单线程处理多个连接,因此使用 mdlc/ndlc 记录 ID 会导致记录不正确的数据(不正确的意思是一个连接 ID 与另一个连接数据一起记录)。我可以使用 logevent 属性,但我必须将连接 ID 传递给我想要登录的每个类/方法。有什么建议吗?

这是自定义记录器

 public void SetFlowmeterSerial(long? flowmeterSerial)
    {
        MappedDiagnosticsLogicalContext.Set("Serial",flowmeterSerial);
    }

    public long GetSerialNumber()
    {
      return   Convert.ToInt64(MappedDiagnosticsLogicalContext.Get("Serial"));


    }

数据库的 NLogConfig

public static void DataBaseTarget(LogLevel min, LogLevel max, LoggingConfiguration config, string 
name,string connectionString,string databaseName)
    {
        var greDateTime = TimeCodec.Trim(DateTime.Now,TimeSpan.TicksPerSecond);
        var persianDateTime = TimeCodec.GreToPersianDateTime(greDateTime);
        var sqlFormattedDateTime = greDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
        var databaseTarget = new DatabaseTarget
        {
            ConnectionString = connectionString,//"server=.;database=FlowMeterSimulatorLOG;integrated security=sspi",
            DBProvider = "System.Data.SqlClient",
            DBDatabase = databaseName,//"FlowMeterSimulatorLOG",
            DBHost = ".",
            CommandText =
                $"insert into SystemLog (FlowMeterSerial,GreDateTime,PersianDateTime,Level,CallSite,Message,ExceptionType,ExceptionMessage,StackTrace)values(@FlowMeterSerial,'{sqlFormattedDateTime}','{persianDateTime}',@Level,@CallSite,@Message,@ExceptionType,@ExceptionMessage,@StackTrace);",
        };
        var param = new DatabaseParameterInfo { Name = "@Level", Layout = "${level}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@CallSite", Layout = "${callsite}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@Message", Layout = "${message}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@ExceptionType", Layout = "${exception:format=type}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@ExceptionMessage", Layout = "${exception:format=message}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@StackTrace", Layout = "${exception:format=stackTrace}" };
        databaseTarget.Parameters.Add(param);
        param = new DatabaseParameterInfo { Name = "@FlowMeterSerial", Layout = "${mdlc:item=Serial}" };
        databaseTarget.Parameters.Add(param);

        config.AddRule(min, max, databaseTarget);
        LogManager.Configuration = config;
    }

Dotnetty 处理程序

    public class LogHandler : ChannelHandlerAdapter
{
    private readonly CustomLogger _logger = (CustomLogger) LogManager.GetCurrentClassLogger(typeof(CustomLogger));

    //private static readonly ILogger _logger = LogManager.GetCurrentClassLogger();
    private long _serialNumber;

    public override void ChannelRead(IChannelHandlerContext context, object message)
    {
        if (!(message is IByteBuffer buffer))
            throw new ArgumentException();
        var deviceInfo = context.Channel.GetAttribute(ProcessHandler.DeviceInfo).Get();
        if (deviceInfo != null)
            _serialNumber = deviceInfo.Serial;
        _logger.SetFlowmeterSerial(_serialNumber);
        _logger?.Debug(
            $"Received: {ByteBufferUtil.HexDump(buffer)}");
        base.ChannelRead(context, message);
    }

    public override async Task WriteAsync(IChannelHandlerContext context, object message)
    {
        try
        {
            if (!(message is IByteBuffer buffer)) throw new ArgumentException();
            try
            {
                //_logger.SetFlowmeterSerial(_serialNumber);
                _logger?.Debug(
                    $"Sent: {ByteBufferUtil.HexDump(buffer)}");
                await base.WriteAsync(context, message).ConfigureAwait(false);
            }
            catch
            {
                if (buffer.ReferenceCount != 0) buffer.Release();
                throw;
            }
        }
        catch (Exception e)
        {
            context.FireExceptionCaught(e);
            //await Task.FromException(e);
        }
    }

}

我有其他类似的处理程序来处理数据并记录它们。

【问题讨论】:

    标签: c# multithreading netty nlog mdc


    【解决方案1】:

    我从未使用过 Netty,所以只是尝试阅读文档:

    https://netty.io/5.0/api/io/netty/channel/ChannelHandlerContext.html

    那么您应该使用IChannelHandlerContext 来处理上下文信息(如 CorrelationId、RequestId 等)。

    不断尝试使 NLog MDLC 与活动的 netty-context 保持同步可能会很脆弱。也许只是实现将 netty-context 作为输入的辅助记录器方法?例如:

    public override void ChannelRead(IChannelHandlerContext context, object message)
    {
        LogDebug(context, "Read");
        base.ChannelRead(context, message);
    }
    
    public override async Task WriteAsync(IChannelHandlerContext context, object message)
    {
        LogDebug(context, "Write");
        await base.WriteAsync(context, message).ConfigureAwait(false);
    }
    
    private void LogDebug(IChannelHandlerContext context, string mesage)
    {
        var deviceInfo = context.Channel.GetAttribute(ProcessHandler.DeviceInfo).Get();
        if (deviceInfo != null)
           _logger.WithProperty("FlowMeterSerial", deviceInfo.Serial).Debug(message);
        else
           _logger.Debug(mesage);
    }
    

    无论如何只是一个随机的建议。对 Java-Netty 或 Dot-Netty 一无所知。

    【讨论】:

      猜你喜欢
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      • 2013-03-25
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      相关资源
      最近更新 更多