NLog – 数据库目标的运行时参数
我正在尝试向我的数据库日志目标添加一些自定义。 在我的NLog.config中我有这个:
在我的C#代码中我有这个:
protected override void updateBeforeLog(LogEventInfo info) { info.Properties["dbDatabase"] = "TempDB"; info.Properties["dbUserName"] = "username"; info.Properties["dbPassword"] = "password"; info.Properties["dbHost"] = "SERVER\SQLSERVER"; info.Properties["commandText"] = "exec InsertLog @LogDate, @LogLevel, @Location, @Message"; info.Parameters = new DatabaseParameterInfo[] { new DatabaseParameterInfo("@LogDate", Layout.FromString("${date:format=yyyy\-MM\-dd HH\:mm\:ss.fff}")), new DatabaseParameterInfo("@LogLevel", Layout.FromString("${level}")), new DatabaseParameterInfo("@Location", Layout.FromString("${event-context:item=location}")), new DatabaseParameterInfo("@Message", Layout.FromString("${event-context:item=shortmessage}")) }; log.Log(info); }
但是我收到一条SQL错误,上面写着“必须声明标量变量”@LogDate“”。
属性正常,因为连接成功。 但由于某种原因,参数不会“绑定”到命令中的标量变量。
如果我在NLog.config文件中手动创建参数,它可以完美地工作:
但这违背了能够在运行时自定义commandText和参数值的全部目的。
请帮助我理解我需要做什么才能使目标正确地获取参数的值。 谢谢!
更新
总的来说,我希望有一种方法可以通过C#代码自定义目标。 我想依赖NLog.config文件只需要很多。 但似乎NLog与配置文件设置非常相关,我试图在该约束内工作但尽可能灵活。 有了这个数据库目标,如果我能弄清楚如何以编程方式更新参数,那么我可以在配置文件中有一个相当通用的目标,然后更新LogEventInfo属性和参数以满足连接或存储的任何数据库的需要执行程序。
更新
事实certificate, LogEventInfo.Parameters
集合用于LogEventInfo.FormattedMessage
属性。 如果要使用LogEventInfo.FormatProvider
或甚至将LogEventInfo.FormatProvider
设置为等于string.format
字符串,则使用Parameters
对象[]数组来提供字符串中的替换。 请参阅此处获取代码 。
尽管命名相似,但LogEventInfo.Parameters
与NLog.config文件中的
不对应。 似乎没有办法通过LogEventInfo
对象获取数据库参数。 (感谢Kim Christensen在NLog项目论坛上发布该链接)
我能够使用自定义目标来实现这一点。 但我仍在质疑为什么我以前的方法不起作用。 看起来如果可以访问 Parameters
数组,NLog应该遵循分配给它的参数。
也就是说,这是我最终使用的代码:
首先,我必须创建自定义目标并将其设置为将数据发送到数据库:
[Target("DatabaseLog")] public sealed class DatabaseLogTarget : TargetWithLayout { public DatabaseLogTarget() { } protected override void Write(AsyncLogEventInfo logEvent) { //base.Write(logEvent); this.SaveToDatabase(logEvent.LogEvent); } protected override void Write(AsyncLogEventInfo[] logEvents) { //base.Write(logEvents); foreach (AsyncLogEventInfo info in logEvents) { this.SaveToDatabase(info.LogEvent); } } protected override void Write(LogEventInfo logEvent) { //string logMessage = this.Layout.Render(logEvent); this.SaveToDatabase(logEvent); } private void SaveToDatabase(LogEventInfo logInfo) { if (logInfo.Properties.ContainsKey("commandText") && logInfo.Properties["commandText"] != null) { //Build the new connection SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); //use the connection string if it's present if (logInfo.Properties.ContainsKey("connectionString") && logInfo.Properties["connectionString"] != null) builder.ConnectionString = logInfo.Properties["connectionString"].ToString(); //set the host if (logInfo.Properties.ContainsKey("dbHost") && logInfo.Properties["dbHost"] != null) builder.DataSource = logInfo.Properties["dbHost"].ToString(); //set the database to use if (logInfo.Properties.ContainsKey("dbDatabase") && logInfo.Properties["dbDatabase"] != null) builder.InitialCatalog = logInfo.Properties["dbDatabase"].ToString(); //if a user name and password are present, then we're not using integrated security if (logInfo.Properties.ContainsKey("dbUserName") && logInfo.Properties["dbUserName"] != null && logInfo.Properties.ContainsKey("dbPassword") && logInfo.Properties["dbPassword"] != null) { builder.IntegratedSecurity = false; builder.UserID = logInfo.Properties["dbUserName"].ToString(); builder.Password = logInfo.Properties["dbPassword"].ToString(); } else { builder.IntegratedSecurity = true; } //Create the connection using (SqlConnection conn = new SqlConnection(builder.ToString())) { //Create the command using (SqlCommand com = new SqlCommand(logInfo.Properties["commandText"].ToString(), conn)) { foreach (DatabaseParameterInfo dbi in logInfo.Parameters) { //Add the parameter info, using Layout.Render() to get the actual value com.Parameters.AddWithValue(dbi.Name, dbi.Layout.Render(logInfo)); } //open the connection com.Connection.Open(); //Execute the sql command com.ExecuteNonQuery(); } } } } }
接下来,我更新了我的NLog.config文件以包含新目标的规则:
然后我创建了一个包装数据库日志调用的类。 它还提供了将Exception
转换为NLog LogEventInfo
对象的函数:
public class DatabaseLogger { public Logger log = null; public DatabaseLogger() { //Make sure the custom target is registered for use BEFORE using it ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(DatabaseLogTarget)); //initialize the log this.log = NLog.LogManager.GetLogger("LogDB"); } /// /// Logs a trace level NLog message public void T(LogEventInfo info) { info.Level = LogLevel.Trace; this.Log(info); } /// /// Allows for logging a trace exception message to multiple log sources. /// public void T(Exception e) { this.T(FormatError(e)); } //I also have overloads for all of the other log levels... /// /// Attaches the database connection information and parameter names and layouts /// to the outgoing LogEventInfo object. The custom database target uses /// this to log the data. /// /// /// public virtual void Log(LogEventInfo info) { info.Properties["dbHost"] = "SQLServer"; info.Properties["dbDatabase"] = "TempLogDB"; info.Properties["dbUserName"] = "username"; info.Properties["dbPassword"] = "password"; info.Properties["commandText"] = "exec InsertLog @LogDate, @LogLevel, @Location, @Message"; info.Parameters = new DatabaseParameterInfo[] { new DatabaseParameterInfo("@LogDate", Layout.FromString("${date:format=yyyy\-MM\-dd HH\:mm\:ss.fff}")), new DatabaseParameterInfo("@LogLevel", Layout.FromString("${level}")), new DatabaseParameterInfo("@Location", Layout.FromString("${event-context:item=location}")), new DatabaseParameterInfo("@Message", Layout.FromString("${event-context:item=shortmessage}")) }; this.log.Log(info); } /// /// Creates a LogEventInfo object with a formatted message and /// the location of the error. /// protected LogEventInfo FormatError(Exception e) { LogEventInfo info = new LogEventInfo(); try { info.TimeStamp = DateTime.Now; //Create the message string message = e.Message; string location = "Unknown"; if (e.TargetSite != null) location = string.Format("[{0}] {1}", e.TargetSite.DeclaringType, e.TargetSite); else if (e.Source != null && e.Source.Length > 0) location = e.Source; if (e.InnerException != null && e.InnerException.Message.Length > 0) message += "nInnerException: " + e.InnerException.Message; info.Properties["location"] = location; info.Properties["shortmessage"] = message; info.Message = string.Format("{0} | {1}", location, message); } catch (Exception exp) { info.Properties["location"] = "SystemLogger.FormatError(Exception e)"; info.Properties["shortmessage"] = "Error creating error message"; info.Message = string.Format("{0} | {1}", "SystemLogger.FormatError(Exception e)", "Error creating error message"); } return info; } }
因此,当我启动应用程序时,我可以轻松地开始记录:
DatabaseLogger dblog = new DatabaseLogger(); dblog.T(new Exception("Error message", new Exception("Inner message")));
稍作努力,我可以从DatabaseLogger
类inheritance并覆盖Log
方法以创建任意数量的不同数据库日志。 如果需要,我可以动态更新连接信息。 我可以更改commandText
和Parameters
以适应每个数据库调用。 我只需拥有一个目标。
如果我想为多种数据库类型提供function,我可以添加一个info.Properties["dbProvider"]
属性,该属性在SaveToDatabase
方法中读取,然后可以生成不同的连接类型。
上述就是C#学习教程:NLog – 数据库目标的运行时参数分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/942223.html