Asynchronous batch logging using Nlog and Asp.net core 2.0 in database - asp.net-core-2.0

I am using NLog for logging in asp.net core 2.0. I am storing my log events in database.
I want my messages to save in batches asynchronously.
Nlog.config settings are:
<?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">
<extensions>
<add assembly="NLog.Web.AspNetCore" />
</extensions>
<targets>
<target name="file" xsi:type="AsyncWrapper" queueLimit="5000" batchSize="5" overflowAction="Discard">
<target name="db" xsi:type="Database"
connectionString="Data Source=.;Initial Catalog=DatabaseName;User Id=userId;Password=pwd;"
commandType="StoredProcedure" commandText="Sp_name" dbProvider="System.Data.SqlClient">
<parameter name="#TimeStamp" layout="${date}" />
<parameter name="#Level" layout="${uppercase:${level}}" />
<parameter name="#Message" layout="${message}" />
<parameter name="#Exception" layout="${exception}" />
<parameter name="#StackTrace" layout="${exception:format=StackTrace,Data:maxInnerExceptionLevel=10}" />
<parameter name="#eventLookupId" layout ="1" />
</target>
</target>
</targets>
<rules>
<logger name="Microsoft.*" minlevel="Info" writeTo="" final="true" />
<logger name="*" minlevel="Info" writeTo="file" />
</rules>
</nlog>
For the above configuration I am expecting it to log in a batch size of 5 but it is logging immediately at the trigger of event rather than logging in a batch.
Not sure if any other configuration is also required to make it work.

NLog will sent the messages continuously with of max of the batchsize (5 here), and with a time between batches. The default "timeToSleepBetweenBatches" for the asyncWrapper is 1 ms.
e.g. when the batchsize is 100 and the timeToSleepBetweenBatches is 1 sec, a max of 6000 messages/minute are sent.
See the options: https://github.com/NLog/NLog/wiki/AsyncWrapper-target#buffering-options

Related

NLog unable to create log file on Linux server (ASP.NET Core application)

It is working fine on the local windows system. When I deploy it on a Linux server it is neither logging logs nor creating log files.
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"
throwConfigExceptions="true">
<!-- enable asp.net core layout renderers -->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!-- the targets to write to -->
<targets>
<target
name="errorLogFile"
xsi:type="File"
fileName="${currentdir}/logs/error/${date:format=yyyyMMdd}.txt"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${callsite}|${message} ${exception:format=tostring} ${newline} "
/>
<target
name="infoLogFile"
xsi:type="File"
fileName="${currentdir}/logs/info/${date:format=yyyyMMdd}.txt"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${callsite}|${message} ${exception:format=tostring} ${newline} "
/>
</targets>
<rules>
<logger name="Microsoft.*" minlevel="Info" maxlevel="Warn" writeTo="" final="true" />
<logger name="*" minlevel="ERROR" writeTo="errorLogFile" />
<logger name="*" minlevel="Info" maxlevel="Warn" writeTo="infoLogFile" />
</rules>
</nlog>
Program.cs > CreateHostBuilder
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
// Enable NLog as one of the Logging Provider
logging.AddNLog();
})

NLog difference between overflowAction Grow and Block

I am using NLog in my .Net window service and below are the configuration that i am using for setup Nlog.
<?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"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Debug" internalLogFile="c:\temp\log.txt">
<targets>
<target xsi:type="AsyncWrapper" name="asyncExceptionDB" overflowAction="Grow" >
<target xsi:type="FallbackGroup" name="String" returnToFirstOnSuccess="true">
<target xsi:type="Database" name="ExceptionDB" dbProvider="System.Data.SqlClient" connectionStringName="nlogconnection" commandType="StoredProcedure" commandText="usp_InsertExceptionLog">
<parameter name="#UserId" layout="${event-properties:item=userId}"/>
<parameter name="#Email" layout="${event-properties:item=email}"/>
<parameter name="#ExceptionType" layout="${event-properties:item=exceptionType}" />
<parameter name="#ExceptionMessage" layout="${event-properties:item=exceptionMessage}" />
<parameter name="#InnerException" layout="${event-properties:item=innerException}" />
<parameter name="#CustomMessage" layout="${message}"/>
<parameter name="#ErrorCode" layout="${event-properties:item=errorCode}" />
</target>
</target>
</target>
<target xsi:type="AsyncWrapper" name="asyncLogDB" overflowAction="Block" >
<target xsi:type="FallbackGroup" name="String" returnToFirstOnSuccess="true">
<target xsi:type="Database" name="LogDB" dbProvider="System.Data.SqlClient" connectionStringName="nlogconnection" commandType="StoredProcedure" commandText="usp_InsertLog">
<parameter name="#UserId" layout="${event-properties:item=userId}"/>
<parameter name="#Email" layout="${event-properties:item=email}"/>
<parameter name="#CustomMessage" layout="${message}"/>
<parameter name="#MeetingId" layout="${event-properties:item=meetingId}" />
<parameter name="#ErrorCode" layout="${event-properties:item=errorCode}" />
</target>
</target>
</target>
<rules>
<!-- add your logging rules here -->
<!-- DO NOT CHANGE NAME HERE (Used in Code) -->
<logger name="SOLog" level="Info" writeTo="asyncLogDB" />
<logger name="SOLog" level="Error" writeTo="asyncExceptionDB" />
<logger name="SOLog" level="Info" writeTo="asyncOHLoggerService" />
<logger name="SOLog" level="Error" writeTo="asyncOHLoggerService" />
<!--<logger name="*" level="Error" writeTo="ExceptionDB" />
<logger name="*" level="Fatal" writeTo="ExceptionDB" />-->
</rules>
</targets>
</nlog>
In my configuration i am using overflow Action value as Grow and Block for different targets. An both work fine in my case as they both write data to there desired destination. But i really didn't understood the difference between both the action Grow and Block. Can any one tell me the actual difference between these two (overflow action Block and Grow) actually the Background details that how they work in background.
I am aware about Grow that it will increase the queue size when it reaches its peak point but one problem of using it in my case with above configuration is that it stop my service and throw an error called OutOfMemoryException and stopped my service after that.
after that i used Block rather then using Grow and my memory utilization is fine in this case and all works fine for me. but the only question that arise in my mind that how come Block is different than Grow. I went through the NLOG documentation but that really didn't help me much to understand the concept of these two i.e Grow and Block.
Have updated the Wiki-page for AsyncWrapper-Target:
overflowAction - Action to be taken when in-memory-queue becomes full (Reached queueLimit). This means the background-writer is falling behind, and cannot keep up with the application-threads logging. Default: Discard
Possible values:
Discard - The application-thread will discard logevent to avoid becoming blocked or causing out-of-memory issues
Block - The application-thread will block until the background-writer-thread has taken the next batch. Avoids loosing important logevents, but can block all application-threads.
Grow - The application-thread will ignore the limit, and will just allocate more memory. Can cause the entire application to experience out-of-memory-issues.

NLog - create log file at specific directory in linux

I've a .net core application on linux server.also in application i used nlog for logging. my application path on linux is /var/www-ninja/html/finance.api.gurukul.ninja. but with use of nlog i want to store logs in other linux directory. which is like /var/log/api/ninja/finance. so can I store logs in that directory. how can i do that ? for more details
nlog.production.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="Info"
internalLogFile="c:\temp\internal-nlog.txt">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
<add assembly="NLog.Extensions.Logging"/>
<add assembly="NLog"/>
</extensions>
<variable name="ExceptionLayout" value="${longdate} [${processid}] ${uppercase:${level}} ${logger:shortName=true} ${environment-user} ${local-ip} ${aspnet-request-url} ${aspnet-request-method} ${message}${exception:format=tostring,Stacktrace}"/>
<variable name="CommonLayout" value="${longdate} [${processid}] ${uppercase:${level}} ${logger:shortName=true} ${environment-user} ${local-ip} ${message} "/>
<variable name ="logDir" value="/var/log/api/ninja/finance" />
<targets async="true">
<target xsi:type="File" name="file" layout="${CommonLayout}" fileName="${logDir}\log-${shortdate}.log" />
<target name="fileAsException"
xsi:type="FilteringWrapper"
condition="length('${exception}')>0">
<target xsi:type="File"
fileName="${logDir}\log-${shortdate}.log"
layout="${ExceptionLayout}" />
</target>
</targets>
<rules>
<logger name="*" writeTo="file,fileAsException"/>
<logger name="Microsoft.*" maxlevel="Info" final="true" />
</rules>
</nlog>
Make sure to use Unix-path, so stop using backslash \
Ex. instead of ${logDir}\log-${shortdate}.log then it should be ${logDir}/log-${shortdate}.log.
If still having issues then try to activate the NLog InternalLogger and check the output https://github.com/NLog/NLog/wiki/Internal-Logging

NLog DB Configuration

From the docs https://github.com/NLog/NLog/wiki/Database-target
It seems settings are shown as attributes on the target element such as:
<target xsi:type="Database"
name="String"
dbUserName="Layout"
dbProvider="String"
and in the example below as separate child nodes:
<target name="database" xsi:type="Database">
<connectionStringName>NLogDb</connectionStringName>
Neither work for me, I just get Invalid configuration exceptions with this message:
NotSupportedException: Parameter connectionStringName not supported on DatabaseTarget
The Config File:
<?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="info"
throwExceptions="true"
internalLogFile="c:\temp\internal-nlog.txt">
<!-- enable asp.net core layout renderers -->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!-- the targets to write to -->
<targets>
<!-- write logs to file -->
<target xsi:type="File" name="allfile" fileName="c:\temp\nlog-all-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
<!-- another file log, only own logs. Uses some ASP.NET core renderers -->
<target xsi:type="File" name="ownFile-web" fileName="c:\temp\nlog-own-${shortdate}.log"
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="Database"
name="database"
keepConnection="true"
useTransactions="true"
dbProvider="System.Data.SqlClient"
connectionStringName="DefaultConnection"
commandText="INSERT INTO Logs (EventDateTime, EventLevel, UserName, MachineName, EventMessage, ErrorSource, ErrorClass, ErrorMethod, ErrorMessage, InnerErrorMessage) VALUES (#EventDateTime, #EventLevel, #UserName, #MachineName, #EventMessage, #ErrorSource, #ErrorClass, #ErrorMethod, #ErrorMessage, #InnerErrorMessage)">
<parameter name="#EventDateTime" layout="${date:s}" />
<parameter name="#EventLevel" layout="${level}" />
<parameter name="#UserName" layout="${aspnet-user-identity}" />
<parameter name="#MachineName" layout="${machinename}" />
<parameter name="#EventMessage" layout="${message}" />
<parameter name="#ErrorSource" layout="${event-context:item=error-source}" />
<parameter name="#ErrorClass" layout="${event-context:item=error-class}" />
<parameter name="#ErrorMethod" layout="${event-context:item=error-method}" />
<parameter name="#ErrorMessage" layout="${event-context:item=error-message}" />
<parameter name="#InnerErrorMessage" layout="${event-context:item=inner-error-message}" />
</target>
</targets>
<!-- rules to map from logger name to target -->
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile,database" />
<!--Skip non-critical Microsoft logs and so log only own logs-->
<logger name="Microsoft.*" maxLevel="Info" final="true
" />
<!-- BlackHole without writeTo -->
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
</nlog>
How it is being called in program.cs
var logger = NLog.Web.NLogBuilder.ConfigureNLog( "nlog.config" ).GetCurrentClassLogger();
(copied from their docs)
Must be missing something obvious, but since there is conflicting info in the docs, and copying other people's configs posted on here, not sure where to go with it
Looks like you are running on NetCore. NLog is not able to read connectionStringName from AppSettings.json as you have found out yourself (Requires extra dependencies to access IConfiguration).
One possible solution is using this extension:
https://www.nuget.org/packages/NLog.Appsettings.Standard/
And use connectionString (Instead of connectionStringName) in NLog.config:
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
<add assembly="NLog.Appsettings.Standard"/>
</extensions>
<target xsi:type="Database" connectionString="${appsettings:name=ConnectionStrings.DefaultConnection}">
Alternative solution is to assign a GDC variable before logging:
NLog.GlobalDiagnosticsContext.Set("DefaultConnection", Configuration.GetConnectionString("DefaultConnection"));
And then use GDC in NLog.config:
<target xsi:type="Database" connectionString="${gdc:item=DefaultConnection}">
See also https://github.com/NLog/NLog/wiki/Gdc-layout-renderer
Update NLog.Extension.Logging ver. 1.4.0
With NLog.Extension.Logging ver. 1.4.0 then you can now use ${configsetting}
See also: https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer

How do I make aspnet-request available in my NLog config?

I am trying to add the ip address to logging. I installed the NLog.Extended package and ensured that the NLog.Extended.dll is present in my bin next to the base NLog.dll. I have added the variable "${aspnet-request:serverVariable=remote_addr}" to my layout renderer. I get a generic error saying:
An error occurred creating the configuration section handler for nlog: Exception occurred when loading configuration from [my Web.config]
Here is my 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">
<extensions>
<add assembly="NLog.Extended" />
</extensions>
<targets async="true">
<target name="fileLog" xsi:type="File" fileName="${basedir}/logs/${shortdate}.log" layout="${aspnet-request:serverVariable=remote_addr} ${longdate} ${callsite} ${level} ${message} ${exception:format=ToString}" />
<target name="dbLog" xsi:type="Database" connectionStringName="db.data" commandText="insert into log ([Date], [Origin], [LogLevel], [Message], [Exception], [StackTrace]) values (#date, #origin, #logLevel, #message, #exception, #stackTrace)">
<parameter name="#date" layout="${date}"/>
<parameter name="#origin" layout="${callsite}"/>
<parameter name="#logLevel" layout="${level}"/>
<parameter name="#message" layout="${message}"/>
<parameter name="#exception" layout="${exception:format=Message,StackTrace}"/>
<parameter name="#stackTrace" layout="${stacktrace}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="dbLog" />
<logger name="*" minlevel="Trace" writeTo="fileLog" />
</rules>
</nlog>
When I remove the AspNetRequest variable it doesn't complain. I've tried replacing "remote_addr" with "remote_host" with no change. This project is using NLog 2.1.0. Any ideas on what I'm doing wrong here?
If you're using NLog 4.0 then you'll need NLog.Web to use the aspnet=* layout renderers.
It turned out that the NLog.Extended.dll(3.1.0.0) had to match the NLog.dll it was referencing. I upgraded the NLog.dll to 3.1.0.0 and everything is working now.
In my ASP.NET webapi 2.0 solution I had a separate projects for my API's and logging. Using nLog 4.4.12 installed through NuGet and all the helper packages (Config,Extended,Web,Schema) in the logging project.
The "aspnet-request" properties in my config would not work until I added the nLog references to my api project, even though "Copy Local" is set to true for all the nLog DLL's in the logging project. My nLog section from my web.config is below.
Hope this help someone,
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="db" xsi:type="Database" connectionStringName="NLogConn" 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:fileName=true:includeSourcePath=false:skipFrames=1}" />
<parameter name="#exception" layout="${exception:tostring}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="db" />
</rules>

Resources