Ich bin völlig neu in Log4net. Ich habe es geschafft, etwas in Gang zu bringen, indem ich eine Konfigurationsdatei hinzugefügt und einfach protokolliert habe. Ich habe den Wert fest codiert, "C:\temp\log.txt"
aber das ist nicht gut genug.
Die Protokolle müssen in die speziellen Ordner verschoben werden
path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
und dieser Pfad ändert sich je nachdem, ob Sie Windows Server 2008 oder Windows XP oder Vista usw. verwenden.
Wie kann ich den Speicherort der Datei in log4net programmgesteuert ändern?
Folgendes habe ich getan:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\temp\log.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
</appender>
</log4net>
class Program
{
protected static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
log.Warn("Log something");
path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
// How can I change where I log stuff?
}
}
Ich muss nur herausfinden, wie ich Änderungen vornehmen kann, um Inhalte dort zu protokollieren, wo ich möchte.
Irgendwelche Vorschläge? Danke vielmals
Antworten:
log4net kann dies für Sie erledigen. Jede Appender-Eigenschaft vom Typ string kann in diesem Fall mit dem Optionshandler log4net.Util.PatternString formatiert werden . PatternString unterstützt auch die Special Enumeration , die die folgende elegante Konfiguration ermöglicht:
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" > <file type="log4net.Util.PatternString" value="%envFolderPath{CommonApplicationData}\\test.txt" /> ... </appender>
Hier ist ein Unit-Test, der den Pudding beweist:
[Test] public void Load() { XmlConfigurator.Configure(); var fileAppender = LogManager.GetRepository() .GetAppenders().First(appender => appender is RollingFileAppender); var expectedFile = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.CommonApplicationData), "test.txt"); Assert.That(fileAppender, Is.Not.Null & Has.Property("File").EqualTo(expectedFile)); }
Der folgende Test überprüft, ob log4net tatsächlich auf die Festplatte schreibt (was dies im Grunde genommen zu einem "Integrationstest" macht, nicht zu einem Komponententest, aber wir lassen es vorerst dabei):
[Test] public void Log4net_WritesToDisk() { var expectedFile = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.CommonApplicationData), "test.txt"); if (File.Exists(expectedFile)) File.Delete(expectedFile); XmlConfigurator.Configure(); var log = LogManager.GetLogger(typeof (ConfigTest)); log.Info("Message from test"); LogManager.Shutdown(); Assert.That(File.ReadAllText(expectedFile), Text.Contains("Message from test")); }
NB: Ich empfehle dringend, die im obigen Beispiel gezeigte kompakte Eigenschaftssyntax zu verwenden. Wenn Sie alle "<property name =" entfernen, ist Ihre Konfiguration viel besser lesbar.
quelle
Ich habe eine Mutation dieses Codes in den Interwebs gefunden:
XmlConfigurator.Configure(); log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy) LogManager.GetRepository(); foreach (IAppender a in h.Root.Appenders) { if (a is FileAppender) { FileAppender fa = (FileAppender)a; // Programmatically set this to the desired location here string logFileLocation = @"C:\MySpecialFolder\MyFile.log"; // Uncomment the lines below if you want to retain the base file name // and change the folder name... //FileInfo fileInfo = new FileInfo(fa.File); //logFileLocation = string.Format(@"C:\MySpecialFolder\{0}", fileInfo.Name); fa.File = logFileLocation; fa.ActivateOptions(); break; } }
Das funktioniert bei mir. Unsere Anwendung muss die Protokolldatei in einem Ordner ablegen, der die Versionsnummer der App basierend auf der Datei AssemblyInfo.cs enthält.
Sie sollten in der Lage sein, die logFileLocation programmgesteuert festzulegen (z. B. können Sie Server.MapPath () verwenden, wenn dies eine Webanwendung ist), um Ihren Anforderungen zu entsprechen.
quelle
Es sieht so aus, als würde Peters Antwort für Log4net v1.2.10.0 nicht funktionieren. Eine alternative Methode wird hier beschrieben .
Grundsätzlich besteht die Methode darin, einen benutzerdefinierten Musterkonverter für die log4net-Konfigurationsdatei zu implementieren.
Fügen Sie diese Klasse zuerst Ihrem Projekt hinzu:
public class SpecialFolderPatternConverter : log4net.Util.PatternConverter { override protected 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)); } }
Richten Sie dann den File-Parameter Ihres FileAppender wie folgt ein:
<file type="log4net.Util.PatternString"> <converter> <name value="folder" /> <type value="MyAppName.SpecialFolderPatternConverter,MyAppName" /> </converter> <conversionPattern value="%folder{CommonApplicationData}\\SomeOtherFolder\\log.txt" /> </file>
Grundsätzlich
%folder
weist es den aufgerufenen Konverter an,folder
der auf die SpecialFolderPatternConverter-Klasse verweist. Anschließend wirdConvert
diese Klasse aufgerufen und der Aufzählungswert CommonApplicationData (oder was auch immer) übergeben.quelle
Wie wäre es mit einem einfachen:
XmlConfigurator.LogFullFilename = @"c:\ProgramData\MyApp\Myapp.log";
Warum ist es so komplex, etwas wirklich Einfaches zu tun?
quelle
Das hat bei mir funktioniert:
<log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> .. <file value="${APPDATA}\MyApp\MyApp Client\logs\Log.txt"/> .. </log4net>
Wenn ich in spezielle Ordner schreiben muss, habe ich hier Hilfe gefunden (2. und 3. Beispiel).
Bearbeiten:
Um OP zu beantworten. Dies funktioniert für den Bereich "Alle Benutzer":
... <file value="${ALLUSERSPROFILE}\MyApp\MyApp Client\logs\Log.txt"/> ...
Dies ist normalerweise "C: \ ProgramData" in neueren Windows-Versionen.
Siehe auch diese:
Wie gebe ich einen allgemeinen Anwendungsdatenordner für log4net an? == https://stackoverflow.com/a/1889591/503621 und Kommentare
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621
quelle
Environment.SpecialFolder.CommonApplicationData
und$(APPDATA)
sind nicht der gleiche OrdnerSo ändern Sie auch den Pfad des Fehlerprotokolls (basierend auf der Antwort von JackAce):
private static void SetLogPath(string path, string errorPath) { XmlConfigurator.Configure(); log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(); foreach (var a in h.Root.Appenders) { if (a is log4net.Appender.FileAppender) { if (a.Name.Equals("LogFileAppender")) { log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a; string logFileLocation = path; fa.File = logFileLocation; fa.ActivateOptions(); } else if (a.Name.Equals("ErrorFileAppender")) { log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a; string logFileLocation = errorPath; fa.File = logFileLocation; fa.ActivateOptions(); } } } }
quelle
JackAces Antwort, nur präziser mit Linq:
C #
XmlConfigurator.Configure(); var appender = (LogManager.GetRepository() as Hierarchy).Root.Appenders .OfType<FileAppender>() .First(); appender.File = logPath; appender.ActivateOptions();
VB.NET
quelle
Großartiger Anwendungsfall für LINQs-
OfType<T>
Filter:/// <summary> /// Applies a transformation to the filenames of all FileAppenders. /// </summary> public static void ChangeLogFile(Func<string,string> transformPath) { // iterate over all FileAppenders foreach (var fileAppender in LogManager.GetRepository().GetAppenders().OfType<FileAppender>()) { // apply transformation to the filename fileAppender.File = transformPath(fileAppender.File); // notify the logging subsystem of the configuration change fileAppender.ActivateOptions(); } }
Wenn der Dateiname in der app.config lautet
log.txt
, ändert sich die Protokollausgabe inlogs/some_name_log.txt
:ChangeLogFile(path => Path.Combine("logs", $"some_name_{Path.GetFileName(path)}"));
Um das ursprüngliche Problem des OP zu beantworten, wäre dies:
quelle
Logger.GetLogger
stattdessen weiter auf den alten Namen.Alternativ dazu können Sie Umgebungsvariablen und anpassbare Muster in der Konfigurationsdatei verwenden. Siehe diese Antwort auf eine ähnliche Frage .
Weitere Informationen finden Sie in den Versionshinweisen zu Log4Net V1.2.10 unter "PatternString für musterbasierte Konfiguration" .
Auch wenn Sie in ein Verzeichnis wie Enviroment.SpecialFolder.CommonApplicationData schreiben möchten, müssen Sie Folgendes berücksichtigen:
Haben alle Instanzen Ihrer Anwendung für alle Benutzer Schreibzugriff auf die Protokolldatei? Ich glaube beispielsweise nicht, dass Nicht-Administratoren in Enviroment.SpecialFolder.CommonApplicationData schreiben können.
Konflikt, wenn mehrere Instanzen Ihrer Anwendung (für denselben oder verschiedene Benutzer) versuchen, dieselbe Datei zu verwenden. Sie können das "Minimal Locking Model" verwenden (siehehttp://logging.apache.org/log4net/release/config-examples.html , damit mehrere Prozesse in dieselbe Protokolldatei schreiben können, dies hat jedoch wahrscheinlich Auswirkungen auf die Leistung. Oder Sie können jedem Prozess eine andere Protokolldatei zuweisen, z. B. indem Sie die Prozess-ID mithilfe eines anpassbaren Musters in den Dateinamen aufnehmen.
quelle
In der aktuellen Version von Log4Net (2.0.8.0) können Sie einfach
<file value="${ProgramData}\myFolder\LogFiles\" />
fürC:\ProgramData\..
und${LocalAppData}
für verwendenC:\Users\user\AppData\Local\
quelle
Wenn Sie auf unbekannten Systemen bereitstellen müssen und die einfache Lösung von Philipp M auch mit verschiedenen speziellen Ordnern verwenden möchten, können Sie den gewünschten speziellen Ordnerpfad abrufen und eine benutzerdefinierte env-Variable festlegen, bevor Sie die log4net-Konfiguration laden.
string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure( ...
... nur um sicherzugehen, dass die env-Variable existiert und den gewünschten Wert hat.
quelle