log4net dynamiczne ustawianie katalogu wyjściowego
Zapewne nie jeden z Was spotkał się kiedyś z problemem typu "Jak dynamicznie w kodzie ustawić katalog wyjściowy pliku z logami?" Nie zawsze jest możliwość lub potrzeba umieszczania pliku z logami "w otoczeniu" głównego katalogu aplikacji przy użyciu relatywnej ścieżki. Czasami konieczna jest możliwość wyboru katalogu docelowego w zależności od spełnienia określonych warunków, lub jak to było w moim przypadku wybór specjalnego katalogu systemowego, którego lokalizacja może być różna w zależności od wersji używanego systemu jak i dysku na którym został zainstalowany. Konkretnie potrzebowałem umieścić logi błędów w folderze znajdującym się w katalogu danych aplikacji (ProgramData). Aby to zrobić w pierwszej kolejności należy zaimplementować klasę pochodną od klasy PatternConverter z przestrzeni nazw log4net.Util, przeciążając funkcję Convert wykonującą konwersję.
public class AppDataFolderPatternConverter : PatternConverter
{
protected override void Convert(System.IO.TextWriter writer, object state)
{
writer.Write(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
}
}
Aby wykorzystać powyższą klasę modyfikujemy plik konfiguracyjny log4net jak w poniższym przykładzie.
<file type="log4net.Util.PatternString">
<converter>
<name value="folder" />
<type value="Drycow.Client.AppDataFolderPatternConverter,ITRSclient" />
</converter>
<conversionPattern value="%folder/KAEL/ITRS Client/Logs/general.txt" />
</file>
Jak widać stworzyliśmy nowy konwerter o nazwie folder, we wzorcu możemy odwoływać się do niego dodając przedrostek %.
Podaną funkcję możemy ulepszyć korzystając z możliwość przekazywania argumentów do funkcji konwersji. Przykładowo chcąc uzyskać ścieżkę do tego samego katalogu danych aplikacji wpis conversionPattern w pliku konfiguracyjnym na:
<conversionPattern value="%folder{CommonApplicationData}/KAEL/ITRS Client/Logs/general.txt" />
Natomiast nasza funkcja konwersji wygląda teraz tak:
protected override void Convert(System.IO.TextWriter writer, object state)
{
Environment.SpecialFolder specialFolder =
(Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder),
base.Option, true);
writer.Write(Environment.GetFolderPath(specialFolder));
}
W ten sposób możemy wybrać katalog docelowy jaki tylko nam się wymarzy.