-
-
Notifications
You must be signed in to change notification settings - Fork 591
/
logging.ts
174 lines (155 loc) · 4.07 KB
/
logging.ts
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import os from 'os';
import * as winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import { Syslog } from 'winston-syslog';
import { LogToEvTransport, NoOpTransport } from './custom_transport';
const { combine, timestamp } = winston.format;
import traverse from "traverse";
import { klona } from "klona/full";
const truncateLength = 200;
let _evSet = false,
_consoleSet = false,
d = Date.now();
const sensitiveKeys = [
/cookie/i,
/sessionData/i,
/passw(or)?d/i,
/^pw$/,
/^pass$/i,
/secret/i,
/token/i,
/api[-._]?key/i,
];
function isSensitiveKey(keyStr) {
if (keyStr) {
return sensitiveKeys.some(regex => regex.test(keyStr));
}
}
function redactObject(obj) {
traverse(obj).forEach(function redactor() {
if (isSensitiveKey(this.key)) {
this.update("[REDACTED]");
} else if(typeof this.node === 'string' && this.node.length > truncateLength) {
this.update(truncate(this.node, truncateLength));
}
});
}
function redact(obj) {
const copy = klona(obj); // Making a deep copy to prevent side effects
redactObject(copy);
const splat = copy[Symbol.for("splat")];
redactObject(splat); // Specifically redact splat Symbol
return copy;
}
function truncate(str: string, n: number) {
return str.length > n ? str.substr(0, n - 1) + '...[TRUNCATED]...' : str;
}
const formatRedact = winston.format(redact);
/**
* To prevent "Attempt to write logs with no transports" error
*/
const placeholderTransport = new NoOpTransport()
const makeLogger = () =>
winston.createLogger({
format: combine(
timestamp(),
winston.format.json(),
formatRedact(),
winston.format.splat(),
winston.format.simple()
),
levels: winston.config.syslog.levels,
transports: [placeholderTransport]
});
/**
* You can access the log in your code and add your own custom transports
*/
export const log = makeLogger();
if(log.warning && !log.warn) log.warn = log.warning
if(log.alert && !log.help) log.help = log.alert
export const addRotateFileLogTransport = (options: any = {}) => {
log.add(
new DailyRotateFile({
filename: 'application-%DATE%.log',
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '2m',
maxFiles: '14d',
...options,
})
);
};
const addSysLogTransport = (options: any = {}) => {
log.add(
new Syslog({
localhost: os.hostname(),
...options,
})
);
};
const enableConsoleLogger = (options: any = {}) => {
if (_consoleSet) return;
log.add(
new winston.transports.Console({
level: 'debug',
timestamp: timestamp(),
...options,
} as any)
);
_consoleSet = true;
};
function enableLogToEv(options: any = {}) {
if (_evSet) return;
log.add(
new LogToEvTransport({
format: winston.format.json(),
...options,
})
);
_evSet = true;
}
export type ConfigLogTransport = {
/**
* The type of winston transport. At the moment only file, console, ev and syslog are supported.
*/
type: 'syslog' | 'console' | 'file' | 'ev';
/**
* The options for the transport. Generally only required for syslog but you can use this to override default options for other types of transports.
*/
options?: any;
done?: boolean;
};
export const setupLogging = (logging: ConfigLogTransport[], sessionId: string = "session") => {
const currentlySetup = [];
const _logging = logging.map((l) => {
if (l.done) return l;
if (l.type === 'console') {
enableConsoleLogger({
...(l.options || {}),
});
} else if (l.type === 'ev') {
enableLogToEv({
...(l.options || {}),
});
} else if (l.type === 'file') {
addRotateFileLogTransport({
...(l.options || {}),
});
} else if (l.type === 'syslog') {
addSysLogTransport({
...(l.options || {}),
appName: `owa-${sessionId}-${d}`
});
}
currentlySetup.push(l);
return {
...l,
done: true,
};
});
currentlySetup.map((l) => {
log.info(`Set up logging for ${l.type}`, l.options);
return l;
});
return _logging;
};