C# - NLog.config setting 'archiveEvery' value programatically on start - c#

I have a NLog.config file with the following target:
<?xml version="1.0" encoding="utf-8" ?>
<nlog 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"
autoReload="true"
throwExceptions="true"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log" >
<variable name="ProgramDataPath"
<target name="MyLog" xsi:type="File" fileName="${ProgramDataPath}/MyLog.txt"
archiveFileName="${ProgramDataPath}/Archive/Mine/{#}_MyLog.txt" archiveNumbering="Date" archiveEvery="Day" archiveDateFormat="dd-MM-yyyy" maxArchiveFiles="7" />
I'd like to be able to modify the 'archiveEvery' property by setting it to either 'Day' or 'Month' value each time I start my app, and that should be done by reading another config file where I have the property:
<IsMylogDailyArchiveEnabled>false</IsMylogDailyArchiveEnabled>
False means it should log monthly, True - daily.
So far I am able to read the later, however nothing inside NLog.config seems to be changed after I start my app...
public string IsMylogDailyArchiveEnabled
{
get { return _isMylogDailyArchiveEnabled ; }
set
{
_isMylogDailyArchiveEnabled = value;
//Here I can see that 'false' is being returned as it should
EnableMyLogDailyArchiving(_isMylogDailyArchiveEnabled );
}
}
private void EnableMyLogDailyArchiving(string value)
{
var config = new XmlLoggingConfiguration("NLog.config");
var target = config.FindTargetByName("MyLog") as FileTarget;
if (value == "false")
{
//Does not work
target.ArchiveEvery = FileArchivePeriod.Month;
}
else
{
target.ArchiveEvery = FileArchivePeriod.Day;
}
//LogManager.ReconfigExistingLoggers();
LogManager.Configuration = config;
}
Tried both options 'LogManager.ReconfigExistingLoggers()' and reassigning configuration (see above), however as mentioned before, I can't see any changes inside the NLog.config file.
Any thoughts or ideas? Thanks

It should work,
When doing LogManager.Configuration = config;, the configuration is reloaded and all targets are initialized. So the new ArchiveEvery setting will be used.
But be aware that auto reload is enabled (autoReload="true"), so every change in the XML config will revert the change made in code. If you don't want that, then change the config by subscribing to
LogManager.ConfigurationReloaded
PS: it's recommend to disabled throwExceptions in production (e.g. by removing throwExceptions="true")

Related

How to include NLog config files in code behind

I have a nlog.config file with the following entry:
<include file="${basedir}/ActiveConfig/NLog/*.config"/>
But I want to solve this via code behind and have not found a method to do so.
LogManager.LoadConfiguration()
is overwriting my existing configuration.
Did I miss something?
You could set it like this:
var config = XmlLoggingConfiguration
.CreateFromXmlString("<include file='${basedir}/ActiveConfig/NLog/*.config' />");
LogManager.Configuration = config; // apply
Think the easy solution is just to load all config-files into an in-memorystream, and then load that into a single XmlLoggingConfiguration:
var xmlReader = System.Xml.XmlReader.Create(memorystream);
NLog.LogManager.Configuration = new XmlLoggingConfiguration(xmlReader, null);
Something like this, where you put the contents of all config-files within the same <nlog>-root:
<nlog>
<!-- XML File 1 -->
<targets>
</targets>
<rules>
</rules>
<! -- XML File 2 -->
<targets>
</targets>
<rules>
</rules>
</nlog>
If you want the AutoReload-feature working also, then this might work:
class MySpecialLoggingConfiguration : XmlLoggingConfiguration
{
private string[] _fileNames;
public MySpecialLoggingConfiguration(string[] fileNames)
{
_fileNames = fileNames;
// Your special concat-logic in memory
}
public override LoggingConfiguration Reload()
{
return new MySpecialLoggingConfiguration(_fileNames);
}
public override IEnumerable<string> FileNamesToWatch => _fileNames;
}

How to inject values into my NLog.config?

I use a NLog.config, but some values I want to change from outside. E.g. target:adress could change so I want to set it each time the software starts.
I imagine some thing like
var logger = new LoggerFactory().AddNLog().CreateLogger<Program>();
logger.target.adress = "myNewAdress";
How can I set values to my NLog.config?
You could edit the config in C# like this:
var configuration = LogManager.Configuration;
var fileTarget = configuration.FindTargetByName<FileTarget>("myTargetName");
fileTarget.FileName = "${basedir}/file.log";
LogManager.Configuration = configuration; //apply
Please note that combining the config file (nlog.config) and changing it in code, the reload of nlog.config could undo your changes. If you combine both, then reapply the changes on the reload event. E.g.
public void UpdateConfig()
{
var configuration = LogManager.Configuration;
var fileTarget = configuration.FindTargetByName<FileTarget>("myTargetName");
fileTarget.FileName = "${basedir}/file.log";
LogManager.Configuration = configuration; //apply
}
// On start of your program
UpdateConfig();
LogManager.ConfigurationReloaded += (sender, e) =>
{
//Re apply if config reloaded
UpdateConfig();
};
See also: https://github.com/NLog/NLog/wiki/Configure-from-code
I recommend that one makes use of the NLog context layoutrenderers instead of modifying target properties at runtime. It ofcourse requires that the target-property supports NLog Layout.
Example of NLog.config:
<nlog>
<targets>
<target type="file" name="file" fileName="${gdc:item=LogDir}\LogFile.txt}" />
</targets>
<rules>
<logger minLevel="Trace" writeTo="file" />
</rules>
</nlog>
Then at runtime you can change the GDC-variables:
NLog.GlobalDiagnosticsContext.Set("LogDir", "C:\\Temp");
${gdc} Can also be combined with WhenEmpty, so one can provide a fallback default value, when nothing has been asigned from code.
See also: https://github.com/NLog/NLog/wiki/Context

How can I change the value of a custom configSections variable?

I have a custom section in the configSections of my App.config file, how can I change the value of one of the variables of this section in code?
The section I would like to change is "serverConfiguration", and I want to change the value of "serverUrl":
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="serverConfiguration" type="someType" />
</configSections>
<serverConfiguration serverUrl="http://development/server/" />
</configuration>
I found this piece of code below from this previous question, App.Config change value.
It looks close to what I need, but I am not sure how to change it myself to use it for a custom section rather than the AppSettings. Will the code below work for what I am trying to do? How do I change the code below to allow me to pass this new String as serverUrl "http://staging/server/"? Thanks!
class Program
{
static void Main(string[] args)
{
UpdateSetting("lang", "Russian");
}
private static void UpdateSetting(string key, string value)
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
configuration.AppSettings.Settings[key].Value = value;
configuration.Save();
ConfigurationManager.RefreshSection("appSettings");
}
}
You have an option to load the config into XML, edit the node value and save it back. Give a try with this
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
xmlDoc.SelectSingleNode("//serverConfiguration").Attributes["serverUrl"].Value = "http://staging/server/";
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
Probably, it is a good idea to refresh the Config sections after file is saved.
ConfigurationManager.RefreshSection

Update config file

I have a problem with update my ConfigFile in VS2013 with C#.
I have this code:
Configuration configManager = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
KeyValueConfigurationCollection confCollection = configManager.AppSettings.Settings;
confCollection["ID_Uzivatele"].Value = ID_Uzivatele;
configManager.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configManager.AppSettings.SectionInformation.Name);
(ID_Uzivatele is a String variable)
and configFile
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ID_Uzivatele" value="default"/>
</appSettings>
</configuration>
My problem is that(error list):
An unhandled exception of type 'System.NullReferenceException' occurred in KomunikacniAplikace.exe
Anybody has an idea what I am doing wrong?
I would suggest looking at an error case where the setting isn't set: this works for me:
(assuming theres a const for the string so you don't get a typo...)
const string ID_UZIVATELE = "ID_Uzivatele";
Main code:
Configuration configManager = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
KeyValueConfigurationCollection confCollection = configManager.AppSettings.Settings;
if (confCollection.AllKeys.Contains(ID_UZIVATELE)) {
Console.Out.WriteLine("Contains key, modifying : was " + confCollection["ID_Uzivatele"].Value);
confCollection["ID_Uzivatele"].Value = "foo";
} else {
Console.Out.WriteLine("Doesn't contain key, adding");
confCollection.Add(ID_UZIVATELE, "Boom");
}
configManager.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configManager.AppSettings.SectionInformation.Name);
If the config file is missing, this will generate it( you might want to check that your App.Config is actually being copied to the output folder (which might be the root cause of your error), but building protection against bad config is always helpful.

How to read AppSettings from app.config in WinForms

I usually use a text file as a config. But this time I would like to utilize app.config to associate a file name (key) with a name (value) and make the names available in combo box
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Scenario1.doc" value="Hybrid1"/>
<add key="Scenario2.doc" value="Hybrid2"/>
<add key="Scenario3.doc" value="Hybrid3"/>
</appSettings>
</configuration>
will this work? how to retrieve the data ?
Straight from the docs:
using System.Configuration;
// Get the AppSettings section.
// This function uses the AppSettings property
// to read the appSettings configuration
// section.
public static void ReadAppSettings()
{
try
{
// Get the AppSettings section.
NameValueCollection appSettings = ConfigurationManager.AppSettings;
// Get the AppSettings section elements.
Console.WriteLine();
Console.WriteLine("Using AppSettings property.");
Console.WriteLine("Application settings:");
if (appSettings.Count == 0)
{
Console.WriteLine("[ReadAppSettings: {0}]",
"AppSettings is empty Use GetSection command first.");
}
for (int i = 0; i < appSettings.Count; i++)
{
Console.WriteLine("#{0} Key: {1} Value: {2}",i, appSettings.GetKey(i), appSettings[i]);
}
}
catch (ConfigurationErrorsException e)
{
Console.WriteLine("[ReadAppSettings: {0}]", e.ToString());
}
}
So, if you want to access the setting Scenario1.doc, you would do this:
var value = ConfigurationManager.AppSettings["Scenario1.doc"];
Edit:
As Gabriel GM said in the comments, you will have to add a reference to System.Configuration.
app settings in app.config are to store application/environment specific settings not to store data which binds to UI.
If you cant avoid storing in config because of weird business requests I would rather stick to one single setting
<add key="FileDropDown" value="File1-Value|File2-Value" />
and write C# code to get this setting ConfigurationManager.AppSettings["FileDropDown"] and do some string Splits ('|') and ('-') to create kvp collection and bind it to UI.

Categories

Resources