@deboxsoft/logger

logger for koa

Usage no npm install needed!

<script type="module">
  import deboxsoftLogger from 'https://cdn.skypack.dev/@deboxsoft/logger';
</script>

README

debox-logger

Add logger to your koa2 server in 3 lines

Usage

Installation

npm i --save debox-logger

Quick Start

const { logger } = require('debox-logger');
app.use(logger());

request log will look like

{
  "req": {
    "headers": {
      "host": "localhost:3000",
      "connection": "keep-alive",
      "upgrade-insecure-requests": "1",
      "user-agent":
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
      "accept":
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
      "dnt": "1",
      "accept-encoding": "gzip, deflate, sdch, br",
      "accept-language":
        "zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,de;q=0.2,ja;q=0.2,it;q=0.2"
    },
    "url": "/hello",
    "method": "GET",
    "href": "http://localhost:3000/hello",
    "query": {}
  },
  "started_at": 1494554053492,
  "res": {
    "headers": {
      "content-type": "application/json; charset=utf-8",
      "content-length": "16"
    },
    "status": 200
  },
  "duration": 8,
  "level": "info",
  "message": "HTTP GET /hello"
}

Configuration

Each parameter has a default value, and you can customize your logger by changing the configuration

app.use(
  logger({
    transports: new winston.transports.Console({ json: true, stringify: true }),
    level: 'info',
    reqKeys: [
      'headers',
      'url',
      'method',
      'httpVersion',
      'href',
      'query',
      'length',
    ],
    reqSelect: [],
    reqUnselect: ['headers.cookie'],
    resKeys: ['headers', 'status'],
    resSelect: [],
    resUnselect: [],
  })
);

Many configuration explain can be found in logger

Examples

Do not record any request fields

app.use(
  logger({
    reqKeys: [],
  })
);

The req object will be empty

{
  "req": {},
  "started_at": 1494486039864,
  "res": {
    "headers": {
      "content-type": "text/plain; charset=utf-8",
      "content-length": "8"
    },
    "status": 200
  },
  "duration": 26,
  "level": "info",
  "message": "HTTP GET /"
}

Do not record any response fields

app.use(
  logger({
    resKeys: [],
  })
);

The res object will be empty

{
  "req": {
    "headers": {
      "host": "127.0.0.1:59534",
      "accept-encoding": "gzip, deflate",
      "user-agent": "node-superagent/3.5.2",
      "connection": "close"
    },
    "url": "/",
    "method": "GET",
    "href": "http://127.0.0.1:59534/",
    "query": {}
  },
  "started_at": 1494486039864,
  "res": {},
  "duration": 26,
  "level": "info",
  "message": "HTTP GET /"
}

Do not record UA

app.use(
  logger({
    reqUnselect: ['headers.cookies', 'headers.user-agent'],
  })
);

The UA of request will be ignored

{
  "req": {
    "headers": {
      "host": "127.0.0.1:59534",
      "accept-encoding": "gzip, deflate",
      "connection": "close"
    },
    "url": "/",
    "method": "GET",
    "href": "http://127.0.0.1:59534/",
    "query": {}
  },
  "started_at": 1494486039864,
  "res": {
    "headers": {
      "content-type": "text/plain; charset=utf-8",
      "content-length": "8"
    },
    "status": 200
  },
  "duration": 26,
  "level": "info",
  "message": "HTTP GET /"
}

Record a response body filed

app.use(
  logger({
    resSelect: ['body.success'],
  })
);

The success field on body will be recorded

{
  "req": {
    "headers": {
      "host": "127.0.0.1:59534",
      "accept-encoding": "gzip, deflate",
      "connection": "close"
    },
    "url": "/",
    "method": "GET",
    "href": "http://127.0.0.1:59534/",
    "query": {}
  },
  "started_at": 1494486039864,
  "res": {
    "headers": {
      "content-type": "text/plain; charset=utf-8",
      "content-length": "8"
    },
    "status": 200,
    "body": {
      // Any possible value given by the server
      "success": false
    }
  },
  "duration": 26,
  "level": "info",
  "message": "HTTP GET /"
}

Simple Benchmark

At node 8.2

middleware x 90,281 ops/sec ±7.89% (13 runs sampled)

At node 8.4

middleware x 112,011 ops/sec ±10.26% (18 runs sampled)

Schema Stringify

With fast-json-stringify support, default transport logger is much faster

total ops/sec { jsonstringify: 73544 }
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
total ops/sec { schemastringify: 90223 }
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

schemastringify is 1.23x faster then jsonstringify in this case

Math.floor vs parseInt

JSPerf link in HERE

Testing in Chrome 70.0.3505 / Mac OS X 10.13.5

parseInt(401 / 100, 10) { 160,092,130 Ops/sec }
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
Math.floor(401 / 100) { 810,032,369 Ops/sec }
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

Math.floor is 5.06x faster then parseInt in this case

JSDoc

clone

clone object

Parameters

  • obj any

keysRecorder

keysRecorder use ldoash pick, get and set to collect data from given target object

Parameters

  • payload Object input arguments (optional, default {})
    • payload.defaults Array<string>? default keys will be collected
    • payload.selects Array<string>? keys will be collected as additional part
    • payload.unselects Array<string>? keys that will be ignored at last

Examples

// without payload
const recorder = keysRecorder();
recorder(); // {}
recorder({ foo: 1, bar: 2, foobar: { a: 3, b: 4 } }); // {}

// with defaults
const recorder = keysRecorder({ defaults: ['foo'] });
recorder(); // {}
recorder({ foo: 1, bar: 2, foobar: { a: 3, b: 4 } }); // { foo: 1 }

// with defaults and selects
const recorder = keysRecorder({ defaults: ['foo'], selects: ['foobar'] });
recorder(); // {}
recorder({
  foo: 1,
  bar: 2,
  foobar: { a: 3, b: 4 },
}); // { foo: 1, foobar: { a: 3, b: 4 } }

// with defaults and unselects
const recorder = keysRecorder({
  defaults: ['foobar'],
  unselects: ['foobar.a'],
});
recorder(); // {}
recorder({
  foo: 1,
  bar: 2,
  foobar: { a: 3, b: 4 },
}); // { foobar: { a: 3 } }

// with defaults and selects and unselects
const recorder = keysRecorder({
  defaults: ['foo'],
  selects: ['foobar'],
  unselects: ['foobar.b'],
});
recorder(); // {}
recorder({
  foo: 1,
  bar: 2,
  foobar: { a: 3, b: 4 },
}); // { foo: 1, foobar: { a: 3 } }

Returns function closure function, setting by given payload

logger

logger middleware for koa2 use winston

Parameters

  • payload object input arguments (optional, default {})
    • payload.transports Array<object> customize transports (optional, default [newFastJsonConsole({stringify})])
    • payload.level string default log level of logger (optional, default 'info')
    • payload.reqKeys string default request fields to be logged (optional, default ['headers','url','method', 'httpVersion','href','query','length'])
    • payload.reqSelect string additional request fields to be logged (optional, default [])
    • payload.reqUnselect string request field will be removed from the log (optional, default ['headers.cookie'])
    • payload.resKeys string default response fields to be logged (optional, default ['headers','status'])
    • payload.resSelect string additional response fields to be logged (optional, default [])
    • payload.resUnselect string response field will be removed from the log (optional, default [])
    • payload.logger string? customize winston logger
    • payload.msg string customize log msg (optional, default HTTP%s%s)

Examples

const { logger } = require('debox-logger');
app.use(logger());
// request logger look like down here
// {
//   "req": {
//     "headers": {
//       "host": "127.0.0.1:59534",
//       "accept-encoding": "gzip, deflate",
//       "user-agent": "node-superagent/3.5.2",
//       "connection": "close"
//     },
//     "url": "/",
//     "method": "GET",
//     "href": "http://127.0.0.1:59534/",
//     "query": {}
//   },
//   "started_at": 1494486039864,
//   "res": {
//     "headers": {
//       "content-type": "text/plain; charset=utf-8",
//       "content-length": "8"
//     },
//     "status": 200
//   },
//   "duration": 26,
//   "level": "info",
//   "message": "HTTP GET /"
// }

Returns function logger middleware