Versions
- Nlog 5.0.4
- .NET 6.0 application
Originally I configured NLog with an XML config file which worked fine, however there was a secret string in the file so I wanted to move to programmatic configuration so I could retrieve the secret string securely in C# and not have it in plaintext in the file.
I was able to get the programmatic configuration to work, but the secret string requires an async method to be retrieved so it cannot be in the Logger constructor. I then took the config code and the async call out of the Logger constructor and made a factory method.
My problem is: I cannot figure out how to get Logger in each class with a private constructor factory method instead of a public constructor due to my configuration requiring an async call.
Here is my current NLog setup:
public class MyLogger : Logger
{
// Private constructor
private MyLogger(LoggingConfiguration config)
{
// Apply config
LogManager.Configuration = config;
}
// FactoryMethod
public async static Task<MyLogger> BuildMyLogger()
{
LoggingConfiguration config = new LoggingConfiguration();
var secret = await CallToGetSecretString();
DatabaseTarget databaseTarget = new DatabaseTarget("database")
{
ConnectionString = secret,
CommandType = System.Data.CommandType.StoredProcedure,
CommandText = "[StoredProcedure]",
Parameters = {
new DatabaseParameterInfo("@logged", "${date}")
// Shortened...
}
};
config.AddRuleForAllLevels(databaseTarget);
return new MyLogger(config);
}
// Other code here...
}
Previously my setup was:
public class MyLogger : Logger
{
public MyLogger()
{
LogManager.Configuration = new XmlLoggingConfiguration("NLog/MyNlogConfig.config");
}
}
This call worked for the previous way, but throws an error when using the new config
private readonly static MyLogger logger = (MyLogger)LogManager.GetCurrentClassLogger(typeof(MyLogger));
System.TypeInitializationException: 'The type initializer for 'App.Logic.MyClass' threw an exception.'
Inner Exception
InvalidCastException: Unable to cast object of type 'NLog.Logger' to type 'App.Nlog.MyLogger'.
I also tried to call the factory method from a class, but that is not possible due to it being async
private readonly static MyLogger logger = await MyLogger.BuildMyLogger();
CS1992 The 'await' operator can only be used when contained within a method or lambda expression marked with the 'async' modifier
Thank you for your time and suggestions on this issue.
CodePudding user response:
You should only attempt to load NLog-configuration once, and not every time creating a Logger-object. The new code probably fails because MyLogger
no longer has a valid default-constructor.
Think you should focus on creating initial NLog-config at application-startup, and assign that to LogManager.Configuration
as early as possible.
Note you can also access application-secrets from NLog.config by using NLog Context. Ex. ${gdc:item=SecretKey} and NLog.GlobalDiagnosticsContext.Set("SecretKey","SomeSecretValue");