项目中使用log4net进行日志记录,使用配置文件对log4net进行配置,都进行得很顺利。但出于security方面的考虑,要求某些敏感字段(如password)不能出现在配置文件中。因此需要在程序中设置这些字段,先从保存敏感信息的地方(比如AKV)读取敏感字段,再写到log4net配置中。
比如改写配置文件中SmtpAppender中的Password属性:
Hierarchy hier = log4net.LogManager.GetRepository() as Hierarchy;
var smtpAppender =
(SmtpAppender)(hier.Root.Appenders.OfType().FirstOrDefault());
if (smtpAppender != null)
{
smtpAppender.Password = parameters.SecureCodeEmailPassword;
smtpAppender.ActivateOptions();
}
在改写配置后调用logger.Error(message)
可以如期工作,似乎一切都很顺利(^_^)然而这时诡异的事情发生了–在改写配置后的某个遥远的地方(在程序入口改写配置,后经过一段业务逻辑处理),日志功能不work了,一脸懵逼o(╯□╰)o
这时候自然需要更多的详细信息帮助定位问题和解决问题,在设置log4net debug属性后(具体可参考开启log4net内部调试),可以定位到问题是程序中改写的配置没有生效!!!
可开始的调用明明显示改写的配置已经生效了,又一脸懵o(╯□╰)o
只好仔细的看日志信息了ε=(´ο`*)))sign
log4net: Creating repository for assembly [AzureKeyVaultAdapter, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]
log4net: Assembly [AzureKeyVaultAdapter, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] Loaded From [D:\Bothell\target\dev\metrics\CheckinMonitoringJob\debug\amd64\AzureKeyVaultAdapter.dll]
log4net: Assembly [AzureKeyVaultAdapter, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] does not have a RepositoryAttribute specified.
log4net: Assembly [AzureKeyVaultAdapter, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] using repository [log4net-default-repository] and repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: Creating repository [log4net-default-repository] using type [log4net.Repository.Hierarchy.Hierarchy]
log4net: Creating repository for assembly [Internal.OSS.GenericLogger, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]
log4net: Assembly [Internal.OSS.GenericLogger, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] Loaded From [D:\Bothell\target\dev\metrics\CheckinMonitoringJob\debug\amd64\Internal.OSS.GenericLogger.dll]
log4net: Assembly [Internal.OSS.GenericLogger, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] does not have a RepositoryAttribute specified.
log4net: Assembly [Internal.OSS.GenericLogger, Version=16.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35] using repository [log4net-default-repository] and repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: repository [log4net-default-repository] already exists, using repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: configuring repository [log4net-default-repository] using file [Xxx.exe.Config] watching for file updates
log4net: configuring repository [log4net-default-repository] using file [Xxx.exe.Config]
log4net: configuring repository [log4net-default-repository] using stream
log4net: loading XML configuration
log4net: Configuring Repository [log4net-default-repository]
log4net: Configuration update mode [Merge].
log4net: Logger [root] Level string is [ALL].
log4net: Logger [root] level set to [name="ALL",value=-2147483648].
log4net: Loading Appender [LogFileAppender] type: [log4net.Appender.FileAppender]
log4net: Setting Property [File] to String value [CheckinMonitoring.log]
从日志中不难发现,每次加载一个Assembly后,都会重新配置log4net默认的repository [log4net-default-repository] 。这是因为每个Assembly都没有指定RepositoryAttribute,log4net会为其选用默认的repository。正是因为如此,所以我们一般都不需要特别关注log4net repository相关的配置,默认的可以适用绝大部分场景。
问题也就找到了:在改写配置之后,因为又新加载了新的Assembly,也是采用log4net默认的repository,并且重新load配置文件配置log4net默认的repository。重新配置覆盖了之前改写的配置。
问题找到了,解决问题大概有下面几种方法:
[assembly: log4net.Config.Repository(name: "myRepository")]
[assembly: log4net.Config.XmlConfigurator()]
Hierarchy hier = log4net.LogManager.GetRepository("myRepository") as Hierarchy;
var smtpAppender =
(SmtpAppender)(hier.Root.Appenders.OfType().FirstOrDefault());
if (smtpAppender != null)
{
smtpAppender.Password = parameters.SecureCodeEmailPassword;
smtpAppender.ActivateOptions();
}
LogManager.GetRepository(repositoryName)
会返回指定的repository,当没有指定repositoryName时,会返回默认的repository,即log4net-default-repository。
完美؏؏☝ᖗ乛◡乛ᖘ☝؏؏