-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathcloud-sdk-logger.ts
218 lines (195 loc) · 6.91 KB
/
cloud-sdk-logger.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import {
Container,
Logger,
LoggerOptions as WinstonLoggerOptions,
transports
} from 'winston';
import { kibana, local } from './format';
const format = process.env.VCAP_SERVICES ? kibana : local;
const loggerReference = 'sap-cloud-sdk-logger';
const exceptionLoggerId = 'sap-cloud-sdk-exception-logger';
const container = new Container();
const exceptionTransport = new transports.Console();
const customLogLevels = {};
const DEFAULT_LOGGER__MESSAGE_CONTEXT = '__DEFAULT_LOGGER__MESSAGE_CONTEXT';
let silent = false;
const moduleLogger = createLogger({
package: 'util',
messageContext: 'cloud-sdk-logger'
});
function toggleMuteLoggers(silence: boolean) {
silent = silence;
container.loggers.forEach(logger => toggleSilenceTransports(logger, silence));
}
function toggleSilenceTransports(logger: Logger, silence: boolean) {
logger.transports.forEach(transport => (transport.silent = silence));
}
/**
* Mute all logger output created by the SAP Cloud SDK Logger. This also applies to future loggers created. Useful for tests.
*/
export function muteLoggers() {
toggleMuteLoggers(true);
}
/**
* Unmute all logger output created by the SAP Cloud SDK Logger. This also applies to future loggers created. Useful for tests.
*/
export function unmuteLoggers() {
toggleMuteLoggers(false);
}
/**
* Default logger for the SAP Cloud SDK for unhandled exceptions.
*/
export const cloudSdkExceptionLogger = container.get(exceptionLoggerId, {
defaultMeta: { logger: loggerReference, test: 'exception' },
format,
exceptionHandlers: [exceptionTransport]
});
/**
* Disable logging of exceptions. Enabled by default.
*/
export function disableExceptionLogger() {
cloudSdkExceptionLogger.exceptions.unhandle();
}
/**
* Enable logging of exceptions. Enabled by default.
*/
export function enableExceptionLogger() {
// Flush all possible handlers to make sure there is only one in the end.
disableExceptionLogger();
cloudSdkExceptionLogger.exceptions.handle(exceptionTransport);
}
/**
* Create a logger for the given message context, if available.
*
* Usage:
* To create a logger in your module, it is recommended to pass a module identifier that will be logged as `messageContext` for all messages from this logger:
* `const logger = createLogger('my-module');`. Not setting any module identifier will retrieve the default logger.
* Use this logger throughout your module. If the module is spread over multiple files, you can retrieve the logger instance by calling the `createLogger` function with the respective module identifier.
* There will always be only one instance of a logger per module identifier.
* You can pass any custom data that you want to be logged in addition by passing an object instead. You can change the default logging level (`INFO`) using the `level` key in the object.
* In those cases, provide the `messageContext` as a key in the object:
* ```
* const logger = createLogger({
* messageContext: 'my-module',
* myCustomKey: 'my-custom-data',
* level: 'debug'
* });
* ```
* You will find these information under the _custom_fields_ key in your Cloud Foundry logs.
*
* To retrieve a logger after its creation use [[getLogger]].
* If you want to change the log level of a logger use [[setLogLevel]].
*
* @param messageContext - Either a key for the message context of all messages produced by the logger or an object with additional keys to set in the message.
* @returns A newly created or an already existing logger for the given context.
*/
export function createLogger(
messageContext?: string | (MessageContextObj & LoggerOptions)
): Logger {
const customFields: { [key: string]: any } =
typeof messageContext === 'string'
? { messageContext }
: { ...messageContext };
const logger = container.get(customFields.messageContext, {
level:
customLogLevels[customFields.messageContext] ||
customFields.level ||
container.options.level ||
'info',
defaultMeta: {
...(Object.entries(customFields).length && {
custom_fields: customFields
}),
logger: customFields.logger || loggerReference
},
format,
transports: [new transports.Console()]
});
toggleSilenceTransports(logger, silent);
return logger;
}
/**
* Get logger for a given message context, if avilable.
* @param messageContext - A key for the message context of all messages produced by the logger
* @returns The logger for the given messageContext if it was created before
*/
export function getLogger(
messageContext = DEFAULT_LOGGER__MESSAGE_CONTEXT
): Logger | undefined {
if (container.has(messageContext)) {
return container.get(messageContext);
}
}
/**
* Change the log level of a logger based on its message context.
* E. g., to set the log level for the destination accessor module of the SDK to _debug_, simply call `setLogLevel('debug', 'destination-acessor')`.
* @param level - level to set the logger to. Use an empty string '' as level to unset context level.
* @param messageContextOrLogger - Message context of the logger to change the log level for or the logger itself
*/
export function setLogLevel(
level: LogLevel | '',
messageContextOrLogger: string | Logger = DEFAULT_LOGGER__MESSAGE_CONTEXT
): void {
const messageContext =
typeof messageContextOrLogger === 'string'
? messageContextOrLogger
: getMessageContext(messageContextOrLogger);
if (messageContext) {
customLogLevels[messageContext] = level;
if (container.has(messageContext)) {
const logger = container.get(messageContext);
logger.level = level;
}
} else if (typeof messageContextOrLogger !== 'string') {
moduleLogger.warn(
'Setting log level for logger with unknown message context'
);
messageContextOrLogger.level = level;
}
}
/**
* Change the global log level of the container which will set default level for all active loggers.
* E. g., to set the global log level call `setGlobalLogLevel('debug')`.
* @param level: LogLevel
*/
export function setGlobalLogLevel(level: LogLevel): void {
container.options.level = level;
}
export function getGlobalLogLevel(): string | undefined {
return container.options.level;
}
function getMessageContext(logger: Logger): string | undefined {
// This is a workaround for the missing defaultMeta property on the winston logger.
const loggerOptions = logger as WinstonLoggerOptions;
if (
loggerOptions &&
loggerOptions.defaultMeta &&
loggerOptions.defaultMeta.custom_fields
) {
return loggerOptions.defaultMeta.custom_fields.messageContext;
}
}
/**
* Npm log levels used for the SAP Cloud SDK logger.
*/
export type LogLevel =
| 'error'
| 'warn'
| 'info'
| 'verbose'
| 'debug'
| 'silly';
/**
* Configurable logger options.
*/
export interface LoggerOptions {
level?: LogLevel;
logger?: string;
}
/**
* Log message context for a logger with additional custom data.
*/
export interface MessageContextObj {
messageContext?: string;
[key: string]: any;
}