github.com/cloudcredo/cloudrocker@v0.0.0-20160108110610-1320f8cc2dfd/sample-apps/node/node_modules/logfmt/README.md (about) 1 # node-logfmt 2 3 [](https://travis-ci.org/csquared/node-logfmt) 4 5 6 "logfmt" is the name for a [key value logging convention](https://github.com/kr/logfmt) we've adopted at Heroku. 7 8 This library is for both converting lines in logfmt format to objects and 9 for logging objects to a stream in logfmt format. 10 11 It provides a logfmt parser, logfmt stringifier, a logging facility, 12 and both streaming and non-streaming body parsers for express and restify. 13 14 You should use this library if you're trying to write structured logs or 15 if you're consuming them (especially if you're writing a logplex drain). 16 17 ## install 18 19 npm install logfmt 20 21 # use 22 23 ## node.js 24 25 The `logfmt` module is a singleton that works directly from require. 26 27 ```javascript 28 var logfmt = require('logfmt'); 29 30 logfmt.stringify({foo: 'bar'}); 31 // 'foo=bar' 32 33 logfmt.parse('foo=bar'); 34 // {foo: 'bar'} 35 ``` 36 37 It is also a constructor function, so you can use `new logfmt` to create 38 a new `logfmt` that you can configure differently. 39 40 ```javascript 41 var logfmt2 = new logfmt; 42 43 // replace our stringify with JSON's 44 logfmt2.stringify = JSON.stringify 45 46 // now we log JSON! 47 logfmt2.log({foo: 'bar'}) 48 // {"foo":"bar"} 49 50 // and the original logfmt is untouched 51 logfmt.log({foo: 'bar'}) 52 // foo=bar 53 ``` 54 55 ## command line 56 57 ### logfmt 58 59 accepts lines on STDIN and converts them to json 60 61 62 > echo "foo=bar a=14 baz=\"hello kitty\" cool%story=bro f %^asdf" | logfmt 63 { "foo": "bar", "a": 14, "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true } 64 65 ### logfmt -r (reverse) 66 67 accepts JSON on STDIN and converts them to logfmt 68 69 > echo '{ "foo": "bar", "a": 14, "baz": "hello kitty", \ 70 "cool%story": "bro", "f": true, "%^asdf": true }' | logfmt -r 71 foo=bar a=14 baz="hello kitty" cool%story=bro f=true %^asdf=true 72 73 round trips for free! 74 75 > echo "foo=bar a=14 baz=\"hello kitty\" cool%story=bro f %^asdf" | logfmt | logfmt -r | logfmt 76 { "foo": "bar", "a": 14, "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true } 77 78 79 # API 80 81 ## stringifying 82 83 Serialize an object to logfmt format 84 85 ### `logfmt.stringify(object)` 86 87 Serializes a single object. 88 89 ```javascript 90 logfmt.stringify({foo: "bar", a: 14, baz: 'hello kitty'}) 91 //> 'foo=bar a=14 baz="hello kitty"' 92 ``` 93 94 ## parsing 95 96 Parse a line in logfmt format 97 98 ### `logfmt.parse(string)` 99 100 ```javascript 101 logfmt.parse("foo=bar a=14 baz=\"hello kitty\" cool%story=bro f %^asdf code=H12") 102 //> { "foo": "bar", "a": '14', "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true, "code" : "H12" } 103 ``` 104 105 The only conversions are from the strings `true` and `false` to their proper boolean counterparts. 106 107 We cannot arbitrarily convert numbers because that will drop precision for numbers that require more than 32 bits to represent them. 108 109 110 ## Streaming 111 112 Put this in your pipe and smoke it. 113 114 ### `logfmt.streamParser()` 115 116 Creates a streaming parser that will automatically split and parse incoming lines and 117 emit javascript objects. 118 119 Stream in from STDIN 120 121 ```javascript 122 process.stdin.pipe(logfmt.streamParser()) 123 ``` 124 125 Or pipe from an HTTP request 126 127 ```javascript 128 req.pipe(logfmt.streamParser()) 129 ``` 130 131 ### `logfmt.streamStringify([options])` 132 133 Pipe objects into the stream and it will write logfmt. 134 You can customize the delimiter via the `options` object, which 135 defaults to `\n` (newlines). 136 137 ```javascript 138 var parseJSON = function(line) { 139 if(!line) return; 140 this.queue(JSON.parse(line.trim())) 141 } 142 143 process.stdin 144 .pipe(split()) 145 .pipe(through(parseJSON)) 146 .pipe(logfmt.streamStringify()) 147 .pipe(process.stdout) 148 ``` 149 150 #### Example 151 152 153 Example command line of parsing logfmt and echoing objects to STDOUT: 154 155 ```javascript 156 var logfmt = require('logfmt'); 157 var through = require('through'); 158 159 process.stdin 160 .pipe(logfmt.streamParser()) 161 .pipe(through(function(object){ 162 console.log(object); 163 })) 164 ``` 165 166 Example HTTP request parsing logfmt and echoing objects to STDOUT: 167 168 ```javascript 169 var http = require('http'); 170 var logfmt = require('logfmt'); 171 var through = require('through'); 172 173 http.createServer(function (req, res) { 174 req.pipe(logfmt.streamParser()) 175 .pipe(through(function(object){ 176 console.log(object); 177 })) 178 179 res.writeHead(200, {'Content-Type': 'text/plain'}); 180 res.end('OK'); 181 }).listen(3000); 182 ``` 183 184 ## express/restify parsing middleware 185 186 ```javascript 187 // streaming 188 app.use(logfmt.bodyParserStream()); 189 // buffering 190 app.use(logfmt.bodyParser()); 191 ``` 192 193 #### `logfmt.bodyParserStream([opts])` 194 195 Valid Options: 196 197 - `contentType`: defaults to `application/logplex-1` 198 199 If you use the `logfmt.bodyParserStream()` for a body parser, 200 you will have a `req.body` that is a readable stream. 201 202 Pipes FTW: 203 204 ```javascript 205 var app = require('express')(); 206 var http = require('http'); 207 var through = require('through'); 208 var logfmt = require('logfmt'); 209 210 app.use(logfmt.bodyParserStream()); 211 212 app.post('/logs', function(req, res){ 213 if(!req.body) return res.send('OK'); 214 215 req.body.pipe(through(function(line){ 216 console.dir(line); 217 })) 218 219 res.send('OK'); 220 }) 221 222 http.createServer(app).listen(3000); 223 ``` 224 225 Or you can just use the `readable` event: 226 227 ```javascript 228 var app = require('express')(); 229 var http = require('http'); 230 var logfmt = require('logfmt'); 231 232 app.use(logfmt.bodyParserStream()); 233 234 // req.body is now a Readable Stream 235 app.post('/logs', function(req, res){ 236 req.body.on('readable', function(){ 237 var parsedLine = req.body.read(); 238 if(parsedLine) console.log(parsedLine); 239 else res.send('OK'); 240 }) 241 }) 242 243 http.createServer(app).listen(3000); 244 ``` 245 246 ### Non-Streaming 247 248 #### `logfmt.bodyParser([opts])` 249 250 Valid Options: 251 252 - `contentType`: defaults to `application/logplex-1` 253 254 If you use the `logfmt.bodyParser()` for a body parser, 255 you will have a `req.body` that is an array of objects. 256 257 ```javascript 258 var logfmt = require('logfmt'); 259 260 app.use(logfmt.bodyParser()); 261 262 // req.body is now an array of objects 263 app.post('/logs', function(req, res){ 264 console.log('BODY: ' + JSON.stringify(req.body)); 265 req.body.forEach(function(data){ 266 console.log(data); 267 }); 268 res.send('OK'); 269 }) 270 271 http.createServer(app).listen(3000); 272 ``` 273 274 test it: 275 276 ```bash 277 curl -X POST --header 'Content-Type: application/logplex-1' -d "foo=bar a=14 baz=\"hello kitty\" cool%story=bro f %^asdf" http://localhost:3000/logs 278 ``` 279 280 ## logging 281 282 Log an object to `logfmt.stream` (defaults to STDOUT) 283 284 Uses the `logfmt.stringify` function to write the result to `logfmt.stream` 285 286 ```javascript 287 logfmt.log({foo: "bar", a: 14, baz: 'hello kitty'}) 288 //=> foo=bar a=14 baz="hello kitty" 289 //> undefined 290 ``` 291 292 ### `logfmt.log(object, [stream])` 293 294 Defaults to logging to `process.stdout` 295 296 ```javascript 297 logfmt.log({ "foo": "bar", "a": 14, baz: 'hello kitty'}) 298 //=> foo=bar a=14 baz="hello kitty" 299 ``` 300 301 #### customizing logging location 302 303 `logfmt.log()` Accepts as 2nd argument anything that responds to `write(string)` 304 ```javascript 305 var logfmt = require('logfmt'); 306 logfmt.log({ "foo": "bar", "a": 14, baz: 'hello kitty'}, process.stderr) 307 //=> foo=bar a=14 baz="hello kitty" 308 ``` 309 310 Overwrite the default global location by setting `logfmt.stream` 311 ```javascript 312 var logfmt = require('logfmt'); 313 logfmt.stream = process.stderr 314 315 logfmt.log({ "foo": "bar", "a": 14, baz: 'hello kitty'}) 316 //=> foo=bar a=14 baz="hello kitty" 317 ``` 318 319 You can have multiple, isolated logfmts by using `new`. 320 321 ```javascript 322 var logfmt = require('logfmt'); 323 var errorLogger = new logfmt; 324 errorLogger.stream = process.stderr 325 326 logfmt.log({hello: 'stdout'}); 327 //=> hello=stdout 328 329 errorLogger.log({hello: 'stderr'}); 330 //=> hello=stderr 331 ``` 332 333 ### `logfmt.namespace(object)` 334 335 Returns a new `logfmt` with object's data included in every `log` call. 336 337 ```javascript 338 var logfmt = require('logfmt').namespace({app: 'logfmt'}); 339 340 logfmt.log({ "foo": "bar", "a": 14, baz: 'hello kitty'}) 341 //=> app=logfmt foo=bar a=14 baz="hello kitty" 342 343 logfmt.log({}) 344 //=> app=logfmt 345 346 logfmt.log({hello: 'world'}) 347 //=> app=logfmt hello=world 348 ``` 349 350 ### `logfmt.time([label])` 351 352 Log how long something takes. 353 Returns a new `logfmt` with elapsed milliseconds included in every `log` call. 354 355 - `label`: optional name for the milliseconds key. defaults to: `elapsed=<milliseconds>ms` 356 357 ```javascript 358 var timer = logfmt.time(); 359 timer.log(); 360 //=> elapsed=1ms 361 ``` 362 363 String `label` changes the key to `<string>=<milliseconds>ms` 364 365 ```javascript 366 var timer = logfmt.time('time'); 367 timer.log(); 368 //=> time=1ms 369 timer.log(); 370 //=> time=2ms 371 ``` 372 373 If you'd like to include data, just chain a call to namespace. 374 375 ```javascript 376 var timer = logfmt.time('time').namespace({foo: 'bar'}); 377 timer.log(); 378 //=> time=1ms foo=bar 379 timer.log(); 380 //=> time=2ms foo=bar 381 ``` 382 383 ### `logfmt.error(error)` 384 385 Accepts a Javascript `Error` object and converts it to logfmt format. 386 387 It will print up to `logfmt.maxErrorLines` lines. 388 389 ```javascript 390 var logfmt = require('logfmt'); 391 logfmt.error(new Error('test error')); 392 //=> at=error id=12345 message="test error" 393 //=> at=error id=12345 line=0 trace="Error: test error" 394 //=> ... 395 ``` 396 397 ## express/restify logging middleware 398 399 ```javascript 400 app.use(logfmt.requestLogger()); 401 //=> ip=127.0.0.1 time=2013-08-05T20:50:19.216Z method=POST path=/logs status=200 content_length=337 content_type=application/logplex-1 elapsed=4ms 402 ``` 403 404 #### `logfmt.requestLogger([options], [formatter(req, res)])` 405 406 If no formatter is supplied it will default to `logfmt.requestLogger.commonFormatter` which is based 407 on having similiar fields to the Apache Common Log format. 408 409 Valid Options: 410 411 - `immediate`: log before call to `next()` (ie: before the request finishes) 412 - `elapsed`: renames the `elapsed` key to a key of your choice when in 413 non-immediate mode 414 415 Defaults to `immediate: true` and `elapsed: 'elapsed'` 416 417 ```javascript 418 app.use(logfmt.requestLogger({immediate: true}, function(req, res){ 419 return { 420 method: req.method 421 } 422 })); 423 //=> method=POST 424 ``` 425 426 ```javascript 427 app.use(logfmt.requestLogger({elapsed: 'request.time'}, function(req, res){ 428 return { 429 "request.method": req.method 430 } 431 })); 432 //=> request.method=POST request.time=12ms 433 ``` 434 435 ##### `formatter(req, res)` 436 437 A formatter takes the request and response and returns a JSON object for `logfmt.log` 438 439 ```javascript 440 app.use(logfmt.requestLogger(function(req, res){ 441 return { 442 method: req.method 443 } 444 })); 445 //=> method=POST elapsed=4ms 446 ``` 447 448 It's always possible to piggyback on top of the `commonFormatter` 449 450 ```javascript 451 app.use(logfmt.requestLogger(function(req, res){ 452 var data = logfmt.requestLogger.commonFormatter(req, res) 453 return { 454 ip: data.ip, 455 time: data.time, 456 foo: 'bar' 457 }; 458 })); 459 //=> ip=127.0.0.1 time=2013-08-05T20:50:19.216Z foo=bar elapsed=4ms 460 ``` 461 462 # Development 463 464 Pull Requests welcome. 465 466 ## Tests 467 468 > npm test 469 470 # License 471 472 MIT