I want to create a CSV file with multiple columns using NLog. There are not enough layouts for this (more than one message). I want to use event-properties for this.
sendEmailLogger.Log(LogLevel.Info, "01.01.2018");
Logger log = LogManager.GetCurrentClassLogger();
LogEventInfo theEvent = new LogEventInfo(LogLevel.Info, "CSVSendLogger", "custom value");
theEvent.Properties["xxx"] = 1234;
log.Log(theEvent);
NLog config file
<target name="CSVSendLogger" xsi:type="File"
fileName="${logDirectory}/send_log/log_mail.csv">
<layout xsi:type="CSVLayout">
<column name="Column1" layout="${event-properties:item=xxx}" />
<column name="Column2" layout="${message}" />
</layout>
Related
The code
LogEventInfo theEvent = new LogEventInfo();
Logger offsetLogger = LogManager.GetLogger("ProdDataLog");
theEvent.Properties["Range"] = calc.Range;
offsetLogger.Log(theEvent);
Below is the target
<target name="ProdDataFile" xsi:type = "File"
fileName="${prodDataDir}ProdFile.csv"
archiveFileName="${prodDataDir}Archive/ProdFile.{#}.csv"
archiveNumbering="DateAndSequence"
archiveAboveSize="500000" archiveEvery="Day" maxArchiveFiles="30"
archiveDateFormat="yyyyMMdd">
<layout xsi:type="CsvLayout" delimiter="Comma" withHeader="true" quoting="Nothing">
<column name="Date" layout="${date:format=yyyy-MM-dd}" />
<column name="Time" layout="${time:HH:mm:ss.ffff}" />
<column name="Range" layout="${event-properties:Range}" />
</layout>
</target>
And the rule
<logger name="ProdDataLog" writeTo="ProdDataFile" final="true" />
The problem is the function
offsetLogger.Log(theEvent);
can take up to 200-300 ms.
Normal logs dont have the delay....but trying to create a csv log.
Any ideas?
I tried adding 'async' to the targets but then the csv wasn't written to at all.
NLog FileTarget uses KeepFileOpen=false by default, as it works across platforms and works with most file-viewers/monitors. But the performance is bad.
Try adding KeepFileOpen="true" like this:
<target name="ProdDataFile" xsi:type = "File"
keepFileOpen="true"
fileName="${prodDataDir}ProdFile.csv"
archiveFileName="${prodDataDir}Archive/ProdFile.{#}.csv"
archiveNumbering="DateAndSequence"
archiveAboveSize="500000" archiveEvery="Day" maxArchiveFiles="30"
archiveDateFormat="yyyyMMdd">
<layout xsi:type="CsvLayout" delimiter="Comma" withHeader="true" quoting="Nothing">
<column name="Date" layout="${date:format=yyyy-MM-dd}" />
<column name="Time" layout="${time:HH:mm:ss.ffff}" />
<column name="Range" layout="${event-properties:Range}" />
</layout>
</target>
Alternative you can use <targets async="true"> (Recommended if having many threads writing to the same File-Target). See also: https://github.com/NLog/NLog/wiki/Performance#file-logging-performance and Remember to Flush
Hello I am using for my console application NLog for logging.
With that being said I would like to log everything that happens in the console using NLog to set that up I am using the NLOG.config:
<target name="FullCSVFile" xsi:type="File" fileName="logs\internal_${date:format=yyyyMMdd_HHmmss}.log" keepFileOpen="true">
<layout xsi:type="CsvLayout">
<column name="Console" layout="${message}" />
<column name="Error" layout="${exception:format=ToString}" />
</layout>
</target>
<logger minlevel="Debug" name="*" writeTo="FullCSVFile" />
But this way the tool makes a new file every second passed in the console, but I want to make one file when the tool starts with that timestamp and write everything in this one. How would I do that?
The trick is to use the ambient property cached=true like this:
<target name="FullCSVFile" xsi:type="File" fileName="logs\internal_${date:format=yyyyMMdd_HHmmss:cached=true}.log" keepFileOpen="true">
<layout xsi:type="CsvLayout">
<column name="Console" layout="${message}" />
<column name="Error" layout="${exception:format=ToString}" />
</layout>
</target>
It will make layout render once, and then just return the same cached value.
See also: https://github.com/nlog/NLog/wiki/Cached-Layout-Renderer
To make it "perfect" then you could use ${processinfo:StartTime:format=yyyyMMdd_HHmmss:cached=true} then the timestamp would be stable even after reloading NLog-config.
Something like this could work, but I have not tested it:
<variable name="started" value="${date:format=yyyyMMdd_HHmmss}"/>
<target name="FullCSVFile" xsi:type="File" fileName="logs\internal_${started}.log" keepFileOpen="true">
<layout xsi:type="CsvLayout">
<column name="Console" layout="${message}" />
<column name="Error" layout="${exception:format=ToString}" />
</layout>
</target>
The idea is similar to the example from the documentation: https://github.com/nlog/nlog/wiki/Configuration-file#variables
in Nlog section i have two target of csvlayout
<nlog throwExceptions="false" 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"
internalLogLevel="off" internalLogFile="c:\logs\nlog-internal.log">
<targets async="false">
<target name="MeLog" xsi:type="File" lineEnding="CRLF"
fileName="c:\logs\tempPro-${level}.csv" concurrentWrites="true" archiveFileName="c:\logs\archive\tempPro-${level}-{#####}.csv" archiveAboveSize="5024000" archiveNumbering="Sequence" maxArchiveFiles="10">
<layout type="CSVLayout" quoting="Auto" withHeader="true">
<column name="Logger" layout="${logger}" />
<column name="Date" layout="${date:format=s}" />
<column name="Level" layout="${level}" />
<column name="Message" layout="${message}" />
</layout>
</target>
<target name="ReLog" xsi:type="File" lineEnding="CRLF" fileName="C:\logs\Re-${level}.csv" concurrentWrites="true" archiveFileName="C:\Logs\archive\Re-${level}-{#####}.csv" archiveAboveSize="512000000" archiveNumbering="Sequence" maxArchiveFiles="2">
<layout type="CSVLayout" quoting="Auto" withHeader="true">
<column name="Logger" layout="${logger}"/>
<column name="Date" layout="${date:format=s}"/>
<column name="Level" layout="${level}"/>
<column name="Message" layout="${message}"/>
</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="MeLog" />
<logger name="*" minlevel="Trace" writeTo="ReLog" />
</rules>
</nlog>
i want to log error dynamically by the file name.
for example on err1 i want log in meLog and for err2 i want tog in relog
public bool testMultiLog()
{
var config = new LoggingConfiguration();
var fileTarget = new FileTarget("ReLog")
{
FileName = "C:\\logs\\Re-${level}.csv"//,
Layout = "${longdate} ${level} ${message} ${exception}"
};
config.AddTarget(fileTarget);
config.AddRuleForOneLevel(LogLevel.Error, fileTarget);
LogManager.Configuration = config;
Logger logger = LogManager.GetLogger("Example");
logger.Trace("trace log message");
logger.Debug("debug log message");
logger.Info("info log message");
logger.Warn("warn log message");
logger.Error("error log message");
logger.Fatal("fatal log message");
return true;
}
But it is generating same error in both file
Use different logger names and then different log instances so you will be able to pick a desired log instance
<logger name="FirstLog" minlevel="Trace" writeTo="MeLog" />
<logger name="SecondLog" minlevel="Trace" writeTo="ReLog" />
<logger name="*" minlevel="Trace" writeTo="Log" />
Creating different logs:
Logger firstLogger = LogManager.GetLogger("FirstLog");
Logger secondLogger = LogManager.GetLogger("SecondLog");
Now firstLogger will log into MeLog and Log, secondLogger into ReLog and Log targets
But don't forget to define Log target
Thanks to Rolf's comment in this question:
NLog in C# with severity AND categories
I am able to record to a text file the category of log message (such as "Thermal" or "Database" or "Mechanical". I'm doing this simply by passing a name to the "GetLogger" method.
public MainWindow()
{
InitializeComponent();
var logger = NLog.LogManager.GetCurrentClassLogger();
logger.Info("Hello World");
(NLog.LogManager.GetLogger("Database")).Info("Here is a DB message");
(NLog.LogManager.GetLogger("Thermal")).Info("Here is a Thermal message");
}
The text file looks like this:
2018-05-13 17:40:47.7442|INFO|NLogExperiments.MainWindow|Hello World
2018-05-13 17:40:50.3404|INFO|Database|Here is a DB message
2018-05-13 17:40:50.3404|INFO|Thermal|Here is a Thermal message
which is pretty good. I might ask in a seperate question how to reformat it.
Now I would like to get these messages into a CSV (Excel) file. I'm using:
<target name="excelfile" xsi:type="File" fileName="nLog.csv" archiveAboveSize="50000000" archiveNumbering="Sequence" maxArchiveFiles="3">
<layout xsi:type="CsvLayout">
<!-- Layout Options -->
<column name="time" layout="${longdate}" />
<column name="level" layout="${level}"/>
<column name="name" layout="${name}"/>
<column name="message" layout="${message}" />
<column name="codeLine" layout="${event-context:item=codeLine}" />
</layout>
</target>
but the output is only:
time,level,name,message,codeLine
2018-05-13 17:40:47.7442,Info,,Hello World,
2018-05-13 17:40:50.3404,Info,,Here is a DB message,
2018-05-13 17:40:50.3404,Info,,Here is a Thermal message,
This isn't surprising. I used "name" as a guess.
What is the field in GetLogger called?
More generally, how do I know all the options I can put in the CSV layout?
Finally, is there a good tutorial on using NLog with CSV? I haven't found one.
Thanks,
Dave
What is the field in GetLogger called?
You're looking for ${logger} - see ${logger} docs
More generally, how do I know all the options I can put in the CSV layout?
You could use all layout renderers, see the list with all layout renderers
For options for the CSV formating, see CsvLayout docs
We are working with NLog. we need to log messages to console with different JSON formats in different scenarios.
Ex: If exception occurred Below is the format
{
“id”:”5656”,
“uuid”:”xdd895-65454”,
“key”:”somekeyname”,
“message”: “** exception message **”,
“stack_trace”: “”**exception stack trace**”
}
If Normal log message
{
"id":"8898998"
“messge”: “Time taken to retrieve data from database”
“Time”: “1100” (in milli seconds)
}
Like this we have 10 scenarios.
Approach 1:
I tried creating different targets in web.config file in nlog section as follows
<target xsi:type="Console" name="console_exception" >
<layout xsi:type="JsonLayout">
<attribute name="id" layout="${mdlc:itemid}" />
<attribute name="uuid" layout="${mdlc:item=uuid}" />
<attribute name="loglevel" layout="${level}" />
<attribute name="timestamp" layout="${date}" />
<attribute name="message" layout="${message}" />
</layout>
</target>
<target xsi:type="Console" name="console_databaseTimeTaken" >
<layout xsi:type="JsonLayout">
<attribute name="id" layout="${mdlc:item=id}" />
<attribute name ="custommessage" layout="Time taken to retrieve data from database"/>
<attribute name="timestamp" layout="${date}" />
<attribute name="message" layout="${message}" />
</layout>
</target>
<rules>
<logger name="*" minLevel="Trace" writeTo ="console"/>
</rules>
I do not know how to set the target and layout programmatically.
So far I have found conditional based logging but, that is not a good approach.
Approach 2:
When logging the message we manually format the string message as per the need and then calling the log method
string logmessag= string.Format("\"id\":\"{0}\",\"messge\": {1}\"\",\"Time\": \"{2}(in milli seconds)\"", id, message, time);
Technologies used: Webapi2, Nlog 4.0.3
IDE: VS2017
Let us know the best approach to solve this problem
Thanks in advance
You'll need to use filters, either on <logger> elements directly, or a child <filters> config element which allows more complex conditions.
Eg. (assuming you can use the logger's name):
<rules>
<logger name='DB' minLevel="Trace" writeTo="console_databaseTimeTaken" final="true" />
<logger name='Error' minLevel="Trace" writeTo="console_exception" final="true" />
…
</rules>
<filter> elements allow more flexibility, but are still fairly limited. Ultimately you can extend NLog with custom conditions.