-
Notifications
You must be signed in to change notification settings - Fork 143
/
logger.js
150 lines (137 loc) · 4.48 KB
/
logger.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const winston = require('winston');
const loggers = {};
const SPLAT = Symbol.for('splat');
const util = require('util');
const safeStringify = require('fast-safe-stringify');
// looks odd, but this is the most efficient way of padding strings in js
const padding = ' ';
// define the formatter for Winston
// this is aimed at being a singleton
const formatter = name => winston.format.combine(
winston.format.timestamp(),
winston.format.metadata({fillExcept: ['message', 'level', 'timestamp', 'label']}),
winston.format.colorize(),
winston.format.padLevels(),
winston.format.printf((info) => {
const {timestamp, level, message} = info;
const str = (`[c-api:${name}]` + padding).substring(0, padding.length);
let out = '';
if (info[SPLAT]) {
out = info[SPLAT].map(e => {
if (e && e.error) {
if (e.error.stack) {
return e.error.stack;
} else {
return e.error.message;
}
} else {
return safeStringify(e);
}
});
}
return `${timestamp} ${level} ${str} ${message} ${out} `;
}
)
);
// a console based transport, again a singleton
let transport;
const getTransport = () => {
if (!transport) {
transport = new winston.transports.Console({
handleExceptions: false,
});
}
return transport;
};
// create a logger
// there is no hierachy or split of loggers; one for future versions
function createLogger (loglevel, name) {
const logger = new winston.createLogger({
level: loglevel,
format: formatter(name),
transports: [
getTransport()
],
exitOnError: false
});
return logger;
}
// map the Hyperledger Fabric standard strings to the matching Winston ones
const levelMapping = (level) => {
let loglevel = 'info';
if (typeof level === 'string') {
switch (level.toUpperCase()) {
case 'CRITICAL':
loglevel = 'fatal';
break;
case 'ERROR':
loglevel = 'error';
break;
case 'WARNING':
loglevel = 'warn';
break;
case 'DEBUG':
loglevel = 'debug';
break;
case 'INFO':
loglevel = 'info';
}
}
return loglevel;
};
// Exported function to get the logger for a given name
module.exports.getLogger = function (name = '') {
// set the logging level based on the environment variable
// configured by the peer
const loglevel = levelMapping(process.env.CORE_CHAINCODE_LOGGING_LEVEL);
let logger;
if (loggers[name]) {
logger = loggers[name];
logger.level = loglevel;
} else {
logger = createLogger(loglevel, name);
loggers[name] = logger;
}
return logger;
};
// Specifically set the logging level
module.exports.setLevel = (level) => {
// set the level of all the loggers currently active
const loglevel = levelMapping(level);
process.env.CORE_CHAINCODE_LOGGING_LEVEL = loglevel;
Object.keys(loggers).forEach((name) => {
loggers[name].level = loglevel;
});
};
// This function is intended for once only use; it will setup a logger
// that will response to the unhanldedExceptions and the unhandledRejections
// Having too many transports that have handleExceptions = true results in
// node warnings about memory leaks.
function firstTime () {
if (!loggers._) {
const loglevel = levelMapping(process.env.CORE_CHAINCODE_LOGGING_LEVEL);
loggers._ = new winston.createLogger({
level: loglevel,
format: formatter('_'),
transports: [
new winston.transports.Console({
handleExceptions: true,
})
],
exitOnError: false
});
if (!process.listeners('unhandledRejection').some(e => e.name === 'loggerUnhandledRejectionFn')) {
const loggerUnhandledRejectionFn = (reason, p) => {
loggers._.error('Unhandled Rejection reason ' + reason + ' promise ' + util.inspect(p));
};
process.on('unhandledRejection', loggerUnhandledRejectionFn);
}
}
}
firstTime();