Quali sono le migliori pratiche per la registrazione in profondità nella sorgente di un'applicazione? È una cattiva pratica avere più voci nel registro eventi per un singolo errore?
Ad esempio, supponiamo di avere un sistema ETL il cui passaggio di trasformazione comporta: un trasformatore, pipeline, algoritmo di elaborazione e motore di elaborazione.
In breve, il trasformatore acquisisce un file di input, analizza i record e invia i record attraverso la pipeline. La pipeline aggrega i risultati dell'algoritmo di elaborazione (che potrebbe eseguire l'elaborazione seriale o parallela). L'algoritmo di elaborazione invia ogni record attraverso uno o più motori di elaborazione. Quindi, ho almeno quattro livelli: Transformer - > Pipeline - > Algoritmo - > Motore.
Il mio codice potrebbe quindi somigliare a quanto segue:
class Transformer {
void Process(InputSource input) {
try {
var inRecords = _parser.Parse(input.Stream);
var outRecords = _pipeline.Transform(inRecords);
} catch (Exception ex) {
var inner = new ProcessException(input, ex);
_logger.Error("Unable to parse source " + input.Name, inner);
throw inner;
}
}
}
class Pipeline {
IEnumerable<Result> Transform(IEnumerable<Record> records) {
// NOTE: no try/catch as I have no useful information to provide
// at this point in the process
var results = _algorithm.Process(records);
// examine and do useful things with results
return results;
}
}
class Algorithm {
IEnumerable<Result> Process(IEnumerable<Record> records) {
var results = new List<Result>();
foreach (var engine in Engines) {
foreach (var record in records) {
try {
engine.Process(record);
} catch (Exception ex) {
var inner = new EngineProcessingException(engine, record, ex);
_logger.Error("Engine {0} unable to parse record {1}", engine, record);
throw inner;
}
}
}
}
}
class Engine {
Result Process(Record record) {
for (int i=0; i<record.SubRecords.Count; ++i) {
try {
Validate(record.subRecords[i]);
} catch (Exception ex) {
var inner = new RecordValidationException(record, i, ex);
_logger.Error(
"Validation of subrecord {0} failed for record {1}",
i, record
);
}
}
}
}
Ci sono alcune cose importanti da notare:
- Un singolo errore al livello più profondo causa tre voci di registro (brutto? DOS?)
- Le eccezioni generate contengono tutte le informazioni importanti e utili
- La registrazione avviene solo quando l'impossibilità di farlo causerebbe la perdita di informazioni utili a un livello inferiore.
Pensieri e dubbi:
- Non mi piace avere tante voci di registro per ogni errore
- Non voglio perdere dati importanti e utili; le eccezioni contengono tutte le informazioni importanti, ma lo stacktrace è in genere l'unica cosa visualizzata oltre al messaggio.
- Posso accedere a diversi livelli (ad es., avviso, informativo)
- Le classi di livello superiore dovrebbero essere completamente inconsapevoli della struttura delle eccezioni di livello inferiore (che potrebbero cambiare con la sostituzione delle diverse implementazioni).
- Le informazioni disponibili ai livelli superiori non devono essere trasmesse ai livelli inferiori.
Quindi, per riformulare le domande principali:
Quali sono le migliori pratiche per la registrazione in profondità nella sorgente di un'applicazione? È una cattiva pratica avere più voci nel registro eventi per un singolo errore?