@flusys/nestjs-shared 1.1.0-beta → 1.2.0-rc.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/README.md +146 -1330
- package/cjs/classes/api-controller.class.js +325 -49
- package/cjs/classes/api-service.class.js +271 -149
- package/cjs/classes/handle-custome-db.js +37 -0
- package/cjs/classes/index.js +2 -2
- package/cjs/classes/winston.logger.class.js +103 -70
- package/cjs/constants/index.js +15 -4
- package/cjs/constants/message-keys.js +68 -0
- package/cjs/constants/permissions.js +287 -0
- package/cjs/decorators/api-response.decorator.js +2 -3
- package/cjs/decorators/index.js +1 -0
- package/cjs/decorators/log-action.decorator.js +149 -0
- package/cjs/decorators/require-permission.decorator.js +5 -5
- package/cjs/dtos/delete.dto.js +10 -0
- package/cjs/dtos/filter-and-pagination.dto.js +24 -34
- package/cjs/dtos/get-by-ids.dto.js +65 -0
- package/cjs/dtos/identity-response.dto.js +4 -8
- package/cjs/dtos/index.js +1 -0
- package/cjs/dtos/pagination.dto.js +4 -8
- package/cjs/dtos/response-payload.dto.js +68 -112
- package/cjs/entities/identity.js +12 -6
- package/cjs/entities/index.js +1 -0
- package/cjs/entities/raw-type.js +4 -0
- package/cjs/entities/user-root.js +15 -15
- package/cjs/enums/index.js +20 -0
- package/cjs/enums/notification-type.enum.js +17 -0
- package/cjs/enums/participant-status.enum.js +17 -0
- package/cjs/enums/recurrence-type.enum.js +18 -0
- package/cjs/exceptions/base-app.exception.js +151 -0
- package/cjs/exceptions/index.js +1 -0
- package/cjs/exceptions/permission.exception.js +13 -9
- package/cjs/filters/global-exception.filter.js +279 -0
- package/cjs/filters/index.js +18 -0
- package/cjs/guards/jwt-auth.guard.js +4 -1
- package/cjs/guards/permission.guard.js +88 -148
- package/cjs/index.js +2 -0
- package/cjs/interceptors/idempotency.interceptor.js +1 -1
- package/cjs/interceptors/index.js +1 -4
- package/cjs/interceptors/set-user-field-on-body.interceptor.js +60 -0
- package/cjs/interceptors/slug.interceptor.js +30 -9
- package/cjs/interfaces/datasource.interface.js +4 -0
- package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
- package/cjs/interfaces/index.js +4 -2
- package/cjs/interfaces/module-config.interface.js +4 -0
- package/cjs/interfaces/notification-adapter.interface.js +11 -0
- package/cjs/interfaces/permission.interface.js +1 -1
- package/cjs/middlewares/logger.middleware.js +133 -115
- package/cjs/modules/cache/cache.module.js +3 -3
- package/cjs/modules/datasource/index.js +0 -1
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +60 -183
- package/cjs/modules/utils/utils.service.js +27 -206
- package/cjs/utils/date-time.util.js +94 -0
- package/cjs/utils/html-sanitizer.util.js +64 -0
- package/cjs/utils/index.js +5 -1
- package/cjs/utils/query-helpers.util.js +60 -0
- package/cjs/utils/request.util.js +96 -0
- package/cjs/utils/string.util.js +63 -0
- package/classes/api-controller.class.d.ts +16 -8
- package/classes/api-service.class.d.ts +30 -25
- package/classes/handle-custome-db.d.ts +3 -0
- package/classes/index.d.ts +2 -2
- package/classes/winston.logger.class.d.ts +1 -0
- package/constants/index.d.ts +2 -1
- package/constants/message-keys.d.ts +45 -0
- package/constants/permissions.d.ts +306 -0
- package/decorators/api-response.decorator.d.ts +1 -1
- package/decorators/current-user.decorator.d.ts +1 -1
- package/decorators/index.d.ts +1 -0
- package/decorators/log-action.decorator.d.ts +8 -0
- package/decorators/require-permission.decorator.d.ts +2 -2
- package/dtos/delete.dto.d.ts +1 -0
- package/dtos/filter-and-pagination.dto.d.ts +0 -2
- package/dtos/get-by-ids.dto.d.ts +4 -0
- package/dtos/index.d.ts +1 -0
- package/dtos/response-payload.dto.d.ts +8 -20
- package/entities/index.d.ts +1 -0
- package/entities/raw-type.d.ts +1 -0
- package/enums/index.d.ts +3 -0
- package/enums/notification-type.enum.d.ts +6 -0
- package/enums/participant-status.enum.d.ts +6 -0
- package/enums/recurrence-type.enum.d.ts +7 -0
- package/exceptions/base-app.exception.d.ts +41 -0
- package/exceptions/index.d.ts +1 -0
- package/exceptions/permission.exception.d.ts +2 -2
- package/fesm/classes/api-controller.class.js +326 -50
- package/fesm/classes/api-service.class.js +274 -152
- package/fesm/classes/handle-custome-db.js +19 -0
- package/fesm/classes/index.js +3 -2
- package/fesm/classes/winston.logger.class.js +100 -68
- package/fesm/constants/index.js +4 -1
- package/fesm/constants/message-keys.js +49 -0
- package/fesm/constants/permissions.js +200 -0
- package/fesm/decorators/api-response.decorator.js +3 -21
- package/fesm/decorators/index.js +1 -0
- package/fesm/decorators/log-action.decorator.js +139 -0
- package/fesm/decorators/require-permission.decorator.js +17 -65
- package/fesm/dtos/delete.dto.js +12 -2
- package/fesm/dtos/filter-and-pagination.dto.js +26 -47
- package/fesm/dtos/get-by-ids.dto.js +55 -0
- package/fesm/dtos/identity-response.dto.js +4 -8
- package/fesm/dtos/index.js +1 -0
- package/fesm/dtos/pagination.dto.js +4 -8
- package/fesm/dtos/response-payload.dto.js +68 -103
- package/fesm/entities/identity.js +12 -6
- package/fesm/entities/index.js +1 -0
- package/fesm/entities/raw-type.js +1 -0
- package/fesm/entities/user-root.js +15 -15
- package/fesm/enums/index.js +3 -0
- package/fesm/enums/notification-type.enum.js +7 -0
- package/fesm/enums/participant-status.enum.js +7 -0
- package/fesm/enums/recurrence-type.enum.js +8 -0
- package/fesm/exceptions/base-app.exception.js +115 -0
- package/fesm/exceptions/index.js +1 -0
- package/fesm/exceptions/permission.exception.js +16 -18
- package/fesm/filters/global-exception.filter.js +269 -0
- package/fesm/filters/index.js +1 -0
- package/fesm/guards/jwt-auth.guard.js +5 -2
- package/fesm/guards/permission.guard.js +90 -150
- package/fesm/index.js +2 -0
- package/fesm/interceptors/idempotency.interceptor.js +2 -2
- package/fesm/interceptors/index.js +1 -4
- package/fesm/interceptors/set-user-field-on-body.interceptor.js +39 -0
- package/fesm/interceptors/slug.interceptor.js +31 -10
- package/fesm/interfaces/datasource.interface.js +1 -0
- package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
- package/fesm/interfaces/index.js +4 -2
- package/fesm/interfaces/module-config.interface.js +5 -0
- package/fesm/interfaces/notification-adapter.interface.js +1 -0
- package/fesm/interfaces/permission.interface.js +1 -3
- package/fesm/middlewares/logger.middleware.js +133 -109
- package/fesm/modules/cache/cache.module.js +2 -2
- package/fesm/modules/datasource/index.js +0 -1
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +61 -184
- package/fesm/modules/utils/utils.service.js +27 -206
- package/fesm/utils/date-time.util.js +70 -0
- package/fesm/utils/html-sanitizer.util.js +69 -0
- package/fesm/utils/index.js +5 -1
- package/fesm/utils/query-helpers.util.js +85 -0
- package/fesm/utils/request.util.js +81 -0
- package/fesm/utils/string.util.js +71 -0
- package/filters/global-exception.filter.d.ts +9 -0
- package/filters/index.d.ts +1 -0
- package/guards/permission.guard.d.ts +4 -6
- package/index.d.ts +2 -0
- package/interceptors/idempotency.interceptor.d.ts +1 -1
- package/interceptors/index.d.ts +1 -4
- package/interceptors/set-user-field-on-body.interceptor.d.ts +5 -0
- package/interceptors/slug.interceptor.d.ts +2 -1
- package/interfaces/api.interface.d.ts +4 -2
- package/interfaces/datasource.interface.d.ts +5 -0
- package/interfaces/event-manager-adapter.interface.d.ts +43 -0
- package/interfaces/identity.interface.d.ts +4 -4
- package/interfaces/index.d.ts +4 -2
- package/interfaces/logged-user-info.interface.d.ts +0 -2
- package/interfaces/module-config.interface.d.ts +6 -0
- package/interfaces/notification-adapter.interface.d.ts +21 -0
- package/interfaces/permission.interface.d.ts +13 -9
- package/middlewares/logger.middleware.d.ts +2 -2
- package/modules/datasource/index.d.ts +0 -1
- package/modules/datasource/multi-tenant-datasource.service.d.ts +5 -16
- package/modules/utils/utils.service.d.ts +3 -14
- package/package.json +21 -14
- package/utils/date-time.util.d.ts +8 -0
- package/utils/html-sanitizer.util.d.ts +2 -0
- package/utils/index.d.ts +5 -1
- package/utils/query-helpers.util.d.ts +16 -0
- package/utils/request.util.d.ts +6 -0
- package/utils/string.util.d.ts +2 -0
- package/cjs/classes/request-scoped-api.service.js +0 -61
- package/cjs/classes/winston-logger-adapter.class.js +0 -121
- package/cjs/interceptors/query-performance.interceptor.js +0 -66
- package/cjs/interceptors/set-create-by-on-body.interceptor.js +0 -40
- package/cjs/interceptors/set-delete-by-on-body.interceptor.js +0 -40
- package/cjs/interceptors/set-update-by-on-body.interceptor.js +0 -40
- package/cjs/interfaces/base-query.interface.js +0 -6
- package/cjs/interfaces/logger.interface.js +0 -7
- package/cjs/modules/datasource/datasource.module.js +0 -120
- package/cjs/utils/error-handler.util.js +0 -67
- package/classes/request-scoped-api.service.d.ts +0 -13
- package/classes/winston-logger-adapter.class.d.ts +0 -20
- package/fesm/classes/request-scoped-api.service.js +0 -51
- package/fesm/classes/winston-logger-adapter.class.js +0 -124
- package/fesm/interceptors/query-performance.interceptor.js +0 -56
- package/fesm/interceptors/set-create-by-on-body.interceptor.js +0 -30
- package/fesm/interceptors/set-delete-by-on-body.interceptor.js +0 -30
- package/fesm/interceptors/set-update-by-on-body.interceptor.js +0 -30
- package/fesm/interfaces/base-query.interface.js +0 -3
- package/fesm/interfaces/logger.interface.js +0 -4
- package/fesm/modules/datasource/datasource.module.js +0 -110
- package/fesm/utils/error-handler.util.js +0 -59
- package/interceptors/query-performance.interceptor.d.ts +0 -8
- package/interceptors/set-create-by-on-body.interceptor.d.ts +0 -5
- package/interceptors/set-delete-by-on-body.interceptor.d.ts +0 -5
- package/interceptors/set-update-by-on-body.interceptor.d.ts +0 -5
- package/interfaces/base-query.interface.d.ts +0 -7
- package/interfaces/logger.interface.d.ts +0 -7
- package/modules/datasource/datasource.module.d.ts +0 -18
- package/utils/error-handler.util.d.ts +0 -24
|
@@ -24,18 +24,15 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
24
24
|
import { instance as winstonLogger } from '../classes/winston.logger.class';
|
|
25
25
|
import { REQUEST_ID_HEADER } from '../constants';
|
|
26
26
|
// Configuration
|
|
27
|
-
const
|
|
27
|
+
const logConfig = envConfig.getLogConfig();
|
|
28
|
+
const IS_DEBUG = logConfig.level === 'debug';
|
|
29
|
+
const DISABLE_HTTP_LOGGING = logConfig.disableHttpLogging;
|
|
28
30
|
const TENANT_ID_HEADER = 'x-tenant-id';
|
|
29
31
|
const EXCLUDED_PATHS = [
|
|
30
32
|
'/health',
|
|
31
33
|
'/metrics',
|
|
32
34
|
'/favicon.ico'
|
|
33
35
|
];
|
|
34
|
-
const EXCLUDED_HEADERS = [
|
|
35
|
-
'authorization',
|
|
36
|
-
'cookie',
|
|
37
|
-
'x-api-key'
|
|
38
|
-
];
|
|
39
36
|
const MAX_BODY_LOG_SIZE = 1000;
|
|
40
37
|
export const requestContext = new AsyncLocalStorage();
|
|
41
38
|
// Context accessors
|
|
@@ -43,26 +40,72 @@ export const getRequestId = ()=>requestContext.getStore()?.requestId;
|
|
|
43
40
|
export const getTenantId = ()=>requestContext.getStore()?.tenantId;
|
|
44
41
|
export const getUserId = ()=>requestContext.getStore()?.userId;
|
|
45
42
|
export const getCompanyId = ()=>requestContext.getStore()?.companyId;
|
|
46
|
-
export const setUserId = (userId)=>{
|
|
47
|
-
const store = requestContext.getStore();
|
|
48
|
-
if (store) store.userId = userId;
|
|
49
|
-
};
|
|
50
|
-
export const setCompanyId = (companyId)=>{
|
|
51
|
-
const store = requestContext.getStore();
|
|
52
|
-
if (store) store.companyId = companyId;
|
|
53
|
-
};
|
|
54
43
|
// Helper Functions
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
function summarizeRequestBody(body) {
|
|
45
|
+
if (!body) return undefined;
|
|
46
|
+
const parsed = typeof body === 'string' ? tryParseJson(body) : body;
|
|
47
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
48
|
+
const str = String(body);
|
|
49
|
+
return str.length > MAX_BODY_LOG_SIZE ? str.substring(0, MAX_BODY_LOG_SIZE) + '...' : str;
|
|
50
|
+
}
|
|
51
|
+
// For API request bodies, provide a concise summary
|
|
52
|
+
const summary = {};
|
|
53
|
+
// Pagination info
|
|
54
|
+
if (parsed.pagination) {
|
|
55
|
+
summary.page = parsed.pagination.currentPage;
|
|
56
|
+
summary.pageSize = parsed.pagination.pageSize;
|
|
57
|
+
}
|
|
58
|
+
// Filter keys only (not values - may contain sensitive data)
|
|
59
|
+
if (parsed.filter && typeof parsed.filter === 'object') {
|
|
60
|
+
const filterKeys = Object.keys(parsed.filter);
|
|
61
|
+
if (filterKeys.length > 0) summary.filterKeys = filterKeys;
|
|
62
|
+
}
|
|
63
|
+
// Select fields count
|
|
64
|
+
if (Array.isArray(parsed.select) && parsed.select.length > 0) {
|
|
65
|
+
summary.selectCount = parsed.select.length;
|
|
66
|
+
}
|
|
67
|
+
// Sort keys
|
|
68
|
+
if (parsed.sort && typeof parsed.sort === 'object') {
|
|
69
|
+
const sortKeys = Object.keys(parsed.sort);
|
|
70
|
+
if (sortKeys.length > 0) summary.sortKeys = sortKeys;
|
|
59
71
|
}
|
|
60
|
-
|
|
72
|
+
// ID for single item operations
|
|
73
|
+
if (parsed.id) summary.id = parsed.id;
|
|
74
|
+
// IDs for bulk operations
|
|
75
|
+
if (Array.isArray(parsed.ids)) summary.idsCount = parsed.ids.length;
|
|
76
|
+
return Object.keys(summary).length > 0 ? JSON.stringify(summary) : '{}';
|
|
61
77
|
}
|
|
62
|
-
function
|
|
78
|
+
function summarizeResponseBody(body) {
|
|
63
79
|
if (!body) return undefined;
|
|
64
|
-
const
|
|
65
|
-
|
|
80
|
+
const parsed = typeof body === 'string' ? tryParseJson(body) : body;
|
|
81
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
82
|
+
const str = String(body);
|
|
83
|
+
return str.length > MAX_BODY_LOG_SIZE ? str.substring(0, MAX_BODY_LOG_SIZE) + '...' : str;
|
|
84
|
+
}
|
|
85
|
+
const summary = {};
|
|
86
|
+
if ('success' in parsed) summary.success = parsed.success;
|
|
87
|
+
if ('message' in parsed) summary.message = parsed.message;
|
|
88
|
+
if ('code' in parsed) summary.code = parsed.code;
|
|
89
|
+
if (Array.isArray(parsed.data)) {
|
|
90
|
+
summary.dataCount = parsed.data.length;
|
|
91
|
+
} else if (parsed.data && typeof parsed.data === 'object') {
|
|
92
|
+
summary.hasData = true;
|
|
93
|
+
}
|
|
94
|
+
if (parsed.meta) {
|
|
95
|
+
summary.total = parsed.meta.total;
|
|
96
|
+
summary.page = parsed.meta.page;
|
|
97
|
+
}
|
|
98
|
+
if (parsed.errors) {
|
|
99
|
+
summary.errorsCount = Array.isArray(parsed.errors) ? parsed.errors.length : 1;
|
|
100
|
+
}
|
|
101
|
+
return JSON.stringify(summary);
|
|
102
|
+
}
|
|
103
|
+
function tryParseJson(str) {
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(str);
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
66
109
|
}
|
|
67
110
|
function getClientIp(req) {
|
|
68
111
|
return req.headers['x-forwarded-for']?.split(',')[0] || req.socket?.remoteAddress || 'unknown';
|
|
@@ -72,136 +115,117 @@ export class LoggerMiddleware {
|
|
|
72
115
|
const requestId = req.headers[REQUEST_ID_HEADER] || uuidv4();
|
|
73
116
|
const tenantId = req.headers[TENANT_ID_HEADER];
|
|
74
117
|
const startTime = Date.now();
|
|
75
|
-
// Set response header
|
|
76
118
|
res.setHeader(REQUEST_ID_HEADER, requestId);
|
|
77
|
-
// Create context
|
|
78
119
|
const context = {
|
|
79
120
|
requestId,
|
|
80
121
|
tenantId,
|
|
81
122
|
startTime
|
|
82
123
|
};
|
|
83
|
-
// Run in AsyncLocalStorage context
|
|
84
124
|
requestContext.run(context, ()=>{
|
|
85
|
-
|
|
86
|
-
const shouldSkipLogging = EXCLUDED_PATHS.some((path)=>req.originalUrl.startsWith(path));
|
|
125
|
+
const shouldSkipLogging = DISABLE_HTTP_LOGGING || EXCLUDED_PATHS.some((path)=>req.originalUrl.startsWith(path));
|
|
87
126
|
if (!shouldSkipLogging) {
|
|
88
127
|
this.logRequest(req, requestId, tenantId);
|
|
89
|
-
|
|
90
|
-
let responseLogged = false;
|
|
91
|
-
// Capture response using multiple hooks to ensure we catch it
|
|
92
|
-
const originalSend = res.send;
|
|
93
|
-
const originalJson = res.json;
|
|
94
|
-
const originalEnd = res.end;
|
|
95
|
-
// Store reference to this for use in callbacks
|
|
96
|
-
const self = this;
|
|
97
|
-
// Override res.send
|
|
98
|
-
res.send = function(body) {
|
|
99
|
-
if (!responseLogged) {
|
|
100
|
-
responseLogged = true;
|
|
101
|
-
self.logResponse(req, res, startTime, body, requestId, tenantId);
|
|
102
|
-
}
|
|
103
|
-
return originalSend.call(this, body);
|
|
104
|
-
};
|
|
105
|
-
// Override res.json
|
|
106
|
-
res.json = function(body) {
|
|
107
|
-
if (!responseLogged) {
|
|
108
|
-
responseLogged = true;
|
|
109
|
-
self.logResponse(req, res, startTime, body, requestId, tenantId);
|
|
110
|
-
}
|
|
111
|
-
return originalJson.call(this, body);
|
|
112
|
-
};
|
|
113
|
-
// Override res.end as fallback
|
|
114
|
-
res.end = function(...args) {
|
|
115
|
-
if (!responseLogged) {
|
|
116
|
-
responseLogged = true;
|
|
117
|
-
self.logResponse(req, res, startTime, args[0], requestId, tenantId);
|
|
118
|
-
}
|
|
119
|
-
return originalEnd.apply(this, args);
|
|
120
|
-
};
|
|
121
|
-
// Handle errors
|
|
122
|
-
res.on('error', (error)=>{
|
|
123
|
-
this.logger.error('Response error', {
|
|
124
|
-
context: 'HTTP',
|
|
125
|
-
requestId,
|
|
126
|
-
tenantId,
|
|
127
|
-
method: req.method,
|
|
128
|
-
url: req.originalUrl,
|
|
129
|
-
path: req.path,
|
|
130
|
-
error: error.message,
|
|
131
|
-
stack: error.stack
|
|
132
|
-
});
|
|
133
|
-
});
|
|
128
|
+
this.setupResponseLogging(req, res, startTime, requestId, tenantId);
|
|
134
129
|
}
|
|
135
130
|
next();
|
|
136
131
|
});
|
|
137
132
|
}
|
|
133
|
+
setupResponseLogging(req, res, startTime, requestId, tenantId) {
|
|
134
|
+
let responseLogged = false;
|
|
135
|
+
const originalSend = res.send;
|
|
136
|
+
const originalJson = res.json;
|
|
137
|
+
const originalEnd = res.end;
|
|
138
|
+
const self = this;
|
|
139
|
+
const logOnce = (body)=>{
|
|
140
|
+
if (!responseLogged) {
|
|
141
|
+
responseLogged = true;
|
|
142
|
+
self.logResponse(req, res, startTime, body, requestId, tenantId);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
res.send = function(body) {
|
|
146
|
+
logOnce(body);
|
|
147
|
+
return originalSend.call(this, body);
|
|
148
|
+
};
|
|
149
|
+
res.json = function(body) {
|
|
150
|
+
logOnce(body);
|
|
151
|
+
return originalJson.call(this, body);
|
|
152
|
+
};
|
|
153
|
+
res.end = function(...args) {
|
|
154
|
+
logOnce(args[0]);
|
|
155
|
+
return originalEnd.apply(this, args);
|
|
156
|
+
};
|
|
157
|
+
res.on('error', (error)=>{
|
|
158
|
+
this.logger.error('Response error', {
|
|
159
|
+
...this.buildBaseLogData(req, requestId, tenantId),
|
|
160
|
+
error: error.message,
|
|
161
|
+
stack: error.stack
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
138
165
|
logRequest(req, requestId, tenantId) {
|
|
166
|
+
const ip = getClientIp(req);
|
|
167
|
+
const contentType = req.headers['content-type'] || 'none';
|
|
168
|
+
// Build descriptive message like: Started processing request "POST" "/api/users" from "192.168.1.1"
|
|
169
|
+
const message = `Started processing request "${req.method}" "${req.originalUrl}" from "${ip}"`;
|
|
139
170
|
const logData = {
|
|
140
|
-
|
|
141
|
-
requestId,
|
|
142
|
-
tenantId,
|
|
143
|
-
method: req.method,
|
|
144
|
-
url: req.originalUrl,
|
|
145
|
-
path: req.path,
|
|
171
|
+
...this.buildBaseLogData(req, requestId, tenantId),
|
|
146
172
|
query: Object.keys(req.query).length > 0 ? req.query : undefined,
|
|
147
|
-
ip
|
|
173
|
+
ip,
|
|
148
174
|
userAgent: req.headers['user-agent'],
|
|
149
|
-
contentType
|
|
175
|
+
contentType,
|
|
150
176
|
contentLength: req.headers['content-length']
|
|
151
177
|
};
|
|
152
|
-
// Add debug details if enabled
|
|
153
178
|
if (IS_DEBUG) {
|
|
154
|
-
logData.
|
|
155
|
-
logData.body = truncateBody(req.body);
|
|
156
|
-
logData.params = Object.keys(req.params).length > 0 ? req.params : undefined;
|
|
179
|
+
logData.body = summarizeRequestBody(req.body);
|
|
157
180
|
}
|
|
158
|
-
this.logger.info(
|
|
181
|
+
this.logger.info(message, logData);
|
|
159
182
|
}
|
|
160
183
|
logResponse(req, res, startTime, body, requestId, tenantId) {
|
|
161
184
|
const duration = Date.now() - startTime;
|
|
162
185
|
const statusCode = res.statusCode;
|
|
163
186
|
const level = statusCode >= 500 ? 'error' : statusCode >= 400 ? 'warn' : 'info';
|
|
187
|
+
const userId = getUserId();
|
|
188
|
+
const companyId = getCompanyId();
|
|
189
|
+
const contentType = res.getHeader('content-type') || 'none';
|
|
190
|
+
const contentLength = res.getHeader('content-length') || 'null';
|
|
191
|
+
// Build descriptive message like: Request finished "HTTP/1.1" "POST" "/api/users" - 200 "application/json" 534.29ms
|
|
192
|
+
const message = `Request finished "HTTP/1.1" "${req.method}" "${req.originalUrl}" - ${statusCode} ${contentLength} "${contentType}" ${duration.toFixed(2)}ms`;
|
|
164
193
|
const logData = {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
method: req.method,
|
|
169
|
-
url: req.originalUrl,
|
|
170
|
-
path: req.path,
|
|
194
|
+
...this.buildBaseLogData(req, requestId, tenantId),
|
|
195
|
+
userId,
|
|
196
|
+
companyId,
|
|
171
197
|
statusCode,
|
|
172
198
|
statusMessage: res.statusMessage,
|
|
173
199
|
duration: `${duration}ms`,
|
|
174
200
|
durationMs: duration,
|
|
175
|
-
contentType
|
|
176
|
-
contentLength
|
|
201
|
+
contentType,
|
|
202
|
+
contentLength
|
|
177
203
|
};
|
|
178
|
-
// Add user context if available
|
|
179
|
-
const userId = getUserId();
|
|
180
|
-
const companyId = getCompanyId();
|
|
181
|
-
if (userId) logData.userId = userId;
|
|
182
|
-
if (companyId) logData.companyId = companyId;
|
|
183
|
-
// Add response body for errors or debug mode
|
|
184
204
|
if (statusCode >= 400 || IS_DEBUG) {
|
|
185
|
-
logData.responseBody =
|
|
205
|
+
logData.responseBody = summarizeResponseBody(body);
|
|
186
206
|
}
|
|
187
|
-
this.logger.log(level,
|
|
188
|
-
// Log slow requests separately
|
|
207
|
+
this.logger.log(level, message, logData);
|
|
189
208
|
if (duration > 3000 && statusCode < 400) {
|
|
190
|
-
this.logger.warn(
|
|
191
|
-
|
|
192
|
-
requestId,
|
|
193
|
-
tenantId,
|
|
209
|
+
this.logger.warn(`Slow request detected: "${req.method}" "${req.originalUrl}" took ${duration}ms (threshold: 3000ms)`, {
|
|
210
|
+
...this.buildBaseLogData(req, requestId, tenantId),
|
|
194
211
|
userId,
|
|
195
212
|
companyId,
|
|
196
|
-
method: req.method,
|
|
197
|
-
url: req.originalUrl,
|
|
198
|
-
path: req.path,
|
|
199
213
|
duration: `${duration}ms`,
|
|
200
214
|
durationMs: duration,
|
|
201
215
|
threshold: '3000ms'
|
|
202
216
|
});
|
|
203
217
|
}
|
|
204
218
|
}
|
|
219
|
+
buildBaseLogData(req, requestId, tenantId) {
|
|
220
|
+
return {
|
|
221
|
+
context: 'HTTP',
|
|
222
|
+
requestId,
|
|
223
|
+
tenantId,
|
|
224
|
+
method: req.method,
|
|
225
|
+
url: req.originalUrl,
|
|
226
|
+
path: req.path
|
|
227
|
+
};
|
|
228
|
+
}
|
|
205
229
|
constructor(){
|
|
206
230
|
_define_property(this, "logger", winstonLogger);
|
|
207
231
|
}
|
|
@@ -4,8 +4,8 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
4
4
|
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
}
|
|
7
|
-
import { HybridCache } from '
|
|
8
|
-
import { CACHE_INSTANCE } from '
|
|
7
|
+
import { HybridCache } from '../../classes/hybrid-cache.class';
|
|
8
|
+
import { CACHE_INSTANCE } from '../../constants';
|
|
9
9
|
import { Module } from '@nestjs/common';
|
|
10
10
|
export class CacheModule {
|
|
11
11
|
static forRoot(isGlobal = true, memoryTtl = 60_000, memorySize = 5000) {
|