2009-10-08 11 views
65

Sono totalmente nuovo a Log4net.
Sono riuscito a far funzionare qualcosa aggiungendo un file di configurazione e una semplice registrazione.
Ho hardcoded il valore per essere "C:\temp\log.txt" ma questo non è abbastanza buono.Come posso modificare la posizione del file a livello di programmazione?

I tronchi devono andare alle cartelle speciali

path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); 

e questo percorso cambia a seconda se si utilizza Windows Server 2008 o Windows XP o Vista, ecc ...

Come posso solo cambiare la posizione del file in log4net a livello di codice?

Questo è quello che ho fatto:

<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? 
    } 
} 

solo bisogno di capire come posso cambiare per accedere roba da dove voglio.

Qualche suggerimento? Grazie mille

+0

Hai bisogno di scavare attraverso IAppenders del vostro logger e impostare la FileAppender.File al percorso di uscita richiesta. Ecco un [ottimo esempio] (http://insario.com/blog/jfk/archive/2004/11/30/164.aspx). –

risposta

82

log4net in grado di gestire questo per voi. Qualsiasi proprietà di appender di tipo stringa può essere formattata, in questo caso, utilizzando il gestore di opzioni log4net.Util.PatternString. Stringamodello supporta anche il SpecialFolder enum che consente la seguente configurazione elegante:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" > 
    <file type="log4net.Util.PatternString" 
     value="%envFolderPath{CommonApplicationData}\\test.txt" /> 
    ... 
</appender> 

Ecco una prova di unità che rende impermeabile il budino:

[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)); 
} 

Il seguente test verifica che log4net in realtà scrive su disco (il che rende praticamente questo un test di "integrazione", non è una prova di unità, ma lasceremo le cose come stanno per ora):

[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: vi consiglio vivamente di utilizzare il comp agire la sintassi delle proprietà dimostrata nel precedente esempio. La rimozione di tutti quelli "< nome proprietà =" rende la configurazione molto più leggibile.

+1

Hi THanks Ho provato questo, ma ancora non accedere in applicazione dei dati ho avuto uno sguardo sul web ho trovato qualcosa che si chiama stringamodello ma non ho idea di come usarlo. Qualcuno ha un esempio? –

+0

@brix - La mia risposta iniziale non ha funzionato, quindi ho dovuto provare a me stesso che log4net può farlo. PatternString è la soluzione :) –

+0

Ciao, ho provato la tua soluzione ma per alcuni motivi non registra affatto. Ho copiato ciò che hai suggerito. Esegui l'app ma nessun file creato. Il tuo effettivamente crea un file? grazie mille –

0

In alternativa a questa operazione in modo programmatico, è possibile utilizzare variabili di ambiente e motivi personalizzabili nel file di configurazione. See this response to a similar question.

Vedere "PatternString per configurazione basata su modello" in the Log4Net V1.2.10 release notes.

Anche se state pensando di scrivere a una directory come Enviroment.SpecialFolder.CommonApplicationData è necessario considerare:

  • Sarà tutte le istanze della propria applicazione per tutti gli utenti hanno accesso in scrittura al file di registro? Per esempio. Non credo che i non amministratori possano scrivere su Enviroment.SpecialFolder.CommonApplicationData.

  • Contesa se più istanze dell'applicazione (per utenti uguali o diversi) stanno tentando lo stesso file. È possibile utilizzare il "modello di blocco minimo" (vedere http://logging.apache.org/log4net/release/config-examples.html per consentire a più processi di scrivere sullo stesso file di registro, ma probabilmente ci sarà un impatto sulle prestazioni.Oppure puoi assegnare a ciascun processo un file di registro diverso, ad es. includendo l'id del processo nel nome file utilizzando un modello personalizzabile.

13

Sembra che Peter's answer non funzioni per Log4net v1.2.10.0. Un metodo alternativo è descritto here.

Fondamentalmente il metodo consiste nell'implementare un convertitore di pattern personalizzato per il file di configurazione log4net.

prima aggiungere questa classe al progetto:

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)); 
    } 
} 

quindi impostare il parametro del file del vostro FileAppender come segue:

<file type="log4net.Util.PatternString"> 
    <converter> 
     <name value="folder" /> 
     <type value="MyAppName.SpecialFolderPatternConverter,MyAppName" /> 
    </converter> 
    <conversionPattern value="%folder{CommonApplicationData}\\SomeOtherFolder\\log.txt" /> 
    </file> 

Fondamentalmente il %folder dice di guardare il convertitore chiamato folder che lo indirizza alla classe SpecialFolderPatternConverter. Quindi chiama Convert su quella classe, passando il valore enum CommonApplicationData (o qualsiasi altra cosa).

+0

Grazie per quello. btw, App in MyAppName Penso che si riferisca a Project piuttosto che a App. –

34

ho trovato una mutazione di questo codice in interwebs:

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; 
    } 
} 

Questo funziona per me. La nostra applicazione deve inserire il file di registro in una cartella che contiene il numero di versione dell'app in base al file AssemblyInfo.cs.

Dovresti essere in grado di impostare logFileLocation in modo programmatico (ad esempio, puoi utilizzare Server.MapPath() se si tratta di un'applicazione Web) in base alle tue esigenze.

+3

penso che sia la migliore risposta :) –

+4

Mi sento come se questo dà molto più controllo sulla posizione del file. – fregas

3

questo ha funzionato per me:

<log4net> 
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 
.. 
     <file value="${APPDATA}\MyApp\MyApp Client\logs\Log.txt"/> 
.. 
    </log4net> 

Se il bisogno di scrivere a cartelle speciali che ho trovato aiuto here (esempio 2 ° e 3 °).

Edit:

Per rispondere OP .. Questo funziona per l'area 'tutti gli utenti':

 ... 
     <file value="${ALLUSERSPROFILE}\MyApp\MyApp Client\logs\Log.txt"/> 
     ... 

che normalmente è "C: \ ProgramData" nelle versioni più recenti di Windows.

Vedi anche questi:
How to specify common application data folder for log4net? == https://stackoverflow.com/a/1889591/503621 e commenti
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621

+1

Mi piace - bello e semplice. –

+0

'Environment.SpecialFolder.CommonApplicationData' e' $ (APPDATA) 'non sono la stessa cartella –

+0

Potete anche provare "$ {} ALLUSERSPROFILE" invece. . – bshea

5

Come su un semplice:

XmlConfigurator.LogFullFilename = @"c:\ProgramData\MyApp\Myapp.log"; 

Perché è così complessa da fare un cosa davvero semplice?

+11

Perché, il percorso cambia a seconda che tu sia in Windows Server 2008 o Winxp o Vista ecc ... In XP non esiste c: \ cartella ProgramData, solo in Win7/Vista. Quindi, se stiamo per distribuire questa app, deve essere compatibile per tutti i sistemi operativi. :-) L'hard coding non è una buona pratica. – Irshad

+4

Sto usando log4net v2.0.3 e questa proprietà non è disponibile su XmlConfigurator. Deve essere stato rimosso poiché la risposta è stata pubblicata. – Appetere

+0

Grazie Jason per aver corretto il mio inglese, questa non è la mia lingua principale;) Grazie! – Eric

0

Se si deve eseguire la distribuzione su sistemi sconosciuti e si desidera utilizzare la soluzione semplice di Philipp M anche con cartelle speciali differenti, è possibile recuperare il percorso speciale della cartella desiderato e impostare una variabile env personalizzata prima di caricare la configurazione di log4net. string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure(...

... solo per essere sicuri che la variabile env esiste e ha il valore desiderato.

2

Per cambiare anche il percorso del registro degli errori (in base alla risposta del 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(); 
      } 
     } 
    } 
} 
0

Grande caso d'uso per LINQs OfType<T> filtro:

/// <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(); 
    } 
} 

Se il nome del file nel app.config è log.txt questo cambierà l'output del registro di logs/some_name_log.txt:

ChangeLogFile(path => Path.Combine("logs", $"some_name_{Path.GetFileName(path)}")); 

Per rispondere alla PO problema originale che sarebbe:

ChangeLogFile(path => Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), path)); 
+0

Quando ho fatto questo, è stato semplicemente ricreato un file vuoto con il nuovo nome, ma "Logger.GetLogger' continuava a scrivere sul vecchio nome. –

Problemi correlati