Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Commit 3f4d32c

Browse files
LOG-16581 Fix winston JSON logging (#21)
1 parent bbbc665 commit 3f4d32c

File tree

5 files changed

+246
-52
lines changed

5 files changed

+246
-52
lines changed

.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
22
"env": { "es6": true, "node": true },
33
"extends": "rapid7/node",
4+
"parserOptions": {
5+
"ecmaVersion": 2018
6+
},
47
"rules": {
58
"comma-dangle": 0,
69
"prefer-rest-params": 0,

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "r7insight_node",
3-
"version": "2.1.1",
3+
"version": "3.0.0",
44
"description": "Rapid7 Insight Platform client for node; use with or without Winston or Bunyan.",
55
"keywords": [
66
"logentries",

src/transport.js

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const _ = require('lodash');
2-
const stringify = require('json-stringify-safe');
32

43
const Logger = require('./logger');
4+
const stringify = require('json-stringify-safe');
55

66
/**
77
* Generate the InsightTransport Winston Transport.
@@ -29,7 +29,7 @@ function generateTransport(winston, winstonTransport) {
2929
*/
3030
constructor(opts) {
3131
super(opts);
32-
this.json = opts.json || false;
32+
this.json = !!opts.json;
3333

3434
const transportOpts = _.clone(opts || {});
3535

@@ -65,21 +65,47 @@ function generateTransport(winston, winstonTransport) {
6565
* @returns {void}
6666
*/
6767
log(info) {
68-
// If we have specified to log in JSON format, then stringify
69-
//
70-
// Also, if the `info` object which is passed from winston has more
71-
// that 2 default keys (`message` and `level`), then that means that
72-
// the `log` function was called with more two than keys
73-
// (referred to as metadata), so in that scenario we stringify the
74-
// entire message since it is not obvious what format the user wants.
68+
// This function is required since Winston passes in metadata in a strange way.
69+
// Rather than giving us a complete object containing all metadata, it hides it away
70+
// in the splat attribute and passes in only the first piece of metadata
7571
//
76-
// log function, without being given a log (like below) will just log
77-
// the level, which in this case is our message.
78-
if (this.json || Object.keys(info).length > 2) {
79-
this.logger.log(stringify(info));
72+
// This seems to be an existing issue faced by devs:
73+
// https://stackoverflow.com/a/60866937
74+
const returnMetadata = (meta) => {
75+
// You can format the splat yourself
76+
const splat = meta[Symbol.for('splat')];
77+
78+
if (splat && splat.length) {
79+
return splat.reduce((result, current) => ({
80+
...result,
81+
...current
82+
}), {});
83+
}
84+
85+
return {};
86+
};
87+
88+
const metadata = returnMetadata(info);
89+
90+
if (this.json) {
91+
// If we are to output JSON, we create the full object containing level, message and metadata.
92+
//
93+
// We don't serialize here but pass in an object since InsightLogger appends extra keys based on
94+
// configuration, e.g. timestamp before serializing to JSON
95+
//
96+
// We also don't specify the first argument of `level` since the winston `info` contains it.
97+
// If we did provide it InsightLogger would append an extra redundant `_level` key.
98+
this.logger.log({
99+
...info,
100+
...metadata,
101+
});
102+
} else if (Object.keys(info).length > 2) {
103+
// If we are not outputting to JSON and have metadata, we use the same format as Winston
104+
const message = `${info.level}: ${info.message} ${stringify(metadata)}`;
105+
106+
this.logger.log(message);
80107
} else {
81-
// If we do get the default keys of `level` and `message` then we
82-
// can use the default format of `<level> <message>`
108+
// If we're not outputting JSON, nor have metadata, we produce a simple message
83109
this.logger.log(info.level, info.message);
84110
}
85111
}

0 commit comments

Comments
 (0)