Vorteile der strukturierten Protokollierung gegenüber der grundlegenden Protokollierung

110

Wir bauen eine neue App und möchten strukturierte Protokollierung einbinden. Mein ideales Setup wäre so etwas wie Serilogfür unseren C # -Code und Bunyanfür unseren JS. Diese würden in fluentdeine beliebige Anzahl von Dingen einfließen und könnten dann herausgehen, dachte ich anfangs elasticsearch + kibana. Wir haben bereits eine MySQL-Datenbank, daher bin ich kurzfristig mehr daran interessiert, dass Serilog + Bunyan-Setup und die Entwickler es verwenden, und wir können uns bei MySQL anmelden, während wir uns etwas mehr Zeit nehmen, um fließend und den Rest zu erledigen.

Einer unserer erfahreneren Programmierer würde es jedoch vorziehen, einfach Folgendes zu tun: select-Anweisungen für MySQL log.debug("Disk quota {0} exceeded by user {1}", quota, user);verwenden log4netund dann ausführen:SELECT text FROM logs WHERE text LIKE "Disk quota";

Welcher Ansatz ist jedoch besser und / oder welche Aspekte müssen bei der Auswahl des Protokollierungssystems berücksichtigt werden?

DTI-Matt
quelle
Ich stimme den vorgenommenen Änderungen zu. Ich versuche nicht so sehr, jemandem etwas zu beweisen, sondern die Vorteile und den Unterschied zwischen strukturierter und grundlegender Protokollierung zu verstehen. Meiner Meinung nach gibt uns strukturiert viel mehr Flexibilität, insbesondere in Bezug auf die Quellen von Protokollen, und wie wir dann in der Lage sind, deren Daten anzuzeigen. Nach meinem Verständnis kann ich nicht erklären, warum das grundlegende Protokollieren und Durchsuchen von MySQL besser / schlechter ist als das strukturierte Protokollieren.
DTI-Matt
2
@ DTI-Matt Die strukturierte Protokollierung von serilog ist nur eine einfache Protokollierung. Sie formatiert nur Objekte, die Sie darauf drucken. Dies können Sie selbst tun, indem Sie ToString sehr einfach überschreiben. Ein wichtigerer Aspekt ist die Konfiguration und Verwaltung der Protokolldateien, nicht die Formatierung eines Strings über einen anderen, sondern die Leistung. Wenn der Entwickler log4net verwenden möchte (eine gute Logging-Bibliothek), dann ist Ihre Wahl von serilog (die cool aussieht) eine dieser "Lösungen auf der Suche nach einem Problem".
gbjbaanb
@ DTI-Matt Aus der Sicht von serilog sieht es log4net sehr ähnlich. log4net verwaltet das Erstellen strukturierter Protokolle in config. Sie müssen die Protokollnachrichten nicht durchsuchen, da zusätzliche Informationen konfiguriert und in eine Tabelle geschrieben werden können. Konfigurieren Sie auch log4net für fluentd tipstuff.org/2014/05/…
RubberChickenLeader
Pass auf, es gibt einige Idioten, die die Idee der konzeptuellen Fragen hier nicht verstehen. Wenn Sie nach der Richtung der Datenbankanwendungen fragen, um einen Überblick über ihre ETL-Funktionen zu erhalten, erhalten Sie einige ernsthafte Nachteile. Ich gehe davon aus, dass Ihre Frage auch auf dem Hackklotz steht.
user3916597
2
@gbjbaanb Serilog funktioniert wie log4net, wenn Ereignisse als Text gerendert werden. Wenn Sie jedoch ein strukturiertes Format zum Speichern von Protokollen verwenden, werden benannte Eigenschaften mit den übergebenen Argumenten verknüpft (dh das Suchen / Filtern ohne Regex usw. wird unterstützt. ) HTH!
Nicholas Blumhardt

Antworten:

140

Der strukturierte Ansatz bringt zwei grundlegende Fortschritte mit sich, die mit Textprotokollen nicht ohne (manchmal extremen) zusätzlichen Aufwand emuliert werden können.

Ereignistypen

Wenn Sie mit log4net zwei Ereignisse schreiben, wie:

log.Debug("Disk quota {0} exceeded by user {1}", 100, "DTI-Matt");
log.Debug("Disk quota {0} exceeded by user {1}", 150, "nblumhardt");

Diese erzeugen ähnlichen Text:

Disk quota 100 exceeded by user DTI-Matt
Disk quota 150 exceeded by user nblumhardt

Bei der maschinellen Verarbeitung handelt es sich jedoch nur um zwei Zeilen mit unterschiedlichem Text.

Möglicherweise möchten Sie alle "Datenträgerkontingent überschritten" -Ereignisse finden, aber der vereinfachte Fall der Suche nach Ereignissen like 'Disk quota%'wird fallen, sobald ein anderes Ereignis eintritt, das wie folgt aussieht:

Disk quota 100 set for user DTI-Matt

Die Textprotokollierung wirft die Informationen weg, die wir ursprünglich über die Quelle des Ereignisses haben, und diese müssen rekonstruiert werden, wenn die Protokolle in der Regel mit immer ausgefeilteren Übereinstimmungsausdrücken gelesen werden.

Im Gegensatz dazu, wenn Sie die folgenden zwei Serilog- Ereignisse schreiben :

log.Debug("Disk quota {Quota} exceeded by user {Username}", 100, "DTI-Matt");
log.Debug("Disk quota {Quota} exceeded by user {Username}", 150, "nblumhardt");

Diese erzeugen eine ähnliche Textausgabe wie die log4net-Version, hinter den Kulissen wird die "Disk quota {Quota} exceeded by user {Username}" Nachrichtenvorlage jedoch von beiden Ereignissen übertragen.

Mit einer geeigneten Senke können Sie später Abfragen schreiben where MessageTemplate = 'Disk quota {Quota} exceeded by user {Username}'und genau die Ereignisse abrufen, bei denen das Datenträgerkontingent überschritten wurde.

Es ist nicht immer bequem , die gesamte Nachrichtenvorlage mit jedem Protokollereignis zu speichern, so dass einige Senken hash die Nachrichtenvorlage in einen numerischen EventTypeWert (zB 0x1234abcd), oder können Sie eine enricher in die Protokollierungs Pipeline in den dies selbst zu tun .

Es ist subtiler als der nächste Unterschied, aber bei großen Log-Volumes enorm leistungsfähig.

Strukturierte Daten

Unter Berücksichtigung der beiden Ereignisse zur Speicherplatznutzung ist es möglicherweise einfach genug, Textprotokolle zu verwenden, um nach einem bestimmten Benutzer mit abzufragen like 'Disk quota' and like 'DTI-Matt'.

Die Produktionsdiagnose ist jedoch nicht immer so einfach. Stellen Sie sich vor, es ist notwendig, Ereignisse zu finden, bei denen das Festplattenkontingent unter 125 MB lag?

Mit Serilog ist dies in den meisten Spülbecken mit einer Variante von:

Quota < 125

Die Erstellung einer solchen Abfrage aus einem regulären Ausdruck ist möglich, wird jedoch schnell müde und ist in der Regel ein Maß für den letzten Ausweg.

Fügen Sie nun einen Ereignistyp hinzu:

Quota < 125 and EventType = 0x1234abcd

Hier sehen Sie, wie diese Funktionen auf einfache Weise kombiniert werden, damit das Debuggen in der Produktion mit Protokollen als erstklassige Entwicklungsaktivität empfunden wird.

Ein weiterer Vorteil, der vielleicht nicht so einfach zu verhindern ist, aber nachdem das Debuggen in der Produktion aus dem Land der Regex-Hacker herausgenommen wurde, beginnen die Entwickler, Protokolle viel mehr zu bewerten und beim Schreiben mehr Sorgfalt und Überlegung walten zu lassen. Bessere Protokolle -> Anwendungen mit besserer Qualität -> Rundum mehr Glück.

Nicholas Blumhardt
quelle
4
Ich liebe diese Antwort. Sehr gut geschrieben und aus irgendeinem Grund kann ich nicht erklären, hält mich auf der Kante meines Sitzes.
Jokab
16

Wenn Sie Protokolle zur Verarbeitung sammeln, sei es zum Parsen in einer Datenbank und / oder zum späteren Durchsuchen der verarbeiteten Protokolle, wird durch die Verwendung der strukturierten Protokollierung ein Teil der Verarbeitung einfacher / effizienter. Der Parser kann die bekannte Struktur ( z. B. JSON, XML, ASN.1, was auch immer) ausnutzen und Zustandsmaschinen zum Parsen verwenden, im Gegensatz zu regulären Ausdrücken (deren Kompilierung und Ausführung rechenintensiv (relativ) sein kann). Das Parsen von Freiform-Text, wie er von Ihrem Kollegen vorgeschlagen wurde, verlässt sich in der Regel auf reguläre Ausdrücke und darauf , dass sich dieser Text nicht ändert . Dies kann das Parsen von Freiformtext sehr anfällig machen ( dh das Parsen ist eng an den genauen Text im Code gekoppelt).

Betrachten Sie auch den Such- / Nachschlagefall, zB :

SELECT text FROM logs WHERE text LIKE "Disk quota";

LIKEBedingungen erfordern Vergleiche mit jedem textZeilenwert; Auch dies ist relativ rechenintensiv, insbesondere wenn Platzhalter verwendet werden:

SELECT text FROM logs WHERE text LIKE "Disk %";

Bei der strukturierten Protokollierung sieht Ihre festplattenfehlerbezogene Protokollmeldung in JSON möglicherweise folgendermaßen aus:

{ "level": "DEBUG", "user": "username", "error_type": "disk", "text": "Disk quota ... exceeded by user ..." }

Die Felder dieser Art von Struktur können sehr einfach zB SQL-Tabellenspaltennamen zugeordnet werden, was wiederum bedeutet, dass die Suche spezifischer / granularer sein kann:

SELECT user, text FROM logs WHERE error_type = "disk";

Sie können Indizes für die Spalten platzieren, deren Werte voraussichtlich häufig durchsucht werden, sofern Sie LIKEfür diese Spaltenwerte keine Klauseln verwenden . Je mehr Sie Ihre Protokollnachricht in bestimmte Kategorien unterteilen können, desto gezielter können Sie nachschlagen. Zum Beispiel, zusätzlich zu dem error_typeFeld / der Spalte im obigen Beispiel, könnten Sie auch sein "error_category": "disk", "error_type": "quota"oder etwas Ähnliches machen.

Je mehr Struktur , die Sie in Ihren Log - Meldungen haben, desto mehr Ihre Analyse / Suchsysteme (wie zum Beispiel fluentd, elasticsearch, kibana) können die Vorteile dieser Struktur, und ihre Aufgaben mit größerer Geschwindigkeit und weniger CPU / Speicher.

Hoffe das hilft!

Castaglia
quelle
1
+1 Ich möchte hinzufügen, dass es nicht nur um Geschwindigkeit und Effizienz geht. Die Relevanz der Suchergebnisse ist bei Verwendung der strukturierten Protokollierung und damit der "strukturierten Abfragen" wesentlich höher. Ohne diese Suche nach Wörtern, die in verschiedenen Kontexten vorkommen, erhalten Sie Tonnen irrelevanter Treffer.
Marjan Venema
1
+1 von mir auch, ich denke das nagelt es. Unten wurde eine etwas andere Formulierung hinzugefügt, um auch den Fall von Ereignistypen zu erläutern.
Nicholas Blumhardt
8

Sie werden von der strukturierten Protokollierung nicht viel profitieren, wenn Ihre App einige hundert Protokollnachrichten pro Tag erstellt. Sie werden es definitiv tun, wenn Sie einige hundert Protokollnachrichten pro Sekunde haben, die von vielen verschiedenen bereitgestellten Apps stammen.

Im Zusammenhang damit eignet sich das Setup, bei dem Protokollnachrichten im ELK-Stapel abgelegt werden, auch für die Skalierung, bei der die Protokollierung in SQL zu einem Engpass wird.

Ich habe das Setup von "Basic Logging and Searching" mit SQL select .. likeund Regexps gesehen, die an ihre Grenzen gestoßen sind, wo sie auseinanderfallen - es gibt falsche Positive, Auslassungen, schrecklichen Filtercode mit bekannten Fehlern, die schwer zu pflegen sind und die niemand anfassen möchte. neue Protokollnachrichten, die nicht den Annahmen des Filters entsprechen, zögern, Protokollanweisungen im Code zu berühren, damit sie keine Berichte beschädigen usw.

Es entstehen verschiedene Softwarepakete, um dieses Problem besser zu lösen. Es gibt Serilog, ich habe gehört, dass das NLog-Team sich das ansieht , und wir haben StructuredLogging.Jsonfür Nlog geschrieben , und ich sehe auch, dass die neuen ASP.Net-Kernprotokollierungsabstraktionen "es Protokollierungsanbietern ermöglichen, ... strukturierte Protokollierung zu implementieren".

Ein Beispiel mit StructuredLogging. Sie melden sich bei einem NLog-Logger wie folgt an:

logger.ExtendedError("Order send failed", new { OrderId = 1234, RestaurantId = 4567 } );

Diese strukturierten Daten gehen an Kibana. Der Wert 1234wird im OrderIdFeld des Protokolleintrags gespeichert . Sie können dann mit der kibana-Abfragesyntax nach z. B. allen Protokolleinträgen suchen, bei denen @LogType:nlog AND Level:Error AND OrderId:1234.

Messageund OrderIdsind jetzt nur noch Felder, die nach Bedarf nach genauen oder ungenauen Übereinstimmungen durchsucht oder nach Anzahl aggregiert werden können. Das ist leistungsstark und flexibel.

Aus den Best Practices von StructuredLogging :

Die protokollierte Nachricht sollte jedes Mal dieselbe sein. Es sollte eine konstante Zeichenfolge sein, keine Zeichenfolge, die so formatiert ist, dass sie Datenwerte wie IDs oder Mengen enthält. Dann ist es einfach zu suchen.

Die protokollierte Nachricht sollte eindeutig sein, dh nicht mit der Nachricht identisch sein, die von einer unabhängigen Protokollanweisung erstellt wurde. Dann stimmt die Suche auch nicht mit anderen Dingen überein.

Anthony
quelle