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


11

Voglio aggiungere la registrazione a un'applicazione su cui sto attualmente lavorando. 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: attualmente lo sto facendo in C #, quindi gli esempi in C # sono ovviamente benvenuti. Vorrei anche vedere esempi in Java e Ruby.


Modifica: sto usando log4net. Non so proprio quale sia il modo migliore per collegarlo.

Risposte:


6

La migliore pratica che consiglierei è usare log4j piuttosto che lanciare il tuo. (Che è stato portato da Java a C # e Ruby, quindi si applica a tutte e 3 le lingue che ti interessano.)

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


5

Dove lavoro scriviamo molte app desktop .NET. Normalmente implementiamo 2 eventi nei nostri componenti, uno per la registrazione delle informazioni e l'altro per la registrazione delle eccezioni (anche se spesso lasciamo che le eccezioni si diffondano invece di generare l'evento separato. Dipende dalla situazione). Utilizzando questa architettura, nessuna delle nostre librerie deve sapere come viene implementata la registrazione o come le informazioni vengono utilizzate, archiviate o trattate. Quindi l'applicazione gestirà gli eventi di registrazione in un modo appropriato per quell'app. Diversi anni fa questa architettura ha reso il nostro passaggio dall'uso della registrazione MS Library Library al componente di registrazione di BitFactory una transizione molto semplice.


+1 per l'utilizzo di un modello di evento / osservatore: cambia l'osservatore, hai modificato la registrazione
Matthieu M.


2

Personalmente, prendo il framework di registrazione preferito (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 l'origine.


Sembra molto interessante, ma ho delle riserve su ciò che si sarebbe in grado di registrare e su quanto sarebbe informativo il registro (cioè più della "giusta" strumentazione dei metodi). Mi piacerebbe vedere un esempio funzionante di questo approccio per vedere cosa si può o non si può fare. Soprattutto perché sto appena iniziando su una nuova app e vorrei vedere dove / fino a dove potrei portare questo.
Marjan Venema,

@marjan Venema: la documentazione post sharp ha un esempio di un aspetto che registra l'accesso / l'uscita da un metodo. doc.sharpcrafters.com/postsharp/2.0/##PostSharp.chm/html/… Nel caso di Post sharp, intreccia il codice dell'attributo nell'origine al momento della creazione, quindi non influisce sulle prestazioni come altri.
Steven Evers,

1

Il sistema su cui sto attualmente lavorando utilizza un'architettura e un sistema di messaggistica basati sugli eventi, in modo che la maggior parte delle azioni nel nostro sistema siano il risultato di un comando e risultino in eventi (come classi DTO che vengono inviate, piuttosto che un evento delegato standard). Alleghiamo gestori di eventi il ​​cui unico scopo è gestire la registrazione. Questo design ci aiuta a non ripeterci, e non è necessario modificare il codice esistente per aggiungere / cambiare funzionalità.

Ecco un esempio di una tale classe di registrazione, 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 si tratta di buone pratiche senza mezzi termini, poiché sembro cambiare idea su cosa e come accedere spesso - e ogni volta che devo usare un registro per diagnosticare un problema, trovo inevitabilmente dei modi per migliorare il informazioni che registro.

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

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

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

1

Come altri hanno già detto, utilizzare log4jo log4neto qualche altro framework di registrazione ben costruito.

Tendo davvero a non gradire il codice di registrazione che ostacola la logica aziendale. Ecco perché lo uso Log4PostSharp. Ciò significa che posso utilizzare la 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 assieme come questo:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]

0

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

  1. traccia a livello di metodo
  2. registrazione delle eccezioni
  3. gli sviluppatori di informazioni di runtime extra ritengono che sia fondamentale per l'analisi in caso di errore di runtime (o qualsiasi comportamento correlato alla situazione di runtime).

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 dichiaratamente la registrazione agli assiemi, qualcosa del tipo 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 è possibile applicare le regole di traccia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.