@mhmdhammoud/meritt-utils 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReleaseNotes.md +4 -0
- package/dist/__tests__/logger.test.d.ts +1 -0
- package/dist/__tests__/logger.test.js +100 -0
- package/dist/lib/logger.d.ts +45 -30
- package/dist/lib/logger.js +123 -69
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +17 -0
- package/dist/types/logger.d.ts +47 -0
- package/dist/types/logger.js +2 -0
- package/package.json +5 -4
- package/src/__tests__/logger.test.ts +88 -0
- package/src/lib/logger.ts +116 -137
- package/src/types/index.ts +1 -0
- package/src/types/logger.ts +49 -0
- package/src/config/index.ts +0 -1
- package/src/config/logger-config.ts +0 -73
package/ReleaseNotes.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## Version 1.4.0
|
|
4
|
+
|
|
5
|
+
- Changed winston logger to Pino logger to improve performance and reduce memory usage
|
|
6
|
+
|
|
3
7
|
## Version 1.3.0
|
|
4
8
|
|
|
5
9
|
- Added toUpperTitle method that accepts a string and removes all non alphanumeric characters and capitalizes each letter of every first word
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const logger_1 = __importStar(require("../lib/logger"));
|
|
27
|
+
const pino_1 = require("pino");
|
|
28
|
+
jest.mock('pino');
|
|
29
|
+
const LOGGER_NAME = 'logger-name';
|
|
30
|
+
const PINO_DESTINATION = {};
|
|
31
|
+
const PINO = {
|
|
32
|
+
info: jest.fn(),
|
|
33
|
+
};
|
|
34
|
+
describe('create logger wrapper', () => {
|
|
35
|
+
test('initially create & configure logger', () => {
|
|
36
|
+
//@ts-ignore
|
|
37
|
+
const mock_pino_destination = jest
|
|
38
|
+
.spyOn(pino_1.pino, 'destination')
|
|
39
|
+
//@ts-ignore
|
|
40
|
+
.mockReturnValue(PINO_DESTINATION);
|
|
41
|
+
//@ts-ignore
|
|
42
|
+
const mock_pino = pino_1.pino.mockReturnValue(PINO);
|
|
43
|
+
/** create logger */
|
|
44
|
+
const logger = new logger_1.default(LOGGER_NAME);
|
|
45
|
+
expect(logger).toBeDefined();
|
|
46
|
+
expect(logger['_name']).toBe(LOGGER_NAME);
|
|
47
|
+
expect(mock_pino).toHaveBeenCalledTimes(1);
|
|
48
|
+
expect(mock_pino).toHaveBeenCalledWith({
|
|
49
|
+
level: 'info',
|
|
50
|
+
timestamp: expect.any(Function),
|
|
51
|
+
}, PINO_DESTINATION);
|
|
52
|
+
expect(mock_pino_destination).toHaveBeenCalledWith({
|
|
53
|
+
minLength: 1024,
|
|
54
|
+
sync: true,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
test('create repeatedly - stick to pino singleton', () => {
|
|
58
|
+
//@ts-ignore
|
|
59
|
+
jest.spyOn(pino_1.pino, 'destination').mockReturnValue(PINO_DESTINATION);
|
|
60
|
+
//@ts-ignore
|
|
61
|
+
const mock_pino = pino_1.pino.mockReturnValue(PINO);
|
|
62
|
+
new logger_1.default(LOGGER_NAME);
|
|
63
|
+
expect(mock_pino).toHaveBeenCalledTimes(1);
|
|
64
|
+
/** create additional logger */
|
|
65
|
+
new logger_1.default(LOGGER_NAME);
|
|
66
|
+
/** no new pino created */
|
|
67
|
+
expect(mock_pino).toHaveBeenCalledTimes(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('validate log level', () => {
|
|
71
|
+
test('throw on invalid log level', () => {
|
|
72
|
+
const INVALID_LOG_LEVEL = 'invalid-log-level';
|
|
73
|
+
expect(() => {
|
|
74
|
+
(0, logger_1.isValidLogLevel)(INVALID_LOG_LEVEL);
|
|
75
|
+
}).toThrowError(`Invalid log level "${INVALID_LOG_LEVEL}": only error, warn, info, debug, trace are valid.`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('route and format logs', () => {
|
|
79
|
+
const LOG_EVENT = {
|
|
80
|
+
code: 'code',
|
|
81
|
+
msg: 'message',
|
|
82
|
+
};
|
|
83
|
+
const DETAILS = {
|
|
84
|
+
key0: 'val0',
|
|
85
|
+
key1: 'val1',
|
|
86
|
+
};
|
|
87
|
+
test('log info with details', () => {
|
|
88
|
+
//@ts-ignore
|
|
89
|
+
jest.spyOn(pino_1.pino, 'destination').mockReturnValue(PINO_DESTINATION);
|
|
90
|
+
//@ts-ignore
|
|
91
|
+
pino_1.pino.mockReturnValue(PINO);
|
|
92
|
+
const logger = new logger_1.default(LOGGER_NAME);
|
|
93
|
+
logger.info(LOG_EVENT, DETAILS);
|
|
94
|
+
expect(PINO.info).toHaveBeenCalledWith({
|
|
95
|
+
component: LOGGER_NAME,
|
|
96
|
+
...LOG_EVENT,
|
|
97
|
+
detail: [DETAILS],
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
package/dist/lib/logger.d.ts
CHANGED
|
@@ -1,43 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ElasticConfig, LOG_LEVEL, LogEvent } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Checks if a given log level is valid.
|
|
4
|
+
* @param level - The log level to check.
|
|
5
|
+
* @returns Whether the log level is valid.
|
|
4
6
|
*/
|
|
5
|
-
declare
|
|
6
|
-
|
|
7
|
+
export declare function isValidLogLevel(level: string): level is LOG_LEVEL;
|
|
8
|
+
/**
|
|
9
|
+
* Logger Wrapper.
|
|
10
|
+
* Wraps a Pino logger instance and provides logging methods.
|
|
11
|
+
*/
|
|
12
|
+
declare class Logger {
|
|
13
|
+
private readonly _name;
|
|
14
|
+
private readonly _logger;
|
|
7
15
|
/**
|
|
8
|
-
* Creates
|
|
9
|
-
* @param
|
|
16
|
+
* Creates a new Logger instance with default configuration.
|
|
17
|
+
* @param name - The name of the logger.
|
|
10
18
|
*/
|
|
11
|
-
constructor(
|
|
19
|
+
constructor(name: string);
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
* Creates a new Logger instance with custom Elasticsearch configuration.
|
|
22
|
+
* @param name - The name of the logger.
|
|
23
|
+
* @param elasticConfig - Optional Elasticsearch configuration.
|
|
24
|
+
*/
|
|
25
|
+
constructor(name: string, elasticConfig?: ElasticConfig);
|
|
26
|
+
private log;
|
|
27
|
+
/**
|
|
28
|
+
* Logs an error message.
|
|
29
|
+
* @param logEvent - The event to log.
|
|
30
|
+
* @param args - Additional arguments to include in the log.
|
|
19
31
|
*/
|
|
20
|
-
|
|
32
|
+
error(logEvent: LogEvent, ...args: unknown[]): void;
|
|
21
33
|
/**
|
|
22
34
|
* Logs a warning message.
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @param logMessage - The log message text.
|
|
26
|
-
* @param userIp - The user's IP address associated with the log.
|
|
27
|
-
* @param data - Additional data associated with the log.
|
|
35
|
+
* @param logEvent - The event to log.
|
|
36
|
+
* @param args - Additional arguments to include in the log.
|
|
28
37
|
*/
|
|
29
|
-
warn(
|
|
38
|
+
warn(logEvent: LogEvent, ...args: unknown[]): void;
|
|
30
39
|
/**
|
|
31
|
-
* Logs an
|
|
32
|
-
* @param
|
|
33
|
-
* @param
|
|
34
|
-
* @param logMessage - The log message text.
|
|
35
|
-
* @param userIp - The user's IP address associated with the log.
|
|
36
|
-
* @param data - Additional data associated with the log.
|
|
40
|
+
* Logs an informational message.
|
|
41
|
+
* @param logEvent - The event to log.
|
|
42
|
+
* @param args - Additional arguments to include in the log.
|
|
37
43
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
info(logEvent: LogEvent, ...args: unknown[]): void;
|
|
45
|
+
/**
|
|
46
|
+
* Logs a debug message.
|
|
47
|
+
* @param logEvent - The event to log.
|
|
48
|
+
* @param args - Additional arguments to include in the log.
|
|
49
|
+
*/
|
|
50
|
+
debug(logEvent: LogEvent, ...args: unknown[]): void;
|
|
51
|
+
/**
|
|
52
|
+
* Logs a trace message.
|
|
53
|
+
* @param logEvent - The event to log.
|
|
54
|
+
* @param args - Additional arguments to include in the log.
|
|
55
|
+
*/
|
|
56
|
+
trace(logEvent: LogEvent, ...args: unknown[]): void;
|
|
41
57
|
}
|
|
42
|
-
declare const Logger: LoggerService;
|
|
43
58
|
export default Logger;
|
package/dist/lib/logger.js
CHANGED
|
@@ -1,92 +1,146 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
const
|
|
29
|
+
exports.isValidLogLevel = void 0;
|
|
30
|
+
const pino_1 = require("pino");
|
|
31
|
+
const dotenv = __importStar(require("dotenv"));
|
|
32
|
+
const pino_elasticsearch_1 = __importDefault(require("pino-elasticsearch"));
|
|
33
|
+
dotenv.config();
|
|
8
34
|
/**
|
|
9
|
-
*
|
|
35
|
+
* Pino logger backend - singleton
|
|
10
36
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
let pinoLogger;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a Pino logger instance with specified Elasticsearch configuration.
|
|
40
|
+
* @param elasticConfig - Optional Elasticsearch configuration.
|
|
41
|
+
* @returns The Pino logger instance.
|
|
42
|
+
*/
|
|
43
|
+
function getLogger(elasticConfig) {
|
|
44
|
+
if (!pinoLogger) {
|
|
45
|
+
if (isValidLogLevel(process.env.LOG_LEVEL)) {
|
|
46
|
+
const transports = [];
|
|
47
|
+
if (process.env.NODE_ENV !== 'local' && process.env.NODE_ENV !== 'test') {
|
|
48
|
+
const esConfig = {
|
|
49
|
+
index: process.env.SERVER_NICKNAME,
|
|
50
|
+
node: process.env.ELASTICSEARCH_NODE,
|
|
51
|
+
auth: {
|
|
52
|
+
username: process.env.ELASTICSEARCH_USERNAME,
|
|
53
|
+
password: process.env.ELASTICSEARCH_PASSWORD,
|
|
54
|
+
},
|
|
55
|
+
flushInterval: 10000,
|
|
56
|
+
};
|
|
57
|
+
if (elasticConfig) {
|
|
58
|
+
Object.assign(esConfig, elasticConfig);
|
|
59
|
+
}
|
|
60
|
+
const esTransport = (0, pino_elasticsearch_1.default)(esConfig);
|
|
61
|
+
transports.push(esTransport);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
transports.push(pino_1.pino.destination({
|
|
65
|
+
minLength: 1024,
|
|
66
|
+
sync: true,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
pinoLogger = (0, pino_1.pino)({
|
|
70
|
+
level: process.env.LOG_LEVEL,
|
|
71
|
+
timestamp: pino_1.stdTimeFunctions.isoTime.bind(pino_1.stdTimeFunctions),
|
|
72
|
+
}, ...transports);
|
|
29
73
|
}
|
|
30
|
-
|
|
74
|
+
}
|
|
75
|
+
return pinoLogger;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a given log level is valid.
|
|
79
|
+
* @param level - The log level to check.
|
|
80
|
+
* @returns Whether the log level is valid.
|
|
81
|
+
*/
|
|
82
|
+
function isValidLogLevel(level) {
|
|
83
|
+
if (!['error', 'warn', 'info', 'debug', 'trace'].includes(level)) {
|
|
84
|
+
throw new Error(`Invalid log level "${level}": only error, warn, info, debug, trace are valid.`);
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
exports.isValidLogLevel = isValidLogLevel;
|
|
89
|
+
/**
|
|
90
|
+
* Logger Wrapper.
|
|
91
|
+
* Wraps a Pino logger instance and provides logging methods.
|
|
92
|
+
*/
|
|
93
|
+
class Logger {
|
|
94
|
+
constructor(name, elasticConfig) {
|
|
95
|
+
this._name = name;
|
|
96
|
+
this._logger = getLogger(elasticConfig);
|
|
97
|
+
}
|
|
98
|
+
log(logLevel, logEvent, ...args) {
|
|
99
|
+
this._logger[logLevel]({
|
|
100
|
+
component: this._name,
|
|
101
|
+
...logEvent,
|
|
102
|
+
detail: args,
|
|
103
|
+
});
|
|
31
104
|
}
|
|
32
105
|
/**
|
|
33
|
-
* Logs an
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
36
|
-
* @param logMessage - The log message text.
|
|
37
|
-
* @param userIp - The user's IP address associated with the log.
|
|
38
|
-
* @param data - Additional data associated with the log.
|
|
106
|
+
* Logs an error message.
|
|
107
|
+
* @param logEvent - The event to log.
|
|
108
|
+
* @param args - Additional arguments to include in the log.
|
|
39
109
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.log('info', message);
|
|
110
|
+
error(logEvent, ...args) {
|
|
111
|
+
this.log('error', logEvent, ...args);
|
|
43
112
|
}
|
|
44
113
|
/**
|
|
45
114
|
* Logs a warning message.
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
48
|
-
* @param logMessage - The log message text.
|
|
49
|
-
* @param userIp - The user's IP address associated with the log.
|
|
50
|
-
* @param data - Additional data associated with the log.
|
|
115
|
+
* @param logEvent - The event to log.
|
|
116
|
+
* @param args - Additional arguments to include in the log.
|
|
51
117
|
*/
|
|
52
|
-
warn(
|
|
53
|
-
|
|
54
|
-
this.log('warn', message);
|
|
118
|
+
warn(logEvent, ...args) {
|
|
119
|
+
this.log('warn', logEvent, ...args);
|
|
55
120
|
}
|
|
56
121
|
/**
|
|
57
|
-
* Logs an
|
|
58
|
-
* @param
|
|
59
|
-
* @param
|
|
60
|
-
* @param logMessage - The log message text.
|
|
61
|
-
* @param userIp - The user's IP address associated with the log.
|
|
62
|
-
* @param data - Additional data associated with the log.
|
|
122
|
+
* Logs an informational message.
|
|
123
|
+
* @param logEvent - The event to log.
|
|
124
|
+
* @param args - Additional arguments to include in the log.
|
|
63
125
|
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.log('error', message);
|
|
126
|
+
info(logEvent, ...args) {
|
|
127
|
+
this.log('info', logEvent, ...args);
|
|
67
128
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
129
|
+
/**
|
|
130
|
+
* Logs a debug message.
|
|
131
|
+
* @param logEvent - The event to log.
|
|
132
|
+
* @param args - Additional arguments to include in the log.
|
|
133
|
+
*/
|
|
134
|
+
debug(logEvent, ...args) {
|
|
135
|
+
this.log('debug', logEvent, ...args);
|
|
76
136
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
this.logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
85
|
-
});
|
|
86
|
-
process.on('uncaughtException', (err) => {
|
|
87
|
-
this.logger.error('Uncaught Exception:', err);
|
|
88
|
-
});
|
|
137
|
+
/**
|
|
138
|
+
* Logs a trace message.
|
|
139
|
+
* @param logEvent - The event to log.
|
|
140
|
+
* @param args - Additional arguments to include in the log.
|
|
141
|
+
*/
|
|
142
|
+
trace(logEvent, ...args) {
|
|
143
|
+
this.log('trace', logEvent, ...args);
|
|
89
144
|
}
|
|
90
145
|
}
|
|
91
|
-
const Logger = new LoggerService(config_1.WinstonConfiguaration);
|
|
92
146
|
exports.default = Logger;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './logger';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./logger"), exports);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log levels
|
|
3
|
+
*/
|
|
4
|
+
export type LOG_LEVEL = 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
|
5
|
+
/**
|
|
6
|
+
* Represents a log event.
|
|
7
|
+
*/
|
|
8
|
+
export interface LogEvent {
|
|
9
|
+
/**
|
|
10
|
+
* The code associated with the log event.
|
|
11
|
+
*/
|
|
12
|
+
code: string;
|
|
13
|
+
/**
|
|
14
|
+
* The message describing the log event.
|
|
15
|
+
*/
|
|
16
|
+
msg: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Configuration options for Elasticsearch.
|
|
20
|
+
*/
|
|
21
|
+
export interface ElasticConfig {
|
|
22
|
+
/**
|
|
23
|
+
* The Elasticsearch index to write logs to.
|
|
24
|
+
*/
|
|
25
|
+
index?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The URL of the Elasticsearch node.
|
|
28
|
+
*/
|
|
29
|
+
node?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Authentication details for accessing Elasticsearch.
|
|
32
|
+
*/
|
|
33
|
+
auth?: {
|
|
34
|
+
/**
|
|
35
|
+
* The username for authentication.
|
|
36
|
+
*/
|
|
37
|
+
username: string;
|
|
38
|
+
/**
|
|
39
|
+
* The password for authentication.
|
|
40
|
+
*/
|
|
41
|
+
password: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The interval (in milliseconds) at which logs are flushed to Elasticsearch.
|
|
45
|
+
*/
|
|
46
|
+
flushInterval?: number;
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mhmdhammoud/meritt-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"private": false,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"dev-ts": "ts-node-dev --respawn --transpile-only src/index.ts",
|
|
16
|
+
"dev-ts": "ts-node-dev --respawn --transpile-only src/index.ts | pino-pretty",
|
|
17
17
|
"dev": "nodemon ./dist/index.js",
|
|
18
18
|
"watch": "tsc --watch",
|
|
19
19
|
"build": "tsc",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"eslint-plugin-tsdoc": "^0.2.14",
|
|
33
33
|
"husky": "^8.0.0",
|
|
34
34
|
"jest": "^29.7.0",
|
|
35
|
+
"pino-pretty": "^10.3.1",
|
|
35
36
|
"ts-jest": "^29.1.1",
|
|
36
37
|
"ts-node-dev": "^1.1.8",
|
|
37
38
|
"typescript": "^4.6.3"
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"axios": "^1.4.0",
|
|
43
44
|
"dotenv": "^16.4.1",
|
|
44
45
|
"imagesloaded": "^5.0.0",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
46
|
+
"pino": "^8.19.0",
|
|
47
|
+
"pino-elasticsearch": "^8.0.0"
|
|
47
48
|
}
|
|
48
49
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import Logger, {isValidLogLevel} from '../lib/logger'
|
|
2
|
+
import {pino} from 'pino'
|
|
3
|
+
|
|
4
|
+
jest.mock('pino')
|
|
5
|
+
|
|
6
|
+
const LOGGER_NAME = 'logger-name'
|
|
7
|
+
const PINO_DESTINATION = {}
|
|
8
|
+
const PINO = {
|
|
9
|
+
info: jest.fn(),
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('create logger wrapper', () => {
|
|
13
|
+
test('initially create & configure logger', () => {
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
const mock_pino_destination = jest
|
|
16
|
+
.spyOn(pino, 'destination')
|
|
17
|
+
//@ts-ignore
|
|
18
|
+
.mockReturnValue(PINO_DESTINATION)
|
|
19
|
+
//@ts-ignore
|
|
20
|
+
const mock_pino = pino.mockReturnValue(PINO)
|
|
21
|
+
|
|
22
|
+
/** create logger */
|
|
23
|
+
const logger = new Logger(LOGGER_NAME)
|
|
24
|
+
|
|
25
|
+
expect(logger).toBeDefined()
|
|
26
|
+
expect(logger['_name']).toBe(LOGGER_NAME)
|
|
27
|
+
expect(mock_pino).toHaveBeenCalledTimes(1)
|
|
28
|
+
expect(mock_pino).toHaveBeenCalledWith(
|
|
29
|
+
{
|
|
30
|
+
level: 'info',
|
|
31
|
+
timestamp: expect.any(Function),
|
|
32
|
+
},
|
|
33
|
+
PINO_DESTINATION
|
|
34
|
+
)
|
|
35
|
+
expect(mock_pino_destination).toHaveBeenCalledWith({
|
|
36
|
+
minLength: 1024,
|
|
37
|
+
sync: true,
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
test('create repeatedly - stick to pino singleton', () => {
|
|
41
|
+
//@ts-ignore
|
|
42
|
+
jest.spyOn(pino, 'destination').mockReturnValue(PINO_DESTINATION)
|
|
43
|
+
//@ts-ignore
|
|
44
|
+
const mock_pino = pino.mockReturnValue(PINO)
|
|
45
|
+
new Logger(LOGGER_NAME)
|
|
46
|
+
expect(mock_pino).toHaveBeenCalledTimes(1)
|
|
47
|
+
|
|
48
|
+
/** create additional logger */
|
|
49
|
+
new Logger(LOGGER_NAME)
|
|
50
|
+
/** no new pino created */
|
|
51
|
+
expect(mock_pino).toHaveBeenCalledTimes(1)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
describe('validate log level', () => {
|
|
55
|
+
test('throw on invalid log level', () => {
|
|
56
|
+
const INVALID_LOG_LEVEL = 'invalid-log-level'
|
|
57
|
+
expect(() => {
|
|
58
|
+
isValidLogLevel(INVALID_LOG_LEVEL)
|
|
59
|
+
}).toThrowError(
|
|
60
|
+
`Invalid log level "${INVALID_LOG_LEVEL}": only error, warn, info, debug, trace are valid.`
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
describe('route and format logs', () => {
|
|
65
|
+
const LOG_EVENT = {
|
|
66
|
+
code: 'code',
|
|
67
|
+
msg: 'message',
|
|
68
|
+
}
|
|
69
|
+
const DETAILS = {
|
|
70
|
+
key0: 'val0',
|
|
71
|
+
key1: 'val1',
|
|
72
|
+
}
|
|
73
|
+
test('log info with details', () => {
|
|
74
|
+
//@ts-ignore
|
|
75
|
+
jest.spyOn(pino, 'destination').mockReturnValue(PINO_DESTINATION)
|
|
76
|
+
//@ts-ignore
|
|
77
|
+
pino.mockReturnValue(PINO)
|
|
78
|
+
const logger = new Logger(LOGGER_NAME)
|
|
79
|
+
|
|
80
|
+
logger.info(LOG_EVENT, DETAILS)
|
|
81
|
+
|
|
82
|
+
expect(PINO.info).toHaveBeenCalledWith({
|
|
83
|
+
component: LOGGER_NAME,
|
|
84
|
+
...LOG_EVENT,
|
|
85
|
+
detail: [DETAILS],
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
})
|
package/src/lib/logger.ts
CHANGED
|
@@ -1,172 +1,151 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import {Logger as PinoLogger, pino, stdTimeFunctions} from 'pino'
|
|
2
|
+
import * as dotenv from 'dotenv'
|
|
3
|
+
import pinoElastic from 'pino-elasticsearch'
|
|
4
|
+
import {ElasticConfig, LOG_LEVEL, LogEvent} from '../types'
|
|
5
|
+
|
|
6
|
+
dotenv.config()
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
|
-
*
|
|
9
|
+
* Pino logger backend - singleton
|
|
6
10
|
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The name of the class that generated the log.
|
|
10
|
-
*/
|
|
11
|
-
className: string
|
|
11
|
+
let pinoLogger: PinoLogger
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Pino logger instance with specified Elasticsearch configuration.
|
|
15
|
+
* @param elasticConfig - Optional Elasticsearch configuration.
|
|
16
|
+
* @returns The Pino logger instance.
|
|
17
|
+
*/
|
|
18
|
+
function getLogger(elasticConfig?: ElasticConfig): PinoLogger {
|
|
19
|
+
if (!pinoLogger) {
|
|
20
|
+
if (isValidLogLevel(process.env.LOG_LEVEL)) {
|
|
21
|
+
const transports = []
|
|
22
|
+
if (process.env.NODE_ENV !== 'local' && process.env.NODE_ENV !== 'test') {
|
|
23
|
+
const esConfig: ElasticConfig = {
|
|
24
|
+
index: process.env.SERVER_NICKNAME,
|
|
25
|
+
node: process.env.ELASTICSEARCH_NODE,
|
|
26
|
+
auth: {
|
|
27
|
+
username: process.env.ELASTICSEARCH_USERNAME,
|
|
28
|
+
password: process.env.ELASTICSEARCH_PASSWORD,
|
|
29
|
+
},
|
|
30
|
+
flushInterval: 10000,
|
|
31
|
+
}
|
|
32
|
+
if (elasticConfig) {
|
|
33
|
+
Object.assign(esConfig, elasticConfig)
|
|
34
|
+
}
|
|
35
|
+
const esTransport = pinoElastic(esConfig)
|
|
36
|
+
transports.push(esTransport)
|
|
37
|
+
} else {
|
|
38
|
+
transports.push(
|
|
39
|
+
pino.destination({
|
|
40
|
+
minLength: 1024,
|
|
41
|
+
sync: true,
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
pinoLogger = pino(
|
|
46
|
+
{
|
|
47
|
+
level: process.env.LOG_LEVEL,
|
|
48
|
+
timestamp: stdTimeFunctions.isoTime.bind(stdTimeFunctions),
|
|
49
|
+
},
|
|
50
|
+
...transports
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return pinoLogger
|
|
55
|
+
}
|
|
17
56
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a given log level is valid.
|
|
59
|
+
* @param level - The log level to check.
|
|
60
|
+
* @returns Whether the log level is valid.
|
|
61
|
+
*/
|
|
62
|
+
export function isValidLogLevel(level: string): level is LOG_LEVEL {
|
|
63
|
+
if (!['error', 'warn', 'info', 'debug', 'trace'].includes(level)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Invalid log level "${level}": only error, warn, info, debug, trace are valid.`
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Logger Wrapper.
|
|
73
|
+
* Wraps a Pino logger instance and provides logging methods.
|
|
74
|
+
*/
|
|
75
|
+
class Logger {
|
|
76
|
+
private readonly _name: string
|
|
77
|
+
private readonly _logger: PinoLogger
|
|
22
78
|
|
|
23
79
|
/**
|
|
24
|
-
*
|
|
80
|
+
* Creates a new Logger instance with default configuration.
|
|
81
|
+
* @param name - The name of the logger.
|
|
25
82
|
*/
|
|
26
|
-
|
|
83
|
+
constructor(name: string)
|
|
27
84
|
|
|
28
85
|
/**
|
|
29
|
-
*
|
|
86
|
+
* Creates a new Logger instance with custom Elasticsearch configuration.
|
|
87
|
+
* @param name - The name of the logger.
|
|
88
|
+
* @param elasticConfig - Optional Elasticsearch configuration.
|
|
30
89
|
*/
|
|
31
|
-
|
|
32
|
-
}
|
|
90
|
+
constructor(name: string, elasticConfig?: ElasticConfig)
|
|
33
91
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
private logger: WinstonLogger
|
|
92
|
+
constructor(name: string, elasticConfig?: ElasticConfig) {
|
|
93
|
+
this._name = name
|
|
94
|
+
this._logger = getLogger(elasticConfig)
|
|
95
|
+
}
|
|
39
96
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.logger = Winston.createLogger({
|
|
46
|
-
...config,
|
|
47
|
-
level: process.env.LOG_LEVEL,
|
|
97
|
+
private log(logLevel: LOG_LEVEL, logEvent: LogEvent, ...args: unknown[]) {
|
|
98
|
+
this._logger[logLevel]({
|
|
99
|
+
component: this._name,
|
|
100
|
+
...logEvent,
|
|
101
|
+
detail: args,
|
|
48
102
|
})
|
|
49
|
-
if (process.env.NODE_ENV === 'local') {
|
|
50
|
-
this.logger.add(
|
|
51
|
-
new Winston.transports.Console({
|
|
52
|
-
level: 'info',
|
|
53
|
-
format: Winston.format.combine(
|
|
54
|
-
Winston.format.simple(),
|
|
55
|
-
Winston.format.colorize(),
|
|
56
|
-
Winston.format.printf(({level, message}) => {
|
|
57
|
-
return `[${level}]: ${JSON.stringify(message)}`
|
|
58
|
-
// Parse the message as JSON and include in the log
|
|
59
|
-
})
|
|
60
|
-
),
|
|
61
|
-
})
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
this.logger.level = process.env.LOG_LEVEL
|
|
66
103
|
}
|
|
67
104
|
|
|
68
105
|
/**
|
|
69
|
-
* Logs an
|
|
70
|
-
* @param
|
|
71
|
-
* @param
|
|
72
|
-
* @param logMessage - The log message text.
|
|
73
|
-
* @param userIp - The user's IP address associated with the log.
|
|
74
|
-
* @param data - Additional data associated with the log.
|
|
106
|
+
* Logs an error message.
|
|
107
|
+
* @param logEvent - The event to log.
|
|
108
|
+
* @param args - Additional arguments to include in the log.
|
|
75
109
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
functionName: string,
|
|
79
|
-
logMessage: string,
|
|
80
|
-
userIp: string
|
|
81
|
-
): void {
|
|
82
|
-
const message = this.createLogMessage(
|
|
83
|
-
className,
|
|
84
|
-
functionName,
|
|
85
|
-
logMessage,
|
|
86
|
-
userIp
|
|
87
|
-
)
|
|
88
|
-
this.log('info', message)
|
|
110
|
+
error(logEvent: LogEvent, ...args: unknown[]) {
|
|
111
|
+
this.log('error', logEvent, ...args)
|
|
89
112
|
}
|
|
90
113
|
|
|
91
114
|
/**
|
|
92
115
|
* Logs a warning message.
|
|
93
|
-
* @param
|
|
94
|
-
* @param
|
|
95
|
-
* @param logMessage - The log message text.
|
|
96
|
-
* @param userIp - The user's IP address associated with the log.
|
|
97
|
-
* @param data - Additional data associated with the log.
|
|
116
|
+
* @param logEvent - The event to log.
|
|
117
|
+
* @param args - Additional arguments to include in the log.
|
|
98
118
|
*/
|
|
99
|
-
warn(
|
|
100
|
-
|
|
101
|
-
functionName: string,
|
|
102
|
-
logMessage: string,
|
|
103
|
-
userIp: string
|
|
104
|
-
): void {
|
|
105
|
-
const message = this.createLogMessage(
|
|
106
|
-
className,
|
|
107
|
-
functionName,
|
|
108
|
-
logMessage,
|
|
109
|
-
userIp
|
|
110
|
-
)
|
|
111
|
-
this.log('warn', message)
|
|
119
|
+
warn(logEvent: LogEvent, ...args: unknown[]) {
|
|
120
|
+
this.log('warn', logEvent, ...args)
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
/**
|
|
115
|
-
* Logs an
|
|
116
|
-
* @param
|
|
117
|
-
* @param
|
|
118
|
-
* @param logMessage - The log message text.
|
|
119
|
-
* @param userIp - The user's IP address associated with the log.
|
|
120
|
-
* @param data - Additional data associated with the log.
|
|
124
|
+
* Logs an informational message.
|
|
125
|
+
* @param logEvent - The event to log.
|
|
126
|
+
* @param args - Additional arguments to include in the log.
|
|
121
127
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
functionName: string,
|
|
125
|
-
logMessage: string,
|
|
126
|
-
userIp: string,
|
|
127
|
-
data: Object = {}
|
|
128
|
-
): void {
|
|
129
|
-
const message = this.createLogMessage(
|
|
130
|
-
className,
|
|
131
|
-
functionName,
|
|
132
|
-
logMessage,
|
|
133
|
-
userIp,
|
|
134
|
-
data
|
|
135
|
-
)
|
|
136
|
-
this.log('error', message)
|
|
128
|
+
info(logEvent: LogEvent, ...args: unknown[]) {
|
|
129
|
+
this.log('info', logEvent, ...args)
|
|
137
130
|
}
|
|
138
131
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
className,
|
|
148
|
-
functionName,
|
|
149
|
-
logMessage,
|
|
150
|
-
userIp,
|
|
151
|
-
data,
|
|
152
|
-
}
|
|
132
|
+
/**
|
|
133
|
+
* Logs a debug message.
|
|
134
|
+
* @param logEvent - The event to log.
|
|
135
|
+
* @param args - Additional arguments to include in the log.
|
|
136
|
+
*/
|
|
137
|
+
debug(logEvent: LogEvent, ...args: unknown[]) {
|
|
138
|
+
this.log('debug', logEvent, ...args)
|
|
153
139
|
}
|
|
154
140
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
this.logger.error('Unhandled Rejection at:', promise, 'reason:', reason)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
process.on('uncaughtException', (err) => {
|
|
166
|
-
this.logger.error('Uncaught Exception:', err)
|
|
167
|
-
})
|
|
141
|
+
/**
|
|
142
|
+
* Logs a trace message.
|
|
143
|
+
* @param logEvent - The event to log.
|
|
144
|
+
* @param args - Additional arguments to include in the log.
|
|
145
|
+
*/
|
|
146
|
+
trace(logEvent: LogEvent, ...args: unknown[]) {
|
|
147
|
+
this.log('trace', logEvent, ...args)
|
|
168
148
|
}
|
|
169
149
|
}
|
|
170
150
|
|
|
171
|
-
const Logger = new LoggerService(WinstonConfiguaration)
|
|
172
151
|
export default Logger
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './logger'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log levels
|
|
3
|
+
*/
|
|
4
|
+
export type LOG_LEVEL = 'error' | 'warn' | 'info' | 'debug' | 'trace'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a log event.
|
|
8
|
+
*/
|
|
9
|
+
export interface LogEvent {
|
|
10
|
+
/**
|
|
11
|
+
* The code associated with the log event.
|
|
12
|
+
*/
|
|
13
|
+
code: string
|
|
14
|
+
/**
|
|
15
|
+
* The message describing the log event.
|
|
16
|
+
*/
|
|
17
|
+
msg: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Configuration options for Elasticsearch.
|
|
22
|
+
*/
|
|
23
|
+
export interface ElasticConfig {
|
|
24
|
+
/**
|
|
25
|
+
* The Elasticsearch index to write logs to.
|
|
26
|
+
*/
|
|
27
|
+
index?: string
|
|
28
|
+
/**
|
|
29
|
+
* The URL of the Elasticsearch node.
|
|
30
|
+
*/
|
|
31
|
+
node?: string
|
|
32
|
+
/**
|
|
33
|
+
* Authentication details for accessing Elasticsearch.
|
|
34
|
+
*/
|
|
35
|
+
auth?: {
|
|
36
|
+
/**
|
|
37
|
+
* The username for authentication.
|
|
38
|
+
*/
|
|
39
|
+
username: string
|
|
40
|
+
/**
|
|
41
|
+
* The password for authentication.
|
|
42
|
+
*/
|
|
43
|
+
password: string
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The interval (in milliseconds) at which logs are flushed to Elasticsearch.
|
|
47
|
+
*/
|
|
48
|
+
flushInterval?: number
|
|
49
|
+
}
|
package/src/config/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {default as WinstonConfiguaration} from './logger-config'
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import {ElasticsearchTransport} from 'winston-elasticsearch'
|
|
2
|
-
import * as dotenv from 'dotenv'
|
|
3
|
-
dotenv.config()
|
|
4
|
-
const {
|
|
5
|
-
ELASTICSEARCH_USERNAME,
|
|
6
|
-
ELASTICSEARCH_PASSWORD,
|
|
7
|
-
ELASTICSEARCH_NODE,
|
|
8
|
-
SERVER_NICKNAME,
|
|
9
|
-
LOG_LEVEL,
|
|
10
|
-
} = process.env
|
|
11
|
-
|
|
12
|
-
const transports =
|
|
13
|
-
process.env.NODE_ENV !== 'local'
|
|
14
|
-
? [
|
|
15
|
-
// Elasticsearch Transport for 'info' logs
|
|
16
|
-
new ElasticsearchTransport({
|
|
17
|
-
level: 'info',
|
|
18
|
-
indexPrefix: process.env.SERVER_NICKNAME, // Index prefix for Elasticsearch
|
|
19
|
-
clientOpts: {
|
|
20
|
-
node: ELASTICSEARCH_NODE,
|
|
21
|
-
tls: {
|
|
22
|
-
rejectUnauthorized: false, // Only for development, not recommended in production
|
|
23
|
-
},
|
|
24
|
-
auth: {
|
|
25
|
-
username: ELASTICSEARCH_USERNAME,
|
|
26
|
-
password: ELASTICSEARCH_PASSWORD,
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
// format: winston.format.combine(winston.format.json()), // Adjust as needed
|
|
30
|
-
}),
|
|
31
|
-
|
|
32
|
-
// Elasticsearch Transport for 'warn' logs
|
|
33
|
-
new ElasticsearchTransport({
|
|
34
|
-
level: LOG_LEVEL,
|
|
35
|
-
indexPrefix: SERVER_NICKNAME, // Index prefix for Elasticsearch
|
|
36
|
-
clientOpts: {
|
|
37
|
-
node: ELASTICSEARCH_NODE,
|
|
38
|
-
tls: {
|
|
39
|
-
rejectUnauthorized: false, // Only for development, not recommended in production
|
|
40
|
-
},
|
|
41
|
-
auth: {
|
|
42
|
-
username: ELASTICSEARCH_USERNAME,
|
|
43
|
-
password: ELASTICSEARCH_PASSWORD,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
// format: winston.format.combine(winston.format.json()), // Adjust as needed
|
|
47
|
-
}),
|
|
48
|
-
|
|
49
|
-
// Elasticsearch Transport for 'error' logs
|
|
50
|
-
new ElasticsearchTransport({
|
|
51
|
-
level: 'error',
|
|
52
|
-
indexPrefix: process.env.SERVER_NICKNAME, // Index prefix for Elasticsearch
|
|
53
|
-
clientOpts: {
|
|
54
|
-
node: ELASTICSEARCH_NODE,
|
|
55
|
-
tls: {
|
|
56
|
-
rejectUnauthorized: false, // Only for development, not recommended in production
|
|
57
|
-
},
|
|
58
|
-
auth: {
|
|
59
|
-
username: ELASTICSEARCH_USERNAME,
|
|
60
|
-
password: ELASTICSEARCH_PASSWORD,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
// format: winston.format.combine(winston.format.json()), // Adjust as needed
|
|
64
|
-
}),
|
|
65
|
-
// eslint-disable-next-line no-mixed-spaces-and-tabs
|
|
66
|
-
]
|
|
67
|
-
: []
|
|
68
|
-
|
|
69
|
-
const loggerConfiguration = {
|
|
70
|
-
transports,
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export default loggerConfiguration
|