het vergelijken van Winston en Bunyan Node.js Logging

laten we praten over loggen, zullen we? Arnold hier draagt een gigantische log voelt als een passende intro van dit artikel waarin we gaan praten over populaire Node.js logging frameworks.

Als u enige vorm van lang leven applicatie aan het schrijven bent, is gedetailleerde logging van het grootste belang om problemen te spotten en debuggen. Zonder logs zou je weinig manieren hebben om te vertellen hoe je applicatie zich gedraagt, zijn er fouten, hoe de prestaties eruit zien, doet het iets of valt het gewoon over elk ander verzoek als je er niet naar kijkt.

vereisten

laten we een paar vereisten identificeren die we kunnen gebruiken om de frameworks tegen elkaar te plaatsen. Sommige van deze eisen zijn vrij triviaal, anderen zijn niet zo veel.

  1. tijdstempel op elke logregel. Deze is vrij zelfverklarend – je zou in staat moeten zijn om te zien wanneer elke log vermelding zich heeft voorgedaan.
  2. het Logboekformaat moet zowel door mensen als door machines goed verteerbaar zijn.
  3. staat meerdere configureerbare doelstreams toe. U kunt bijvoorbeeld trace logs naar één bestand schrijven, maar wanneer een fout wordt aangetroffen, schrijft u naar hetzelfde bestand, vervolgens naar het foutbestand en verzendt u tegelijkertijd een e-mail.

op basis van deze vereisten (en populariteit) zijn er twee logging frameworks voor Node.js de moeite waard, in het bijzonder:

  • Bunyan door Trent Mick.Winston maakt deel uit van het Flatiron framework en wordt gesponsord door nodejitstu.

console

voordat we bij Bunyan en Winston komen, laten we eens kijken naar onze oude vriend console. Het meest rudimentaire type logging dat je zou kunnen doen is het gebruik vanconsole.log enconsole.error methoden. Dit is beter dan niets, maar nauwelijks de beste oplossing. Console schrijft naar respectievelijk STDOUT en STDERR. Er is een zeer interessant voorbehoud om te weten als het gaat om console methoden in Node.js.

De consolefuncties zijn synchroon wanneer de bestemming een terminal of een bestand is (om verloren berichten te voorkomen in geval van voortijdig afsluiten) en asynchroon wanneer het een pipe is (om blokkering voor lange tijd te voorkomen).

dat wil zeggen dat in het volgende voorbeeld stdout niet blokkeert terwijl stderr blokkeert:

$ node script.js 2> error.log | tee info.log

Dit is in principe een “roll your own” logging aanpak. Het is volledig handmatig, je moet komen met uw eigen formaat en in principe alles zelf beheren. Dit is tijdrovend, vatbaar voor fouten en u wilt zich waarschijnlijk richten op uw applicatie-functies in plaats daarvan. Gezien het feit dat er open source logging bibliotheken die er zijn die actief worden onderhouden, Dit is niet de moeite waard als je probeert te concentreren op het leveren van functies.

Winston

een van de meest populaire knooppunten.js logging frameworks is Winston. Het is ontworpen om een eenvoudige en universele logging bibliotheek met ondersteuning voor meerdere transporten (een transport in Winston ‘ s wereld is in wezen een opslagapparaat, bijvoorbeeld waar uw logs uiteindelijk worden opgeslagen). Elke instantie van een Winston logger kan meerdere transporten geconfigureerd op verschillende logging niveaus.

installatie

npm install winston

gebruik

het meest basale gebruik van Winston bestaat uit het aanroepen van de standaard instantie die wordt geëxporteerd vanuit de winstonmodule.

var winston = require('winston');winston.log('info', 'Hello distributed log files!');winston.info('Hello again distributed logs');

het bovenstaande is hetzelfde als:

beide voorbeelden produceren de volgende uitvoer:

info: Hello distributed log files!info: Hello again distributed logs

opmaak

persoonlijk ik ben een beetje verbaasd door het gebrek aan details in de standaard Formatter. Er is geen tijdstempel, machine naam of proces-ID en de output formaat is mild geschikt voor machine parsing. Dat gezegd hebbende, kunt u alle informatie uit jezelf met slechts een beetje extra werk.

winston.info('Hello world!', {timestamp: Date.now(), pid: process.pid});

produceert de volgende uitvoer, die informeler is, maar nog steeds niet erg geschikt voor het ontleden van machines.

info: Hello world! timestamp=1402286804314, pid=80481

de log methode biedt dezelfde string interpolatie-methoden zoals util.format, bijvoorbeeld:

winston.log('info', 'test message %d', 123);

Vervoerders

Winston kan worden geconfigureerd via de constructor opties of blootgesteld methode die zeer grondig gedocumenteerd op de GitHub pagina. Het grootste deel van de configuratie draait meestal om verschillende transporten. Out of the box Winston wordt geleverd met console en bestand gebaseerde transporten en als je een kijkje op npmjs.org u zult zien dat er community modules voor vrijwel alles denkbaar, variërend van MongoDB tot commerciële platforms van derden.

een van de meest opvallende transporters naar mijn mening is winston-irc van Nathan Zadoks die je kunt gebruiken om fouten in te loggen op het IRC-kanaal van je team. Ik zie dit van pas komen.

winston.add(require('winston-irc'), { host: 'irc.somewhere.net', nick: 'logger', pass: 'hunter2', channels: { '#logs': true, 'sysadmin': }});

meerdere Loggers

zodra uw toepassing begint te groeien, is de kans groot dat u meerdere loggers met verschillende configuraties wilt hebben waarbij elke logger verantwoordelijk is voor een ander functiegebied (of categorie). Winston ondersteunt dat op twee manieren: door winston.loggers en instanties van winston.Container. In feite is winston.loggers slechts een vooraf gedefinieerde instantie van winston.Container:

winston.loggers.add('category1', {console: { ... }, file: { ... }});winston.loggers.add('category2', {irc: { ... }, file: { ... }});

nu uw loggers zijn geconfigureerd, kunt u Winston in elk bestand in uw toepassing nodig hebben en toegang krijgen tot deze vooraf geconfigureerde loggers:

var category1 = winston.loggers.get('category1');category1.info('logging from your IoC container-based logger');

meer

Dit is het meest basale gebruik van Winston, maar er zijn nogal wat andere functies, met name:

  • profilering
  • String interpolatie
  • opvragen en streamen
  • Handling exeptions

Bunyan

Illustratie door Brendan Corris

Bunyan door Trent Mick is een ander logboekraamwerk dat naar mijn mening moet worden overwogen. Bunyan neemt een iets andere benadering van logging dan Winston het maken van haar missie om gestructureerde, machine leesbare logs als eerste klas burgers. Als gevolg hiervan is een log record van Bunyan één regel van JSON.stringify uitvoer met enkele algemene namen voor de vereiste en gemeenschappelijke velden voor een log record.

installatie

npm install bunyan

gebruik

var bunyan = require('bunyan');var log = bunyan.createLogger({name: 'myapp'});log.info('hi');log.warn({lang: 'fr'}, 'au revoir');

die de volgende uitvoer zal produceren:

box Bunyan is niet erg mensvriendelijk, maar de meeste moderne logging systemen begrijpen JSON-formaat native, wat betekent dat er weinig te doen is hier om de logs elders te voeden voor opslag en verwerking. Standaard is er nogal wat metagegevens opgenomen bij elk bericht, zoals tijdstempel, proces-ID, hostnaam en naam van de toepassing.

natuurlijk vinden wij mensen dit niet erg verteerbaar en om aan te pakken is er een bunyan CLI tool die JSON via STDIN opneemt. Hier is hetzelfde voorbeeld dat door bunyan:

node example.js | bunyan

produceert de volgende uitvoer:

 INFO: myapp/13372 on pwony-2: hi WARN: myapp/13372 on pwony-2: au revoir (lang=fr)

het belangrijkste voordeel hier is dat u niets opnieuw hoeft te configureren voor de ontwikkelomgeving, het enige wat u hoeft te doen is pipe naar bunyan. Bekijk de GitHub pagina voor meer documentatie over de CLI tool.

JSON

een van de belangrijkste verschillen tussen Bunyan en Winston is dat Bunyan echt goed werkt wanneer je complexe contexten en objecten wilt loggen. Laten we eens kijken naar deze lijn en de uitvoer van het bovenstaande voorbeeld:

u kunt zien dat {lang: 'fr'} werd samengevoegd met het hoofdlogobject en au revoir werd msg. Stel je nu iets als dit voor:

log.info(user, 'registered');log.info({user: user}, 'registered');

welke produceert:

of wanneer doorgesluisd bunyan:

De schoonheid van deze aanpak zal duidelijk worden als je naar child loggers kijkt.

Child Loggers

Bunyan heeft een concept van child loggers, wat het mogelijk maakt om een logger te specialiseren voor een subcomponent van uw toepassing, d.w.z. een nieuwe logger maken met extra gebonden velden die worden opgenomen in de logrecords. Een dochterlogger wordt aangemaakt met log.child(...). Dit komt in ongelooflijk handig als u wilt hebben scoped loggers voor verschillende componenten in uw systeem, Verzoeken, of gewoon functie oproepen. Laten we eens wat code bekijken.

stel je voor dat je verzoek-ID door alle logregels voor een bepaald verzoek wilt laten lopen, zodat je ze allemaal aan elkaar kunt koppelen.

de req.log logger zal altijd zijn context doorgeven aan de log.child() functie en samenvoegen met alle volgende aanroepen, zodat de uitvoer er ongeveer zo uit zou zien:

{"name":"myapp","hostname":"pwony-2","pid":14837,"level":30,"reqId":"XXXX-XX-XXXX","user":"[email protected]","time":"2014-05-26T18:27:43.530Z","v":0}

Serializers

twee problemen doen zich voor wanneer Bunyan gehele objecten probeert te stringifyen:

  1. cirkelreferenties. Winston is hier een beetje slimmer en detecteert cirkelreferenties wanneer ze voorkomen (echter de resultaatuitvoer $ref=$ is niet erg nuttig).
  2. ongewenste ruis. Het voelt voor mij dat omdat objecten eersteklas zijn, het veel gemakkelijker is om de gewoonte te krijgen om alles gewoon in het logboek te dumpen.

om met beide zaken om te gaan, heeft Bunyan een concept van serializer dat in principe transformatiefuncties zijn die je toelaten om objecten te benaderen die gewoonlijk worden doorgegeven aan alleen de velden waarin je geïnteresseerd bent:

Probeer nu req object zou alleen de drie velden bevatten waarin we geïnteresseerd zijn.

Streams

Streams in Bunyan zijn hetzelfde als transporters in Winston – het is een manier om uw logs elders te sturen voor weergave-en opslagdoeleinden. Bunyan gebruikt een beschrijfbare Stream interface met een aantal extra attributen. Een Bunyan logger instantie heeft een of meer streams en zijn opgegeven met de streams optie:

var log = bunyan.createLogger({ name: "foo", streams: });

meer

Hier zijn nog een paar opmerkelijke dingen om te verkennen in Bunyan:

  • runtime log snooping via Dtrace ondersteuning
  • Log Record velden

welke te kiezen?

Winston en Bunyan zijn beide zeer volwassen en gevestigde logging frameworks en zijn zeer vergelijkbaar in termen van functies. Winston heeft veel steun van de Gemeenschap met verschillende logging modules. Bunyan maakt het gemakkelijk uit de doos om logs te ontleden, maar laat de consumptie van de gebruiker (over het algemeen syslog drain werkt vrij goed hier). Ik voel dat het allemaal komt neer op de voorkeur en hoe gemakkelijk het is om te integreren met uw stack.

  • Wat komt er naar de volgende Node release? Lees over acht spannende nieuwe Node v0. 12 Functies en hoe u het meeste van hen te maken, van de auteurs zelf.
  • klaar om API ‘ s te ontwikkelen in Node.js en krijgen ze verbonden met uw gegevens? Kijk eens naar het knooppunt.js LoopBack API framework. We hebben het gemakkelijk gemaakt om lokaal of op uw favoriete cloud aan de slag te gaan, met een eenvoudige NPM-installatie.
  • opleiding en certificering nodig voor knooppunt? Meer informatie over zowel de private als open opties StrongLoop biedt.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.