I am having a bit of a problem using a stored procedure instead of a SQL INSERT statement when using NLog in a C# web application. The connection string "Logger" is correctly configured in Web.config and works properly when replacing the commandText with a SQL statement. I would appreciate a hint in the right direction. In this example the stored procedure is under the "Logs" schema and it is called "LogError".
<targets>
<target xsi:type="Database"
name="dberrorlog"
connectionStringName="Logger"
keepConnection="true"
commandText="[Logs].[LogError]" >
<parameter name="#ProgName" layout="MyAppName"/>
<parameter name="#CompName" layout="${machinename}"/>
<parameter name="#LogLevel" layout="${level}"/>
<parameter name="#UserName" layout="${identity}"/>
<parameter name="#Error" layout="${exception:format=Message}"/>
<parameter name="#SourceObj" layout="${exception:format=Method}"/>
<parameter name="#StackTrace" layout="${exception:format=StackTrace}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="dberrorlog" />
</rules>
From this NLog forum post, try using the text to execute the stored procedure:
commandtext="exec AddActivityLog
#ApplicationName,
#ApplicationTime,
#Severity,
#Logger,
#SaxoID,
#EventID,
#Message,
#URL,
#URLReferrer,
#RemoteAddress,
#Callsite,
#CurrentUICulture,
#ThreadIdentity,
#WindowsIdentity,
#MachineName,
#ProcessID,
#ThreadID,
#ThreadName,
#Stacktrace,
#Exception,
#Cookie,
#FormVariables,
#QueryString,
#HTTPUserAgent"
Side note: Claus Rathje's answer wouldn't render in my browser, so I had to look a the page source to see the configuration he posted.
Note that while #JeffOgata's solution works, it's probably not the way you want to go about solving the problem.
You can do something like this instead:
commandText="AddActivityLog"
commandType="StoredProcedure"
That way you don't have to worry about properly formatting an EXEC query.
Related
I'm using NLog for logging into database. It seems to me its misplacing value in columns. For instance, it writes StackTrace in Message column and Exception information in StackTrace column
Configuration:
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwConfigExceptions="true" throwExceptions="true">
<targets>
<target name="database" type="Database" connectionString="Data Source=Server1;initial catalog=MyDb;Integrated Security=True;">
<commandText>insert into dbo.AppException ([Level], Logger, Message, Exception, StackTrace) values (#Level, #Logger, #Message, #Exception, #StackTrace);</commandText>
<parameter name="#Level" layout="${level}" />
<parameter name="#Logger" layout="${logger}" />
<parameter name="#Message" layout="${message}" />
<parameter name="#Exception" layout="${exception}" />
<parameter name="#StackTrace" layout="${stacktrace}" />
<dbProvider>System.Data.SqlClient</dbProvider>
</target>
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="database" />
</rules>
</nlog>
My test code:
throw new IOException("This is my message");
Logging code:
logger.Error(ex);
Below is a sample row in database
In my opinion, the value in "Exception" field should be written in "Message" column and value of "StackTrace" should be written into "Exception" column and finally value of "Message" should be written in "StackTrace".
Is there anything wrong in my configuration or my expectation is wrong?
I'm guessing you are logging the exception like this:
catch (Exception ex)
{
_logger.Error(ex); // ${message} will become ex.ToString(), since no message provided.
}
If you changed to this instead:
catch (Exception ex)
{
_logger.Error(ex, "Exception caught while testing");
}
And updated NLog.config to this:
<parameter name="#Exception" layout="${exception:format=tostring,data}" />
Then you will probably get what you want.
After reading answer posted by #Rolf, I found my nlog.config setting is not correct. The format setting in nlog is important
NLog Document
I changed my nlog to below and it worked as expected
<parameter name="#Message" layout="${exception:format=message}" />
<parameter name="#Exception" layout="${exception:format=type}" />
<parameter name="#StackTrace" layout="${exception:format=stacktrace}" />
I use nlog dll to write to database - oracle with entity frameWork in the line :
logger.Log(logLevel, "try");
I get in the logs of NLog the following error:
Warn DatabaseTarget: Parameter: 'TIME_STAMP' - Failed to assign DbType=OracleDbType.Date
Error DatabaseTarget(Name=WS_TRACE): Error when writing to database. Exception: System.Data.OracleClient.OracleException (0x80131938): ORA-01843: Invalid month
the code is:
SetPropGDC(LogEntity);
NLog.LogLevel logLevel = SetLogLevel(Level.Debug);
logger.Log(logLevel, "try");
ClearGDC();
private void SetPropGDC(LogEntity LogEntity)
{
GlobalDiagnosticsContext.Set(processId, LogEntity.PROCESS_ID.ToString());
GlobalDiagnosticsContext.Set("TIME_STAMP", DateTime.Now);
GlobalDiagnosticsContext.Set(customerId, LogEntity.CUSTOMER_ID.ToString());
}
<targets>
<target name="TRACEDatabase" type="DataBase" keepConnection="false"
dbProvider="Oracle.ManagedDataAccess.Client" connectionString="${gdc:connectionString}"
commandText="insert into TLOG_SITE_GENERAL_TRACE( PROCESS_ID,TIME_STAMP,CUSTOMER_ID)
values(:PROCESS_ID,:TIME_STAMP,:CUSTOMER_ID)">
<parameter name="PROCESS_ID" layout="${gdc:PROCESS_ID}" />
<parameter name="TIME_STAMP" layout="${gdc:TIME_STAMP}" dbType="OracleDbType.Date" />
<parameter name="CUSTOMER_ID" layout="${gdc:CUSTOMER_ID}" />
</target>
</targets>
I tried in the Web.config to change the line:
<parameter name="TIME_STAMP" layout="${gdc:TIME_STAMP}" dbType="OracleDbType.Date" />
to:
<parameter name="TIME_STAMP" layout="${longDate}" dbType="OracleDbType.Date" />
and I got the same error
First of all, it's highly recommend to use the built in layout renderers.
For example, ${longdate}, but also ${processid}. Those are optimized and easier to use.
You can find all of them here
Be aware is that using global context (GDC), could be dangerous in multi threaded programs. Also in single threaded you could "leak" some context.
But I guess the real issue here is that your NLog is out to date. DbType support is added in NLog 4.6.
So first update NLog (using Nuget is highly recommend). I use here NLog 4.6.3+, but would recommend to update to NLog 4.7
Then for the code I would recommend to do this:
logger.WithProperty("CustomerId", LogEntity.CUSTOMER_ID).Log(loglevel, "Message");
and configure like this:
<targets>
<target name="TRACEDatabase" type="DataBase" keepConnection="false"
dbProvider="Oracle.ManagedDataAccess.Client" connectionString="${gdc:connectionString}"
commandText="insert into TLOG_SITE_GENERAL_TRACE( PROCESS_ID,TIME_STAMP,CUSTOMER_ID)
values(:PROCESS_ID,:TIME_STAMP,:CUSTOMER_ID)">
<parameter name="PROCESS_ID" layout="${processid}" dbType="Int32" />
<parameter name="TIME_STAMP" layout="${longdate}" dbType="Date" />
<parameter name="CUSTOMER_ID" layout="${event-properties:CUSTOMER_ID}" dbType="Int32" />
</target>
</targets>
See also ${event-properties}
There is no need for using a specific OracleDbType, so therefor I choose to just use "Date" (which is DbType.Date, see DbType
I found the solution!
I changed the dbType parameter from:
<parameter name="TIME_STAMP" layout="${gdc:TIME_STAMP}" dbType="OracleDbType.Date" />
To:
<parameter name="TIME_STAMP" layout="${gdc:TIME_STAMP}" dbType="DateTime" />
and it works!
I have setup NLog on my project that will save the logging to my audit database (separate from the default database). However, it is failing to write to the database. I have a console logger target as well and that is logging as expected. No errors are shown or given. It merely fails to write to the database.
I have tried various methods provided from google, but none seemed to have worked. I have also tried using NLogBuilder to configure the config for that specific controller but still, it doesn't write to the database
nlog.config file:
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>
<nlog internalLogLevel="Trace">
<targets>
<target name="ConsoleLogger" type="Console"
layout="${longdate}|${level:uppercase=true}|${logger}|${message}"/>
<target name="DatabaseLog" type="Database">
<commandtext>
INSERT INTO Logs
(LogDate, LogLevel, Message, Exception)
VALUES
(#log_date, #log_level, #message, #exception)
</commandtext>
<parameter name="#log_date"
layout="${log_date}"
dbType="DateTime"/>
<parameter name="#thread"
layout="${thread}"
dbType="String"
size="255"/>
<parameter name="#log_level"
layout="${log_level}"
dbType="String"
size="20" />
<parameter name="#logger"
layout="${logger}"
dbType="String"
size="250" />
<parameter name="#message"
layout="${message}"
dbType="String"
size="4000" />
<parameter name="#exception"
layout="${exception}"
dbType="String"
size="4000" />
<dbProvider>MySql.Data.MySqlClient.MySqlConnection, MySql.Data</dbProvider>
<connectionString>User Id=username;Password=password;Host=localhost;Database=audit_database;TreatTinyAsBoolean=false</connectionString>
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" maxlevel="Fatal" writeTo="ConsoleLogger,DatabaseLog" />
</rules>
</nlog>
Controller method:
public static Logger _logger = LogManager.GetCurrentClassLogger(typeof(ActionerController));
_logger.Info("text");
Main.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddNLog();
}).ConfigureAppConfiguration((hostingContext, config) =>
{
config
.AddJsonFile($"environment-mount/appsettings.json", optional: true)
.AddEnvironmentVariables();
}).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
For MySQL, make sure you have installed the MySql.Data package.
There are also some mistakes in your config and code:
${log_date}, ${log_level} and ${thread} don't exist. I guess you mean ${date}, ${level} and ${threadid}. See all options here.
LogManager.GetCurrentClassLogger with an argument expects a logger type - so inherits from NLog.Logger. I think you are looking for LogManager.GetCurrentClassLogger() or LogManager.GetLogger(typeof(ActionerController).FullName). See API docs
Of course there could be other errors, e.g. a wrong query, mistyped colum names or wrong column types. NLog could of course tell you the problem:
Or enable exceptions. In your config <nlog throwExceptions=true >
Or enable the internal log: <nlog internalLogFile="c:\log.txt" internalLogLevel="Warn">. Read more here
I'm trying to setup a CorrelationID across threads to establish a link between calls to my server, and the corresponding calls that I make to external web services. The correlation ID is a GUID which I'm saving in Logical Context structures of NLog (logical contexts work fine across threads, supposedly).
The idea is to have a GUID that is shared between any request to my server, and the corresponding requests that I issue to various web services due to this request. I tried using both MDLC and NDLC.
The problem is that the value is getting stored correctly only for the first request, and it's saving blank values for all subsequent ones, even though a GUID is correctly generated for each new request to my server.
I tried logging either to a database or in a file. The problem seems to solve itself if I add a breakpoint within the code, or if I add a System.Threading.Sleep anywhere around the logging method. What's also weird is that I can add the Sleep either before or after the method that sets the value in the logical context, and it still works either way. Removing the Sleep/breakpoint would cause it to break again.
I am using NLog v4.5.2.
Logging module:
using System;
using System.Web;
using NLog;
namespace Shift.Stardust.Engine.Modules
{
public class LoggingHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += HandleBeginRequest;
}
public void Dispose()
{
}
private void HandleBeginRequest(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(500);
var guid = Guid.NewGuid().ToString();
NestedDiagnosticsLogicalContext.Push(guid);
}
}
}
Placing a breakpoint anywhere in HandleBeginRequest produces correct output. Similarly for adding System.Threading.Thread.Sleep(500). Naturally, I wouldn't want to add such a line in my code just to resolve this issue.
NLog config:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="c:\temp\nlog-internal.txt" internalLogLevel="Trace">
<variable name="logDirectory" value="${basedir}/logs"/>
<targets>
<target name="asyncdatabase"
xsi:type="AsyncWrapper"
queueLimit="5000"
overflowAction="Block">
<target xsi:type="Database"
connectionStringName="ConnectionStringHere"
keepConnection="true">
<commandText>[db].[P_Log_Insert] #CreateDate, #ApplicationName, #MachineName, #LoggerName, #LogLevel, #Message, #Exception, NULL, #EngineSessionId, #CorrelationId</commandText>
<parameter name="#CreateDate" layout="${date}"/>
<parameter name="#ApplicationName" layout="${appsetting:name=Shift.Stardust.ApplicationName}"/>
<parameter name="#MachineName" layout="${machinename}"/>
<parameter name="#LoggerName" layout="${logger}"/>
<parameter name="#LogLevel" layout="${level}"/>
<parameter name="#Message" layout="${message}"/>
<parameter name="#Exception" layout="${exception:format=tostring}"/>
<parameter name="#EngineSessionId" layout="${aspnet-sessionid}"/>
<parameter name="#CorrelationId" layout="${ndlc}"/>
</target>
</target>
</targets>
<rules>
<logger name="Http.*" minlevel="Info" writeTo="asyncdatabase" final="true" />
</rules>
</nlog>
I expect to have a different CorrelationID for each incoming request, but this is only true for the first one. All of the subsequent ones have an empty string as value.
I think it's better to write to the HTTP context for this case.
e.g.
HttpContext.Current.Items["myvariable"] = 123;
and usage:
${aspnet-item:variable=myvariable} - produces "123"
See docs
You need the package NLog.Web (ASP.NET non-core) for that.
Note: ASP.NET Core uses should use NLog.Web.AspNetCore instead of NLog.Web
I'm trying to use NLog to log to an Oracle database, already created the table but when I try to log something I get the exception:
ORA-00928: missing SELECT keyword
My NLog.config file is:
<?xml version="1.0" ?>
<nlog autoReload="true" throwExceptions="true" internalLogFile="${basedir}/App_Data/nlog.txt" internalLogLevel="Debug"
internalLogToConsole="true">
<targets>
<!--Useful for debugging-->
<target name="filelog" type="File" fileName="C:/App_Data/Site.log"
layout="${date}: ${message}" />
<target name="databaselog" type="Database">
<dbProvider>Oracle.DataAccess.Client</dbProvider>
<!-- database connection parameters -->
<!-- alternatively you could provide a single 'connectionstring' parameter -->
<connectionString>DATA SOURCE=database;PERSIST SECURITY INFO=True;USER ID=user;Password=password;Validate Connection=true</connectionString>
<commandText>
insert into RS_LOGTABLE ([log_user],[log_level],[log_date],[log_message]) values(#log_user,#log_level,#log_date,#log_message);
</commandText>
<parameter name="#log_user" layout="${message}"/>
<parameter name="#log_level" layout="${message}"/>
<parameter name="#log_date" layout="${date}"/>
<parameter name="#log_message" layout="${message}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="filelog" />
<logger name="*" minlevel="Trace" writeTo="databaselog" />
</rules>
</nlog>
And the exception occurs when I do this:
logger = LogManager.GetCurrentClassLogger();
logger.Debug("Teste logger");
I already tried to do the insert without the brackets and get another exception:
**ORA-00936: missing expression**
I guess it's bit late for you, but I hope my solution will be helpful for others.
I changed characters # for colons at commandText and at parameter tags I removed it completely. I don't use brackets and it started to work.
It should be correct this way:
<commandText>
insert into RS_LOGTABLE (log_user,log_level,log_date,log_message) values(:log_user,:log_level,:log_date,:log_message);
</commandText>
<parameter name="log_user" layout="${message}"/>
<parameter name="log_level" layout="${message}"/>
<parameter name="log_date" layout="${date}"/>
<parameter name="log_message" layout="${message}"/>
I tested it with dbProvider Oracle.DataAccess.Client.
Warning for others:
I had a variable named with reserved word and it throws another exception. More details are here PHP ORA-01745: invalid host/bind variable name Warning