Zėŋōfōbìå

24 marzo 2007

Gestire i log con log4net

Filed under: C#, informatica — Tag:, — Zeno @ 11:01

Ho sempre dedicato una fetta del tempo di sviluppo di qualunque applicazione di un certo rilievo alla realizzazione di una libreria di log che fosse comoda e adatta alle esigenze del programma. In genere quello che occorre è sempre uguale: una routine che permetta di salvare su un file, piuttosto che in un sql, un insieme di informazioni che comprenda: data del log, entità del problema, thread, riga del file di codice (ammesso che sia possibile), messaggio.
Mi è capitato più di una volta di perdere del tempo per una cattiva implementazione della libreria, alla quale non si vuole dedicare mai troppo tempo.

Sto provando Log4Net, soluzione di Apache che mi pare eccellente. Modulare, configurabile, comoda, semplice, è una meraviglia.

Un esempio per chiarirne la comodità:

using log4net;
using log4net.Config;

...
static class Program
{
    private static readonly ILog log =
        LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    static void Main()
    {
        // Set up a configuration taken from xml.
        XmlConfigurator.Configure(new System.IO.FileInfo("logfile.xml"));

        log.Info("Main");
    }
}

Notate che non viene determinata la forma del log: questa è descritta nel file xml logfile.xml, che contiene:

<?xml version="1.0" encoding="utf-8" ?>

<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="filelog.log" />

    <appendToFile value="true" />
    <maximumFileSize value="1000KB" />
    <maxSizeRollBackups value="10" />

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger (%file:%line) - %message%newline" />
    </layout>

  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="RollingFile" />

  </root>
</log4net>

In questa maniera vengono creati dei file di nome myproject.log, per un massimo di 100Kb e 20 files.
conversionPattern definisce la formattazione, che in questo caso produce log del tipo:

2007-03-22 15:27:43,923 [10] INFO Program (C:ProgettitestLog4net.cs:26) - Main

Annunci

3 commenti »

  1. Io invece sto creando un’applicazione che utilizzi la reflection per ottenere dinamicamente il nome della funzione che genera il log, completo del namespace della classe.

    Avevo creato uno pseudo-servizio di logging con una classe singleton, in quanto doveva essere l’unico LoggingService ad essere istanziato nella soluzione.

    Non è la cosa più bella del mondo, lo ammetto. Posto il codice per sapere quanto è brutto, secondo voi e se è possibile migliorarne la costruzione. Programmo in C# nel tempo libero, intendiamoci… :)

    using System;
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Diagnostics;
    
    using log4net;
    
    namespace Vetz.Vecio.Core.Services
    {
    	/// 
    	/// Service which provide Logging capabilities to Vecio. Does not derive
    	/// from IService 'cause does not need to be initialized
    	/// 
    	public sealed class LoggingService : IService
    	{
    		private static LoggingService instance = new LoggingService();
    		
    		public static LoggingService Instance
    		{
    			get { return instance; }
    		}
    
    		private LoggingService()
    		{
    			log4net.Config.XmlConfigurator.Configure();
    		}
    		
    		public void Initialize() { }
    		
    		public string ServiceName
    		{
    			get { return "LoggingService"; }
    		}
    		
    		private static string _GetLoggerName()
    		{
    			StackFrame stackFrame = new StackFrame(2);
    			
    			return (stackFrame.GetMethod().DeclaringType.FullName
    			        + "." + stackFrame.GetMethod().Name);
    		}
    		
    		public static void Debug(object message)
    		{
    			ILog _logger = LogManager.GetLogger(_GetLoggerName());
    			
    			if (_logger.IsDebugEnabled)
    				_logger.Debug(message);
    		}
    		
    		public static void Debug(string format, params object[] args)
    		{
    			ILog _logger = LogManager.GetLogger(_GetLoggerName());
    			
    			if (_logger.IsDebugEnabled)
    				_logger.DebugFormat(format, args);
    		}
    	}
    }
    

    Commento di ilvetz — 9 marzo 2009 @ 17:59

  2. Interessante. Solo un po’ oneroso in termini di performance, perché ad ogni Debug chiami lo stacktrace. Io in genere metto, per ogni metodo, almeno un paio di log: uno d’entrata con i parametri (a livello TRACE, subito dopo le assert sui parametri), uno d’uscita a livello TRACE e un certo numero variabile di DEBUG per monitorare lo stato. In pratica ad ogni azione corrisponde un log. E’ poi a livello di log che devo scegliere quali produrre e quali no. Per farlo ho una matrice che associa ad ogni SECTION (o file) il livello minimo da stampare…

    Un primo tentativo di ottimizzazione lo puoi fare includendo ILog _logger = LogManager.GetLogger(_GetLoggerName()); all’interno di if (_logger.IsDebugEnabled) .

    Commento di Fabrizio — 10 marzo 2009 @ 7:47

  3. @Vetz: anche io avevo in mente una cosa del genere per rimpiazzare le comodissime macro __FILE__, __FUNCTION__, __LINE__ del C/C++.

    Sfortunatamente funziona tutto tranne il replacement per la __LINE__: il metodo GetFileLineNumber() ritorna sempre 0 se non si è in debug… -.-‘

    Il C# è un gran linguaggio ma poi mi casca sull’__ABC__ (macro)… :D

    @Zeno: lo stacktrace non è oneroso perchè il framework/VM gestisce già il tutto e non deve produrre nulla di nuovo. Se proprio sono le scritture a video o su file a rallentare il tutto… :D

    Commento di jp — 23 marzo 2009 @ 15:51


RSS feed for comments on this post. TrackBack URI

Rispondi

Effettua il login con uno di questi metodi per inviare il tuo commento:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

Blog su WordPress.com.

%d blogger hanno fatto clic su Mi Piace per questo: