pinojs / pino

🌲 super fast, all natural json logger
http://getpino.io
MIT License
14.22k stars 874 forks source link

Simpler default logging output for objects #2037

Closed winksaville closed 1 month ago

winksaville commented 1 month ago

I'm testing pino:

$ npm list pino
pino-logging@0.1.0 /home/wink/prgs/javascript/exper-pino-logger
└── pino@9.3.2

I like what I see, but I have one problem. When I use console.log to log the contents of an object the default output is the first level of that objects contents. For example:

$ cat test-object-logging.js 
const pino = require('pino');

const log = pino();

const mysql = require("mysql2/promise");
console.log("mysql=%s", mysql);
//log.info(mysql, "mysql");

log.debug("test-pino:-");

This output is ok and has 636 characters:

$ node test-object-logging.js 
mysql={
  createConnection: [Function: createConnection],
  createPool: [Function: createPool],
  createPoolCluster: [Function: createPoolCluster],
  escape: [Function: escape],
  escapeId: [Function: escapeId],
  format: [Function: format],
  raw: [Function: raw],
  PromisePool: [class PromisePool extends EventEmitter],
  PromiseConnection: [class PromiseConnection extends EventEmitter],
  PromisePoolConnection: [class PromisePoolConnection extends PromiseConnection],
  Types: [Getter],
  Charsets: [Getter],
  CharsetToEncoding: [Getter],
  setMaxParserCache: [Function (anonymous)],
  clearParserCache: [Function (anonymous)]
}

$ node test-object-logging.js | wc -c
636

But if I enable just pino log.info in the little app it outputs 10,0020 characters:

$ cat test-object-logging.js 
const pino = require('pino');

const log = pino();

const mysql = require("mysql2/promise");
//console.log("mysql=%s", mysql);
log.info(mysql, "mysql");

$ node test-object-logging.js | wc -c
10020

I had a conversation with GPT4o and there is a way to get the similar output using pino, it suggested something like:

$ cat test-first-level-properties.js 
const pino = require('pino');
const log = pino();

const mysql = require("mysql2/promise");

// Iterate over the first-level properties
// of an object and return them
function flp(obj) {
  const firstLevelProperties = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      firstLevelProperties[key] = typeof obj[key];
    }
  }

  return firstLevelProperties
}

console.log("mysql:", mysql);
log.info(flp(mysql), "flp(mysql)");

$ node test-first-level-properties.js | pino-pretty 
mysql: {
  createConnection: [Function: createConnection],
  createPool: [Function: createPool],
  createPoolCluster: [Function: createPoolCluster],
  escape: [Function: escape],
  escapeId: [Function: escapeId],
  format: [Function: format],
  raw: [Function: raw],
  PromisePool: [class PromisePool extends EventEmitter],
  PromiseConnection: [class PromiseConnection extends EventEmitter],
  PromisePoolConnection: [class PromisePoolConnection extends PromiseConnection],
  Types: [Getter],
  Charsets: [Getter],
  CharsetToEncoding: [Getter],
  setMaxParserCache: [Function (anonymous)],
  clearParserCache: [Function (anonymous)]
}
[12:35:11.463] INFO (836220): flp(mysql)
    createConnection: "function"
    createPool: "function"
    createPoolCluster: "function"
    escape: "function"
    escapeId: "function"
    format: "function"
    raw: "function"
    PromisePool: "function"
    PromiseConnection: "function"
    PromisePoolConnection: "function"
    Types: "object"
    Charsets: "object"
    CharsetToEncoding: "object"
    setMaxParserCache: "function"
    clearParserCache: "function"

Is there a way to have something like flp() be the default serializer for objects?

mcollina commented 1 month ago

You should use serializers.

https://getpino.io/#/docs/api?id=serializers-object

winksaville commented 1 month ago

You should use serializers.

https://getpino.io/#/docs/api?id=serializers-object

Do you mean these https://github.com/pinojs/pino-std-serializers or do you mean create per object custom serializes or something else?

Note; in my example I'm pointing out that the "default" serialization to a string that console.log uses for arbitrary Objects (first-level properties) seems much friendlier/convenient than the default in pino (all properties). Is there a way to adopt the approach used by console.log as a default serializer for Objects in general. Maybe such a mechanism already exists for me, the user, to override the current default serialization for each of JavaScript fundamental types?

Note.Note: I'm a relative js noob so I am very likely confused and suggesting some totally stupid, please pardon my ignorance :)

mcollina commented 1 month ago

console.log() uses utils.inspect() internally:

https://nodejs.org/dist/latest-v18.x/docs/api/util.html#utilinspectobject-showhidden-depth-colors

Note that the output is not JSON. It indicates "skipped" objects with .... This same behavior is not possible with JSON, so those properties will be completely skipped.

winksaville commented 1 month ago

I'm not looking for exactly the same behavior. I'm just thinking it'd be nice if the pino default was simpler. The flp() function seems good enough to for now, TXS!

jsumners commented 1 month ago

Pino is designed for recording logs in applications used in a "production" scenario. The defaults are designed to provide the information necessary in such a case.

winksaville commented 1 month ago

IMO, logging is used through the dev cycle and that's why there are features such as levels. In addition, a default is just that, a default, and is intended to be overridden if inappropriate for the current situation. I suggest the current is overly verbose, definitely arguable. But not being able to easily and efficiently change the default seems a significant short coming.

Would a feature request be considered or a waste of my time? If I were to make the request I would also consider providing a PoC implementation, although I'd appreciate guidance on how to proceed.

jsumners commented 1 month ago

It is configurable. The documentation for the configuration was linked by Matteo. Please read it.

winksaville commented 1 month ago

It is configurable. The documentation for the configuration was linked by Matteo. Please read it.

AFAICT @mcollina provided two links

Neither appear to me to refer to a default global serializer.

github-actions[bot] commented 2 weeks ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.