La propriété ThreadContext n'écrit pas dans AdoNetAppender
-
03-07-2019 - |
Question
J'utilise log4net 1.2.10.0. J'ai étendu ILog et LogManager pour inclure un nouveau niveau, "AUDIT". Je souhaite utiliser un AdoNetAppender
pour consigner le % message
dans une base de données. J'ai besoin d'autres informations consignées et j'ai essayé d'utiliser log4net.ThreadContext.Properties
.
Je n'obtiens aucune sortie lorsque j'essaie d'utiliser une propriété de contexte comme valeur pour un paramètre SQL.
<log4net>
<level>
<name value="AUDIT" />
<value value="35000" />
</level>
<appender name="AdoNetAppender.Audit" type="log4net.Appender.AdoNetAppender">
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="AUDIT" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<connectionType value="System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=db1;User ID=user;Password=pass" />
<commandText value="INSERT INTO table1 VALUES(:custom_prop, :message)" />
<parameter>
<parameterName value=":custom_prop" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{custom_prop}" />
</layout>
</parameter>
<parameter>
<parameterName value=":message" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender.Audit" />
</root>
</log4net>
Le code en cours d’exécution est (en supposant que log4net a été lancé et qu’un journal, "log", a été créé).
log4net.ThreadContext.Properties["custom_prop"] = "value";
log.Audit("a message");
Appender utilise le filtre AUDIT si je code une valeur au lieu d’utiliser un paramètre SQL.
...
<commandText value="INSERT INTO table1 VALUES('value', :message)" />
...
Appender utilise la propriété context si je filtre sur un niveau intégré, comme INFO.
...
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="INFO" />
</filter>
...
Un FileAppender
fonctionne avec le filtre AUDIT et la propriété de contexte!
<appender name="FileAppender" type="log4net.Appender.FileAppender" >
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="AUDIT" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<file value="test.log" />
<layout type="log4net.Layout.PatternLayout" >
<conversionPattern value="%-5level [%property{custom_prop}] - %message%newline" />
</layout>
</appender>
Résultat dans
AUDIT [value] - a message
L'utilisation d'une propriété de contexte global fonctionne avec les filtres AdoNetAppender
et AUDIT. Mais j'ai besoin d'une résolution de contexte de thread.
log4net.GlobalContext.Properties["custom_prop"] = "value";
log.Audit("a message");
Résultat dans
table1
custom_prop message
=========== =======
value a message
Alors, je ne sais pas s'il s'agit d'un problème avec AdoNetAppender
, mes classes étendues ou ma configuration.
La solution
Le problème était dû à un avortement précoce du fil de premier plan. Je pense que log4net exécutait une opération asynchrone. Mettre un sommeil à la fin de l'application de test a résolu le problème
...
log4net.ThreadContext.Properties["custom_prop"] = "value";
log.Audit("a message");
...
Thread.Sleep(1000);
ou, lorsque vous vous connectez à un fil séparé, y adhérer
Thread t = new Thread(new ThreadStart(delegate
{
log4net.ThreadContext.Properties["custom_prop"] = "value";
log.Audit("a message");
}));
t.Start();
...
t.Join();
En fonctionnement normal, log4net devrait disposer d'un délai suffisant entre le dernier appel AUDIT et la fin de l'exécution.