Serilog 的 StoredProcedure 自定义接收器
StoredProcedure custom sink for Serilog
我想使用 Serilog 调用存储过程。我知道没有这样的接收器,所以我正在创建一个自定义接收器。我的逻辑是在实现 ILogEventSink 的 StoredProcedureSink 的 Emit 方法中调用存储过程。现在,这个存储过程 returns 一个值。我如何在使用 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.
}
}
这在使用普通 Serilog 模型的实践中不太可能可行。
标准处理涉及 LogEvent
在主线程上被 捕获 ,然后依次提供给每个接收器 - 通常是异步的,并且经常被缓冲。
另一个问题是,一般来说,sink 肯定不会向调用者传播异常(有审计日志记录,但即便如此也不是为这种通信而设计的)。
在我看来,您要完成的审计类型与 Serilog 的最佳点有一定距离(尽管我可能是错的 - 如果是这样,请在您的问题中添加更多细节)。
如果您绝对必须这样做,您可以在记录日志时添加一个 Enricher,它将回调 Action
隔离到 LogEvent 的属性中,并将其传回。不过,在实际执行此操作之前,请仔细考虑!
I ended up creating a static variable of StoredProcedureSink class and assigning the return value to that variable. Not sure if this would be the best way to do it.
class StoredProcedureSink : ILogEventSink
{
private string _connectionString;
**public static int returnValue;**
public StoredProcedureSink(string connectionString)
{
_connectionString = connectionString;
}
public void Emit(LogEvent logEvent)
{
var outputParam = new SqlParameter()
{
Direction = ParameterDirection.Output
};
try
{
using (SqlConnection conn = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand(logEvent.MessageTemplate.ToString().Substring(0, logEvent.MessageTemplate.ToString().IndexOf('{')), conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
var properties = logEvent.Properties.GetValueOrDefault("SqlParams");
var jsonProp = JObject.Parse(properties.ToString().Substring(properties.ToString().IndexOf('{') - 1).Replace(@"\",""));
var lastParam = jsonProp.Last;
foreach (var kvp in jsonProp)
{
if(kvp.Key == lastParam.Path)
{
outputParam.ParameterName = kvp.Key;
outputParam.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(outputParam);
break;
}
cmd.Parameters.Add(new SqlParameter(kvp.Key, ((JValue)kvp.Value).Value));
}
cmd.ExecuteNonQuery();
}
**returnValue = (int)outputParam.Value;**
}
}
catch(System.Exception e)
{
Debug.WriteLine(e.Message);
}
}
}
public class DBLogger : ILogger
{
public DBLogger()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.StoredProcedureSink(
"connectionString")
.CreateLogger();
}
~DBLogger()
{
Log.CloseAndFlush();
}
public static IHost CreateHostBuilder(string[] args) =>
new HostBuilder()
.UseSerilog() // <- Add this line
.Build();
public int Information<T>(string storedProcedureName, T parameters)
{
try
{
Log.Information(storedProcedureName, parameters);
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
**return StoredProcedureSink.returnValue;**
}
}
我想使用 Serilog 调用存储过程。我知道没有这样的接收器,所以我正在创建一个自定义接收器。我的逻辑是在实现 ILogEventSink 的 StoredProcedureSink 的 Emit 方法中调用存储过程。现在,这个存储过程 returns 一个值。我如何在使用 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.
}
}
这在使用普通 Serilog 模型的实践中不太可能可行。
标准处理涉及 LogEvent
在主线程上被 捕获 ,然后依次提供给每个接收器 - 通常是异步的,并且经常被缓冲。
另一个问题是,一般来说,sink 肯定不会向调用者传播异常(有审计日志记录,但即便如此也不是为这种通信而设计的)。
在我看来,您要完成的审计类型与 Serilog 的最佳点有一定距离(尽管我可能是错的 - 如果是这样,请在您的问题中添加更多细节)。
如果您绝对必须这样做,您可以在记录日志时添加一个 Enricher,它将回调 Action
隔离到 LogEvent 的属性中,并将其传回。不过,在实际执行此操作之前,请仔细考虑!
I ended up creating a static variable of StoredProcedureSink class and assigning the return value to that variable. Not sure if this would be the best way to do it.
class StoredProcedureSink : ILogEventSink
{
private string _connectionString;
**public static int returnValue;**
public StoredProcedureSink(string connectionString)
{
_connectionString = connectionString;
}
public void Emit(LogEvent logEvent)
{
var outputParam = new SqlParameter()
{
Direction = ParameterDirection.Output
};
try
{
using (SqlConnection conn = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand(logEvent.MessageTemplate.ToString().Substring(0, logEvent.MessageTemplate.ToString().IndexOf('{')), conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
var properties = logEvent.Properties.GetValueOrDefault("SqlParams");
var jsonProp = JObject.Parse(properties.ToString().Substring(properties.ToString().IndexOf('{') - 1).Replace(@"\",""));
var lastParam = jsonProp.Last;
foreach (var kvp in jsonProp)
{
if(kvp.Key == lastParam.Path)
{
outputParam.ParameterName = kvp.Key;
outputParam.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(outputParam);
break;
}
cmd.Parameters.Add(new SqlParameter(kvp.Key, ((JValue)kvp.Value).Value));
}
cmd.ExecuteNonQuery();
}
**returnValue = (int)outputParam.Value;**
}
}
catch(System.Exception e)
{
Debug.WriteLine(e.Message);
}
}
}
public class DBLogger : ILogger
{
public DBLogger()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.StoredProcedureSink(
"connectionString")
.CreateLogger();
}
~DBLogger()
{
Log.CloseAndFlush();
}
public static IHost CreateHostBuilder(string[] args) =>
new HostBuilder()
.UseSerilog() // <- Add this line
.Build();
public int Information<T>(string storedProcedureName, T parameters)
{
try
{
Log.Information(storedProcedureName, parameters);
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
**return StoredProcedureSink.returnValue;**
}
}