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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -n \"ECONNREFUSED\" /Users/seunghunlee/agent_workspace/nodejs_agent/lib/observers/*.js /Users/seunghunlee/agent_workspace/nodejs_agent/lib/core/agent.js 2>/dev/null)"
5
+ ]
6
+ }
7
+ }
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
- Logger.initializer.process();
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
- return Logger.print("WHATAP-111", "Can not find application root directory", false);
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(conf.getProperty('log_root', null)){
172
- root = conf.getProperty('log_root', null);
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 (conf.getProperty('log_root', null)) {
203
- root = conf.getProperty('log_root', null);
204
- if (fs.existsSync(root) == false) {
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
- return function(...args) {
41
- // 원래 생성자 호출
42
- const instance = originalConstructor.apply(this, args);
43
-
44
- // 패치 적용
45
- self.patchPrismaInstance(instance);
46
-
47
- return instance;
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.13",
5
- "releaseDate": "20260226",
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": {},