Skip to content

Commit

Permalink
Add custom functions for start and finish messages (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
picollomartin authored Jul 13, 2020
1 parent 8639507 commit bfe9ad7
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 24 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ The exported `expressRequestIdMiddleware` function takes one argument, [`options
#### `options` (Object)

##### `loggerFn` (Function)
Logger function used for start and end log actions.
Logger function used for start and end log actions with the default message format.

##### `startFn` (Function)
Function used in start log actions, mainly for custom messages.

##### `endFn` (Function)
Function used in end log actions, mainly for custom messages.

##### `obfuscatePlaceholder` (String)
Default: [SECURE]
Expand Down
42 changes: 32 additions & 10 deletions lib/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,39 @@ const getSecureBody = ({ params, url, method, body, placeholder }) => {
}
};

const logStartMsg = ({ req, formattedBody, loggerFn, startFn }) => {
if (startFn) {
return startFn({ req, formattedBody });
}

const { method, params, query } = req;
const url = req.originalUrl || req.url;
return loggerFn(
`Started ${url} ${method} with params: %j query: %j body: %j`,
params || {},
query || {},
formattedBody || {}
);
};

const logEndMsg = ({ req, res, loggerFn, endFn, responseTime }) => {
if (endFn) {
return endFn({ req, res, responseTime });
}

const { method } = req;
const url = req.originalUrl || req.url;
const status = res.statusCode;
return loggerFn(`Ended ${method} ${url} with status: ${status} in ${responseTime} ms`);
};

const expressMiddleware = opts => {
// TODO: add a check that all the config is safe
const { loggerFn, obfuscateBody = true, obfuscatePlaceholder = secure } = opts || {};
const { loggerFn, startFn, endFn, obfuscateBody = true, obfuscatePlaceholder = secure } = opts || {};
if (!loggerFn && (!startFn || !endFn)) throw Error('You need to define a loggerFn or a startFn and endFn');

return (req, res, next) => {
const { method, params, query, body } = req;
const { method, body } = req;
const url = req.originalUrl || req.url;
const formattedBody = getSecureBody({
params: obfuscateBody,
Expand All @@ -37,18 +65,12 @@ const expressMiddleware = opts => {
placeholder: obfuscatePlaceholder
});

loggerFn(
`Started ${url} ${method} with params: %j query: %j body: %j`,
params || {},
query || {},
formattedBody || {}
);
logStartMsg({ req, formattedBody, loggerFn, startFn });
const begin = Date.now();
const onFinish = namespace.bind((error, response) => {
const end = Date.now();
const responseTime = error ? '-' : end - begin;
const status = response.statusCode;
loggerFn(`Ended ${method} ${url} with status: ${status} in ${responseTime} ms`);
logEndMsg({ req, res: response, loggerFn, endFn, responseTime });
});
onFinished(res, onFinish);
next();
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "express-wolox-logger",
"version": "3.0.0",
"version": "3.1.0",
"description": "ExpressJS Wolox Logger",
"main": "index.js",
"scripts": {
Expand Down
48 changes: 37 additions & 11 deletions test/middlewares.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,75 @@ describe('middlewares', () => {
const testUrl = '/test_url';
const makeRequest = (server, method = 'get') => request(server)[method](testUrl);

describe('express middleware', () => {
const startFn = jest.fn();
const endFn = jest.fn();
const middlewaresScenarios = [
['with loggerFn', { config: {} }],
['with custom hooks', { config: { startFn, endFn } }]
];

describe.each(middlewaresScenarios)('express middleware (%s)', (name, scenario) => {
const loggerMock = jest.spyOn(logger, 'info').mockImplementation(() => {}); // eslint-disable-line
const server = options =>
createServer(
expressMiddleware({
loggerFn: logger.info,
...scenario.config,
...options
})
);

afterEach(() => {
startFn.mockClear();
endFn.mockClear();
loggerMock.mockClear();
});

const getLoggerCalledParams = num => loggerMock.mock.calls[num].map(JSON.stringify).join('');

const getLoggerMsg = () =>
loggerMock.mock.calls.length > 0 ? getLoggerCalledParams(0) : startFn.mock.calls[0][0].formattedBody;

test('should log when request starts', done => {
makeRequest(server()).end(() => {
expect(getLoggerCalledParams(0)).toEqual(
expect.stringMatching(/Started \/test_url GET with params:.*query:.*body.*/)
);
if (scenario.config.startFn) {
expect(startFn).toHaveBeenCalledTimes(1);
} else {
expect(getLoggerCalledParams(0)).toEqual(
expect.stringMatching(/Started \/test_url GET with params:.*query:.*body.*/)
);
}
done();
});
});
test('should log when request finishes', done => {
makeRequest(server()).end(() => {
expect(getLoggerCalledParams(1)).toEqual(
expect.stringMatching(/Ended GET \/test_url with status: [2-5]+00 in [0-9]+ ms/)
);
if (scenario.config.endFn) {
expect(endFn).toHaveBeenCalledTimes(1);
} else {
expect(getLoggerCalledParams(1)).toEqual(
expect.stringMatching(/Ended GET \/test_url with status: [2-5]+00 in [0-9]+ ms/)
);
}
done();
});
});

test('should obfuscate full body of any endpoint', done => {
makeRequest(server({ obfuscateBody: true }), 'post')
.send({ secure: 'secretValue' })
.end(() => {
expect(getLoggerCalledParams(0)).toContain('[SECURE]');
expect(getLoggerCalledParams(0)).not.toContain('secretValue');
expect(getLoggerMsg()).toContain('[SECURE]');
expect(getLoggerMsg()).not.toContain('secretValue');
done();
});
});
test('should obfuscate full body of specific endpoint', done => {
makeRequest(server({ obfuscateBody: { [testUrl]: { POST: true } } }), 'post')
.send({ secure: 'secretValue' })
.end(() => {
expect(getLoggerCalledParams(0)).toContain('[SECURE]');
expect(getLoggerCalledParams(0)).not.toContain('secretValue');
expect(getLoggerMsg()).toContain('[SECURE]');
expect(getLoggerMsg()).not.toContain('secretValue');
done();
});
});
Expand Down

0 comments on commit bfe9ad7

Please sign in to comment.