|
1 | 1 | const _ = require('lodash'); |
2 | | -const stringify = require('json-stringify-safe'); |
3 | 2 |
|
4 | 3 | const Logger = require('./logger'); |
| 4 | +const stringify = require('json-stringify-safe'); |
5 | 5 |
|
6 | 6 | /** |
7 | 7 | * Generate the InsightTransport Winston Transport. |
@@ -29,7 +29,7 @@ function generateTransport(winston, winstonTransport) { |
29 | 29 | */ |
30 | 30 | constructor(opts) { |
31 | 31 | super(opts); |
32 | | - this.json = opts.json || false; |
| 32 | + this.json = !!opts.json; |
33 | 33 |
|
34 | 34 | const transportOpts = _.clone(opts || {}); |
35 | 35 |
|
@@ -65,21 +65,47 @@ function generateTransport(winston, winstonTransport) { |
65 | 65 | * @returns {void} |
66 | 66 | */ |
67 | 67 | 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 |
75 | 71 | // |
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); |
80 | 107 | } 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 |
83 | 109 | this.logger.log(info.level, info.message); |
84 | 110 | } |
85 | 111 | } |
|
0 commit comments