0
votes

I am trying to group all configuration and log files of my application in one base folder (C:\MY_PRODUCT\ ) to have the following structure:

C:\MY_PRODUCT\CONFIGURATION\
C:\MY_PRODUCT\LOGS\
...

I am using log4net for logging, and using the environment variables in log4net FileAppender configuration works correctly:

<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<file value="${PRODUCT_BASE}\LOGS\file.log" />
<threshold value="ALL" />
<appendToFile value="true" />
<maximumFileSize value="10MB" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="200" />
<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="[%date{O}] [%-5level] [%-3thread] [%logger] [%method] %message%newline" />
</layout>

However, by separating the log4net configuration in new file (C:\MY_PRODUCT\CONFIGURATION\Log4Net.config), the log4net is unable to locate this configuration file when using the environment variable by setting the property ConfigSource:

<log4net configSource="${PRODUCT_BASE}\CONFIGURATION\Log4Net.config" />

Note that the if i replace ${PRODUCT_BASE} environment variable by its value (the path C:\MY_PRODUCT) it works correctly and log4net is able to find the config file.

Log4Net logs :

I enabled the log4net debug mode to see whats happen, and i got the following errors:

log4net:ERROR Failed to parse config file. Is the specified as: System.Configuration.ConfigurationErrorsException: Unable to open configSource file '${PRODUCT_BASE}\config\Log4Net.config'. (Tests\bin\Debug\MY_PRODUCT.Core.Tests.dll.config line 10) at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult) at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSection(String configKey) at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName) at System.Configuration.ConfigurationManager.GetSection(String sectionName) at log4net.Config.XmlConfigurator.InternalConfigure(ILoggerRepository repository)

I don't know if Log4Net is expanding the environment variable of the property ConfigSource, i already posted the issue on Apache Log4Net issues platform, until they answer or solve the issue, is there any way to achieve this approach ?

1

1 Answers

1
votes

After googling, It seems that it is not a Log4Net issue, as they said on this msdn post:

No, that can't be done natively.

I ended by adding a new application setting in app.config :

<add key="log4net.config" value="%PRODUCT_BASE%\config\Log4Net.config"/>

and when configuring the log4net at startup:

string log4NetConfigFile = ConfigurationManager.AppSettings["log4net.config"];
        var fileInfo = new FileInfo(Environment.ExpandEnvironmentVariables(log4NetConfigFile));
        XmlConfigurator.Configure(fileInfo);

I hope this will help others having the same issue.