whatap 1.0.13 → 1.0.14-canary.0
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/.claude/settings.local.json +7 -0
- package/lib/core/agent.js +11 -4
- package/lib/logger.js +9 -26
- package/lib/observers/http-observer.js +38 -37
- package/lib/observers/prisma-observer.js +78 -10
- package/lib/requestlog.js +9 -5
- package/package.json +2 -2
package/lib/core/agent.js
CHANGED
|
@@ -1307,13 +1307,20 @@ NodeAgent.prototype.init = function(cb) {
|
|
|
1307
1307
|
Logger.print('WHATAP-114', 'WHATAP_HOME not set, using application root: ' + process.env.WHATAP_HOME, false);
|
|
1308
1308
|
}
|
|
1309
1309
|
|
|
1310
|
-
|
|
1311
|
-
Logger.print('WHATAP-110', 'Start initialize WhaTap Agent... Root[' + self._conf['app.root'] + ']', true);
|
|
1312
|
-
|
|
1310
|
+
// Fallback: app.root가 없으면 WHATAP_HOME을 사용
|
|
1313
1311
|
if (self._conf['app.root'] == null || self._conf['app.root'].length == 0) {
|
|
1314
|
-
|
|
1312
|
+
if (process.env.WHATAP_HOME) {
|
|
1313
|
+
self._conf['app.root'] = process.env.WHATAP_HOME;
|
|
1314
|
+
Logger.print('WHATAP-115', 'app.root not found (no package.json), using WHATAP_HOME: ' + process.env.WHATAP_HOME, false);
|
|
1315
|
+
} else {
|
|
1316
|
+
self._conf['app.root'] = process.cwd();
|
|
1317
|
+
Logger.print('WHATAP-115', 'app.root not found (no package.json), using cwd: ' + process.cwd(), false);
|
|
1318
|
+
}
|
|
1315
1319
|
}
|
|
1316
1320
|
|
|
1321
|
+
Logger.initializer.process();
|
|
1322
|
+
Logger.print('WHATAP-110', 'Start initialize WhaTap Agent... Root[' + self._conf['app.root'] + ']', true);
|
|
1323
|
+
|
|
1317
1324
|
// Initialize configuration with proper home directory
|
|
1318
1325
|
if (!self.initConfig('WHATAP_HOME')) {
|
|
1319
1326
|
Logger.printError("WHATAP-051", "Failed to initialize configuration", null, false);
|
package/lib/logger.js
CHANGED
|
@@ -163,16 +163,13 @@
|
|
|
163
163
|
if(conf.log_file_enabled === false ) { return; }
|
|
164
164
|
var log_prefix = WHATAP_CONF+"-hook-";
|
|
165
165
|
|
|
166
|
-
var root = conf['app.root'];
|
|
166
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
167
167
|
if(root==null || root ==undefined){
|
|
168
168
|
console.log('[WHATAP]Logger Error - WHATAP ROOT DIR IS NULL');
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
|
-
if(
|
|
172
|
-
|
|
173
|
-
if(fs.existsSync(root) == false) {
|
|
174
|
-
fs.mkdirSync(root, {recursive: true});
|
|
175
|
-
}
|
|
171
|
+
if(fs.existsSync(root) == false) {
|
|
172
|
+
fs.mkdirSync(root, {recursive: true});
|
|
176
173
|
}
|
|
177
174
|
var dir = path.join(root, 'logs');
|
|
178
175
|
if(fs.existsSync(dir) == false) {
|
|
@@ -198,12 +195,10 @@
|
|
|
198
195
|
return;
|
|
199
196
|
}
|
|
200
197
|
|
|
201
|
-
var root = conf['app.root'];
|
|
202
|
-
if
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fs.mkdirSync(root, {recursive: true});
|
|
206
|
-
}
|
|
198
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
199
|
+
if(root==null || root ==undefined){ return; }
|
|
200
|
+
if(fs.existsSync(root) == false) {
|
|
201
|
+
fs.mkdirSync(root, {recursive: true});
|
|
207
202
|
}
|
|
208
203
|
var nowUnit = DateUtil.getDateUnit(),
|
|
209
204
|
dir = path.join(root, 'logs'),
|
|
@@ -248,13 +243,7 @@
|
|
|
248
243
|
|
|
249
244
|
|
|
250
245
|
|
|
251
|
-
var root = conf['app.root'];
|
|
252
|
-
if(conf.getProperty('log_root', null)){
|
|
253
|
-
root = conf.getProperty('log_root', null);
|
|
254
|
-
if(fs.existsSync(root) == false) {
|
|
255
|
-
fs.mkdirSync(root, {recursive: true});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
246
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
258
247
|
if(root==null ){
|
|
259
248
|
return null;
|
|
260
249
|
}
|
|
@@ -297,13 +286,7 @@
|
|
|
297
286
|
|
|
298
287
|
var o = new MapValue();
|
|
299
288
|
if(conf.log_file_enabled === false ) { return o; }
|
|
300
|
-
var root = conf['app.root'];
|
|
301
|
-
if(conf.getProperty('log_root', null)){
|
|
302
|
-
root = conf.getProperty('log_root', null);
|
|
303
|
-
if(fs.existsSync(root) == false) {
|
|
304
|
-
fs.mkdirSync(root, {recursive: true});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
289
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
307
290
|
if(root==null){
|
|
308
291
|
return o;
|
|
309
292
|
}
|
|
@@ -130,6 +130,7 @@ HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps
|
|
|
130
130
|
ctx.service_name = req.url ? req.url : "";
|
|
131
131
|
ctx.isStaticContents = isStatic(ctx.service_name);
|
|
132
132
|
if(ctx.isStaticContents){
|
|
133
|
+
TraceContextManager.end(ctx.id);
|
|
133
134
|
return callback(req, res);
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -179,6 +180,43 @@ HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps
|
|
|
179
180
|
|
|
180
181
|
try {
|
|
181
182
|
AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
|
|
183
|
+
|
|
184
|
+
/************************************/
|
|
185
|
+
/* Header / param Trace */
|
|
186
|
+
/************************************/
|
|
187
|
+
var header_enabled = false;
|
|
188
|
+
if (conf.profile_http_header_enabled === true && req.headers) {
|
|
189
|
+
header_enabled = true;
|
|
190
|
+
var prefix = conf.profile_header_url_prefix;
|
|
191
|
+
if (prefix && ctx.service_name.indexOf(prefix) < 0) {
|
|
192
|
+
header_enabled = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (header_enabled) {
|
|
197
|
+
var header_ignore_key_set = new Set();
|
|
198
|
+
if (profile_http_header_ignore_keys) {
|
|
199
|
+
header_ignore_key_set = new Set(profile_http_header_ignore_keys.split(','));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
var headerDesc = Object.keys(req.headers).map(function (key) {
|
|
204
|
+
if (!header_ignore_key_set.has(key)) {
|
|
205
|
+
return `${key}=${req.headers[key]}`;
|
|
206
|
+
}
|
|
207
|
+
}).filter(element => {
|
|
208
|
+
if (element) return element
|
|
209
|
+
}).join('\n');
|
|
210
|
+
|
|
211
|
+
if (headerDesc) {
|
|
212
|
+
let headerDatas = ['HTTP-HEADERS', 'HTTP-HEADERS', headerDesc];
|
|
213
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, headerDatas);
|
|
214
|
+
}
|
|
215
|
+
} catch (e) {
|
|
216
|
+
Logger.printError('WHATAP-236', 'Header parsing error', e, false);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
182
220
|
return callback.apply(this, arguments);
|
|
183
221
|
} catch (e) {
|
|
184
222
|
Logger.printError("WHATAP-235", 'Hooking request failed..', e, false);
|
|
@@ -252,43 +290,6 @@ function initCtx(req, res) {
|
|
|
252
290
|
// Host
|
|
253
291
|
ctx.host = req.headers.host;
|
|
254
292
|
|
|
255
|
-
/************************************/
|
|
256
|
-
/* Header / param Trace */
|
|
257
|
-
/************************************/
|
|
258
|
-
var header_enabled = false;
|
|
259
|
-
if (conf.profile_http_header_enabled === true && req.headers) {
|
|
260
|
-
header_enabled = true;
|
|
261
|
-
var prefix = conf.profile_header_url_prefix;
|
|
262
|
-
if (prefix && ctx.service_name.indexOf(prefix) < 0) {
|
|
263
|
-
header_enabled = false;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (header_enabled) {
|
|
268
|
-
var header_ignore_key_set = new Set();
|
|
269
|
-
if (profile_http_header_ignore_keys) {
|
|
270
|
-
header_ignore_key_set = new Set(profile_http_header_ignore_keys.split(','));
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
try {
|
|
274
|
-
var headerDesc = Object.keys(req.headers).map(function (key) {
|
|
275
|
-
if (!header_ignore_key_set.has(key)) {
|
|
276
|
-
return `${key}=${req.headers[key]}`;
|
|
277
|
-
}
|
|
278
|
-
}).filter(element => {
|
|
279
|
-
if (element) return element
|
|
280
|
-
}).join('\n');
|
|
281
|
-
|
|
282
|
-
if (headerDesc) {
|
|
283
|
-
let headerDatas = ['HTTP-HEADERS', 'HTTP-HEADERS', headerDesc];
|
|
284
|
-
ctx.start_time = Date.now();
|
|
285
|
-
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, headerDatas);
|
|
286
|
-
}
|
|
287
|
-
} catch (e) {
|
|
288
|
-
Logger.printError('WHATAP-236', 'Header parsing error', e, false);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
293
|
/************************************/
|
|
293
294
|
/* Multi Server Transaction Trace */
|
|
294
295
|
/************************************/
|
|
@@ -37,19 +37,87 @@ PrismaObserver.prototype.inject = function(mod, moduleName) {
|
|
|
37
37
|
// Prisma Client 초기화 메서드 후킹
|
|
38
38
|
if (mod.PrismaClient) {
|
|
39
39
|
shimmer.wrap(mod, 'PrismaClient', function(originalConstructor) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
class WhatapPrismaClient extends originalConstructor {
|
|
41
|
+
constructor(...args) {
|
|
42
|
+
super(...args);
|
|
43
|
+
if (this.__whatap_observe__) return;
|
|
44
|
+
this.__whatap_observe__ = true;
|
|
45
|
+
|
|
46
|
+
self.setupConnectionInfo(this);
|
|
47
|
+
|
|
48
|
+
if (typeof this.$use === 'function') {
|
|
49
|
+
// Prisma v4: $use 미들웨어 사용
|
|
50
|
+
self.hookUseMiddleware(this);
|
|
51
|
+
} else if (typeof this._request === 'function') {
|
|
52
|
+
// Prisma v5+: _request 메서드 직접 래핑
|
|
53
|
+
self.hookRequestMethod(this);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
Object.defineProperty(WhatapPrismaClient, 'name', {
|
|
58
|
+
value: originalConstructor.name,
|
|
59
|
+
});
|
|
60
|
+
return WhatapPrismaClient;
|
|
49
61
|
});
|
|
50
62
|
}
|
|
51
63
|
};
|
|
52
64
|
|
|
65
|
+
PrismaObserver.prototype.hookRequestMethod = function(prismaInstance) {
|
|
66
|
+
const self = this;
|
|
67
|
+
const originalRequest = prismaInstance._request;
|
|
68
|
+
|
|
69
|
+
prismaInstance._request = function(params) {
|
|
70
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
71
|
+
if (!ctx) {
|
|
72
|
+
return originalRequest.call(this, params);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const model = params.model;
|
|
76
|
+
const action = params.action || params.clientMethod || 'unknown';
|
|
77
|
+
// model이 있으면 "Prisma User.findMany", 없으면(raw query) "Prisma $queryRawUnsafe"
|
|
78
|
+
const queryInfo = model
|
|
79
|
+
? `Prisma ${model}.${action}`
|
|
80
|
+
: `Prisma ${params.clientMethod || action}`;
|
|
81
|
+
|
|
82
|
+
ctx.start_time = Date.now();
|
|
83
|
+
ctx.elapsed = 0;
|
|
84
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbc]);
|
|
85
|
+
|
|
86
|
+
var sql_start_time = Date.now();
|
|
87
|
+
|
|
88
|
+
ctx.footprint(`${queryInfo} Start`);
|
|
89
|
+
ctx.sql_count = (ctx.sql_count || 0) + 1;
|
|
90
|
+
ctx.active_sqlhash = HashUtil.hashFromString(queryInfo);
|
|
91
|
+
ctx.active_dbc = dbc_hash;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const result = originalRequest.call(this, params);
|
|
95
|
+
|
|
96
|
+
// _request는 Promise/thenable을 반환하므로 .then()으로 후처리
|
|
97
|
+
if (result && typeof result.then === 'function') {
|
|
98
|
+
return result.then(
|
|
99
|
+
function(res) {
|
|
100
|
+
self._finishQuery(ctx, sql_start_time, res, queryInfo);
|
|
101
|
+
ctx.footprint(`${queryInfo} Done`);
|
|
102
|
+
return res;
|
|
103
|
+
},
|
|
104
|
+
function(err) {
|
|
105
|
+
self._handleError(ctx, sql_start_time, err, queryInfo);
|
|
106
|
+
ctx.footprint(`${queryInfo} Error`);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return result;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
self._handleError(ctx, sql_start_time, err, queryInfo);
|
|
115
|
+
ctx.footprint(`${queryInfo} Error`);
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
53
121
|
PrismaObserver.prototype.patchPrismaInstance = function(prismaInstance) {
|
|
54
122
|
if (prismaInstance.__whatap_observe__) {
|
|
55
123
|
return;
|
|
@@ -92,7 +160,7 @@ PrismaObserver.prototype.setupConnectionInfo = function(prismaInstance) {
|
|
|
92
160
|
|
|
93
161
|
PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
94
162
|
const self = this;
|
|
95
|
-
|
|
163
|
+
|
|
96
164
|
if (typeof prismaInstance.$use === 'function') {
|
|
97
165
|
prismaInstance.$use(async (params, next) => {
|
|
98
166
|
const ctx = TraceContextManager.getCurrentContext();
|
package/lib/requestlog.js
CHANGED
|
@@ -172,11 +172,14 @@ var RequestLog = {
|
|
|
172
172
|
if(conf.log_file_enabled === false ) { return; }
|
|
173
173
|
var log_prefix = WHATAP_CONF+"-";
|
|
174
174
|
|
|
175
|
-
var root = conf['app.root'];
|
|
175
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
176
176
|
if(root==null || root ==undefined){
|
|
177
|
-
console.log('[WHATAP]RequestLog Error - WHATAP ROOT DIR IS NULL
|
|
177
|
+
console.log('[WHATAP]RequestLog Error - WHATAP ROOT DIR IS NULL');
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
|
+
if(fs.existsSync(root) == false) {
|
|
181
|
+
fs.mkdirSync(root, {recursive: true});
|
|
182
|
+
}
|
|
180
183
|
var dir = path.join(root, 'logs');
|
|
181
184
|
if(fs.existsSync(dir) == false) {
|
|
182
185
|
fs.mkdirSync(dir);
|
|
@@ -197,8 +200,9 @@ var RequestLog = {
|
|
|
197
200
|
if(conf.reqlog_rotation_enabled === false || conf.reqlog_enabled === false) { return; }
|
|
198
201
|
if(conf.reqlog_keep_days <= 0) { return; }
|
|
199
202
|
|
|
203
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
204
|
+
if(root==null || root ==undefined){ return; }
|
|
200
205
|
var nowUnit = DateUtil.getDateUnit(),
|
|
201
|
-
root = conf['app.root'],
|
|
202
206
|
dir = path.join(root, 'logs'),
|
|
203
207
|
log_prefix = WHATAP_CONF+"-";
|
|
204
208
|
|
|
@@ -238,7 +242,7 @@ var RequestLog = {
|
|
|
238
242
|
return null;
|
|
239
243
|
if (file.startsWith(WHATAP_CONF) == false) return null;
|
|
240
244
|
|
|
241
|
-
var root = conf['app.root'];
|
|
245
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
242
246
|
if(root==null ){
|
|
243
247
|
return null;
|
|
244
248
|
}
|
|
@@ -281,7 +285,7 @@ var RequestLog = {
|
|
|
281
285
|
|
|
282
286
|
var o = new MapValue();
|
|
283
287
|
if(conf.log_file_enabled === false ) { return o; }
|
|
284
|
-
var root = conf['app.root'];
|
|
288
|
+
var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
|
|
285
289
|
if(root==null){
|
|
286
290
|
return o;
|
|
287
291
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whatap",
|
|
3
3
|
"homepage": "http://www.whatap.io",
|
|
4
|
-
"version": "1.0.
|
|
5
|
-
"releaseDate": "
|
|
4
|
+
"version": "1.0.14-canary.0",
|
|
5
|
+
"releaseDate": "20260323",
|
|
6
6
|
"description": "Monitoring and Profiling Service",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {},
|