Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatting feature #2251

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/winston/formatter/defaultTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const formatDefaultTransform = (info) => {
return info;
};

module.exports = { formatDefaultTransform };

9 changes: 9 additions & 0 deletions lib/winston/formatter/ecsTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const formatEcsTransform = (info) => {
if (typeof info.service === 'string') {
info.service = { name: info.service };
}
return info;
};

module.exports = { formatEcsTransform };

12 changes: 12 additions & 0 deletions lib/winston/formatter/formatInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { formatDefaultTransform } = require('./defaultTransform');
const { formatEcsTransform } = require('./ecsTransform');

function formatInput(info, formatTransformName) {
const func = {
ecsTransform: formatEcsTransform
}[formatTransformName] || formatDefaultTransform;

return func(info);
}

module.exports = { formatInput };
2 changes: 2 additions & 0 deletions lib/winston/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { Stream, Transform } = require('readable-stream');
const asyncForEach = require('async/forEach');
const { LEVEL, SPLAT } = require('triple-beam');
const isStream = require('is-stream');
const { formatInput } = require('./formatter/formatInput');
const ExceptionHandler = require('./exception-handler');
const RejectionHandler = require('./rejection-handler');
const LegacyTransportStream = require('winston-transport/legacy');
Expand Down Expand Up @@ -310,6 +311,7 @@ class Logger extends Transform {
// (and re-throw) any errors generated by the user-provided format, but also
// guarantee that the streams callback is invoked so that we can continue flowing.
try {
info = formatInput(info, this.format.transform.name);
this.push(this.format.transform(info, this.format.options));
} finally {
this._writableState.sync = false;
Expand Down
3 changes: 2 additions & 1 deletion test/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ var helpers = exports;
* @param {function} write Write function for the specified stream
* @returns {Logger} A winston.Logger instance
*/
helpers.createLogger = function (write, format) {
helpers.createLogger = function (write, format, defaultMeta) {
return winston.createLogger({
format,
defaultMeta,
transports: [
mockTransport.createMockTransport(write)
]
Expand Down
57 changes: 57 additions & 0 deletions test/helpers/mocks/mock-ecsFormat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const winston = require('../../../lib/winston');
const { MESSAGE } = require('triple-beam');

/**
* Create a mock Winston format for ecs-logging output.
*
* @param {object} info object to be transformed
* @returns {object} object with ecs format
*/
function ecsTransform(info) {
const reservedFields = {
level: true,
'log.level': true,
ecs: true,
'@timestamp': true,
err: true,
req: true,
res: true
};

const ecsFields = {
'@timestamp': new Date().toISOString(),
'log.level': info.level,
message: info.message,
ecs: { "version":"1.6.0" }
};

const keys = Object.keys(info);
for (let i = 0, len = keys.length; i < len; i++) {
const key = keys[i];
if (!reservedFields[key]) {
ecsFields[key] = info[key];
}
}

const mockStringify = function(ecsFields) {
let serviceObject;

if (typeof ecsFields.service === 'string'){
for (let i=0; i <= ecsFields.service.length; i++){
serviceObject[`${i}`] = ecsFields.service[i];
}
} else {
serviceObject = ecsFields.service;
}

const serviceString = JSON.stringify(serviceObject);
const ecsVersionString = JSON.stringify(ecsFields.ecs);

return `{"@timestamp":"${ecsFields['@timestamp']}","log.level":${ecsFields['log.level']}","ecs":${ecsVersionString},"service":${serviceString}}`;
}

info[MESSAGE] = mockStringify(ecsFields);
return info;
}

module.exports = winston.format(ecsTransform);
38 changes: 38 additions & 0 deletions test/unit/winston/formatter/transform.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const assume = require("assume");
const { formatInput } = require('../../../../lib/winston/formatter/formatInput');

describe('Format Info', function () {
describe('formatEcsTransform', function () {
it('should turn info.service from a string to an object', function() {
const info = {
level: 'info',
service: 'account'
};

const formattedInfo = formatInput(info, "ecsTransform");
const expectedInfo = {
level: 'info',
service: {name: 'account'}
};

assume(formattedInfo).deep.equals(expectedInfo);
});
});

describe('defaultTransform', function () {
it('should do nothing to the info', function() {
const info = {
level: 'info',
service: 'account'
};

const formattedInfo = formatInput(info, null);
const expectedInfo = {
level: 'info',
service: 'account'
};

assume(formattedInfo).deep.equals(expectedInfo);
});
});
});
10 changes: 10 additions & 0 deletions test/unit/winston/logger.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const TransportStream = require('winston-transport');
const format = require('../../../lib/winston').format;
const helpers = require('../../helpers');
const mockTransport = require('../../helpers/mocks/mock-transport');
const mockEcsFormat = require('../../helpers/mocks/mock-ecsFormat');
const testLogFixturesPath = path.join(__dirname, '..', '..', 'fixtures', 'logs');

describe('Logger Instance', function () {
Expand Down Expand Up @@ -920,6 +921,15 @@ describe('Logger Instance', function () {
const log = logger.info;
log('test');
});

it('adjust defaultMeta correctly to given format', (done) => {
let logger = helpers.createLogger(function (info){
assume(info.service).is.a('object');
done();
}, mockEcsFormat(), {service: 'user-account'});
logger.log({level: 'info'});
});

});
});

Expand Down