GithubHelp home page GithubHelp logo

pino-http's Introduction

pino-http  Build Status

High-speed HTTP logger for Node.js

To our knowledge, pino-http is the fastest HTTP logger in town.

Benchmarks

Benchmarks log each request/response pair while returning 'hello world', using autocannon with 100 connections and 10 pipelined requests.

  • http-ndjson (equivalent info): 7730.73 req/sec
  • http-ndjson (standard minimum info): 9522.37 req/sec
  • pino-http: 21496 req/sec
  • pino-http (extreme): 25770.91 req/sec
  • no logger: 46139.64 req/sec

All benchmarks where taken on a Macbook Pro 2013 (2.6GHZ i7, 16GB of RAM).

Install

npm i pino-http --save

Example

'use strict'

const http = require('http')
const server = http.createServer(handle)

const logger = require('pino-http')()

function handle (req, res) {
  logger(req, res)
  req.log.info('something else')
  res.end('hello world')
}

server.listen(3000)
$ node example.js | pino-pretty
[2016-03-31T16:53:21.079Z] INFO (46316 on MBP-di-Matteo): something else
    req: {
      "id": 1,
      "method": "GET",
      "url": "/",
      "headers": {
        "host": "localhost:3000",
        "user-agent": "curl/7.43.0",
        "accept": "*/*"
      },
      "remoteAddress": "::1",
      "remotePort": 64386
    }
[2016-03-31T16:53:21.087Z] INFO (46316 on MBP-di-Matteo): request completed
    res: {
      "statusCode": 200,
      "header": "HTTP/1.1 200 OK\r\nX-Powered-By: restify\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 11\r\nETag: W/\"b-XrY7u+Ae7tCTyyK7j1rNww\"\r\nDate: Thu, 31 Mar 2016 16:53:21 GMT\r\nConnection: keep-alive\r\n\r\n"
    }
    responseTime: 10
    req: {
      "id": 1,
      "method": "GET",
      "url": "/",
      "headers": {
        "host": "localhost:3000",
        "user-agent": "curl/7.43.0",
        "accept": "*/*"
      },
      "remoteAddress": "::1",
      "remotePort": 64386
    }

API

pinoHttp([opts], [stream])

opts: it has all the options as pino and

  • logger: parent pino instance for a child logger instance, which will be used by pino-http. To refer to this child instance, use pinoHttp.logger
  • genReqId: you can pass a function which gets used to generate a request id. The first argument is the request itself. As fallback pino-http is just using an integer. This default might not be the desired behavior if you're running multiple instances of the app
  • useLevel: the logger level pino-http is using to log out the response. default: info
  • customLogLevel: set to a function (req, res, err) => { /* returns level name string */ }. This function will be invoked to determine the level at which the log should be issued (silent will prevent logging). This option is mutually exclusive with the useLevel option. The first two arguments are the HTTP request and response. The third argument is an error object if an error has occurred in the request.
  • autoLogging: set to false, to disable the automatic "request completed" and "request errored" logging. Defaults to true. If set to an object, you can provide more options.
  • autoLogging.ignore: set to a function (req) => { /* returns boolean */ }. Useful for defining logic based on req properties (such as a user-agent header) to ignore successful requests.
  • stream: same as the second parameter
  • customReceivedMessage: set to a function (req, res) => { /* returns message string */ } This function will be invoked at each request received, setting "msg" property to returned string. If not set, nothing value will be used.
  • customReceivedObject: set to a function (req, res, loggableObject) => { /* returns loggable object */ } This function will be invoked at each request received, replacing the base loggable received object. When set, it is up to the reponsibility of the caller to merge with the loggableObject parameter. If not set, default value will be used.
  • customSuccessMessage: set to a function (req, res) => { /* returns message string */ } This function will be invoked at each successful response, setting "msg" property to returned string. If not set, default value will be used.
  • customSuccessObject: set to a function (req, res, loggableObject) => { /* returns loggable object */ } This function will be invoked at each successful response, replacing the base loggable success object. When set, it is up to the reponsibility of the caller to merge with the loggableObject parameter. If not set, default value will be used.
  • customErrorMessage: set to a function (req, res, err) => { /* returns message string */ } This function will be invoked at each failed response, setting "msg" property to returned string. If not set, default value will be used.
  • customErrorObject: set to a function (req, res, err, loggableObject) => { /* returns loggable object */ } This function will be invoked at each failed response, the base loggable error object. When set, it is up to the reponsibility of the caller to merge with the loggableObject parameter. If not set, default value will be used.
  • customAttributeKeys: allows the log object attributes added by pino-http to be given custom keys. Accepts an object of format { [original]: [override] }. Attributes available for override are req, res, err, responseTime and, when using quietReqLogger, reqId.
  • wrapSerializers: when false, custom serializers will be passed the raw value directly. Defaults to true.
  • customProps: set to a function (req, res) => { /* returns on object */ } or { /* returns on object */ } This function will be invoked for each request with req and res where we could pass additional properties that need to be logged outside the req.
  • quietReqLogger: when true, the child logger available on req.log will no longer contain the full bindings and will now only have the request id bound at reqId (note: the autoLogging messages and the logger available on res.log will remain the same except they will also have the additional reqId property). default: false

stream: the destination stream. Could be passed in as an option too.

Examples

Use as Express middleware
const express = require('express')
const logger = require('pino-http')

const app = express()

app.use(logger())

function handle (req, res) {
  req.log.info('something else')
  res.end('hello world')
}

app.listen(3000)
Logger options
'use strict'

const http = require('http')
const server = http.createServer(handle)
const { randomUUID } = require('node:crypto')
const pino = require('pino')
const logger = require('pino-http')({
  // Reuse an existing logger instance
  logger: pino(),

  // Define a custom request id function
  genReqId: function (req, res) {
    const existingID = req.id ?? req.headers["x-request-id"]
    if (existingID) return existingID
    const id = randomUUID()
    res.setHeader('X-Request-Id', id)
    return id
  },

  // Define custom serializers
  serializers: {
    err: pino.stdSerializers.err,
    req: pino.stdSerializers.req,
    res: pino.stdSerializers.res
  },

  // Set to `false` to prevent standard serializers from being wrapped.
  wrapSerializers: true,

  // Logger level is `info` by default
  useLevel: 'info',

  // Define a custom logger level
  customLogLevel: function (req, res, err) {
    if (res.statusCode >= 400 && res.statusCode < 500) {
      return 'warn'
    } else if (res.statusCode >= 500 || err) {
      return 'error'
    } else if (res.statusCode >= 300 && res.statusCode < 400) {
      return 'silent'
    }
    return 'info'
  },

  // Define a custom success message
  customSuccessMessage: function (req, res) {
    if (res.statusCode === 404) {
      return 'resource not found'
    }
    return `${req.method} completed`
  },

  // Define a custom receive message
  customReceivedMessage: function (req, res) {
    return 'request received: ' + req.method
  },

  // Define a custom error message
  customErrorMessage: function (req, res, err) {
    return 'request errored with status code: ' + res.statusCode
  },

  // Override attribute keys for the log object
  customAttributeKeys: {
    req: 'request',
    res: 'response',
    err: 'error',
    responseTime: 'timeTaken'
  },

  // Define additional custom request properties
  customProps: function (req, res) {
    return {
      customProp: req.customProp,
      // user request-scoped data is in res.locals for express applications
      customProp2: res.locals.myCustomData
    }
  }
})

function handle (req, res) {
  logger(req, res)
  req.log.info('something else')
  res.log.info('just in case you need access to logging when only the response is in scope')
  res.end('hello world')
}

server.listen(3000)
Structured Object Hooks

It is possible to override the default structured object with your own. The hook is provided with the pino-http base object so that you can merge in your own keys.

This is useful in scenarios where you want to augment core pino-http logger object with your own event labels.

If you simply want to change the message which is logged then check out the custom[Received|Error|Success]Message hooks e.g. customReceivedMessage

const logger = require('pino-http')({
  //... remaining config omitted for brevity
  customReceivedObject: (req, res, val) => {
    return {
      category: 'ApplicationEvent',
      eventCode: 'REQUEST_RECEIVED'
    };
  },

  customSuccessObject: (req, res, val) => {
    return {
      ...val,
      category: 'ApplicationEvent',
      eventCode:
        res.statusCode < 300
          ? 'REQUEST_PROCESSED'
          : 'REQUEST_FAILED'
    };
  },

  customErrorObject: (req, res, error, val) => {
    const store = storage.getStore();
    const formattedBaggage = convertBaggageToObject(store?.baggage);

    return {
      ...val,
      category: 'ApplicationEvent',
      eventCode: 'REQUEST_FAILED'
    };
  }

  // ...remaining config omitted for brevity
})
PinoHttp.logger (P.Logger)

The pinoHttp instance has a property logger, which references to an actual logger instance, used by pinoHttp. This instance will be a child of an instance, passed as opts.logger, or a fresh one, if no opts.logger is passed. It can be used, for example, for doing most of the things, possible to do with any pino instance, for example changing logging level in runtime, like so:

const pinoHttp = require('pinoHttp')();
pinoHttp.logger.level = 'silent';
pinoHttp.startTime (Symbol)

The pinoHttp function has a property called startTime which contains a symbol that is used to attach and reference a start time on the HTTP res object. If the function returned from pinoHttp is not the first function to be called in an HTTP servers request listener function then the responseTime key in the log output will be offset by any processing that happens before a response is logged. This can be corrected by manually attaching the start time to the res object with the pinoHttp.startTime symbol, like so:

const http = require('http')
const logger = require('pino-http')()
const someImportantThingThatHasToBeFirst = require('some-important-thing')
http.createServer((req, res) => {
  res[logger.startTime] = Date.now()
  someImportantThingThatHasToBeFirst(req, res)
  logger(req, res)
  res.log.info('log is available on both req and res');
  res.end('hello world')
}).listen(3000)
Custom formatters

You can customize the format of the log output by passing a Pino transport.

const logger = require('pino-http')({
  quietReqLogger: true, // turn off the default logging output
  transport: {
    target: 'pino-http-print', // use the pino-http-print transport and its formatting output
    options: {
      destination: 1,
      all: true,
      translateTime: true
    }
  }
})

Default serializers

pinoHttp.stdSerializers.req

Generates a JSONifiable object from the HTTP request object passed to the createServer callback of Node's HTTP server.

It returns an object in the form:

{
  pid: 93535,
  hostname: 'your host',
  level: 30,
  msg: 'my request',
  time: '2016-03-07T12:21:48.766Z',
  v: 0,
  req: {
    id: 42,
    method: 'GET',
    url: '/',
    headers: {
      host: 'localhost:50201',
      connection: 'close'
    },
    remoteAddress: '::ffff:127.0.0.1',
    remotePort: 50202
  }
}
pinoHttp.stdSerializers.res

Generates a JSONifiable object from the HTTP response object passed to the createServer callback of Node's HTTP server.

It returns an object in the form:

{
  pid: 93581,
  hostname: 'myhost',
  level: 30,
  msg: 'my response',
  time: '2016-03-07T12:23:18.041Z',
  v: 0,
  res: {
    statusCode: 200,
    header: 'HTTP/1.1 200 OK\r\nDate: Mon, 07 Mar 2016 12:23:18 GMT\r\nConnection: close\r\nContent-Length: 5\r\n\r\n'
  }
}

Custom serializers

Each of the standard serializers can be extended by supplying a corresponding custom serializer. For example, let's assume the request object has custom properties attached to it, and that all of the custom properties are prefixed by foo. In order to show these properties, along with the standard serialized properties, in the resulting logs, we can supply a serializer like:

const logger = require('pino-http')({
  serializers: {
    req (req) {
      Object.keys(req.raw).forEach((k) => {
        if (k.startsWith('foo')) {
          req[k] = req.raw[k]
        }
      })
      return req
    }
  }
})

If you prefer to work with the raw value directly, or you want to honor the custom serializers already defined by opts.logger, you can pass in opts.wrapSerializers as false:

const logger = require('pino-http')({
  wrapSerializers: false,
  serializers: {
    req (req) {
      // `req` is the raw `IncomingMessage` object, not the already serialized request from `pino.stdSerializers.req`.
      return {
        message: req.foo
      };
    }
  }
})
Logging request body

Logging of requests' bodies is disabled by default since it can cause security risks such as having private user information (password, other GDPR-protected data, etc.) logged (and persisted in most setups). However if enabled, sensitive information can be redacted as per redaction documentation.

Furthermore, logging more bytes does slow down throughput. This video by pino maintainers Matteo Collina & David Mark Clements goes into this in more detail.

After considering these factors, logging of the request body can be achieved as follows:

const http = require('http')
const logger = require('pino-http')({
  serializers: {
    req(req) {
      req.body = req.raw.body;
      return req;
    },
  },
});
Custom serializers + custom log attribute keys

If custom attribute keys for req, res, or err log keys have been provided, serializers will be applied with the following order of precedence:

serializer matching custom key > serializer matching default key > default pino serializer

Team

Matteo Collina

https://github.com/mcollina

https://www.npmjs.com/~matteo.collina

https://twitter.com/matteocollina

David Mark Clements

https://github.com/davidmarkclements

https://www.npmjs.com/~davidmarkclements

https://twitter.com/davidmarkclem

Acknowledgements

This project was kindly sponsored by nearForm.

Logo and identity designed by Beibhinn Murphy O'Brien: https://www.behance.net/BeibhinnMurphyOBrien.

License

MIT

pino-http's People

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

pino-http's Issues

res headers is unformatted

Is it possible to format the response headers in the same way request headers appear in the log output?

Currently they appear as:

res: {
      "statusCode": 200,
      "header": "Content-Type: application/json; charset=utf-8\r\nContent-Length: 34"
}

Ideally they should be:

res: {
      "statusCode": 200,
      "headers:" {
           "content-type": "application/json; charset=utf-8\r\n",
           "content-length": 34
      }
}

TypeScript type definitions?

I've started working on some definitions but haven't had a chance (and don't have the knowledge) to finish them. They're mostly cobbled together from pino's types and logger.js here.

import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http';
import { Level, Logger, SerializerFn } from 'pino';
import { Duplex, Transform, Writable } from 'stream';

declare function PinoHttp(
  optionsOrStream?: PinoHttp.Options | Duplex | Transform | Writable,
): any;

declare function PinoHttp(stream: Duplex | Transform | Writable): any;

declare namespace PinoHttp {
  interface Options {
    serializers?: {
      req?: SerializerFn;
      res?: SerializerFn;
      err?: SerializerFn;
    };
    useLevel?: Level;
    stream?: Duplex | Transform | Writable;
    logger?: Logger;
    genReqId?: (req: IncomingMessage) => number;
  }

  const stdSerializers: {
    /**
     * Generates a JSONifiable object from the HTTP `request` object passed to the `createServer` callback of Node's HTTP server.
     */
    req(
      req: IncomingMessage,
    ): {
      method: string;
      url: string;
      headers: IncomingHttpHeaders;
      remoteAddress: string;
      remotePort: number;
    };
    /**
     * Generates a JSONifiable object from the HTTP `response` object passed to the `createServer` callback of Node's HTTP server.
     */
    res(res: ServerResponse): { statusCode: number; header: string };
  };

  const startTime: symbol;
}

export = PinoHttp;

Wrong stack trace on request errors (Express)

I have an Express app with a catch-all error handler as per the Express docs:

app.use(function (err, req, res, next) {
  req.log.error(err)
  res.status(500).send('Internal Server Error');
}

However, the above code logs the error fine:

[1553698996126] ERROR (52887 on MacBook-Pro): Uncaught (in promise): ReferenceError: <foo> is not defined
ReferenceError: <foo> is not defined
    at <full stack trace>

But the request log itself has the wrong level (info?) & stack trace:

[1553698996235] INFO  (52887 on MacBook-Pro): request errored
    req: {
      "id": 1,
      "method": "GET",
      "url": "/<foo>",
      "headers": {
        "host": "localhost:4000",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
      },
      "remoteAddress": "::1",
      "remotePort": 64724
    }
    res: {
      "statusCode": 500,
      "headers": {
        "x-powered-by": "Express",
        "content-type": "text/html; charset=utf-8",
        "content-length": "139339",
        "etag": "W/\"2204b-wKSbSPj2LUqOYJm+RUU9W+R5pJQ\""
      }
    }
    err: {
      "type": "Error",
      "message": "failed with status code 500",
      "stack":
          Error: failed with status code 500
              at ServerResponse.onResFinished (/<foo>/node_modules/pino-http/logger.js:48:33))
              at ServerResponse.emit (events.js:187:15)
              at onFinish (_http_outgoing.js:678:10)
    }
    responseTime: 499

Is this the expected behavior? Removing the custom error handler doesn't fix the problem, Express then does log the correct error (stack trace) in the console by default. I'm using Express 4.16.4 & express-pino-logger 4.0.0.

Provide custom names for req/res log attributes.

Hi pino-http team,

This middleware is perfect for our product, however due to an agreed logging standard within our organisation, we need to rename req and res to httpReq and httpRes within our logs.

We've managed to hack around the issue by mutating the log message after the fact. However, it would be far cleaner if we could control these currently hard-coded attribute names with config.

I can raise a PR if this is something you would consider accepting?

How to use it with stream?

Hello

const logger = require('pino-http')({
  logger: pino(pino.destination('./logs'))
})

it still stdout http logs, but error correctly are saved to logs file.

I would prefer to split logs on http logs and application logs. Is it possible?
Something like

const logger = require('pino-http')({
  logger: pino(pino.destination('./logs')),
  stream: pino.destination('./http')
})

In your implementation I see it's not possible?

  if (prevLogger) {
    opts.logger = undefined
    opts.genReqId = undefined
    logger = prevLogger.child(opts)
    opts.logger = prevLogger
    opts.genReqId = prevGenReqId
  } else {
    logger = pino(opts, stream)
  }

Cannot serialize custom req values

I would expect that:

app.use(pinoHttp({
  serializers: {
    req: (req) => ({
      url: req.url,
      customValue: req.customValue
    })
  }
}))

...would log req.customValue, if such a property is set on req. But it doesn't. Minimal test case:

const app = require('express')()
const pinoHttp = require('pino-http')

app.use((req, res, next) => {
  req.customValue = '1234'
  next()
})

app.use(pinoHttp({
  serializers: {
  prettyPrint: true,
    req: (req) => ({
      url: req.url,
      customValue: req.customValue
    })
  }
}))

app.get('/', (req, res) => {
  res.end('ok')
})

app.listen(3000)

Then:

$ curl http://localhost:3000

...causes the following log output:

$ node app.js 
[2018-03-05T16:07:11.830Z] INFO (4656 on laptop): request completed
    req: {
      "url": "/"
    }
    res: {
      "statusCode": 200,
      "header": "HTTP/1.1 200 OK\r\nX-Powered-By: Express\r\nDate: Mon, 05 Mar 2018 16:07:11 GMT\r\nConnection: keep-alive\r\nContent-Length: 2\r\n\r\n"
    }
    responseTime: 6

Versions: pino-http 3.2.0 (also happening on 3.1.0)

Support custom request id

I'm already using a request id on req.id (gets set by external load balancer).
This module overwrites that one with an incrementing id, which results in duplicated request ids if I have multiple processes running.

if (!req.id) {
  req.id = ++nextId
  nextId = ...
}

Do you think that is good enough?

req.emit is not a function

when using pino-http after an error, I get this:

_http_client.js:269
  req.emit('close');
      ^

TypeError: req.emit is not a function
    at TLSSocket.socketCloseListener (_http_client.js:269:7)
    at emitOne (events.js:101:20)
    at TLSSocket.emit (events.js:188:7)
    at TCP._handle.close [as _onclose] (net.js:492:12)

npm ERR! Darwin 15.6.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "start"
npm ERR! node v6.2.0

got this under v4.4.5 also … let me see if i can get a minimal code example

Add option to disable automatic request logging

There should be an option to disable the automatic request logging - i.e. "request finished" and "request errored" - as we want to customize the output. Currently we get two logs, our custom and the automatic logging.

this.log should be replaced with req.log

I tried this:

req.log = req.log.child({ something: true });

but it didn't work. After digging into sourcecode I found this:

var log = this.log

this refers to res object, so that would mean res.log. After changing that code, something appeared in my output.

This is very misleading since all examples suggest to use req.log. Also there isn't res.log doesn't have typescript type definition.

autoLogging to false doesn't trigger anything

Hey!

When I set autoLogging to false, It doesn't show any logs, even my custom serialize logs

const pino = require("pino-http")({
  logger, {
	 serializers: {
       err: pino.stdSerializers.err,
       req: pino.stdSerializers.req,
      res: pino.stdSerializers.res
     },
    autoLogging: true,
}

Thank you :)

customLogLevel does not support 'silent'

https://github.com/pinojs/pino/blob/HEAD/docs/api.md#level-string
https://www.npmjs.com/package/express-pino-logger#api

'use strict';

const isProduction = process.env.NODE_ENV === 'production';

const pino = require('pino')();

const expressPinoConfig = {
  logger: pino,
  customLogLevel: (res, err) => {
    if (isProduction && res.statusCode === 404) {
      return 'silent';
    }
    return 'info';
  },
};

const expressPino = require('express-pino-logger')(expressPinoConfig);

Will lead to:

TypeError: log[level] is not a function
    at ServerResponse.onResFinished (/<redacted>/node_modules/pino-http/logger.js:58:15)
    at ServerResponse.emit (events.js:323:22)
    at onFinish (_http_outgoing.js:730:10)
    at onCorkedFinish (_stream_writable.js:721:5)
    at afterWrite (_stream_writable.js:528:5)
    at afterWriteTick (_stream_writable.js:515:10)
    at processTicksAndRejections (internal/process/task_queues.js:83:21)

Currently, there is no way to prevent requests having a specific status code from being logged.

timeouts when using pino-http 2.4 + express under alpine linux

Apologies for the brevity of this, I'll add more information as I get it but I thought it was a sufficiently worrying issue to raise straightaway.

Setup:

Using pino-http under express running on the alpine-node:7.4.0 docker image in aws.

hit the express endpoint with a lot of traffic and everything starts backing up + memory usage grows continually. Eventually the server just starts returning timeout errors.

Under 2.3 everything works fine.

I'll add more info as my investigation continues.

Ignores custom serializers on `opts.logger`

I have a global logger which is used throughout my application with a custom err serializer.

This middleware appears to always override it when passing in my logger which is quite unexpected, e.g.

const app = require("express")();
const pino = require("pino");
const pinoMiddleware = require("express-pino-logger");

const logger = pino({
  prettyPrint: true,
  serializers: {
    err: (err) => {
      return {
        message: err.message,
      };
    },
  },
});

app.use(
  pinoMiddleware({
    logger,
  })
);

// This correctly uses my custom err serializer
logger.error({ err: new Error("b0rked 1") });

app.get("/", function (req, res) {
  // This does not use my custom err serializer?!
  req.log.error({ err: new Error("b0rked 2") });
});

app.listen(3000);

Too verbose for development?

The multiple-line logs in console feel a bit verbose during development. Is there an easy (less custom code) way to output a simple one-line log for each request similar as Morgan?

I realized pino-toke is built for that. But it is also meant to be a CLI tool. We already need to pipe the output to pino-pretty. How do you suggest to use pino-pretty and pino-toke together?

genReqId() to be exposed in code

Currently, genReqId() is called when the request comes in. We need genReqId() to be called when an event comes in lets say from Event Hub. Is this supported?

dynamic serializer swapping

Consider a situation where we log every time for a certain route,
and we're not interested in seeing the request completed for this route
(in particularly I'm thinking about transmitting logs from the browser to the server,
say to a /logs route)

I'd like to be able to do

var pinoHttp = require('pino-http')({ignore: ['/logs']}) 

and maybe even

var pinoHttp = require('pino-http')({ignore: [{method: 'POST', url: '/logs'}]}) 

It would also be good to be able to do

var pinoHttp = require('pino-http')
pinoHttp.ignore('/logs') // or pinoHttp.ignore({method: 'POST', url: '/logs'}]})

This wouldn't remove the req.log method, it would just avoid emitting the "request completed" log for a route

Link to pino formatters in readme

Now that pinojs/pino#317 has been merged, add pre-defined formatters for development.

Morgan logger has a predefined dev formatter, which makes adding the logger during development quick and easy. Adding similar functionality to pino-http would be useful.

Not sure about the api? Maybe add a formatter: option?

option to disable headers

not finding them super useful, and they could contain potentially sensitive information (access tokens, cookies, etc). any way we could add an option to disable writing them to logs?

Add option for custom logging format

Using the serializers I can customize what get's logged. However, I do not have control over the logging format. For example, I would like to log like so:

[1574212772844] INFO (35 on db805887c09f): 11.11.111.111 - GET /url/path - Status Code: 200

Essentially it would mean removing the object with res & err here in logger.js:

      log[level]({
        res: this,
        err: err || this.err || new Error('failed with status code ' + this.statusCode),
        responseTime: responseTime
      }, 'request errored')
      return
    }


    log[level]({
      res: this,
      responseTime: responseTime
    }, 'request completed')

...allowing the user to decide how to format the log.

Pino Http not working with cls-proxify

Hi, I'm trying to setup logging with pino and cls-proxify (and express), but pino http seems to lose the bindings somehow. When setting up my own middleware, the bindings appear in the logs e.g

const baseLogger = pino({ timestamp: false, base: null })
const log = clsProxify('clsKeyLogger', baseLogger)
app.use([
  clsProxifyExpressMiddleware('clsKeyLogger', (req) => baseLogger.child({ foo: 'bar' })),
  (req, res, next) => {
    log.info('trace 1')
    next()
  },
  (req, res, next) => {
    res.on('finish', () => log.info('trace 2'))
    next()
  },
  pinoHttp({  logger: log })])

But pino http logs don't contain the bindings.

Do you expect this library to work with cls-proxify?

support a singleton logger cache?

no one want's to use multiple loggers - but you tend to want to load middleware in the same place you use it

we export the created pino instance as the logger property (e.g. require('pino-http')().logger

For a project to use the logger in pieces that are outside of a web framework (e.g. not in a piece of middleware) there's two options for logger reuse - pass the logger into an exported function, or create a singleton logger module (either with pino directly, or one that exports the created middleware with logger)

Maybe we should promote a different pattern

At first instantiation we can get a logger instance as normal:

const pino = require('pino-http')()
const {logger} = pino

But in another file, if we want the logger instance:

const {logger} = require('pino-http')

This would mean throwing if pino-http is called twice:

 require('pino-http')() // logger added to module object
 require('pino-http')() // throw because logger already there

@mcollina @jsumners @watson @marcbachmann - thoughts?

Support custom serializer for auto logging?

Apologies if I've missed something here.

When using the autoLogging feature, I get a huge amount of information logged, as the autologger logs everything in the res object by default. In my case, res contains a _req property, which in turn contains the entirety of the request object, including sensitive information (for example, the request body).

It would appear that a custom serializer for the object logged in onResFinished might be beneficial here?

Finally, I've only tried this in development. Perhaps this isn't the same behaviour if NODE_ENV is "production"?

Support for customLevels, and useCustomLevels?

Currently using pino-http@^4.0.0 as express middleware

TypeError: log.error is not a function
    at ServerResponse.onResFinished (/path/to/project/node_modules/pino-http/logger.js:39:11)
    at emitNone (events.js:111:20)
    at ServerResponse.emit (events.js:208:7)
    at onFinish (_http_outgoing.js:723:10)
    at onCorkedFinish (_stream_writable.js:629:5)
    at afterWrite (_stream_writable.js:454:3)
    at _combinedTickCallback (internal/process/next_tick.js:144:20)
    at process._tickCallback (internal/process/next_tick.js:180:9)

https://github.com/pinojs/pino/blob/master/docs/api.md#useonlycustomlevels-boolean

// usage example
const logger = pino({
  customLevels: {
    foo: 35
  },
  useOnlyCustomLevels: true,
  level: 'foo'
})
logger.foo('hi')
logger.info('hello') // Will throw an error saying info in not found in logger object

Package json

@davidmarkclements all loggers are flagged as dependencies, not just pino

also the metadata in package.json are not ok, it's missing all the relevant URLs etc..

Add support for request-received middleware

The request-received middleware at https://github.com/cabinjs/request-received exposes a Symbol.for property, which this package could conditionally consume if interested (as opposed to just generating a new Date().

e.g. https://github.com/pinojs/pino-http/blob/master/logger.js#L63 would change as follows:

-    res[startTime] = res[startTime] || Date.now()
+    res[startTime] = res[startTime] || req[Symbol.for('request-received.startTime')] ? req[Symbol.for('request-received.startTime')].getTime() : Date.now()

Ref: #65

Logging req.user properties

I would really like to log some properties off of req.user which is added in middleware that is after pino-http. It looks like pino-http serializes the req object immediately because it creates a child logger with the request object. Would it be possible to postpone serialization of req until the request finishes? Or possibly add another hook that could be used to serialize once the request is finished? Could anyone offer a suggestion of how I could accomplish what I'm trying to do here?

Docs: `req.id`

This module reads from req.id:

return req.id || (nextReqId = (nextReqId + 1) & maxInt)

However this property doesn't seem to be documented anywhere. It's not something provided by Express, for example.

Could we add some docs to specify what this is for and how to use it along with this module? I suspect it can be used like this:

app.use((req, _res, next) => {
  req.id = req.get('x-request-id');
  next();
});

app.use(expressPinoLogger);

Then Pino will infer the request ID from the req.id we defined.

The same thing can be achieved with the genReqId option, however this also overrides the fallback for when x-request-id/req.id is not defined, which is not always desired. (For context, we want to use x-request-id when it's defined, otherwise use Pino's own request IDs.)

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.