NLog, how to execute code on logging ERROR and higher? - c#

I'm quite new to NLog and I wanted to execute some code when logs are done.
Basically, I got a RichTextBoxTarget. The RichTextBox is hidden by default. I want to display it when a Error log or higher is done.
How could I do this, if it's possible ?

Sounds like you would like to have 2 targets listening for events:
RichTextBox-Target for capturing all events in the error-window.
MethodCall-Target for reacting to error-events and show the error-window.
So the trick is just to setup the two targets:
<nlog>
<targets>
<target name="richtext" xsi:type="RichTextBox" />
<target name="showrichtext" xsi:type="MethodCall" className="SomeNamespace.MyClass, MyAssembly" methodName="LogMethod" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="richtext" />
<logger name="*" minlevel="Error" writeTo="showrichtext" />
</rules>
</nlog>
And implement a suitable static method for the MethodCall-Target to call.
See also: https://github.com/NLog/NLog/wiki/MethodCall-target
See also: https://github.com/NLog/NLog/wiki/RichTextBox-target

What is the purpose of this RichTextBox exactly?
If you want to show errors on input error then the ErrorProvider is better for that.
If you want to capture Error Logging also into this RTB as well as to say file, then you can write your own target, register it, and then it can process the events.
See:
https://github.com/NLog/NLog/wiki/Extending-NLog

Related

NLog - 2 separate log files - How to write to one or the other

I want to explicitly write to 2 different log files. Based on the method or type of operations.
How to?
I have seen the following StackOverFlow post
Having NLog loggers with different configuration
How do I configure NLog ? What code do I need too, so I can write to 1 file or the other? using code like :log.Error("My Big Error");
The post contains the following
<targets>
<target name="f1" xsi:type="File" fileName="${logger}.txt" />
<target name="f2" xsi:type="File" fileName="${shortdate}.txt" />
</targets>
So, if it's 'general error' I want write to f1. If it's file operation error I want to write to f2
thx in advance
In the NLog configuration you need to set up some rules to write to the targets (otherwise nothing get logged). In those rules you could add filters and conditions.
Simple example
For example:
<rules>
<logger name="Logger1" writeTo="f1" />
<logger name="Logger2" writeTo="f2" />
</rules>
The name attribute is here a filter, so the first rule means: write to f1 if logger name is equals to "Logger1". The rules are processed from top to bottom.
So when calling LogManager.GetLogger("Logger1").Info("My message") this will write to target f1 and LogManager.GetLogger("Logger2").Info("My message") will write to target f2.
GetCurrentClassLogger
When using LogManager.GetCurrentClassLogger(), the logger name is constructed of the current class and namespace name, e.g. "MyNameSpace.MyClass". This means you could adjust the name attribute to name="MyNameSpace.MyClass", or name="*.MyClass" for matching.
Final
You could also write this:
<rules>
<logger name="Logger1" writeTo="f1" final="true" />
<logger name="*" writeTo="f2" />
</rules>
This will write events of Logger1 to f1, and others to f2. You probably need the filter attribute, otherwise also the events of Logger1 will be written to f2 - and that isn't always what you need.
Other filter rules
There are many more filter options, e.g. min level, max level, but also more advanced filters (not only on logger name). You could read more about that here

In NLog, is it possible to use layouts to define the log level?

I would like to use Layouts in NLog to be able to change the minimum log level using an external variable :
<nlog>
<variable name="loglevel" value="Debug"/>
<targets>
<target ... />
</targets>
<rules>
<logger name="*" minlevel="${loglevel}" writeTo="LogFile" />
</rules>
</nlog>
After starting NLog, all log levels (eg : Tracing, Debug, Info, ...) are set to false which indicate NLog failed to parse minlevel attribute properly.
The NLog layout feature seems to works with target attributes only.
What I want to achieve : in my real app, loglevel is not a constant but rather a custom layout renderer.
I have also tried to replace value="Debug" by value="LogLevel.Debug" without success.
** Updated Answer **
NLog ver. 4.6 added support for using NLog-Config-Variables in minLevel. See https://github.com/NLog/NLog/pull/2709
NLog ver. 4.6.7 added support for adjusting minLevel at runtime, by modifying NLog-Config-Variables and calling ReconfigExistingLoggers(). See https://github.com/NLog/NLog/pull/3184
** Original Answer **
The minlevel, maxlevel and level attributes on <logger> should be fixed strings.
In this case you could use a <filter>, e.g.
<nlog>
<variable name="loglevel" value="Debug"/>
<targets>
<target ... />
</targets>
<rules>
<logger name="*" writeTo="LogFile" >
<filter condition="${level} >= ${loglevel}" action="Log">
</logger>
</rules>
</nlog>
See the docs

NLog create log files based on static variable

How can I set NLog file name based on static variable in my application.
I have windows service that performs different tasks. Reads configuration file with task details.
I would like to create log file based on given task name.
NOTE: class name will not work, since all the tasks call the same code.
NOTE: I am already using ${logger} variable as my current class. Since I need to know where I am as well.
-------------UPDATE--------------
Seems like this is not possible to do.
Modified question: How to set variable values at run time?
I am talking about this:
<variable name="logFileName" value="" />
Thank you.
You cannot, I believe. But you can use something like this:
In code:
static NLog.Logger loggerA = NLog.LogManager.GetLogger("nameA");
static NLog.Logger loggerB = NLog.LogManager.GetLogger("nameB");
void Something()
{
loggerA.Error("Something");
}
void SomethingElse()
{
loggerB.Error("SomethingElse");
}
NLog config:
<nlog ...>
<targets>
<target name="Error" xsi:type="AsyncWrapper">
<target name="file" xsi:type="File" fileName="${basedir}/Logs/Error.txt">
<layout ... />
</target>
</target>
</targets>
<!--other targets pointing to different files.-->
<rules>
<logger name="nameA" minlevel="Warn" writeTo="Error" />
<logger name="nameB" minlevel="Trace" maxLevel="Info" writeTo="Log" />-->
<logger name="*" minlevel="Trace" maxLevel="Info" writeTo="CommonLog" />
</rules>
</nlog>
You can also use SomeNamespace.Component.* as name of a logger and than only logs from SomeNamespace.Component will be logged via it. In that case the logger would be obtained like this:
static NLog.Logger loggerA = NLog.LogManager.GetCurrentClassLogger();
Here is the documentation for Nlog: https://github.com/NLog/NLog/wiki/Tutorial
There is a way to edit NLog configuration programmatically: https://github.com/nlog/NLog/wiki/Configuration-API
The easy solution is to use NLog GlobalDiagnosticsContext:
<target name="file" xsi:type="File" fileName="${gdc:logFileName:whenEmpty=DefaultApp}.txt">
Then you can override it like this:
NLog.GlobalDiagnosticsContext.Set("logFileName", "HelloApp");
See also: https://github.com/nlog/nlog/wiki/Gdc-Layout-Renderer

NLog: disable/enable multiple log files

I have 2 loggers: one for Info messages, and another for other ones.
<logger name="ErrLogger" levels="Trace,Debug,Warn,Fatal,Error" writeTo="logfile_w" />
<logger name="InfoLogger" level="Info" writeTo="logfile_i" />
Each one write information to his own file.
Is it possible in runtime turn off and on certain loggers?
Btw, for each class I'm using code like this:
private static Logger _logger = LogManager.GetCurrentClassLogger();
And then in functions I use _logger.Info("message");. Should I modify class loggers too?
You can use filtering for that.
Example
<rules>
<logger name="*" writeTo="file">
<filters>
<when condition="${logger}==loggername" action="Ignore" />
</filters>
</logger>
</rules>
See filtering on NLog wiki and the ${logger} layout renderer.
Hint: not sure what the (full) name of the logger is? Just log something with ${logger} and check the logs.

Is this the correct way to log to a specific target with NLog?

I'd like to log some special events into a different table that will contain more data then the general application log.
If I add a second database target to the NLog.config how can I use it in my code?
Would this be the right thing to do:
NLog
.LogManager
.Configuration
.AllTargets
.Single(x => x.Name == "mySecondLogTable")
.WriteAsyncLogEvent(...);
Then in the NLog.config I would just skip this target in the rules element, right?
Summary: I'd like to define multiple database targets like a general log and specialized log for cases where I need to log more details into a different table. I'd like to use the general log by default and the special log only in functions that need this special kind of logging because of their business logic.
You can always create another logger instance and use the NLog LoggingRules for redirection to the wanted target.
For example I want to make an extended logging into a separate file. Then I go and create:
<nlog>
<rules>
<!--- Notice that final=true stops the logevents from also reaching defaultTarget -->
<logger name="ExtendedLogging" minlevel="Trace" writeTo="extendedTarget" final="true" />
<!--- Wildcard rule will capture all logevents not matching the "final" rule above -->
<logger name="*" minlevel="Trace" writeTo="defaultTarget" />
</rules>
<targets>
<target name="extendedTarget" xsi:type="File" fileName="ExtendedLog_${shortdate}.log" />
<target name="defaultTarget" xsi:type="File" fileName="AppLog_${shortdate}.log" />
</targets>
</nlog>
And then I go to the code and create
private readonly Logger logger = LogManager.GetLogger("ExtendedLogging");
I don't think it's a good idea to search for something inside the config-file and perform logging through something like a backdoor. It's better to make all this things explicitly.
See also: https://github.com/nlog/nlog/wiki/Configuration-file#rules
var fileLogger = LogManager.Configuration.AllTargets.Single(x => x.Name == "file");
fileLogger.WriteAsyncLogEvents(
new LogEventInfo(LogLevel.Info, null, error.ToString())
.WithContinuation(new NLog.Common.AsyncContinuation(_ => { })));
I am not sure what did I do but it works. Because the accepted solution didn't

Categories