jämföra Winston och Bunyan nod.js loggning

Låt oss prata om loggning, ska vi? Arnold här med en jätte logg känns som en lämplig introduktion till den här artikeln där vi ska prata om popular Node.js loggning ramar.

Om du skriver någon form av long living-applikation är detaljerad loggning avgörande för att upptäcka problem och felsökning. Utan loggar skulle du ha några sätt att berätta hur din ansökan beter sig, finns det fel, Hur är prestanda, gör det någonting alls eller faller det bara över alla andra förfrågningar när du inte tittar på det.

krav

låter identifiera några krav som vi kan använda för att ställa ramarna mot varandra. Några av dessa krav är ganska triviala, andra är inte så mycket.

  1. tidsstämpel varje loggrad. Den här är ganska självförklarande – du borde kunna berätta när varje loggpost inträffade.
  2. Loggningsformat bör lätt smältas av människor såväl som maskiner.
  3. möjliggör flera konfigurerbara destinationsströmmar. Du kan till exempel skriva spårningsloggar till en fil men när ett fel uppstår skriver du till samma fil, sedan till felfil och skickar ett e-postmeddelande samtidigt.

baserat på dessa krav (och popularitet) finns det två loggningsramar för Node.js värt att kolla in, särskilt:

  • Bunyan av Trent Mick.
  • Winston är en del av Flatiron framework och sponsras av nodejitstu.

konsol

innan vi kommer till Bunyan och Winston, låt oss titta på vår gamla vän console. Den mest rudimentära typen av loggning du kan göra är att användaconsole.log ochconsole.error metoder. Detta är bättre än ingenting men knappast den bästa lösningen. Console skriver till STDOUT respektive STDERR. Det finns en mycket intressant varning att veta när det gällerconsole metoder i Nod.js.

konsolfunktionerna är synkrona när destinationen är en terminal eller en fil (för att undvika förlorade meddelanden vid för tidig utgång) och asynkron när det är ett rör (för att undvika blockering under långa perioder).

det vill säga i följande exempel är stdout icke-blockerande medan stderr blockerar:

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

detta är i grunden en” rulla din egen ” loggningsmetod. Det är helt manuellt, du måste komma med ditt eget format och i princip hantera allt själv. Detta är tidskrävande, benäget för fel och du vill förmodligen fokusera på dina applikationsfunktioner istället. Med tanke på att det finns öppen källkodsloggningsbibliotek där ute som aktivt underhålls, är det inte värt ansträngningen om du försöker fokusera på att leverera funktioner.

Winston

en av de mest populära noden.js loggning ramar är Winston. Den är utformad för att vara ett enkelt och universellt loggbibliotek med stöd för flera transporter (en transport i Winstons värld är i huvudsak en lagringsenhet, t.ex. där dina loggar slutar lagras). Varje instans av en Winston logger kan ha flera transporter konfigurerade på olika loggningsnivåer.

Installation

npm install winston

användning

den mest grundläggande Winston-användningen består av att anropa standardinstansen som exporteras från modulen winston.

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

ovanstående är samma som:

båda exemplen kommer att producera följande utgång:

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

formatering

personligen är jag lite förbryllad av bristen på detaljer i standardformatet. Det finns ingen tidsstämpel, maskinnamn eller process-ID och utdataformatet är mildt lämpligt för maskinparsning. Med detta sagt kan du få all information själv med bara lite extra arbete.

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

producerar följande utdata, vilket är mer informativt, men fortfarande inte särskilt lämpligt för maskinparsning.

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

slutligen tillhandahåller logmetoden samma stränginterpoleringsmetoder somutil.format, till exempel:

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

transportörer

Winston kan konfigureras via konstruktörsalternativ eller exponerad metod som är mycket noggrant dokumenterade på GitHub-sidan. Det mesta av konfigurationen kretsar vanligtvis kring olika transporter. Out of the box Winston kommer med konsol-och filbaserade transporter och om du tittar på npmjs.org du kommer att se att det finns samhällsmoduler för i stort sett allt som kan tänkas, allt från MongoDB till kommersiella tredjepartsplattformar.

en av de mer anmärkningsvärda transportörerna enligt min mening är winston-irc av Nathan Zadoks som du kan använda för att logga fel på ditt lags IRC-kanal. Jag kan se detta komma till nytta.

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

flera Loggers

När din ansökan börjar växa, är chansen att du kommer att vilja ha flera loggers med olika konfigurationer där varje logger är ansvarig för en annan funktion område (eller kategori). Winston stöder det på två sätt: genom winston.loggers och instanser av winston.Container. Faktum är att winston.loggers bara är en fördefinierad instans av winston.Container:

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

Nu när dina loggers är konfigurerade kan du kräva Winston i någon fil i din ansökan och få tillgång till dessa förkonfigurerade loggers:

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

mer

detta är mest grundläggande Winston användning, men det finns en hel del andra funktioner, notably:

  • profilering
  • String interpolation
  • fråga och streaming
  • hantering exeptions

Bunyan

Illustration av Brendan Corris

Bunyan av Trent Mick är ett annat loggningsramverk som jag tycker bör övervägas. Bunyan tar en något annorlunda inställning till loggning än Winston gör sitt uppdrag att ge strukturerad, maskinläsbara loggar som förstklassiga medborgare. Som ett resultat är en loggpost från Bunyan en rad medJSON.stringify – utgång med några vanliga namn för nödvändiga och vanliga fält för en loggpost.

Installation

npm install bunyan

användning

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

som kommer att producera följande utgång:

som du kan se, Out of the box Bunyan är inte särskilt mänsklig vänlig, men de flesta moderna loggningssystem förstår JSON-format naturligt, vilket innebär att det finns lite att göra här för att mata loggarna någon annanstans för lagring och bearbetning. Som standard finns det en hel del metadata som ingår i varje meddelande, till exempel tidsstämpel, process-ID, värdnamn och Applikationsnamn.

naturligtvis finner vi människor inte detta mycket smältbara och för att ta itu med att det finns ett bunyan CLI-verktyg som tar in JSON via STDIN. Här är samma exempel som leds genom bunyan:

node example.js | bunyan

producerar följande utgång:

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

den största fördelen här är att du inte behöver konfigurera någonting för utvecklingsmiljö, allt du behöver göra är att röret till bunyan. Kassa GitHub-sidan för mer dokumentation om CLI-verktyget.

JSON

en av de viktigaste skillnaderna mellan Bunyan och Winston är att Bunyan fungerar riktigt bra när du vill logga komplexa sammanhang och objekt. Låt oss titta på den här raden och dess utgång från exemplet ovan:

Du kan se att {lang: 'fr'} slogs samman med huvudloggobjektet och au revoir blev msg. Nu bild något så här:

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

som producerar:

eller när den leds genom bunyan:

skönheten i detta tillvägagångssätt kommer att bli tydlig när du tittar på barnloggare.

Barnloggare

Bunyan har ett koncept med barnloggare, vilket gör det möjligt att specialisera en logger för en delkomponent i din ansökan, dvs. för att skapa en ny logger med ytterligare bundna fält som kommer att ingå i dess loggposter. En barnlogger skapas med log.child(...). Detta kommer otroligt praktiskt om du vill ha scoped loggers för olika komponenter i ditt system, förfrågningar eller helt enkelt funktionsanrop. Låt oss titta på någon kod.

Tänk dig att du vill bära begäran ID genom alla logglinjer för en given begäran så att du kan binda dem alla tillsammans.

req.log logger kommer alltid att hålla sitt sammanhang skickat till funktionen log.child() och slå samman den med alla efterföljande samtal, så utmatningen skulle se ut så här:

{"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

två problem uppstår när Bunyan försöker stränga hela objekt:

  1. cirkulära referenser. Winston är lite smartare här och upptäcker cirkulära referenser när de inträffar (men resultatutgången $ref=$ är inte särskilt användbar).
  2. oönskat brus. Det känns för mig att eftersom objekt är första klass i det är mycket lättare att komma in i en vana att bara dumpa allt i stocken.

För att hjälpa till att hantera båda har Bunyan ett koncept av serialiserare som i grunden är transformationsfunktioner som låter dig täcka ner vanligtvis passerade objekt till bara de fält som du är intresserad av:

nu försöker logga req objekt skulle bara inkludera de tre fälten som vi är intresserade av.

strömmar

strömmar i Bunyan är samma sak som transportörer i Winston – det är ett sätt att skicka dina loggar någon annanstans för visning och lagring. Bunyan använder ett skrivbart strömgränssnitt med några ytterligare attribut. En Bunyan logger-instans har en eller flera strömmar och anges med streams alternativ:

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

mer

här är några mer anmärkningsvärda saker att utforska i Bunyan:

  • Runtime log snooping via DTrace-stöd
  • loggpostfält

vilken ska du välja?

Winston och Bunyan är båda mycket mogna och etablerade loggningsramar och är mycket på nivå när det gäller funktioner. Winston har mycket samhällsstöd med olika loggmoduler. Bunyan gör det enkelt ur lådan för att tolka loggar men lämnar Konsumtionen upp användaren (i allmänhet syslog drain fungerar ganska bra här). Jag känner att allt kommer ner till preferens och hur lätt det är att integrera med din stack.

  • vad kommer till nästa Node release? Läs om åtta spännande nya Node v0.12-funktioner och hur man får ut det mesta av dem, från författarna själva.
  • redo att utveckla API: er i Node.js och få dem anslutna till dina data? Kolla in noden.js LoopBack API ramverk. Vi har gjort det enkelt att komma igång antingen lokalt eller på ditt favoritmoln, med en enkel npm-installation.
  • behöver du utbildning och certifiering för Node? Läs mer om både privata och öppna alternativ StrongLoop erbjuder.

Lämna ett svar

Din e-postadress kommer inte publiceras.