UNPKG

5.25 kBJavaScriptView Raw
1const interceptor = require('./lib/interceptor');
2const Logger = require('./lib/logger');
3const utils = require('./lib/utils');
4const defaultResponseProcessor = require('./lib/default-response-processor');
5const LogStatusType = require('../utils/log-status-type');
6const _ = require('lodash');
7
8const logger = new Logger();
9const baseConfig = {
10 serviceName: '',
11 protectedFields: [
12 'password',
13 'currentPassword',
14 'newPassword',
15 'confirmationNewPassword',
16 ],
17 skip: [],
18 responseProcessor: defaultResponseProcessor
19};
20let config;
21
22const getType = (req) => {
23 const createMethods = [ 'POST' ];
24 const updateMethods = [ 'PUT', 'PATCH' ];
25 const deleteMethods = [ 'DELETE' ];
26 const readMethods = [ 'GET' ];
27 switch (true) {
28 case createMethods.indexOf(req.method) >= 0:
29 return 'Service Create';
30 case updateMethods.indexOf(req.method) >= 0:
31 return 'Service Update';
32 case deleteMethods.indexOf(req.method) >= 0:
33 return 'Service Delete';
34 case readMethods.indexOf(req.method) >= 0:
35 return 'Service Read';
36 default:
37 return 'Service Read';
38 }
39};
40
41const getData = req => {
42 return Object.assign({},
43 req.query,
44 req.params,
45 req.body
46 );
47};
48
49// removes object keys with "." in values and replace for the same thing but kebabCased
50const mongoiseKeys = data => {
51 if (_.isArray(data)) {
52 return data;
53 }
54
55 return Object.keys(data).reduce((accumulator, key) => {
56 const objKey = (key.indexOf('.') >= 0) ? _.kebabCase(key) : key
57 accumulator[objKey] = data[key];
58
59 return accumulator;
60 }, {});
61};
62
63const clearProtectedData = data => {
64 if (_.isArray(data)) {
65 return data;
66 }
67
68 return _.omit(data, config.protectedFields);
69};
70
71const executeResponseProcessor = (data, req) => {
72 const processedData = config.responseProcessor(data, req);
73 if (typeof data !== 'object') {
74 console.log('data processor return must be an object');
75 throw new Error('data processor return must be an object');
76 }
77
78 return _.omit(processedData);
79};
80
81const normalizeData = _.flow(
82 mongoiseKeys,
83 clearProtectedData,
84);
85
86const shouldLog = req => {
87 const allowedAction = req.method !== 'OPTIONS';
88 const allowedPath = !config.skip.some(pathToSkip => new RegExp(pathToSkip).test(req.originalUrl));
89 return allowedAction && allowedPath;
90}
91
92const logRequest = (req, res) => {
93 if (!shouldLog(req)) {
94 return false;
95 }
96
97 const type = getType(req);
98 const data = getData(req);
99 const result = 'trying';
100 const reason = `${config.serviceName} - ${req.originalUrl}`;
101 const system_id = req.system_id || _.get(req, 'user.system_id');
102 const contractorId = req.contractor_id;
103
104 if (!system_id) {
105 console.warn('you must pass system_id to be able to log it', req.originalUrl);
106 return false;
107 }
108
109 const promise = contractorId ?
110 logger.log(type, reason, _.omit(normalizeData(data)), result, system_id, contractorId) :
111 logger.broadcast(type, reason, _.omit(normalizeData(data)), result, system_id);
112
113 return promise.catch(error => handleError(error, config));
114};
115
116const logResponse = (req, response, result) => {
117 if (!shouldLog(req)) {
118 return false;
119 }
120
121 const type = getType(req);
122 const data = typeof response === 'object' ? response : { response };
123 const reason = `${config.serviceName} - ${req.originalUrl}`;
124 const system_id = req.system_id || _.get(req, 'user.system_id');
125 const contractorId = req.contractor_id || _.get(data, 'contractor_id');
126
127 if (!system_id) {
128 console.warn('you must pass system_id to be able to log it', req.originalUrl);
129 return false;
130 }
131
132
133 const promise = contractorId ?
134 logger.log(type, reason, executeResponseProcessor(normalizeData(data), req), result, system_id, contractorId) :
135 logger.broadcast(type, reason, executeResponseProcessor(normalizeData(data), req), result, system_id);
136
137 return promise.catch(error => handleError(error, config));
138};
139
140const configureLogResponse = (req, res) => {
141 interceptor.getResponseBody(res).then(responseBody => {
142 const response = utils.parseResponse(responseBody);
143 const responseStatus = _.get(response, 'statusLog[0].type') || LogStatusType.SUCCESS;
144 const data = _.get(response, 'data') || _.get(response, 'statusLog[0]') || response;
145
146 const status = responseStatus === LogStatusType.SUCCESS ? 'success' : 'error';
147 logResponse(req, data, status);
148 });
149};
150
151const configure = customConfig => (req, res, next) => {
152 try {
153 config = Object.assign({}, baseConfig, customConfig);
154
155 logger.setRequestMetaData(interceptor.getRequestMetadata(req));
156 logRequest(req, res);
157 configureLogResponse(req, res);
158 } catch (error) {
159 handleError(error, config);
160 }
161
162 next();
163};
164
165const handleError = (error, config) => {
166 const errorCode = _.get(error, 'code');
167 console.error(`there was an error when logging ${config.serviceName}. code:`, errorCode);
168};
169
170module.exports = {
171 configure,
172 logger,
173};