NLog ReconfigExistingLoggers creating new log? - c#

I'm using Nlog and I need to change the name of the default log to include information such as a company name. I've used this code a long time ago on an a console app and it renamed the file as expected.
I'm now trying to use the same code in a new app and it's creating a new log file instead of just renaming the current one. For example, I now have two files (2019-10.07.log and 2019-10-07_CompanyName.log). The default log will have few initial log entries and then it the remainder of the logs go into the new one.
Looking for any suggestions. I've been searching for fixes but everything points me back to the code I'm already using.
NLog v4.6.7
fileNameOnly = "CompanyName";
FileTarget defaultTarget = FindNLogTargetByName("DefaultTarget");
defaultTarget.FileName = logDirectory + string.Format("{0:yyyy-MM-dd}", DateTime.Now) + "_" + fileNameOnly + ".log";
LogManager.ReconfigExistingLoggers();

NLog doesn't support renaming an existing file. If a new file name is used, all the logs will be appended to the new file.
So for the file name you need to use System.IO.File.Move(path, pathnew) and change NLog.
Unfortunately it's a bit tricky when doing high volume logging, as NLog will recreate the old log file until the target is changed.

NLog can load settings (like Company name) from app.config or appsettings.json.
Just update your NLog.config to reference the setting. Ex.
<target type="file" name="myfile" fileName="${appsetting:CompanyName}${shortdate}.log" />
See also: https://github.com/NLog/NLog/wiki/AppSetting-Layout-Renderer (Net Framework)
See also: https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer (Net Core)

Related

Writing each json message to unique file with NLog

I want to log each json message received from the network into a unique file.
At first I thought to do File.WriteAllText($"{Guid.NewGuid()}.json", jsonMsg);. But, I need to be able to archive and delete old log files. So, I have to watch the folder when the application starts up and do all the things that NLog already knows how to do.
With NLog, I can create and add a new Target for each message from code. But I'm not sure how to remove those targets after the message has been written. Otherwise, it will create memory leak.
So, should I just stick with my first idea and just implement the logic to archive and delete files, or is there a way to do this with NLog?
I recommend that you use a single filetarget for doing the writing, but avoid using MaxArchiveFiles for archive-cleanup:
var myguid = Guid.NewGuid();
var logEvent = NLog.LogEventInfo.Create(NLog.LogLevel.Info, null, jsonMsg);
logEvent.Properties["msguid"] = myguid;
logger.Log(logEvent);
And then use ${event-properties} in the FileName-option:
<target type="file" name="fileNetworkMessages"
fileName="messages/Archive/Output-${event-properties:myguid}.json"
layout="${message}" keepFileOpen="false" />
When including Guid in the filename, then you should avoid using MaxArchiveFiles, because it will introduce a performance-hit for every new file created, and cleanup will not work (HEX-letters will disturb file-wildcard).
NLog FileTarget MaxArchiveFiles has an overhead when rolling to a new file, where it scans all existing files to see if cleanup is necessary. This works fine when only rolling once every hour/day. But when using Guid in the filename, then NLog FileTarget will trigger a cleanup-check for every new file created. This will introduce a performance overhead.

Want to pass dynamic File path from main web application to a separate DLL. That DLL is separately done using NLog

This is the code I am using to pass the file path and giving the file path in NLOG.config file in DLL (class library) from other web application to generate the logs file . But I am unable to do this.
string filePath = path;
var target = (FileTarget)LogManager.Configuration.FindTargetByName("logFile");
target.FileName = "" + filePath + "/current.log";
LogManager.ReconfigExistingLoggers();
Normally there is only one global NLog.config for the entire application.
Instead of modifying the individual targets in the active NLog-config, then I think it is easier to modify the NLog global variables.
https://github.com/NLog/NLog/wiki/Gdc-layout-renderer
https://github.com/NLog/NLog/wiki/Var-Layout-Renderer
You could do it like this:
<target type="file" filename="${gdc:item=MyAppPath}current.log" />
And then at startup execute this command to modify the GDC:
NLog.GlobalDiagnosticsContext.Set("MyAppPath", filePath + "/");

Unittesting Nlog's archive feature

In my project I have created a logging system which is basically a shell on top of nLog. I am trying to unittest the archive feature of the logging system. It is currently setup to do rolling archives with a max archive files of 5 (Nlog is setup via code, no configuration file is used):
var myFileTarget = new FileTarget();
LogConfig.AddTarget("file", myFileTarget);
myFileTarget.FileName = LogFile;
myFileTarget.Layout = LogFileLayout;
myFileTarget.AutoFlush = true;
//Archive specifics
var token = "{#}";
var archiveFileName = $"{Path.GetFileNameWithoutExtension(LogFile)}.{token}.{Path.GetExtension(LogFile)}";
myFileTarget.ArchiveFileName = archiveFileName;
myFileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
myFileTarget.ArchiveEvery = toFileArchivePeriod(LogStyle);
myFileTarget.EnableFileDelete = true;
myFileTarget.MaxArchiveFiles = TTL; //Time to Live
myFileTarget.DeleteOldFileOnStartup = true;
To simulate that a lot of logs already exists, I create a range of logs with the same structure as the ArchiveFileName above:
LogFileName = "LogTTLDailyTest.log";
LogStyle = "daily";
LogTTL = 5; //Time To Live
//Arrange old filelogs
for (int i = 0; i < 100; i++)
{
var filename = $"LogTTLDailyTest.{i}.log";
File.WriteAllText(TestLogsDirectory + filename, "UNITTEST");
var creationTime = DateTime.Now.AddDays((i + 1)* -1);
File.SetCreationTime(TestLogsDirectory + filename, creationTime);
File.SetLastWriteTime(TestLogsDirectory + filename, creationTime);
}
But when I write a log to nlog via my Log system it does not see the old log files I created and therefore do not delete them. It does however clean up the old current log file, so deleting files work:
NLog: 2017-07-20 12:54:20.7434 Info Closing old configuration.
NLog: 2017-07-20 12:54:20.7434 Info Found 36 configuration items
NLog: 2017-07-20 12:54:20.7594 Info Found 36 configuration items
NLog: 2017-07-20 12:54:26.9157 Info Deleting old archive file: 'C:\<projectpath>\bin\Debug\unittestlogsea984b05-3c33-4142-9d1a-c900bad89006\LogTTLDailyTest.log'.
My current theory is that the nlog sees the old logs but have some kind of validation process of the contents of the files which I only fill up with "UNITTEST" as content, but I haven't been able to "restart" nlog or force it to see the logs.
Hope you can help me
This is no issue here, just me not setting the test up right. What I forgot is that rolling does not delete, but merely rename all files to the next rolling number. The last file in this rolling manner is deleted. Any other file is ignored by nlog. I also forgot to set my current log file a day back. This meant that nlog saw I had a current file that was not a day old. But because i had DeleteOldFileOnStartup activated it deleted that file.
So, to fix my mistake I made sure I only create as many files as I needed or less and made sure the latest file did not have a rolling number and was a day old. I also removed the DeleteOldFileOnStartup option. The Nlog is now doing what I expect it to do flawlessly.

How to programatically read the xx.exe.confg file of another application

I am trying to read the app settings in the config file of another application (app.exe.config).
I have tried several things. Most recently I used this:
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(FullPath() + ".config");
// Get the AppSetins section.
AppSettingsSection appSettingSection = config.AppSettings;
// Display raw xml.
Debug.WriteLine(appSettingSection.SectionInformation.GetRawXml());
but the GetRawXml() returns nothing. Where am I going wrong? The FullPath() method returns the correct path, I have tested this.
M
Config files are valid xml files so you can also try using XElement.Load(filepath) and process the xml tree as desired.
var appSettingsRawXml = System.Xml.Linq.XElement.Load(FullPath() + ".config")
.Element("appSettings")
.ToString();
GetRawXml supports the .NET Framework infrastructure and is not intended to be used directly from your code. MSDN

Multiple `.settings` Files Based on Configuration

I wanted to know if there was a way to have multiple .settings files based on configuration that are honored at runtime. So, at the moment I have a Settings.settings and a Release.settings file under the Properties folder. I'm not saying this is right by any means, I'm just saying that's what I currently have.
But, when running this line of code I always get the value out of the Settings.settings file.
Properties.Settings.Default.Setting
I realize that the Settings part of that line is explicitly defining the file I want, but I'm trying to find a way to get an abstracted line of code that will pull it out based off of the configuration.
So, unlike a config transform where it can be used to simply produce a different version of the file on deployment, I need to be able to actually see different values at runtime based on the configuration I'm running under.
I hope somebody can help, and thanks!
Yes it is possible. I was just wanting to do the same thing myself.
From the Project menu, choose Add New Item. The Add New Item dialog
box opens.
In the Add New Item dialog box, select Settings File, type in a name
for the file, and click Add to add a new settings file to your
solution.
In Solution Explorer, drag the new Settings file into the Properties
folder. This allows your new settings to be available in code.
Add and use settings in this file as you would any other settings
file. You can access this group of settings via the
Properties.Settings object.
Then you can reference each settings file by its prefix.
Config config = new Config();
if (Debugger.IsAttached)
{
config = new Config()
{
Interval = Dev.Default.Interval,
Username = Dev.Default.Username,
Password = Dev.Default.Password,
Directory = Dev.Default.Directory
};
}
else
{
config = new Config()
{
Interval = Settings.Default.Interval,
Username = Settings.Default.Username,
Password = Settings.Default.Password,
Directory = Settings.Default.Directory
};
}

Categories

Resources