GithubHelp home page GithubHelp logo

bunyan-logger's Introduction

bunyan-logger

Update: Koa team member @niftylettuce released a logging package alternative at https://cabinjs.com!

NOTE: that you're reading the README of the version which targets Koa v2.x, if you want to read about the old 1.X version, switch to Tag 1.3.0.

Flexible log context and request logging middleware for koa using bunyan.

Inspired by koa-bunyan, koa-json-logger, bunyan-request, and others.

Build Status Coverage Status npm

A primary goal of this module is to be as flexible as possible, while remaining relatively lightweight, leaving advanced functionality and customization the app.

const koa = require('koa');
const koaBunyanLogger = require('koa-bunyan-logger');

const app = koa();
app.use(koaBunyanLogger());

app.use(function (ctx, next) {
  ctx.log.info('Got a request from %s for %s', ctx.request.ip, ctx.path);
  return next();
});

app.listen(8000);

Server:

node examples/simple.js | ./node_modules/.bin/bunyan -o short`

Client:

curl http://localhost:8000/

Server output:

07:50:14.014Z  INFO koa: Got a request from ::1 for /

Request logging

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());
app.use(koaBunyanLogger.requestLogger());

Server:

node examples/requests.js | ./node_modules/.bin/bunyan -o short

Client:

curl -H "X-Request-Id: 1234" http://localhost:8000/

Server output:

20:19:24.526Z  INFO koa:   --> GET / (req_id=1234)
    GET / HTTP/1.1
    --
    req.header: {
      "user-agent": "curl/7.30.0",
      "host": "localhost:8000",
      "accept": "*/*",
      "x-request-id": "1234"
    }
20:19:24.527Z  INFO koa:   <-- GET / 1ms (req_id=1234, duration=1, res.status=200, res.message=OK)
    GET / HTTP/1.1
    --
    x-powered-by: koa
    content-type: text/plain; charset=utf-8
    content-length: 11
    --
    req.header: {
      "user-agent": "curl/7.30.0",
      "host": "localhost:8000",
      "accept": "*/*",
      "x-request-id": "1234"
    }

Ignoring specific path from logging

It is possible to skip logs from some endpoints with ignorePath option.

app.use(koaBunyanLogger.requestLogger({ ignorePath: ['/ping'] }))

Suppressing default error stack traces

To ensure that stack traces from request handling don't get logged in their raw non-JSON forms, you can disable the app's default error handler:

app.on('error', function () {});

API Reference

koaBunyanLogger(logger)

Parameters:

  • logger: bunyan logger instance or an object to pass to bunyan.createLogger()

Examples

Use an existing logger:

const bunyan = require('bunyan');
const koaBunyanLogger = require('koa-bunyan-logger');

const appLogger = bunyan.createLogger({
  name: 'myapp',
  level: 'debug',
  serializers: bunyan.stdSerializers
});

app.use(koaBunyanLogger(appLogger));

Shortcut to create a new logger:

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger({
  name: 'myapp',
  level: 'debug'
}));

koaBunyanLogger.requestLogger(opts)

Options:

  • durationField: Name of field to store request duration in ms

  • levelFn: Function which will be called with (status, err) and should return the name of a log level to be used for the response log entry. The default function will log status 400-499 as warn, 500+ as error, and all other responses as info.

  • updateLogFields: Function which will be called with a single argument, an object containing the fields (req, res, err) to be logged with the request and response message.

    The function has the opportunity to add or remove fields from the object, or return a different object to replace the default set of fields. The function will be called using the koa 'this' context, once for the request and again for the response.

  • updateRequestLogFields: Function which will be called with a request fields object when logging a request, after processing updateLogFields.

  • updateResponseLogFields: Function which will be called with a response fields object when logging a response, after processing updateLogFields. It also receives a second argument, err, if an error was thrown.

  • formatRequestMessage: Function which will be called to generate a log message for logging requests. The function will be called in the context of the koa 'this' context and passed the request fields object. It should return a string.

  • formatResponseMessage: Same as formatRequestLog, but for responses.

Examples

Basic usage:

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestLogger());

Add custom fields to include in request and response logs:

app.use(koaBunyanLogger.requestLogger({
  // Custom fields for both request and response
  updateLogFields: function (fields) {
    fields.authorized_user = this.user.id;
    fields.client_version = this.request.get('X-Client-Version');
  },

  // Custom fields for response only
  updateResponseLogFields: function (fields, err) {
    if (err) {
      fields.last_db_query = this.db.lastDbQuery();
    }
  }
}));

koaBunyanLogger.requestIdContext(opts)

Get X-Request-Id header, or if the header does not exist, generates a random unique id for each request.

Options:

  • header: name of header to get request id from
  • prop: property to store on context; defaults to 'reqId' e.g. this.reqId
  • requestProp: property to store on request; defaults to 'reqId' e.g. this.request.reqId
  • field: field to add to log messages in downstream middleware and handlers; defaults to 'req_id'

Examples

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());

Or use a different header:

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext({
  header: 'Request-Id'
}));

By default, the request id will be accessible as this.reqId and this.request.reqId:

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());

app.use(function (ctx) {
  ctx.response.set('X-Server-Request-Id', ctx.reqId);
  ctx.body = "Hello world";
});

koaBunyanLogger.timeContext(opts)

Adds time(label) and timeEnd(label) methods to the koa context, which records the time between the time() and timeEnd() calls for a given label.

Calls to time() and timeEnd() can be nested or interleaved as long as they're balanced for each label.

Options:

  • logLevel: name of log level to use; defaults to 'trace'
  • updateLogFields: function which will be called with arguments (fields) in koa context; can update fields or return a new object.

Examples

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());
app.use(koaBunyanLogger.timeContext());

app.use(function (ctx) {
  ctx.time('get data');

  return getUser()
  .then(u => {
    return getFriend(u)
    .then(f => [u, f]);
  })
  .then(data => {
    let user = data[0];
    let friends = data[1];

    ctx.timeEnd('get data');
    ctx.time('serialize');
    ctx.body = serialize(user, friends);
    ctx.timeEnd('serialize');
  });
});

The same but using async functions

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());
app.use(koaBunyanLogger.timeContext());

app.use(async function (ctx) {
  ctx.time('get data');
  let user = await getUser();
  let friends = await getFriend(user);
  ctx.timeEnd('get data');

  ctx.time('serialize');
  ctx.body = serialize(user, friends);
  ctx.timeEnd('serialize');
});

Example output:

{"name":"koa","hostname":"localhost","pid":9228,"level":10,"label":"get data","duration":102,"msg":"","time":"2014-11-07T01:45:53.711Z","v":0}
{"name":"koa","hostname":"localhost","pid":9228,"level":10,"label":"serialize","duration":401,"msg":"","time":"2014-11-07T01:45:54.116Z","v":0}

To return different fields, such as nesting the data under a single field, add a updateLogFields function to the options:

const koaBunyanLogger = require('koa-bunyan-logger');

app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());
app.use(koaBunyanLogger.timeContext({
  updateLogFields: function (fields) {
    return {
      request_trace: {
        name: fields.label,
        time: fields.duration
      }
    };
  }
}));

bunyan export

The internal copy of bunyan is exported as .bunyan:

const koaBunyanLogger = require('koa-bunyan-logger');
const bunyan = koaBunyanLogger.bunyan;

Sponsored by

Pebble Technology!

License

MIT

bunyan-logger's People

Contributors

aheckmann avatar alxarch avatar aui avatar dcboy avatar dependabot[bot] avatar ifraixedes avatar jlai avatar kevinawoo avatar marcbachmann avatar niftylettuce avatar oleg-koval avatar venables avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bunyan-logger's Issues

Add Typescript definition file

I am using Typescript in my Koa project and want to use bunyan logging -- when I import the module Typescript is complaining of a missing definition's file (because -- well -- one is). Any chance we can add such a file?

Is this repository still being maintained?

Hello,

I'd like to know if this repository is still being maintained.
There are some automated PRs to update dependencies still open.

I'd like to contribute to what I think is an issue with the format of the logs but first I'd like to see if someone could actually validate my changes, merge them and do a release.

Thanks,
Jorge

updateLogFields mutates ctx

For security reasons I'd like to not log cookie headers. Since updateLogFields mutates ctx, this means I end up stripping headers from requests -- and I need those, just not in the logs. Would you be open to a PR that deep clones ctx when it goes into the update functions? I have a little wrapper in my own code that strips out log fields before actually logging somewhere, but it feels like something that belongs in the library.

Can't publish to NPM

@aheckmann or @jlai --

@oleg-koval and I (Mostly Ed!) have a new release ready for NPM. However, we don't have the authority to push a new release. :(

Can someone fix this so we can actually publish the release? My NPM login in sjmcdowall not sure what Ed's (oleg-koval) is .

Thanks!

Koa 2 support

Would be nice to add a version for Koa 2 with promises! :)

Control output level with external bunyan

I have specified my own bunyan instance which is a child component with its own level. However, If I set the level to info, I still get the amount of logging I would expect with debug or trace (it logs the req object). If I don't specify my own bunyan instance at all, then I get the expected output of just the request parameters and not the entire req object.

Node v6.7.0
Bunyan 1.8.1
Koa 2.0.0-alpha.7
koa-bunyan-logger 2.0.0-pre1

let logger = bunyan.createLogger({
  name: 'website',
  stream: process.stdout,
  level: 'debug'
})
logger.req = logger.child({
  component: 'req',
  level: 'info'
})
app.use(koaBunyanLogger(logger.req))
app.use(koaBunyanLogger.requestIdContext())
app.use(koaBunyanLogger.requestLogger())
[2016-10-02T00:37:13.505Z]  INFO: website/req/24532 on vm:   <-- GET /api (req_id=399c55dc-eaa6-4418-8ee8-d6499f3aaebb, req.readable=true, req.domain=null, req._events={}, req._eventsCount=0, req.connection=[Circular], req.httpVersionMajor=1, req.httpVersionMinor=1, req.complete=false, req.rawTrailers=[], req.upgrade=false, req.statusCode=null, req.statusMessage=null, req.client=[Circular], req._consuming=false, req._dumped=false)
    GET /api HTTP/1.1
    host: 127.0.0.1:3000
    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0
    accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,text/csv;q=0.9
    accept-language: en-US,en;q=0.5
    accept-encoding: gzip, deflate
    dnt: 1
    connection: keep-alive
    upgrade-insecure-requests: 1
    cache-control: max-age=0
    --
    req._readableState: {
      "objectMode": false,
      "highWaterMark": 16384,
      "buffer": {
        "head": null,
        "tail": null,
        "length": 0
      },
      "length": 0,
      "pipes": null,
      "pipesCount": 0,
      "flowing": null,
      "ended": false,
      "endEmitted": false,
      "reading": false,
      "sync": true,
      "needReadable": false,
      "emittedReadable": false,
      "readableListening": false,
      "resumeScheduled": false,
      "defaultEncoding": "utf8",
      "ranOut": false,
      "awaitDrain": 0,
      "readingMore": true,
      "decoder": null,
      "encoding": null
    }
    --
    req.socket: {
      "connecting": false,
      "_hadError": false,
      "_handle": {
        "bytesRead": 376,
        "_externalStream": {},
        "fd": 22,
        "reading": true,
        "owner": "[Circular]",
        "onconnection": null,
        "writeQueueSize": 0
      },
      "_parent": null,
      "_host": null,
      "_readableState": {
        "objectMode": false,
        "highWaterMark": 16384,
        "buffer": {
          "head": null,
          "tail": null,
          "length": 0
        },
        "length": 0,
        "pipes": null,
        "pipesCount": 0,
        "flowing": true,
        "ended": false,
        "endEmitted": false,
        "reading": true,
        "sync": false,
        "needReadable": true,
        "emittedReadable": false,
        "readableListening": false,
        "resumeScheduled": false,
        "defaultEncoding": "utf8",
        "ranOut": false,
        "awaitDrain": 0,
        "readingMore": false,
        "decoder": null,
        "encoding": null
      },
      "readable": true,
      "domain": null,
      "_events": {
        "end": [
          null,
          null
        ],
        "drain": [
          null,
          null
        ],
        "error": [
          null,
          null
        ],
        "close": [
          null,
          null,
          null
        ]
      },
      "_eventsCount": 10,
      "_writableState": {
        "objectMode": false,
        "highWaterMark": 16384,
        "needDrain": false,
        "ending": false,
        "ended": false,
        "finished": false,
        "decodeStrings": false,
        "defaultEncoding": "utf8",
        "length": 0,
        "writing": false,
        "corked": 0,
        "sync": true,
        "bufferProcessing": false,
        "writecb": null,
        "writelen": 0,
        "bufferedRequest": null,
        "lastBufferedRequest": null,
        "pendingcb": 0,
        "prefinished": false,
        "errorEmitted": false,
        "bufferedRequestCount": 0,
        "corkedRequestsFree": {
          "next": null,
          "entry": null
        }
      },
      "writable": true,
      "allowHalfOpen": true,
      "destroyed": false,
      "_bytesDispatched": 0,
      "_sockname": null,
      "_pendingData": null,
      "_pendingEncoding": "",
      "server": {
        "domain": null,
        "_events": {},
        "_eventsCount": 2,
        "_connections": 1,
        "_handle": {
          "bytesRead": 0,
          "_externalStream": {},
          "fd": 21,
          "reading": false,
          "owner": "[Circular]",
          "onread": null,
          "writeQueueSize": 0
        },
        "_usingSlaves": false,
        "_slaves": [],
        "_unref": false,
        "allowHalfOpen": true,
        "pauseOnConnect": false,
        "httpAllowHalfOpen": false,
        "timeout": 120000,
        "_pendingResponseData": 0,
        "_connectionKey": "4:127.0.0.1:3000"
      },
      "_server": "[Circular]",
      "_idleTimeout": 120000,
      "_idleNext": {
        "_idleNext": "[Circular]",
        "_idlePrev": "[Circular]",
        "_timer": {
          "_list": "[Circular]"
        },
        "_unrefed": true,
        "msecs": 120000
      },
      "_idlePrev": "[Circular]",
      "_idleStart": 13088,
      "parser": {
        "_headers": [],
        "_url": "",
        "_consumed": true,
        "socket": "[Circular]",
        "incoming": "[Circular]",
        "outgoing": null,
        "maxHeaderPairs": 2000
      },
      "_paused": false,
      "_consuming": true,
      "_httpMessage": {
        "domain": null,
        "_events": {
          "finish": [
            null,
            null
          ]
        },
        "_eventsCount": 2,
        "output": [],
        "outputEncodings": [],
        "outputCallbacks": [],
        "outputSize": 0,
        "writable": true,
        "_last": false,
        "upgrading": false,
        "chunkedEncoding": false,
        "shouldKeepAlive": true,
        "useChunkedEncodingByDefault": true,
        "sendDate": true,
        "_removedHeader": {},
        "_contentLength": null,
        "_hasBody": true,
        "_trailer": "",
        "finished": false,
        "_headerSent": false,
        "socket": "[Circular]",
        "connection": "[Circular]",
        "_header": null,
        "_headers": null,
        "_headerNames": {},
        "statusCode": 404
      },
      "_peername": {
        "address": "127.0.0.1",
        "family": "IPv4",
        "port": 51787
      }
    }
    --
    req.rawHeaders: [
      "Host",
      "127.0.0.1:3000",
      "User-Agent",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0",
      "Accept",
      "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,text/csv;q=0.9",
      "Accept-Language",
      "en-US,en;q=0.5",
      "Accept-Encoding",
      "gzip, deflate",
      "DNT",
      "1",
      "Connection",
      "keep-alive",
      "Upgrade-Insecure-Requests",
      "1",
      "Cache-Control",
      "max-age=0"
    ]
[2016-10-02T00:37:13.525Z]  INFO: website/req/24532 on vm:   --> GET /api 200 14ms (req_id=399c55dc-eaa6-4418-8ee8-d6499f3aaebb, duration=14, req.readable=true, req.domain=null, req._events={}, req._eventsCount=0, req.connection=[Circular], req.httpVersionMajor=1, req.httpVersionMinor=1, req.complete=true, req.rawTrailers=[], req.upgrade=false, req.statusCode=null, req.statusMessage=null, req.client=[Circular], req._consuming=false, req._dumped=true, res.domain=null, res._eventsCount=1, res.output=[], res.outputEncodings=[], res.outputCallbacks=[], res.outputSize=0, res.writable=true, res._last=false, res.upgrading=false, res.chunkedEncoding=false, res.shouldKeepAlive=true, res.useChunkedEncodingByDefault=true, res.sendDate=true, res._contentLength=12, res._hasBody=true, res._trailer="", res.finished=true, res._headerSent=true, res.socket=null, res.connection=null, res.__onFinished=null, res.statusMessage=OK)
    GET /api HTTP/1.1
    host: 127.0.0.1:3000
    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0
    accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,text/csv;q=0.9
    accept-language: en-US,en;q=0.5
    accept-encoding: gzip, deflate
    dnt: 1
    connection: keep-alive
    upgrade-insecure-requests: 1
    cache-control: max-age=0
    --
    HTTP/1.1 200 OK
    --
    req._readableState: {
      "objectMode": false,
      "highWaterMark": 16384,
      "buffer": {
        "head": null,
        "tail": null,
        "length": 0
      },
      "length": 0,
      "pipes": null,
      "pipesCount": 0,
      "flowing": true,
      "ended": true,
      "endEmitted": false,
      "reading": false,
      "sync": true,
      "needReadable": false,
      "emittedReadable": true,
      "readableListening": false,
      "resumeScheduled": true,
      "defaultEncoding": "utf8",
      "ranOut": false,
      "awaitDrain": 0,
      "readingMore": true,
      "decoder": null,
      "encoding": null
    }
    --
    req.socket: {
      "connecting": false,
      "_hadError": false,
      "_handle": {
        "bytesRead": 376,
        "_externalStream": {},
        "fd": 22,
        "reading": true,
        "owner": "[Circular]",
        "onconnection": null,
        "writeQueueSize": 0
      },
      "_parent": null,
      "_host": null,
      "_readableState": {
        "objectMode": false,
        "highWaterMark": 16384,
        "buffer": {
          "head": null,
          "tail": null,
          "length": 0
        },
        "length": 0,
        "pipes": null,
        "pipesCount": 0,
        "flowing": true,
        "ended": false,
        "endEmitted": false,
        "reading": true,
        "sync": false,
        "needReadable": true,
        "emittedReadable": false,
        "readableListening": false,
        "resumeScheduled": false,
        "defaultEncoding": "utf8",
        "ranOut": false,
        "awaitDrain": 0,
        "readingMore": false,
        "decoder": null,
        "encoding": null
      },
      "readable": true,
      "domain": null,
      "_events": {
        "end": [
          null,
          null
        ],
        "drain": [
          null,
          null
        ],
        "error": [
          null
        ],
        "close": [
          null
        ]
      },
      "_eventsCount": 10,
      "_writableState": {
        "objectMode": false,
        "highWaterMark": 16384,
        "needDrain": false,
        "ending": false,
        "ended": false,
        "finished": false,
        "decodeStrings": false,
        "defaultEncoding": "utf8",
        "length": 0,
        "writing": false,
        "corked": 0,
        "sync": false,
        "bufferProcessing": false,
        "writecb": null,
        "writelen": 0,
        "bufferedRequest": null,
        "lastBufferedRequest": null,
        "pendingcb": 1,
        "prefinished": false,
        "errorEmitted": false,
        "bufferedRequestCount": 0,
        "corkedRequestsFree": {
          "next": null,
          "entry": null
        }
      },
      "writable": true,
      "allowHalfOpen": true,
      "destroyed": false,
      "_bytesDispatched": 153,
      "_sockname": null,
      "_pendingData": null,
      "_pendingEncoding": "",
      "server": {
        "domain": null,
        "_events": {},
        "_eventsCount": 2,
        "_connections": 1,
        "_handle": {
          "bytesRead": 0,
          "_externalStream": {},
          "fd": 21,
          "reading": false,
          "owner": "[Circular]",
          "onread": null,
          "writeQueueSize": 0
        },
        "_usingSlaves": false,
        "_slaves": [],
        "_unref": false,
        "allowHalfOpen": true,
        "pauseOnConnect": false,
        "httpAllowHalfOpen": false,
        "timeout": 120000,
        "_pendingResponseData": 0,
        "_connectionKey": "4:127.0.0.1:3000"
      },
      "_server": "[Circular]",
      "_idleTimeout": 120000,
      "_idleNext": {
        "_idleNext": "[Circular]",
        "_idlePrev": "[Circular]",
        "_timer": {
          "_list": "[Circular]"
        },
        "_unrefed": true,
        "msecs": 120000
      },
      "_idlePrev": "[Circular]",
      "_idleStart": 13120,
      "parser": {
        "_headers": [],
        "_url": "",
        "_consumed": true,
        "socket": "[Circular]",
        "incoming": "[Circular]",
        "outgoing": null,
        "maxHeaderPairs": 2000
      },
      "_paused": false,
      "_consuming": true,
      "_httpMessage": null,
      "_peername": {
        "address": "127.0.0.1",
        "family": "IPv4",
        "port": 51787
      }
    }
    --
    req.rawHeaders: [
      "Host",
      "127.0.0.1:3000",
      "User-Agent",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0",
      "Accept",
      "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,text/csv;q=0.9",
      "Accept-Language",
      "en-US,en;q=0.5",
      "Accept-Encoding",
      "gzip, deflate",
      "DNT",
      "1",
      "Connection",
      "keep-alive",
      "Upgrade-Insecure-Requests",
      "1",
      "Cache-Control",
      "max-age=0"
    ]
    --
    req._parsedUrl: {
      "protocol": null,
      "slashes": null,
      "auth": null,
      "host": null,
      "port": null,
      "hostname": null,
      "hash": null,
      "search": null,
      "query": null,
      "pathname": "/api",
      "path": "/api",
      "href": "/api",
      "_raw": "/api"
    }
    --
    res._events: {
      "finish": [
        null
      ]
    }
    --
    res._removedHeader: {
      "content-length": false
    }
    --
    res._header: HTTP/1.1 200 OK
    Content-Type: text/plain; charset=utf-8
    Content-Length: 12
    Date: Sun, 02 Oct 2016 00:37:13 GMT
    Connection: keep-alive


    --
    res._headers: {
      "content-type": "text/plain; charset=utf-8",
      "content-length": "12"
    }
    --
    res._headerNames: {
      "content-type": "Content-Type",
      "content-length": "Content-Length"
    }

Add package-lock.json

package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.

This file is intended to be committed into source repositories, and serves various purposes:

Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.

Provide a facility for users to "time-travel" to previous states of node_modules without having to commit the directory itself.

To facilitate greater visibility of tree changes through readable source control diffs.

And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.

One key detail about package-lock.json is that it cannot be published, and it will be ignored if found in any place other than the toplevel package. It shares a format with npm-shrinkwrap.json(5), which is essentially the same file, but allows publication. This is not recommended unless deploying a CLI tool or otherwise using the publication process for producing production packages.

If both package-lock.json and npm-shrinkwrap.json are present in the root of a package, package-lock.json will be completely ignored.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.