StoredProcedure custom sink for Serilog

时间:2019-01-09 22:09:34

标签: serilog

I want to call a stored procedure using Serilog. I am aware that there is no such sink so I am creating a custom Sink. I have my logic to call the stored procedure inside the Emit method of the StoredProcedureSink that implements ILogEventSink. Now, this stored procedure returns a value. How can I get this value when I use Log.Information();

class StoredProcedureSink : ILogEventSink
    {
        private string _connectionString;
        public StoredProcedureSink(string connectionString)
        {
            _connectionString = connectionString;
        }

        public void Emit(LogEvent logEvent)
        {
            var conn = new SqlConnection(_connectionString);
            conn.Open();
            SqlCommand cmd = new SqlCommand(logEvent.MessageTemplate.ToString().Substring(0, logEvent.MessageTemplate.ToString().IndexOf('{')), conn);
            cmd.CommandType = CommandType.StoredProcedure;
            var properties = logEvent.Properties.GetValueOrDefault("SqlParams");
            var json = JObject.Parse(properties.ToString().Substring(properties.ToString().IndexOf('{') - 1));
            foreach(var kvp in json)
            {
                cmd.Parameters.Add(new SqlParameter(kvp.Key, ((JValue)kvp.Value).Value));
            }
            cmd.ExecuteNonQuery();
//I would like to read the value returned by the stored proc.
        }
    }

//I have a wrapper DBLogger in which I configure the serilog. I have published DBLogger as a nuget package so I can use it in all my apps.

public class DBLogger()
{

public DBLogger()
{
Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .Enrich.FromLogContext()
            .WriteTo.StoredProcedureSink(
                "connectionString")
            .CreateLogger();
}

public void Information(string storedProcedureName, T parameters)
        {
            try
            {
               Log.Information(storedProcedureName, parameters);
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
            }
        }
}

public class Program
{
   static void Main()
   {
     var logger = new DBLogger();
     logger.Information("storedProcedureName", params); //need the Id returned by the stored proc here.
    }
}

2 个答案:

答案 0 :(得分:0)

使用普通的Serilog模型实际上不太可能。

标准处理包括将LogEvent捕获在主线程上,然后依次提供给每个接收器-通常是异步的,并且经常对其进行缓冲。

另一个问题是,通常来说,接收器也绝对不会向调用方传播异常(有审核日志记录,但即使这样也不打算用于此类通信)。

在我看来,您要完成的审计工作与Serilog的最佳位置有些距离(不过,我可能是错的-如果是,请在问题中添加更多详细信息)。


如果绝对必须这样做,则可以在登录时添加一个Enricher,该Enricher将回调Action隔离到LogEvent的Properties中,并将其传递回去。不过,在进行此操作之前,请您三思而后行!

答案 1 :(得分:0)

{% set photo = (musicien.photo) ? musicien.photo : 'your_default_photo' %}
<td><img class="img-vignette" src="data:image/jpeg;base64,{{ photo }}"/></td>