How to implement Log4Net in a new .NET Application
Info
This page describes the steps about how to add the Nodinite Log4Net Appender to your Visual Studio Project and Log events using the Log4Net framework to Nodinite.
Tip
You should use the SeriLog if you are using .NET.
Step 1. Add package reference
Start by adding the Nodinite Log4Net Nuget Package to your Visual Studio project.
Step 2. Create handle
Then, add a variable to acquire a handle to the Log4Net instance:
var log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
.NET Framework.
Step 3. Include namespace
Resolve the issue with the missing namespace by adding a using declaration at the top of the Class:
using log4net;
.NET Framework.
Step 4. Add the Log4Net configuration file
Add the log4net.config
file, make sure to set Copy to Output Directory to Copy Always
.
Tip
You can override the configuration values in code!
Step 5. Manage Log4Net configuration
Add the following default XML configuration to the log4net.config
file (Change values to your liking or even better, overide the run-time values in code).
The fields map 1:1 with the Nodinite JSON Log Event. LogText (Exception object) and LogStatus are implicitly provided in your code.
Note
The message param is the Body (Payload) in Nodinite.
<log4net>
<appender name="Log4NetAppender" type="Nodinite.LogAgent.Log4NetAppender.NodiniteLog4NetAppender,Nodinite.LogAgent.Log4NetAppender">
<!-- Custom Parameters -->
<OriginalMessageType value="Nodinite.LogAgent.Log4NetAppender/2.0#DefaultMessageType" />
<MessageTypeExtractFromBody value="false" />
<LogAgentID value="101"/>
<EventNumber value="0"/>
<EventDirection value="66">
<EndPointDirection value="-2">
<EndPointName value="Log4Net Unit Test"/>
<EndPointUri value="VS.local.log4net.test"/>
<!--<LogText value =""/>--> <!-- Should not be part of the configuration file -->
<!--<LogStatusId value ="255"/>--> <!-- Should not be part of the configuration file -->
<ProcessingUser value="Administrator"/>
<ModuleType value="unit test"/>
<ProcessName value="unit test"/>
<ProcessingMachineName value="DEV"/>
<ProcessingModuleType value="unit test"/>
<ProcessingModuleName value="VS"/>
<LogApiServiceURI value="http://localhost/Nodinite/Dev/logapi"/>
<ApplicationInterchangeId value="RUN-123">
<LocalInterchangeId value="{E4CDDF18-9925-4A79-8E9F-71BC0D4C5172}"/>
<ServiceInstanceActivityId value="{E4CDDF18-9925-4A79-8E9F-71BC0D4C5173}"/>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="Log4NetAppender"/>
</root>
</log4net>
Important
Ensure the LogApiServiceURI has a valid address (URI) to the Nodinite Log API OR has a folder that exist on disk. Make sure the path ends with a trailing backslash
\
.
LogApiServiceURI
LogApiServiceURI | Comment | |
---|---|---|
Log API | http://localhost/Nodinite/Dev/logapi |
NOTE: The call is synchronous, hence, if service is unavailable, you will lose the log event |
Folder New 6.0.8 | c:\temp\ |
Ensure the target folder is highly available. Use the Nodinite Pickup service to consume the files, and use the Nodinite File Monitoring Agent to ensure the files do not stockpile |
What's new New 6.0.8
LogText
can be set unless you are logging an Exception.Note
Internally, the
LogText
is set to null on each Log. You must set it again for each event to be logged.ApplicationInterchangeId
can be a string.EndPointDirection can be set, the default is "None (-2)".
EventDirection can be set, default is "Process Outgoing (66)".
All config values except
MessageTypeExtractFromBody
can be overriden in code.LogApiServiceURI can either be a folder, or an address to the Nodinite Log API.
SequenceNo
can be set programmatically (should not be set in config file).
What's new New 6.0.0.9
You can set the Log4Net Appender to legacy mode, by default, this option is turned off. We built the Logger to Log Business Transactions. If you set this property to true
, then Hello World
is in the Log Text field if your code is: _logger.LogInformation("Hello World");
.
This is a new property to set in the config file
<LogMessageObjectAsLogText value="true"/>
Set the LogMessageObjectAsLogText
to true
to enable legacy mode.
Note
This settings also affects logging errors!
Step 6. Add Watcher
Add the line: [assembly: log4net.Config.XmlConfigurator(Watch = true)]
to the Properties.cs file to make sure Log4Net reflects changes in the configuration-
file during run-time.
Step 7. Initialize Log4Net configuration
The code is different depending on the type of .NET run-time:
.NET Framework
Example using a .NET Framework (>4.6.2) solution.
var fileInfo = new System.IO.FileInfo("log4net.config");
XmlConfigurator.Configure(fileInfo);
.NET
Worker service example.
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddLog4Net();
});
services.AddHostedService<Worker>();
})
.Build();
Step 8. Perform Logging
Perform the logging by adding code depending on the different Log levels, view examples below:
Log using the .NET Framework
// Message is payload (Body)
log.Info("<Orders><Order><Id>123</Id></Order></Orders>");
log.Error("<Orders><Order><Id>123</Id></Order></Orders>", new Exception("Guru Meditation"));
Here's an example of a simple .NET Framework-based Logging example.
Log using .NET
public class Worker
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
public void DoLogging()
{
_logger.LogInformation("<Orders><Order><Id>{OrderId}</Id></Order></Orders>", 123);
_logger.LogError(ex, "<Orders><Order><Id>{OrderId}</Id></Order></Orders>", 123);
}
}
Here's an example of a simple .NET-based Logging example.
Error example (.NET)
Override Configuration Values
New 6.0.8 All configuration values can be overriden using the name as in the example below:
log4net.GlobalContext.Properties["ApplicationInterchangeId"] = "RUN-456";
log4net.GlobalContext.Properties["SequenceNo"] = 1;
log.Info("<Orders><Order><Id>123</Id></Order></Orders>");
.NET Framework example.
log4net.GlobalContext.Properties["ApplicationInterchangeId"] = "RUN-456";
log4net.GlobalContext.Properties["SequenceNo"] = 2;
log4net.GlobalContext.Properties["LogText"] = "Finished Processing";
_logger.LogInformation(""); //NOTE: LogText is set on previous row
.NET Framework example.
Add any Context
New 6.0.8
You can add arbitrary Key/Values as to the Context
. These will appear as Context Properties in the Nodinite Log Event. Then, you can create Search Fields and
use the Message Context Key plugin to have Nodinite extract the values. Use this in Nodinite Log Views and allow your business users to gain access, and search for data.
log4net.GlobalContext.Properties["Context"] = new Dictionary<string, string>
{
{ "Key1", "Value1" },
{ "Key2", "Value2" }
};
Info
The code above applies to .NET and .NET Framework.
Example overriding all config values
log4net.GlobalContext.Properties["LogText"] = "SAMPLE:LogText"; // NOTE: This value is reset after EACH log event
log4net.GlobalContext.Properties["LogApiServiceURI"] = "C:\\Code\\Nodinite.LogAgent.Log4NetAppender\\Nodinite.LogAgent.Log4NetAppender.TestClient\\Logs\\"; // Should "only" be set in config file
log4net.GlobalContext.Properties["SequenceNo"] = "0"; // This value should be set +1 before any Log operation
log4net.GlobalContext.Properties["ApplicationInterchangeId"] = "SAMPLE:ApplicationInterchangeId";
log4net.GlobalContext.Properties["OriginalMessageType"] = "SAMPLE:OriginalMessageType";
log4net.GlobalContext.Properties["LogAgentID"] = "42";
log4net.GlobalContext.Properties["EventDirection"] = "1";
log4net.GlobalContext.Properties["EventNumber"] = "1337";
log4net.GlobalContext.Properties["EndPointDirection"] = "1";
log4net.GlobalContext.Properties["EndPointName"] = "SAMPLE:EndPointName";
log4net.GlobalContext.Properties["EndPointUri"] = "SAMPLE:EndPointUri";
log4net.GlobalContext.Properties["ProcessingUser"] = "SAMPLE:ProcessingUser";
log4net.GlobalContext.Properties["ModuleType"] = "SAMPLE:ModuleType";
log4net.GlobalContext.Properties["ProcessName"] = "SAMPLE:ProcessName";
log4net.GlobalContext.Properties["ProcessingMachineName"] = "SAMPLE:ProcessingMachineName";
log4net.GlobalContext.Properties["ProcessingModuleType"] = "SAMPLE:ProcessingModuleType";
log4net.GlobalContext.Properties["ProcessingModuleName"] = "SAMPLE:ProcessingModuleName";
log4net.GlobalContext.Properties["ApplicationInterchangeId"] = "SAMPLE:ApplicationInterchangeId";
log4net.GlobalContext.Properties["LocalInterchangeId"] = "SAMPLE:LocalInterchangeId";
log4net.GlobalContext.Properties["ServiceInstanceActivityId"] = "SAMPLE:ServiceInstanceActivityId";
log4net.GlobalContext.Properties["Context"] = new Dictionary<string, string>
{
{ "Key1", "Value1" },
{ "Key2", "Value2" }
};
Please review the JSON Log Event user guide for details about each entry.