I am learning NLog and have moved on to Database logging. I have tried multiple examples on the web and can't get any of them to actually insert a record. I can't see why the log attempt failed due to NLog gobbling up any exceptions it gets. My logger and the config is found without issue. It executes the line as if it worked but the table remains empty. I did step for step on Nlog's example but it doesn't work either! :(
Nlog Database Example
UPDATE: I ended up deleting and starting over on the config and it now works. Not sure what fixed the issue from the new config file but i also realized the asp renders were causing errors so i removed them.
<target name="db"
xsi:type="Database"
dbProvider="System.Data.SqlClient"
connectionString="Data Source=Server;Initial Catalog=Database;Persist Security Info=True;Integrated Security=SSPI;"
commandType="StoredProcedure"
commandText="[dbo].[NLog_AddEntry_p]">
<parameter name="#machineName" layout="${machinename}" />
<parameter name="#siteName" layout="${iis-site-name}" />
<parameter name="#logged" layout="${date}" />
<parameter name="#level" layout="${level}" />
<parameter name="#username" layout="${aspnet-user-identity}" />
<parameter name="#message" layout="${message}" />
<parameter name="#logger" layout="${logger}" />
<parameter name="#properties" layout="${all-event-properties:separator=|}" />
<parameter name="#serverName" layout="${aspnet-request:serverVariable=SERVER_NAME}" />
<parameter name="#port" layout="${aspnet-request:serverVariable=SERVER_PORT}" />
<parameter name="#url" layout="${aspnet-request:serverVariable=HTTP_URL}" />
<parameter name="#https" layout="${when:inner=1:when='${aspnet-request:serverVariable=HTTPS}' == 'on'}${when:inner=0:when='${aspnet-request:serverVariable=HTTPS}' != 'on'}" />
<parameter name="#serverAddress" layout="${aspnet-request:serverVariable=LOCAL_ADDR}" />
<parameter name="#remoteAddress" layout="${aspnet-request:serverVariable=REMOTE_ADDR}:${aspnet-request:serverVariable=REMOTE_PORT}" />
<parameter name="#callSite" layout="${callsite}" />
<parameter name="#exception" layout="${exception:tostring}" />
</target>
try
{
int zero = 0;
int result = 100 / zero;
}
catch (Exception ex)
{
Logger filelogger = LogManager.GetLogger("filelogger");
Logger dblogger = LogManager.GetLogger("dblogger");
//filelogger.Error(ex, "Whoops");
dblogger.Error(ex, "Whoops");
}
The issue was with asp layout renders and missing a package for them. Also i had set the internalLogging flag to an invalid value. These corrections fixed the problem.
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 a dotnet core API that's up on version 2.2 with NLog.Web.AspNetCore 4.7.0 (NLog 4.5.11) which was previously working back in version 4.5.4. With the update, it now doesn't appear to be logging to the database. Nothing in terms of the logging infrastructure has changed within my code.
I should mention, I also have in the log this lovely line, so I know it's somewhat working. But I use to get A LOT more information, and of course, the database would have stuff written to it as well.
2018-12-26 15:06:59.9503||DEBUG|SomeApp.API.Program|init main |url: |action:
I tried looking around in the github issues and on here, but I haven't found anything of much use, any help is greatly appreciated!
Initial Setup in Program.cs
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("init main");
}
catch (Exception ex)
{
//NLog: catch setup errors
logger.Error(ex, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
Implementation
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseIISIntegration()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog() // NLog: setup NLog for Dependency injection
.Build();
nlog config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Trace"
internalLogFile="C:\temp\internal-nlog.txt">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets async="true">
<target type="File" name="file" fileName="${basedir}\logs\logfile.txt"
maxArchiveFiles="5" archiveAboveSize="20971520" archiveEvery="Day"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
<target xsi:type="Null" name="blackhole" />
<target name="database" xsi:type="Database">
<connectionString>${gdc:item=connectionString}</connectionString>
<commandText>
insert into dbo.Log (
EventId, Logged, Level, Message,
Username,
ServerName, Port, Url, Https,
ServerAddress, RemoteAddress,
Logger, CallSite, Exception
) values (
#EventId, #Logged, #Level, #Message,
#Username,
#ServerName, #Port, #Url, #Https,
#ServerAddress, #RemoteAddress,
#Logger, #Callsite, #Exception
);
</commandText>
<parameter name="#EventId" layout="${event-properties:item=EventId_Id}" />
<parameter name="#logged" layout="${date}" />
<parameter name="#level" layout="${level}" />
<parameter name="#message" layout="${message}" />
<parameter name="#username" layout="${aspnet-user-identity}" />
<parameter name="#serverName" layout="${aspnet-request:serverVariable=SERVER_NAME}" />
<parameter name="#port" layout="${aspnet-request:serverVariable=SERVER_PORT}" />
<parameter name="#url" layout="${aspnet-request:serverVariable=HTTP_URL}" />
<parameter name="#https" layout="${when:inner=1:when='${aspnet-request:serverVariable=HTTPS}' == 'on'}${when:inner=0:when='${aspnet-request:serverVariable=HTTPS}' != 'on'}" />
<parameter name="#serverAddress" layout="${aspnet-request:serverVariable=LOCAL_ADDR}" />
<parameter name="#remoteAddress" layout="${aspnet-request:serverVariable=REMOTE_ADDR}:${aspnet-request:serverVariable=REMOTE_PORT}" />
<parameter name="#logger" layout="${logger}" />
<parameter name="#callSite" layout="${callsite}" />
<parameter name="#exception" layout="${exception:tostring}" />
</target>
</targets>
<rules>
<!--Limit to only configured logs for all logs, change name="*"-->
<logger name="SomeApp.*" minlevel="Info" writeTo="database" />
<logger name="*" minlevel="Trace" writeTo="file" />
<!--Skip Microsoft logs and so log only own logs-->
<logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
</rules>
</nlog>
Sample logging code
_logger.LogInformation(1001, "Login success: {0}", userForLoginDto.Username);
appsettings.json & appsettings.Development.json Logging Settings
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Information"
}
The NLog internal log doesn't seem to have anything of significance, I can provide it if requested though.
Apologies for any weird formatting issues, the nlog.config file did not want to come willingly.
The NLog.config file does not set the connection string.
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="c:\temp\internal-nlog.txt">
<!-- Load the ASP.NET Core plugin -->
<extensions>
<add assembly="NLog.Web.AspNetCore" />
</extensions>
<variable name="SirNLogDb" value="data source=SQL_MULALLEY;initial catalog=LogFiles;User ID=xxx;Password=yyy;">
</variable>
<!-- providerName="System.Data.SqlClient"-->
<!-- the targets to write to -->
<targets>
<target name="db"
xsi:type="Database"
dbProvider="System.Data.SqlClient"
connectionString="${var:SirNLogDb}"
commandType="StoredProcedure"
commandText="[dbo].[NLog_AddEntry_p]">
<parameter name="#machineName" layout="${machinename}" />
<parameter name="#siteName" layout="${iis-site-name}" />
<parameter name="#logged" layout="${date}" />
<parameter name="#level" layout="${level}" />
<parameter name="#username" layout="${aspnet-user-identity}" />
<parameter name="#message" layout="${message}" />
<parameter name="#logger" layout="${logger}" />
<parameter name="#properties" layout="${all-event-properties:separator=|}" />
<parameter name="#serverName" layout="${aspnet-request:serverVariable=SERVER_NAME}" />
<parameter name="#port" layout="${aspnet-request:serverVariable=SERVER_PORT}" />
<parameter name="#url" layout="${aspnet-request:serverVariable=HTTP_URL}" />
<parameter name="#https" layout="${when:inner=1:when='${aspnet-request:serverVariable=HTTPS}' == 'on'}${when:inner=0:when='${aspnet-request:serverVariable=HTTPS}' != 'on'}" />
<parameter name="#serverAddress" layout="${aspnet-request:serverVariable=LOCAL_ADDR}" />
<parameter name="#remoteAddress" layout="${aspnet-request:serverVariable=REMOTE_ADDR}:${aspnet-request:serverVariable=REMOTE_PORT}" />
<parameter name="#callSite" layout="${callsite}" />
<parameter name="#exception" layout="${exception:tostring}" />
</target>
</targets>
<!-- rules to map from logger name to target -->
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="database" />
</rules>
</nlog>
I put a breakpoint and the connection string is null;
My Startup method is as follows;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddMvcOptions(o => o.OutputFormatters.Add(
new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared)));
var connectionStringMSurveyV2 = Configuration.GetConnectionString("MSurveyV2Db");
services.AddScoped<MSurveyV2Db>(_ => new MSurveyV2Db(connectionStringMSurveyV2));
var connectionStringSir = Configuration.GetConnectionString("SirDb");
services.AddScoped<SirDb>(_ => new SirDb(connectionStringSir));
services.AddScoped<IPropertiesRepo, PropertiesRepo>();
services.AddScoped<ISirUoW, SirUoW>();
services.AddScoped<Services.IMailService, Services.MailService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
loggerFactory.AddDebug();
loggerFactory.AddNLog();
//add NLog.Web
app.AddNLogWeb();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler();
}
app.UseMvc();
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Exception, OperationStatus>();
cfg.CreateMap<ViewSelectedContracts, ContractDto>();
});
var logger = LogManager.GetCurrentClassLogger();
logger.Info("Logged in");
}
}
EDIT - I change the logger rule to <logger name="*" minlevel="Trace" writeTo="db" /> but still it didn't output anything. However I looked for the c:\temp\internal-nlog.txt and it had not been created. So it appears the nlog.config file is being ignored. But it is in my project next to the Startup.cs file.
EDIT2: - the null configuration can be solved by setting "Copy to output directory" to "copy always".
From the comments underneath I have now got this working.
Updated answer
Since NLog.Web.AspNetCore 4.8 (NLog.Extensions.Logging 1.4 for .NET Core console programs) you could directly read from your appSettings.json
${configsetting:name=MyConnectionString}
see docs
Original answer
Unfortunately reading connectionstrings/settings from appSettings.json / app.config is not yet supported in NLog for .NET core.
Two options:
Set the connectionstring programmatically, by using variables.
In your nlog.config:
<target ... connectionString="${var:myConnectionstring}" ... />
and in code: (e.g. in Configure)
LogManager.Configuration.Variables["myConnectionstring"] = "...."; //read config here
Or, set the connectionstring in nlog.config.
In your nlog.config:
<variable name="myConnectionstring" value="...." />
and using in your target in nlog.config:
<target ... connectionString="${var:myConnectionstring}" ... />
Another option is to create and register a custom NLog layout-renderer (startup.cs):
https://github.com/NLog/NLog/wiki/How-to-write-a-custom-layout-renderer
Which outputs the ConnectionString after having read it from your favorite configuration-location. Then you don't have the connectionstring in your nlog.config, but just refer to your custom layout-renderer.
Maybe cheer for this pending issue:
https://github.com/NLog/NLog.Web/issues/107
I'm testing a very simple script to try and run my ant build file from CruiseControl.NET. I followed the steps I found on the net of how to do this but i keep getting nAnt task failed in CruiseControl without any explanation and yet when i run the NAnt build script separately, it runs fine.
Can anybody take a look at my build script, the Ccnet.config file and the output in the log and point me in the right direction?
My XmLib.build NAnt file
<?xml version="1.0"?>
<project default="start">
<property name="code.directory" value="C:\SHS" />
<property name="server.code.directory" value="${code.directory}\XmLib" />
<property name="server.code.project" value="${server.code.directory}\XmLib.sln" />
<target name="start">
<echo message="Building XmLib Component " />
</target>
</project>
My output when I ran my build file using Nant.exe via command line.
Buildfile: file:///C:/SHS/Build Scripts/XmLib.build
Target framework: Microsoft .NET Framework 4.0
Target(s) specified: start
start:
[echo] Building XmLib Component
BUILD SUCCEEDED
Total time: 0.4 seconds.
My CruiseControl.NET config file
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<project name="XmLib">
<tasks>
<nant>
<executable>C:\Program Files (x86)\NAnt\bin\nant.exe</executable>
<baseDirectory>C:\SHS\Build Scripts</baseDirectory>
<buildFile>XmLib.build</buildFile>
<logger>NAnt.Core.XmlLogger</logger>
<targetList>
<target>start</target>
</targetList>
<buildTimeoutSeconds>80</buildTimeoutSeconds>
</nant>
</tasks>
<publishers>
<xmllogger logDir="C:\tmp" />
</publishers>
</project>
</cruisecontrol>
The error I get when I try to run this via CruiseControl.NET using its dashboard.
<cruisecontrol project="XmLib">
<request source="BUILDHPSMV" buildCondition="ForceBuild">Administrator triggered a build (ForceBuild) from BUILDHPSMV</request>
<parameters>
<parameter name="$CCNetArtifactDirectory" value="C:\Program Files (x86)\CruiseControl.NET\server\XmLib\Artifacts" />
<parameter name="$CCNetBuildCondition" value="ForceBuild" />
<parameter name="$CCNetBuildDate" value="2013-01-16" />
<parameter name="$CCNetBuildId" value="a7fb196a3193468e8d8505f7db7641d5" />
<parameter name="$CCNetBuildTime" value="17:06:44" />
<parameter name="$CCNetFailureTasks" value="System.Collections.ArrayList" />
<parameter name="$CCNetFailureUsers" value="System.Collections.ArrayList" />
<parameter name="$CCNetIntegrationStatus" value="Unknown" />
<parameter name="$CCNetLabel" value="1" />
<parameter name="$CCNetLastIntegrationStatus" value="Failure" />
<parameter name="$CCNetListenerFile" value="C:\Program Files(x86)\CruiseControl.NET\server\XmLib\Artifacts\XmLib_ListenFile.xml" />
<parameter name="$CCNetModifyingUsers" value="System.Collections.ArrayList" />
<parameter name="$CCNetNumericLabel" value="1" />
<parameter name="$CCNetProject" value="XmLib" />
<parameter name="$CCNetProjectUrl" value="http://BUILDHPSMV/ccnet" />
<parameter name="$CCNetRequestSource" value="BUILDHPSMV" />
<parameter name="$CCNetUser" value="Administrator" />
<parameter name="$CCNetWorkingDirectory" value="C:\Program Files(x86)\CruiseControl.NET\server\XmLib\WorkingDirectory" />
</parameters>
<modifications />
<integrationProperties>
<CCNetArtifactDirectory>C:\Program Files(x86)\CruiseControl.NET\server\XmLib\Artifacts</CCNetArtifactDirectory>
<CCNetBuildCondition>ForceBuild</CCNetBuildCondition>
<CCNetBuildDate>2013-01-16</CCNetBuildDate>
<CCNetBuildTime>17:06:44</CCNetBuildTime>
<CCNetFailureUsers />
<CCNetFailureTasks>
<task>NAntTask</task>
</CCNetFailureTasks>
<CCNetIntegrationStatus>Failure</CCNetIntegrationStatus>
<CCNetLabel>1</CCNetLabel>
<CCNetLastIntegrationStatus>Failure</CCNetLastIntegrationStatus>
<CCNetListenerFile>C:\Program Files(x86)\CruiseControl.NET\server\XmLib\Artifacts\XmLib_ListenFile.xml</CCNetListenerFile>
<CCNetModifyingUsers />
<CCNetNumericLabel>1</CCNetNumericLabel>
<CCNetProject>XmLib</CCNetProject>
<CCNetProjectUrl>http://BUILDHPSMV/ccnet</CCNetProjectUrl>
<CCNetRequestSource>BUILDHPSMV</CCNetRequestSource>
<CCNetWorkingDirectory>C:\Program Files(x86)\CruiseControl.NET\server\XmLib\WorkingDirectory</CCNetWorkingDirectory>
<CCNetUser>Administrator</CCNetUser>
<CCNetBuildId>a7fb196a3193468e8d8505f7db7641d5</CCNetBuildId>
<LastIntegrationStatus>Failure</LastIntegrationStatus>
<LastSuccessfulIntegrationLabel>UNKNOWN</LastSuccessfulIntegrationLabel>
<LastModificationDate>1/15/2013 5:06:44 PM</LastModificationDate>
</integrationProperties>
<build date="2013-01-16 17:06:44" buildtime="00:00:00" error="true"buildcondition="ForceBuild"></build>
</cruisecontrol>
Only a guess but I suspect unquoted paths as cause of the failure. Try "C:\Program Files (x86)\NAnt\bin\nant.exe" resp. "C:\SHS\Build Scripts".