Quali sono alcuni schemi e anti-schemi di registrazione delle applicazioni? [chiuso]


67

Di recente ho dovuto indagare su un problema sul campo per la nostra grande applicazione aziendale. Sono rimasto inorridito dai log che ho dovuto esaminare nel tentativo di trovare il problema e alla fine i log non hanno aiutato affatto a identificare / isolare il bug.

Nota: capisco che non tutti i bug sono rilevabili attraverso i registri. Ciò non cambia il fatto che i log siano orribili.

Ci sono alcuni ovvi problemi con la nostra registrazione che possiamo già tentare di risolvere. Non desidero elencarli qui e non posso semplicemente mostrarti i nostri file di registro in modo che tu possa dare consigli su cosa fare.

Invece, al fine di valutare quanto stiamo facendo male sul fronte della registrazione, vorrei sapere:

  1. Quali sono alcune linee guida , se presenti, quando si tratta di accedere a un'applicazione, in particolare un'applicazione di grandi dimensioni.
  2. Ci sono degli schemi che dovremmo seguire o degli anti-schemi di cui dovremmo essere consapevoli?
  3. È una cosa importante da risolvere o può anche essere riparato o tutti i file di registro sono semplicemente enormi e hai bisogno di script supplementari per analizzarli?

Nota a margine: usiamo log4j.

Risposte:


56

Alcuni punti che la mia pratica si è dimostrata utile:

  • Conservare tutto il codice di registrazione nel codice di produzione. Avere la possibilità di abilitare la registrazione più / meno dettagliata nella produzione, preferibilmente per sottosistema e senza riavviare il programma.

  • Rendi i log facili da analizzare grepa occhio nudo. Attenersi a diversi campi comuni all'inizio di ogni riga. Identifica il tempo, la gravità e il sottosistema in ogni riga. Formulare chiaramente il messaggio. Rendi ogni messaggio di log facile da mappare alla sua riga di codice sorgente.

  • Se si verifica un errore, prova a raccogliere e registrare quante più informazioni possibili. Potrebbe richiedere molto tempo, ma va bene perché l'elaborazione normale non è riuscita comunque. Non dover aspettare quando si verificano le stesse condizioni in produzione con un debugger collegato non ha prezzo.

I registri sono principalmente necessari per il monitoraggio e la risoluzione dei problemi. Mettiti nei panni di uno strumento per la risoluzione dei problemi e pensa a che tipo di log ti piacerebbe avere quando qualcosa di sbagliato sta accadendo o è successo nel cuore della notte.


10
Mi piace questa risposta, ma aggiungerei che è importante registrare quale scelta è stata fatta nei punti decisionali. Ho visto molti sistemi in cui è stata registrata molta posta indesiderata ma le decisioni chiave non sono state registrate. Quindi il 95% della registrazione è sostanzialmente inutile. Anche per i sistemi di tipo richiesta / risposta è più importante poter accedere per richiesta che per sottosistema.
Kevin,

4
+1. Mi piace il tuo punto di metterti nei panni di uno strumento per la risoluzione dei problemi. Sembra che le dichiarazioni dei registri debbano contenere molti più messaggi di qualità rispetto a quello che abbiamo fatto ...
c_maker,

1
È importante notare che la registrazione degli errori deve essere registrata nel registro eventi appropriato e nei registri dell'applicazione.
Steven Evers,

2
@SnOrfus: esistono diversi modi per archiviare i registri, ma l'essenza è che i messaggi di registro devono essere disponibili fino all'ultimo secondo in cui il sistema si è schiantato, come una scatola nera di un aereo. Se si utilizza qualsiasi tipo di buffering, fornire un'opzione per ignorarlo / svuotare ogni messaggio.
rwong

1
@Rig: d'altra parte, molti logger di produzione propria non hanno implementato alcun buffering (e svuotano diligentemente ogni messaggio), portando a prestazioni molto scadenti. Ecco perché deve essere reso facoltativo.
rwong,

28

Lavoro con sistemi real-time critici per la sicurezza e la registrazione è spesso l'unico modo per catturare rari bug che si presentano una volta una luna blu ogni 53 martedì quando è una luna piena, se catturi la mia deriva. Questo tipo di ti rende ossessivo sull'argomento, quindi mi scuserò ora se comincio a fare la schiuma alla bocca. Quanto segue è stato scritto per i log di debug del codice nativo, ma la maggior parte è applicabile anche al mondo gestito ...

Usa file di registro di testo. Sembra ovvio, ma alcune persone provano a generare file di registro binari: è semplicemente stupido perché non ho bisogno di cercare uno strumento di lettura quando sono sul campo. Inoltre, se si tratta di testo e il debug è dettagliato, ci sono buone possibilità che l'ingegnere del campo possa leggere il file e diagnosticare il problema senza mai tornare da me. Tutti vincono.

Progetto sistemi in grado di registrare praticamente tutto, ma non accendo tutto per impostazione predefinita. Le informazioni di debug vengono inviate a una finestra di dialogo di debug nascosta che le timestamp e le invia in una casella di riepilogo (limitata a circa 500 righe prima dell'eliminazione) e la finestra di dialogo mi consente di interromperla, salvarla automaticamente in un file di registro o deviarla in un debugger collegato. Questa diversione mi permette di vedere l'output di debug da più applicazioni tutte ordinatamente serializzate, il che può essere un salvavita a volte. Ho usato per usare livelli di registrazione numerici (più alto è di impostare il livello, più si cattura):

off
errors only
basic
detailed
everything

ma questo è troppo inflessibile: man mano che ti avvicini a un bug, è molto più efficiente riuscire a concentrarti accedendo esattamente a ciò di cui hai bisogno senza dover guadare tonnellate di detriti e potrebbe essere un particolare tipo di transazione o operazione che causa l'errore. Se questo richiede di accendere tutto, stai solo rendendo il tuo lavoro più difficile. Hai bisogno di qualcosa di più fine.

Quindi ora sono in procinto di passare alla registrazione basata su un sistema di flag. Tutto ciò che viene registrato ha una bandiera che specifica il tipo di operazione, e c'è una serie di caselle di controllo che mi consentono di definire ciò che viene registrato. In genere tale elenco è simile al seguente:

#define DEBUG_ERROR          1
#define DEBUG_BASIC          2
#define DEBUG_DETAIL         4
#define DEBUG_MSG_BASIC      8
#define DEBUG_MSG_POLL       16
#define DEBUG_MSG_STATUS     32
#define DEBUG_METRICS        64
#define DEBUG_EXCEPTION      128
#define DEBUG_STATE_CHANGE   256
#define DEBUG_DB_READ        512
#define DEBUG_DB_WRITE       1024
#define DEBUG_SQL_TEXT       2048
#define DEBUG_MSG_CONTENTS   4096

Questo sistema di registrazione viene fornito con la versione di rilascio , attivata e salvata nel file per impostazione predefinita. È troppo tardi per scoprire che avresti dovuto registrarti DOPO che il bug si è verificato, se quel bug si verifica solo una volta ogni sei mesi in media e non hai modo di riprodurlo. La registrazione che funziona solo con build di debug è giusta. pianura. muto.

Il software viene generalmente fornito con ERROR, BASIC, STATE_CHANGE ed EXCEPTION attivati, ma questo può essere modificato nel campo tramite la finestra di dialogo di debug (o un'impostazione del registro / ini / cfg, dove queste cose vengono salvate).

Oh e una cosa: il mio sistema di debug genera un file al giorno. Le tue esigenze potrebbero essere diverse. Assicurati però che il tuo codice di debug avvii ogni file con la data, la versione del codice che stai eseguendo e, se possibile, qualche marcatore per l'ID cliente, l'ubicazione del sistema o altro. Puoi ottenere un miscuglio di file di registro che arrivano dal campo e hai bisogno di un record di ciò che è venuto da dove e quale versione del sistema erano in esecuzione che è in realtà nei dati stessi e non puoi fidarti del cliente / ingegnere sul campo per dirti quale versione hanno - potrebbero semplicemente dirti quale versione PENSANO di avere. Peggio ancora, potrebbero segnalare la versione exe presente sul disco, ma la versione precedente è ancora in esecuzione perché si sono dimenticati di riavviare dopo la sostituzione. Chiedi al tuo codice di dirti.

Infine, non vuoi che il tuo codice generi i propri problemi, quindi inserisci una funzione timer per eliminare i file di registro dopo tanti giorni o settimane (controlla la differenza tra ora e ora della creazione del file). Questo è OK per un'app server in esecuzione tutto il tempo, su un'app lato client è possibile ottenere con l'eliminazione di tutti i vecchi dati all'avvio. Generalmente eliminiamo i dati dopo circa 30 giorni, su un sistema senza frequenti visite da parte dell'ingegnere si consiglia di lasciarlo più a lungo. Ovviamente questo dipende anche dalle dimensioni dei file di registro.


1
+1 In generale ottima risposta, ma soprattutto per inserire l'ID dell'applicazione e le informazioni sulla versione nel file di registro, sfortunatamente questo è mancato molto spesso.
Binary Worrier

27

La mia risorsa pubblica preferita per le linee guida per la registrazione sono le migliori pratiche di Apache JCL .

Le migliori pratiche per JCL sono presentate in due categorie: Generale ed Enterprise. I principi generali sono abbastanza chiari. Le pratiche aziendali sono un po 'più coinvolte e non è sempre chiaro il motivo per cui sono importanti.

I principi delle best practice aziendali si applicano ai componenti e agli strumenti del middleware che dovrebbero essere eseguiti in un ambiente di livello "Enterprise". Questi problemi riguardano la registrazione come internazionalizzazione e il rilevamento dei guasti. Le imprese richiedono più impegno e pianificazione, ma sono fortemente incoraggiate (se non richieste) nei sistemi a livello di produzione. Le diverse aziende / ambienti aziendali hanno requisiti diversi, quindi essere flessibili aiuta sempre ...

Nonostante abbiano come target JCL, questi sembrano essere abbastanza generici da essere adottati per la registrazione in generale.

  • Le mie "linee guida" personali per la registrazione sono che a livello di debug cerco di leggere i miei registri come una storia, con una logica comprensibile e dettagli sufficienti (ma non sovraccarichi).

Il più famoso anti-pattern è probabilmente "ingoiare le eccezioni" - basta cercarlo sul web.

Per quanto riguarda gli enormi file di log, nella mia pratica questo era principalmente il caso normale. E sì, anche gli script supplementari come li chiami e / o strumenti come Chainsaw mi sembrano normali.

  • Sopra non significa però che devi sempre mettere alla cieca tutti i registri in un unico file enorme. A volte potrebbe essere utile scrivere / copiare alcuni dei registri in file separati. Ad esempio, nel mio recente progetto, i ragazzi del QA hanno chiesto file dedicati per metriche e dati di temporizzazione e brevi rapporti sulle operazioni del sistema. Hanno detto che ne trarranno beneficio e lo hanno fatto gli sviluppatori (beneficiano di un breve file di report davvero significativo).

PS. Per quanto riguarda gli anti-schemi, altri che vengono in mente sono messaggi "inondanti" e insensati.

  • Lo chiamo alluvione quando vedo più messaggi simili provenienti da un ciclo con molte iterazioni. Per me, l'allagamento è abbastanza fastidioso da provare a liberarmene quando lo rilevo nel codice sorgente. Di solito migliorarlo richiede un po 'di arte - perché, beh, le cose che accadono all'interno del ciclo possono essere interessanti. Quando non ho tempo per migliorarlo più a fondo, provo almeno a cambiare il livello di registrazione di tali messaggi in uno più basso per semplificare il filtraggio.

  • I messaggi senza senso sembrano essere spazzatura piuttosto popolare. Sembrano innocui quando letti nel codice sorgente - Immagino che si debba passare attraverso il dolore di analizzare l'output di debug come ...

    step #1
    step #2
    step #3
    

    ... per apprezzare profondamente la loro bruttezza intrinseca. La mia euristica preferita per rilevare questo tipo di problemi a livello di codice sorgente (proposta dal collega in uno dei miei progetti passati) è calcolare il numero di occorrenze dei simboli di spazio nei letterali di stringa utilizzati nella registrazione. Nella mia esperienza, zero spazi garantisce sostanzialmente che la dichiarazione di registrazione sia priva di senso, uno spazio è anche un buon indicatore del potenziale problema.


4
Per evitare inondazioni di solito raccolgo l'euristica del ciclo e lo emetto dopo il ciclo. Significa che qualsiasi cosa accada nel ciclo dovrebbe essere memorizzata in una variabile (come somethingSpecialHappenedCount) e quindi inviata al logger.
Spoike,

@Spoike buon punto! la memorizzazione in una variabile è davvero uno dei miei trucchi personali preferiti per combattere le inondazioni
moscerino

1
Eseguo l'output di tutti i diversi contatori nel logger come tabella ASCII nel registro dopo la fine del ciclo in modo che possano essere facilmente confrontati. L'idea del tavolo è stata ispirata da quella che genera lo StopWatch.prettyPrint () di Spring . A parte questo, rendere il testo del registro leggibile e pertinente è ancora un '"arte" come menzionato precedentemente nella risposta.
Spoike,

@Spoike: (e @gnat) Questo è interessante. Quindi in pratica aggiungi il codice effettivo alla logica aziendale solo allo scopo di accedere? Non ne ho mai sentito parlare o fatto prima e non sono sicuro di come lo giustificherei ai miei colleghi. Temo che se iniziamo a farlo, alcuni dei nostri sviluppatori ingombreranno il codice sorgente a tal punto che la logica aziendale diventa contorta e difficile da leggere. Basta semplicemente registrare un'istruzione per rendere la fonte più brutta.
c_maker,

2
@c_maker il tuo punto sul mescolare la registrazione con la logica di business sembra una domanda dedicata. Personalmente non ho ancora una forte opinione su questi argomenti. In teoria si possono immaginare alcuni miglioramenti della separazione usando AOP e iirc ci sono persino applicazioni pratiche per questo approccio. In pratica, tuttavia, seguo un approccio "misto" e finora non ho avuto grossi problemi. Il disordine del codice sorgente è un vero pericolo, ma, di nuovo, finora sono stato in grado di farlo coesistere con il codice di registrazione piuttosto "pacificamente". Questo ovviamente richiede un certo sforzo.
moscerino il

11

Registra l'eccezione una sola volta!

Uno dei punti dolenti più comuni che ho notato è la registrazione e il rilancio di un'eccezione. Di conseguenza, i file di registro contengono le stesse eccezioni più volte su più livelli di stack.


5

Ecco un anti-pattern: Rendere due dozzine di campi "generici-variabili" in una tabella di database per tenere traccia di qualsiasi cosa concepibile e quindi avere 88 (e contare) valori enum diversi per diversi tipi di log.


+1 - L'ho visto. Le "Tabelle degli errori" che hanno colonne come string1, string2, string3, string4, string5, in cui la concaturazione di tutte le colonne comporterà un codice di errore a cui non viene fatto riferimento in nessuno dei documenti. Il risultato è una registrazione che è al tempo stesso confusa e inutile; noto anche come "app-enterprise-di-terze-parti-con-sviluppo-personalizzato-debugging-hell".
Morgan Herlocker,

Nel mio caso è "un sistema di registrazione a rotazione manuale senza alcuna idea di cosa significhi effettivamente la registrazione"
Wayne Molina,

4

La mia esperienza con i registri è tanto migliore quanto maggiore è, ma essere abbastanza coerente da renderlo filtrabile per macchina ed essere in grado di configurare un livello di gravità per ogni componente dell'applicazione individualmente.

Inoltre, è molto difficile prevedere quale registrazione sarà necessaria per trovare un bug futuro. La maggior parte dei luoghi ovvi per la registrazione degli errori viene risolta prima che il prodotto esca dalla porta. Non è raro che il risultato di una segnalazione di bug sia che hai appena aggiunto la registrazione per aiutarti a diagnosticare se si verifica di nuovo.


2

Un paio di note dal lato operazioni della casa qui:

1) Assicurati che i log siano configurabili localmente, preferibilmente con uno strumento non più pesante di un editor di testo. Il più delle volte non vogliamo ottenere la registrazione a livello di TRACE, ma adoriamo poterlo attivare.

2) Se possibile, assicurati che i registri possano essere letti con uno strumento non più pesante di un editor di testo. Niente è peggio che dover andare a caccia di utensili in un'ora dispari quando il sistema di produzione non funziona.


1

Dalla mia esperienza di lavoro con le applicazioni Web:

(e considerando che l'archiviazione è molto economica oggi)

  • Accedi quante più informazioni disponibili (in quel preciso momento) come puoi.
  • Includo sempre DateTime.Now nelle mie stringhe di registro.
  • Registro sempre (se possibile) la durata di alcune "azioni" specifiche.
  • Sii coerente con le tue stringhe di registro. Da sempre uso questo tipo di modello:

    • "[Info X] [Info Y] [Info Z] [ecc.]"

1

Oltre allo stacktrace, registra lo stato corrente dell'applicazione e l'input.

Il software è deterministico, questi due sono in genere l'unica cosa di cui hai bisogno per riprodurre il bug. La memorizzazione dello stato completo potrebbe in alcuni casi essere problematica, quindi anche i modi per riprodurre lo stato corrente, ad esempio input precedenti, sono buoni.

Ovviamente sempre più dati è sempre meglio, ma almeno questi due sono un buon inizio per gli arresti più facili.


3
"Software is deterministic" => non sempre purtroppo. Pensa ad esempio ai bug della concorrenza.
Assylias,
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.