Dal punto di vista del design, quali sono le migliori pratiche per la registrazione? [chiuso]

11

Voglio aggiungere la registrazione a un'applicazione a cui sto lavorando attualmente. Ho aggiunto la registrazione prima, non è un problema qui.

Ma dal punto di vista del design in un linguaggio orientato agli oggetti, quali sono le migliori pratiche per la registrazione che seguono OOP e schemi?

Nota: al momento sto facendo questo in C #, quindi gli esempi in C # sono ovviamente benvenuti. Mi piacerebbe anche vedere esempi in Java e Ruby.

Modifica: sto utilizzando log4net. Solo non so qual è il modo migliore per collegarlo.     
posta Edgar Gonzalez 08.06.2011 - 16:44
fonte

7 risposte

6

La migliore pratica che raccomanderei è quella di utilizzare log4j anziché far girare il tuo. (Che è stato trasferito da Java a C # e a Ruby, quindi si applica a tutte e 3 le lingue che ti interessano.)

Se leggi questa pagina di manuale scoprirai diverse altre buone pratiche. Ad esempio la leggerezza, configurabile all'esterno dell'applicazione, la possibilità di attivare e disattivare la registrazione per diverse parti dell'applicazione in modo indipendente e così via.

    
risposta data 08.06.2011 - 16:53
fonte
5

Dove lavoro scriviamo molte app desktop .NET. Normalmente implementiamo 2 eventi nei nostri componenti, uno per le informazioni di registrazione e l'altro per la registrazione delle eccezioni (anche se spesso lasciamo scoppiare le eccezioni anziché sollevare l'evento separato. Dipende dalla situazione). Usando questa architettura, nessuna delle nostre librerie deve sapere come viene implementata la registrazione o come le informazioni vengono utilizzate, memorizzate o trattate. Quindi l'applicazione gestisce gli eventi di registrazione in un modo appropriato per quell'app. Un certo numero di anni fa questa architettura ha reso il passaggio dall'utilizzo della registrazione della MS Enterprise Library al componente di registrazione di BitFactory una transizione molto semplice.

    
risposta data 08.06.2011 - 17:47
fonte
2

Dato che lo stai facendo in C #, ti consiglio di consultare NLog ed ElMAH. Possono essere MOLTO facilmente installati usando NUGET. Ho messo alcuni link a quelli qui sotto in modo da poter ottenere maggiori informazioni.

risposta data 08.06.2011 - 17:13
fonte
2

Personalmente, prendo il framework di registrazione di scelta (nel mio caso, Entlib perché lavoro con .NET) e scrivo un aspetto AOP per la registrazione.

È quindi possibile attribuire qualsiasi metodo / proprietà / classe / spazio dei nomi e aggiungere la registrazione ad essi senza ingombrare la fonte.

    
risposta data 08.06.2011 - 17:59
fonte
1

Il sistema su cui sto lavorando utilizza un'architettura e una messaggistica event-driven, così che la maggior parte delle azioni nel nostro sistema sono il risultato di un comando e generano eventi (come classi DTO che vengono inviate, piuttosto che un delegato standard) evento). Alleghiamo gestori di eventi il cui unico scopo è gestire la registrazione. Questo design ci aiuta a non ripeterci e anche a non modificare il codice esistente per aggiungere / modificare funzionalità.

Ecco un esempio di una classe di registrazione di questo tipo, che gestisce tutti gli eventi da registrare da una sezione ristretta della nostra applicazione (quelli riguardanti una particolare fonte di contenuto da cui importiamo).

Non dirò necessariamente che questa è una buona pratica, poiché mi sembra di cambiare idea su cosa e come registrare spesso - e ogni volta che ho bisogno di usare un log per diagnosticare un problema, trovo inevitabilmente dei modi per fare miglioramenti alle informazioni che registro.

Dirò, tuttavia, che la registrazione delle informazioni pertinenti (specialmente in Ctrl-F / trova il modo di ricerca) è la parte più importante.

La seconda parte più importante è ottenere il codice di accesso dalla logica principale: può rendere un metodo brutto e lungo e molto contorto molto .

public class MctLogger :
    IEventHandler<StoryImported>,
    IEventHandler<StoryScanned>,
    IEventHandler<SourceDirectoryMissing>,
    IEventHandler<SourceDirectoryAccessError>,
    IEventHandler<CannotCreateScannedStoryDirectory>,
    IEventHandler<CannotReadStoryDocument>,
    IEventHandler<StorySkippedPastCutoff>,
    IEventHandler<StorySkippedDuplicateUniqueId>,
    IEventHandler<StorySkippedByFilter>
{

    public void Observe(StoryImported e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryImported");
        log.Info("Story Unique ID: {Story.UniqueId}, Content ID: {ContentId}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StoryScanned e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryScanned");
        log.Info("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(SourceDirectoryMissing e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryMissing");
        log.Error("Directory: " + e.Directory);
    }

    public void Observe(SourceDirectoryAccessError e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryAccessError");
        log.Error(e.Exception, "Exception: " + e.Exception.Message);
    }

    public void Observe(CannotCreateScannedStoryDirectory e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotCreateScannedStoryDirectory");
        log.Error(e.Exception, "Directory: {Directory}, Exception: {Exception.Message}".SmartFormat(e));
    }

    public void Observe(CannotReadStoryDocument e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotReadStoryDocument");
        if (e.Exception == null) {
            log.Warn("File: {FilePath}".SmartFormat(e));
        }
        else {
            log.Warn(e.Exception, "File: {FilePath}, Exception: {Exception.Message}".SmartFormat(e));
        }
    }

    public void Observe(StorySkippedPastCutoff e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedPastCutoff");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedDuplicateUniqueId e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedDuplicateUniqueId");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedByFilter e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedByFilter");
        log.Warn("Story Unique ID: {Story.UniqueId}, Reason: {Reason}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }
}
    
risposta data 08.06.2011 - 19:28
fonte
1

Come altri hanno già detto, usa log4j o log4net o qualche altro framework di registrazione ben costruito.

Di solito non mi piace che il codice di accesso interferisca con la logica del business. Ecco perché utilizzo Log4PostSharp . Ciò significa che posso usare Programmazione orientata agli aspetti per annotare metodi come questo:

[Log(LogLevel.Info, "Counting characters.")]
int CountCharacters(string arg) 
{
    return arg.Length;
}

O ogni metodo in un assembly come questo:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]
    
risposta data 08.06.2011 - 19:34
fonte
0

Non sono sicuro che qualsiasi framework faccia questo, ma dal punto di vista del design, modellerei le informazioni che devono essere registrate principalmente in tre categorie:

  1. traccia del livello del metodo
  2. registrazione delle eccezioni
  3. gli sviluppatori di informazioni in fase di esecuzione supplementari ritengono che sia di vitale importanza per le indagini in caso di un errore in fase di esecuzione (o di qualsiasi comportamento correlato alla situazione di sola esecuzione).

Per le prime due categorie, il mio framework di registrazione ideale dovrebbe gestirle come un processo post-build e trasparente per gli sviluppatori. Sarebbe bello aggiungere in modo dichiarativo la registrazione agli assembly, qualcosa di simile al seguente:

Trace YourNamespace.* [public methods|constructors]
{  # options
   ignore trivial methods,
   format: "{time stamp}: {method name}({parameter list})",
   condition: "{Context.Instance.UserID in (12432,23432)}",
}

Exception YourNamespace.Program.Main [unhandled exceptions]
{
  format: "{time stamp}: {Context.Instance.UserId} {exception}",
  action: die,  # options are throw, swallow,
}

Per la terza categoria, i programmatori possono semplicemente creare uno o più metodi di "registrazione" dedicati e sfruttare la traccia per la prima categoria. I metodi di registrazione non fanno altro che servire un punto di stub a cui possono essere applicate le regole di tracciamento.

    
risposta data 08.06.2011 - 18:42
fonte

Leggi altre domande sui tag