Last week, we added NLog to our .NET ScriptLink project to generate debugger log entries. Having NLog now configured and in place we can consider additional targets for the log entries. These targets include: the console, file, mail, databases, and more. Today, we are going to expand our configuration to use a file target, setup filters, and auto-archiving.
A key advantage of this setup is that we can change or add logging targets without having to modify the log entries scattered throughout our project. This means that since we have already created our log entries all we have to do is update our NLog configuration to add our new targets. Let’s go.
The Specification
For this example, we are going to create three file targets to collect the log entries from our Web Services (*.asmx), Commands, and Factory.
- Api: api.log
- Commands: api.commands.log
- Factories: api.factories.log
In other implementations I have also created targets for my repositories and services.
We will also setup these log files to archive daily and keep up to 14 days of logs in the archive.
Add the Targets
First, let’s add our new targets to the web.config file.
<targets async="true">
<target name="debugger" xsi:type="Debugger" />
<target name="file.api" xsi:type="File"
fileName="\Logs\RS.ScriptLinkDemo\api.log"
archiveFileName="\Logs\RS.ScriptLinkDemo\Archive\Api\api.{#}.log"
archiveEvery="Day"
archiveNumbering="Date"
maxArchiveFiles="14"
concurrentWrites="true"
keepFileOpen="false"
encoding="UTF8" />
<target name="file.api.commands" xsi:type="File"
fileName="\Logs\RS.ScriptLinkDemo\api.commands.log"
archiveFileName="\Logs\RS.ScriptLinkDemo\Archive\Api\api.commands.{#}.log"
archiveEvery="Day"
archiveNumbering="Date"
maxArchiveFiles="14"
concurrentWrites="true"
keepFileOpen="false"
encoding="UTF8" />
<target name="file.api.factories" xsi:type="File"
fileName="\Logs\RS.ScriptLinkDemo\api.factories.log"
archiveFileName="\Logs\RS.ScriptLinkDemo\Archive\Api\api.factories.{#}.log"
archiveEvery="Day"
archiveNumbering="Date"
maxArchiveFiles="14"
concurrentWrites="true"
keepFileOpen="false"
encoding="UTF8" />
</targets>
By design I have nested the commands and factories under the api logs. You can see that when they are archived they will also go into a common Api folder. I have found this helpful when I was logging other activities such as those from my repositories and services. Each of which was given their own section.
You can also see the various configurations describe in the specification. I like to use the name of the project in the logging path to keep my logs for conflicting with each other. Typically, this would only apply to you development system, but if you run multiple applications on the same web server this could be helpful as well.
The above configuration can be customized with variables.
Ok. Now we need to setup the rules.
Add the Logging Rules
These rules will allow us to filter all of the log entries being generated and write them to the correct log file.
<rules>
<logger name="*" minlevel="Debug" writeTo="debugger" />
<logger name="RS.ScriptLinkDemo.Soap.api.*" minlevel="Debug" writeTo="file.api" />
<logger name="RS.ScriptLinkDemo.Soap.Commands.*" minlevel="Debug" writeTo="file.api.commands" />
<logger name="RS.ScriptLinkDemo.Soap.Factories.*" minlevel="Debug" writeTo="file.api.factories" />
</rules>
Based on the above configuration we should see all of our log entries (“*”) be written to the debugger logger, but the file loggers will only be written to based on the namespace of the class that is logging.
Testing
As with each of our previous changes, it is time to test. Let’s submit a request from our SoapUI or Postman samples and see if the log entries are entered as expected. I will test my DefaultCommand first by sending in an invalid parameter. This should generate log entries in the debugger and each of the files.
Debugger Target
You should see something similar to below in your debugger log.

If so, then let’s check on our file logs.
File Targets
Let’s check the directory we established to see if our log files are there.

Hopefully, you see the three files where you expected them. Next, let’s open them up and make sure the entries match what we expect to find in them. If so, great!
Next Steps
Test, test, test. Try sending a request to your HelloWorld command. Try sending a request to your v1 or v2 web service, if you made one. Try sending a GetVersion request. You should see all of these entries filtered into their proper locations.
There are other things you can try to make this logging solution more robust.
- Use variables to define a common filename directory.
- Play with different archive configurations to meet your needs.
- Try out different layout options. We are using the Simple option in our above example.
- Use layout renderers to add additional information to your log entries.
- Try out another Target. Do you want to send an email when a Fatal error occurs? Do you want to send your logs to a database, a logging service, or the Windows Event Log?
- Use the Web.Debug.config and the Web.Release.config transforms to change the minimum logging level when released to test and/or production.
- Perhaps you don’t want to use the web.config file to configure NLog. You can use a different configuration file or even configure it programatically.
There are many options to tailor this to your environment and needs. You should now have all of the basics to meet your logging needs. Please let me know how it goes. Are there any other logging configuration examples that you would like to see?
You must be logged in to post a comment.