Nlog在点网处理程序中无法正常工作

时间:2019-12-31 04:33:34

标签: c# multithreading netty nlog mdc

我编写了一个Dotnetty服务器,并使用Nlog作为日志记录框架。每个连接都有自己的ID,我想将此ID与其他数据(消息,Datetime等...)一起记录到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);
        }
    }

}

我还有其他类似的处理程序,用于处理数据并记录它们。

1 个答案:

答案 0 :(得分:0)

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

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

然后,您应该使用IChannelHandlerContext处理上下文信息(例如CorrelationId,RequestId等)。

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

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一无所知。