whatap 1.0.4 → 1.0.5-canary.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/lib/core/agent.js +2 -2
- package/lib/counter/counter-manager.js +1 -4
- package/lib/counter/task/activetransaction.js +7 -4
- package/lib/observers/grpc-observer.js +335 -0
- package/lib/observers/http-observer.js +75 -4
- package/lib/observers/socket.io-observer.js +1 -1
- package/lib/observers/websocket-observer.js +1 -1
- package/lib/trace/trace-context-manager.js +1 -2
- package/lib/util/nodeutil.js +1 -2
- package/package.json +2 -2
package/lib/core/agent.js
CHANGED
|
@@ -29,7 +29,7 @@ var Interceptor = require('./interceptor').Interceptor,
|
|
|
29
29
|
IORedisObserver = require('../observers/ioredis-observer').IORedisObserver,
|
|
30
30
|
MssqlObserver = require('../observers/mssql-observer').MssqlObserver,
|
|
31
31
|
PgSqlObserver = require('../observers/pgsql-observer').PgSqlObserver,
|
|
32
|
-
|
|
32
|
+
GRpcObserver = require('../observers/grpc-observer').GRpcObserver,
|
|
33
33
|
ApolloObserver = require('../observers/apollo-server-observer').ApolloServerObserver,
|
|
34
34
|
PrismaObserver = require('../observers/prisma-observer').PrismaObserver,
|
|
35
35
|
OracleObserver = require('../observers/oracle-observer').OracleObserver,
|
|
@@ -1105,7 +1105,7 @@ NodeAgent.prototype.loadObserves = function() {
|
|
|
1105
1105
|
observes.push(IORedisObserver);
|
|
1106
1106
|
observes.push(MssqlObserver);
|
|
1107
1107
|
observes.push(PgSqlObserver);
|
|
1108
|
-
|
|
1108
|
+
observes.push(GRpcObserver);
|
|
1109
1109
|
observes.push(ApolloObserver);
|
|
1110
1110
|
observes.push(PrismaObserver);
|
|
1111
1111
|
observes.push(OracleObserver);
|
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
* can be found in the LICENSE file.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
var
|
|
8
|
-
secuMaster = require('../net/security-master'),
|
|
9
|
-
conf = require('../conf/configure'),
|
|
10
|
-
DateUtil = require('./../util/dateutil'),
|
|
7
|
+
var conf = require('../conf/configure'),
|
|
11
8
|
Logger = require('../logger'),
|
|
12
9
|
GCAction = require('../system/gc-action');
|
|
13
10
|
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
var conf = require('../../conf/configure'),
|
|
8
8
|
TraceContextManager = require('../../trace/trace-context-manager'),
|
|
9
|
-
|
|
10
|
-
HashUtil = require('../../util/hashutil'),
|
|
11
|
-
Logger = require('../../logger'),
|
|
12
|
-
Long = require('long');
|
|
9
|
+
Logger = require('../../logger');
|
|
13
10
|
|
|
14
11
|
function ActiveTransaction() {}
|
|
15
12
|
ActiveTransaction.prototype.getActiveStats = function () {
|
|
16
13
|
var stats = new Array(5).fill(0);
|
|
17
14
|
var en = TraceContextManager.getContextEnumeration();
|
|
15
|
+
|
|
16
|
+
if(conf.getProperty('debug_activestats_size_enabled', false)){
|
|
17
|
+
Logger.print("WHATAP-DEBUG-ACTIVESTATS-1", "Size: " + TraceContextManager.size(), false);
|
|
18
|
+
Logger.print("WHATAP-DEBUG-ACTIVESTATS-2", "Pid: " + process.pid, false);
|
|
19
|
+
}
|
|
20
|
+
|
|
18
21
|
try {
|
|
19
22
|
while (en.hasMoreElements()) {
|
|
20
23
|
var ctx = en.nextElement();
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2016 the WHATAP project authors. All rights reserved.
|
|
3
|
+
* Use of this source code is governed by a license that
|
|
4
|
+
* can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
8
|
+
conf = require('../conf/configure'),
|
|
9
|
+
Logger = require('../logger');
|
|
10
|
+
const HashUtil = require("../util/hashutil");
|
|
11
|
+
const shimmer = require('../core/shimmer');
|
|
12
|
+
const AsyncSender = require('../udp/async_sender');
|
|
13
|
+
const PacketTypeEnum = require('../udp/packet_type_enum');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
|
|
16
|
+
var grpc_profile_enabled = conf.getProperty('grpc_profile_enabled', true);
|
|
17
|
+
var grpc_profile_stream_client_enabled = conf.getProperty('grpc_profile_stream_client_enabled', true);
|
|
18
|
+
var grpc_profile_stream_server_enabled = conf.getProperty('grpc_profile_stream_server_enabled', true);
|
|
19
|
+
var grpc_profile_ignore_method = conf.getProperty('grpc_profile_ignore_method', '');
|
|
20
|
+
var ignore_method_set = null;
|
|
21
|
+
conf.on('grpc_profile_enabled', function(newProperty) {
|
|
22
|
+
grpc_profile_enabled = newProperty;
|
|
23
|
+
});
|
|
24
|
+
conf.on('grpc_profile_stream_client_enabled', function(newProperty) {
|
|
25
|
+
grpc_profile_stream_client_enabled = newProperty;
|
|
26
|
+
});
|
|
27
|
+
conf.on('grpc_profile_stream_server_enabled', function(newProperty) {
|
|
28
|
+
grpc_profile_stream_server_enabled = newProperty;
|
|
29
|
+
});
|
|
30
|
+
conf.on('grpc_profile_ignore_method', function(newProperty) {
|
|
31
|
+
grpc_profile_ignore_method = newProperty;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
var GRpcObserver = function(agent) {
|
|
35
|
+
this.agent = agent;
|
|
36
|
+
this.packages = ['@grpc/grpc-js'];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const types = {
|
|
40
|
+
unary: 'unary',
|
|
41
|
+
client_stream: 'clientStream',
|
|
42
|
+
server_stream: 'serverStream',
|
|
43
|
+
bidi: 'bidi'
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
GRpcObserver.prototype.inject = function(mod, moduleName) {
|
|
47
|
+
if (mod.__whatap_observe__) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
mod.__whatap_observe__ = true;
|
|
51
|
+
Logger.initPrint("GRpcObserver");
|
|
52
|
+
|
|
53
|
+
if (grpc_profile_enabled) {
|
|
54
|
+
shimmer.wrap(mod.Server.prototype, 'register', wrapRegister);
|
|
55
|
+
shimmer.wrap(mod.Client.prototype, 'register', wrapRegister);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function checkIgnoreMethod(ignore_method, method_name){
|
|
60
|
+
try{
|
|
61
|
+
if (ignore_method) {
|
|
62
|
+
ignore_method_set = new Set(ignore_method.split(','));
|
|
63
|
+
} else {
|
|
64
|
+
ignore_method_set = null;
|
|
65
|
+
}
|
|
66
|
+
if (ignore_method_set && ignore_method_set.has(method_name)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}catch (e) {
|
|
70
|
+
Logger.printError('WHATAP-263', 'gRPC checkIgnoreMethod error: ' + e, false);
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function wrapHandler(handler, methodName, type) {
|
|
76
|
+
return function(call, callback) {
|
|
77
|
+
var method_name = methodName.includes('/') ? methodName.substring(methodName.lastIndexOf('/')+1, methodName.length) : methodName;
|
|
78
|
+
|
|
79
|
+
if (!grpc_profile_enabled || checkIgnoreMethod(conf.getProperty('grpc_profile_ignore_method', ''), method_name)) {
|
|
80
|
+
return handler.call(this, call, callback);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
TraceContextManager._asyncLocalStorage.run(initCtx(call, methodName), () => {
|
|
84
|
+
var ctx = TraceContextManager._asyncLocalStorage.getStore();
|
|
85
|
+
if (!ctx) {
|
|
86
|
+
return handler.call(this, call, callback);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// TX_START: 트랜잭션 시작
|
|
91
|
+
let startDatas = [
|
|
92
|
+
os.hostname(),
|
|
93
|
+
methodName,
|
|
94
|
+
ctx.remoteIp || '0.0.0.0',
|
|
95
|
+
'', // userAgent
|
|
96
|
+
'', // referer
|
|
97
|
+
String(ctx.userid || 0),
|
|
98
|
+
'false', // isStaticContents
|
|
99
|
+
method_name
|
|
100
|
+
];
|
|
101
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, startDatas);
|
|
102
|
+
|
|
103
|
+
// TX_MSG: Type 정보
|
|
104
|
+
let typeDatas = ['Type', 'Type', type];
|
|
105
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, typeDatas);
|
|
106
|
+
|
|
107
|
+
// TX_MSG: Method 정보
|
|
108
|
+
let methodDatas = ['Method', 'Method', method_name];
|
|
109
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, methodDatas);
|
|
110
|
+
|
|
111
|
+
// TX_MSG: Parameter 정보
|
|
112
|
+
if (call.request && Object.keys(call.request).length > 0) {
|
|
113
|
+
let paramDatas = ['Parameter', 'Parameter', JSON.stringify(call.request)];
|
|
114
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, paramDatas);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function wrappedCallback(err, response, ctx) {
|
|
118
|
+
if (err) {
|
|
119
|
+
// TX_ERROR: 에러 발생
|
|
120
|
+
let errors = [
|
|
121
|
+
err.name || err.constructor?.name || 'GrpcError',
|
|
122
|
+
err.message || 'Unknown error'
|
|
123
|
+
];
|
|
124
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
125
|
+
ctx.status = 500;
|
|
126
|
+
} else {
|
|
127
|
+
ctx.status = 200;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
endTransaction(ctx);
|
|
131
|
+
|
|
132
|
+
if (typeof callback === 'function') {
|
|
133
|
+
return callback(err, response);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return handler.call(this, call, (err, response) => wrappedCallback(err, response, ctx));
|
|
138
|
+
} catch (err) {
|
|
139
|
+
Logger.printError('WHATAP-261', 'gRPC wrapHandler error: ' + err, false);
|
|
140
|
+
|
|
141
|
+
// TX_ERROR: 예외 발생
|
|
142
|
+
let errors = [
|
|
143
|
+
err.name || err.constructor?.name || 'GrpcError',
|
|
144
|
+
err.message || 'Unknown error'
|
|
145
|
+
];
|
|
146
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
147
|
+
|
|
148
|
+
endTransaction(ctx);
|
|
149
|
+
|
|
150
|
+
return handler.call(this, call, callback);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function wrapStreamHandler(handler, methodName, type) {
|
|
157
|
+
return function(call, callback) {
|
|
158
|
+
var method_name = methodName.includes('/') ? methodName.substring(methodName.lastIndexOf('/')+1, methodName.length) : methodName;
|
|
159
|
+
|
|
160
|
+
if (!grpc_profile_enabled || checkIgnoreMethod(conf.getProperty('grpc_profile_ignore_method', ''), method_name)) {
|
|
161
|
+
return handler.call(this, call, callback);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
switch (type) {
|
|
165
|
+
case 'serverStream':
|
|
166
|
+
if (!grpc_profile_stream_server_enabled) {
|
|
167
|
+
return handler.call(this, call, callback);
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
case 'clientStream':
|
|
171
|
+
if (!grpc_profile_stream_client_enabled) {
|
|
172
|
+
return handler.call(this, call, callback);
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
case 'bidi':
|
|
176
|
+
if (!grpc_profile_stream_server_enabled || !grpc_profile_stream_client_enabled) {
|
|
177
|
+
return handler.call(this, call, callback);
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
TraceContextManager._asyncLocalStorage.run(initCtx(call, methodName), () => {
|
|
183
|
+
var ctx = TraceContextManager._asyncLocalStorage.getStore();
|
|
184
|
+
if (!ctx) {
|
|
185
|
+
return handler.call(this, call, callback);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
// TX_START: 트랜잭션 시작
|
|
190
|
+
let startDatas = [
|
|
191
|
+
os.hostname(),
|
|
192
|
+
methodName,
|
|
193
|
+
ctx.remoteIp || '0.0.0.0',
|
|
194
|
+
'', // userAgent
|
|
195
|
+
'', // referer
|
|
196
|
+
String(ctx.userid || 0),
|
|
197
|
+
'false', // isStaticContents
|
|
198
|
+
method_name
|
|
199
|
+
];
|
|
200
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, startDatas);
|
|
201
|
+
|
|
202
|
+
// TX_MSG: Type 정보
|
|
203
|
+
let typeDatas = ['Type', 'Type', type];
|
|
204
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, typeDatas);
|
|
205
|
+
|
|
206
|
+
// TX_MSG: Method 정보
|
|
207
|
+
let methodDatas = ['Method', 'Method', method_name];
|
|
208
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, methodDatas);
|
|
209
|
+
|
|
210
|
+
ctx.status = 200;
|
|
211
|
+
|
|
212
|
+
call.on('end', () => {
|
|
213
|
+
endTransaction(ctx);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
call.once('cancelled', () => {
|
|
217
|
+
// TX_MSG: Cancelled 정보
|
|
218
|
+
let cancelDatas = ['Cancelled', 'Cancelled', 'Request cancelled'];
|
|
219
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, cancelDatas);
|
|
220
|
+
ctx.status = 499; // Client Closed Request
|
|
221
|
+
endTransaction(ctx);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
call.on('error', (err) => {
|
|
225
|
+
// TX_ERROR: 에러 발생
|
|
226
|
+
let errors = [
|
|
227
|
+
err.name || err.constructor?.name || 'GrpcError',
|
|
228
|
+
err.message || 'Unknown error'
|
|
229
|
+
];
|
|
230
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
231
|
+
ctx.status = 500;
|
|
232
|
+
endTransaction(ctx);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return handler.call(this, call);
|
|
236
|
+
} catch (e) {
|
|
237
|
+
Logger.printError('WHATAP-262', 'gRPC wrapStreamHandler error: ' + e, false);
|
|
238
|
+
|
|
239
|
+
// TX_ERROR: 예외 발생
|
|
240
|
+
let errors = [
|
|
241
|
+
e.name || e.constructor?.name || 'GrpcError',
|
|
242
|
+
e.message || 'Unknown error'
|
|
243
|
+
];
|
|
244
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
245
|
+
|
|
246
|
+
endTransaction(ctx);
|
|
247
|
+
|
|
248
|
+
return handler.call(this, call);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function wrapRegister(register) {
|
|
255
|
+
return function(name, handler, serialize, deserialize, type) {
|
|
256
|
+
if (typeof handler === 'function') {
|
|
257
|
+
switch (type) {
|
|
258
|
+
case types.client_stream:
|
|
259
|
+
// Client Streaming은 callback이 필요하므로 wrapHandler 사용
|
|
260
|
+
handler = wrapHandler(handler, name, 'clientStream');
|
|
261
|
+
break;
|
|
262
|
+
case types.server_stream:
|
|
263
|
+
handler = wrapStreamHandler(handler, name, 'serverStream');
|
|
264
|
+
break;
|
|
265
|
+
case types.bidi:
|
|
266
|
+
handler = wrapStreamHandler(handler, name, 'bidi');
|
|
267
|
+
break;
|
|
268
|
+
case types.unary:
|
|
269
|
+
default:
|
|
270
|
+
handler = wrapHandler(handler, name, 'unary');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return register.call(this, name, handler, serialize, deserialize, type);
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function endTransaction(ctx) {
|
|
278
|
+
if (!ctx || TraceContextManager.isExist(ctx.id) === false) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
284
|
+
|
|
285
|
+
// TX_END: 트랜잭션 종료
|
|
286
|
+
let endDatas = [
|
|
287
|
+
os.hostname(),
|
|
288
|
+
ctx.service_name,
|
|
289
|
+
ctx.mtid || 0,
|
|
290
|
+
ctx.mdepth || 0,
|
|
291
|
+
ctx.mcaller_txid || 0,
|
|
292
|
+
ctx.mcaller_pcode || 0,
|
|
293
|
+
ctx.mcaller_spec || '',
|
|
294
|
+
String(ctx.mcaller_url_hash || 0),
|
|
295
|
+
ctx.status || 0
|
|
296
|
+
];
|
|
297
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, endDatas);
|
|
298
|
+
|
|
299
|
+
TraceContextManager.end(ctx.id);
|
|
300
|
+
} catch (e) {
|
|
301
|
+
Logger.printError('WHATAP-265', 'gRPC end transaction error: ' + e, false);
|
|
302
|
+
TraceContextManager.end(ctx.id);
|
|
303
|
+
ctx = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function initCtx(call, methodName) {
|
|
308
|
+
if (!grpc_profile_enabled) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const ctx = TraceContextManager.start();
|
|
313
|
+
if (!ctx) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// gRPC 메타데이터에서 정보 추출
|
|
318
|
+
try {
|
|
319
|
+
if (call.metadata) {
|
|
320
|
+
// Remote IP 추출 시도
|
|
321
|
+
const metadata = call.metadata.getMap();
|
|
322
|
+
ctx.remoteIp = metadata['x-forwarded-for'] || metadata['x-real-ip'] || '0.0.0.0';
|
|
323
|
+
}
|
|
324
|
+
} catch (e) {
|
|
325
|
+
Logger.printError('WHATAP-264', 'gRPC metadata parsing error: ' + e, false);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
ctx.service_name = methodName;
|
|
329
|
+
ctx.service_hash = HashUtil.hashFromString(methodName);
|
|
330
|
+
ctx.start_time = Date.now();
|
|
331
|
+
|
|
332
|
+
return ctx;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
exports.GRpcObserver = GRpcObserver;
|
|
@@ -145,6 +145,31 @@ HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps
|
|
|
145
145
|
self.__endTransaction(null, ctx, req, res);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
// 브라우저가 닫히면 진행 중인 외부 HTTP 요청도 정리하고 TX_HTTPC, TX_END 전송
|
|
149
|
+
res.on('close', function () {
|
|
150
|
+
if (ctx == null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 진행 중인 모든 외부 HTTP 요청에 대해 TX_HTTPC 전송
|
|
155
|
+
// if (ctx.activeHttpcList && ctx.activeHttpcList.length > 0) {
|
|
156
|
+
// ctx.activeHttpcList.forEach(function(httpcInfo) {
|
|
157
|
+
// try {
|
|
158
|
+
// let urls = `${httpcInfo.host}:${httpcInfo.port}${httpcInfo.url}`;
|
|
159
|
+
// let httpcDatas = [urls, httpcInfo.mcallee];
|
|
160
|
+
// ctx.elapsed = Date.now() - httpcInfo.start_time;
|
|
161
|
+
// TraceHttpc.isSlowHttpc(ctx);
|
|
162
|
+
// AsyncSender.send_packet(PacketTypeEnum.TX_HTTPC, ctx, httpcDatas);
|
|
163
|
+
// } catch (e) {
|
|
164
|
+
// Logger.printError('WHATAP-243', 'Failed to send TX_HTTPC on close', e, false);
|
|
165
|
+
// }
|
|
166
|
+
// });
|
|
167
|
+
// ctx.activeHttpcList = [];
|
|
168
|
+
// }
|
|
169
|
+
|
|
170
|
+
self.__endTransaction(null, ctx, req, res);
|
|
171
|
+
});
|
|
172
|
+
|
|
148
173
|
try {
|
|
149
174
|
AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
|
|
150
175
|
return callback.apply(this, arguments);
|
|
@@ -181,6 +206,9 @@ function initCtx(req, res) {
|
|
|
181
206
|
return null;
|
|
182
207
|
}
|
|
183
208
|
|
|
209
|
+
// 진행 중인 외부 HTTP 요청 정보를 저장 (여러 개 동시 추적)
|
|
210
|
+
ctx.activeHttpcList = [];
|
|
211
|
+
|
|
184
212
|
// RemoteIP
|
|
185
213
|
var remote_addr;
|
|
186
214
|
try {
|
|
@@ -495,10 +523,20 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
495
523
|
ctx.httpc_host = options.host || options.hostname || '';
|
|
496
524
|
ctx.httpc_port = options.port || -1;
|
|
497
525
|
ctx.active_httpc_hash = true;
|
|
498
|
-
|
|
526
|
+
|
|
499
527
|
if (ctx.httpc_port < 0) {
|
|
500
528
|
ctx.httpc_port = 80
|
|
501
529
|
}
|
|
530
|
+
|
|
531
|
+
// Send TX_HTTPC at start if enabled (for lost connection cases)
|
|
532
|
+
if (conf.getProperty('profile_httpc_start_step_enabled', false)) {
|
|
533
|
+
ctx.active_httpc_hash = false;
|
|
534
|
+
let urls = `${ctx.httpc_host}:${ctx.httpc_port}${ctx.httpc_url}`;
|
|
535
|
+
let httpcDatas = [urls, ctx.mcallee];
|
|
536
|
+
ctx.elapsed = 0;
|
|
537
|
+
TraceHttpc.isSlowHttpc(ctx);
|
|
538
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_HTTPC, ctx, httpcDatas);
|
|
539
|
+
}
|
|
502
540
|
} catch (e) {
|
|
503
541
|
Logger.printError('WHATAP-240', 'Http Setup Error', e, false);
|
|
504
542
|
return original.apply(this, arguments);
|
|
@@ -507,6 +545,30 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
507
545
|
return original.apply(this, arguments);
|
|
508
546
|
}
|
|
509
547
|
|
|
548
|
+
// 진행 중인 요청 정보 저장 (여러 개 추적)
|
|
549
|
+
const httpcInfo = {
|
|
550
|
+
host: ctx.httpc_host,
|
|
551
|
+
port: ctx.httpc_port,
|
|
552
|
+
url: ctx.httpc_url,
|
|
553
|
+
mcallee: ctx.mcallee,
|
|
554
|
+
start_time: ctx.start_time
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// 배열에 추가
|
|
558
|
+
if (ctx.activeHttpcList) {
|
|
559
|
+
ctx.activeHttpcList.push(httpcInfo);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// 배열에서 제거하는 헬퍼 함수
|
|
563
|
+
const removeHttpcInfo = function() {
|
|
564
|
+
if (ctx.activeHttpcList) {
|
|
565
|
+
const index = ctx.activeHttpcList.indexOf(httpcInfo);
|
|
566
|
+
if (index > -1) {
|
|
567
|
+
ctx.activeHttpcList.splice(index, 1);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
510
572
|
var wrappedCallback;
|
|
511
573
|
if (typeof callback === 'function') {
|
|
512
574
|
wrappedCallback = function (response) {
|
|
@@ -515,7 +577,10 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
515
577
|
}
|
|
516
578
|
|
|
517
579
|
response.on('end', function () {
|
|
518
|
-
//
|
|
580
|
+
// 배열에서 제거
|
|
581
|
+
removeHttpcInfo();
|
|
582
|
+
|
|
583
|
+
// HTTP 클라이언트 에러 처리
|
|
519
584
|
if (response.statusCode >= 400 && transaction_status_error_enable) {
|
|
520
585
|
let error = {
|
|
521
586
|
class: response.statusMessage,
|
|
@@ -538,6 +603,9 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
538
603
|
return;
|
|
539
604
|
}
|
|
540
605
|
|
|
606
|
+
// 배열에서 제거
|
|
607
|
+
removeHttpcInfo();
|
|
608
|
+
|
|
541
609
|
const isIgnoreHttpc = shouldIgnoreError(err.code, ctx.httpc_url, httpc_status_ignore, httpc_status_ignore_set);
|
|
542
610
|
|
|
543
611
|
const networkErrorToStatusCode = {
|
|
@@ -574,7 +642,6 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
574
642
|
bodyData = arguments[0].toString('utf8');
|
|
575
643
|
}
|
|
576
644
|
if (bodyData) {
|
|
577
|
-
console.log(`body Data: ${bodyData}`)
|
|
578
645
|
let paramDatas = ['HTTP-PARAMETERS', options.method, bodyData];
|
|
579
646
|
AsyncSender.send_packet(PacketTypeEnum.TX_SECURE_MSG, ctx, paramDatas);
|
|
580
647
|
}
|
|
@@ -591,12 +658,16 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
|
|
|
591
658
|
}
|
|
592
659
|
});
|
|
593
660
|
|
|
594
|
-
// HTTP 클라이언트 종료 처리 - 단순화
|
|
595
661
|
function endHttpc(ctx) {
|
|
596
662
|
if (ctx == null) {
|
|
597
663
|
return;
|
|
598
664
|
}
|
|
599
665
|
|
|
666
|
+
// If profile_httpc_start_step_enabled is true, TX_HTTPC was already sent at start
|
|
667
|
+
if (conf.getProperty('profile_httpc_start_step_enabled', false)) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
600
671
|
ctx.active_httpc_hash = false;
|
|
601
672
|
let urls = `${ctx.httpc_host}:${ctx.httpc_port}${ctx.httpc_url}`;
|
|
602
673
|
let httpcDatas = [urls, ctx.mcallee];
|
|
@@ -509,7 +509,7 @@ SocketIOObserver.prototype.__endTransaction = function(error, ctx) {
|
|
|
509
509
|
AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, datas);
|
|
510
510
|
|
|
511
511
|
TraceContextManager.end(ctx.id);
|
|
512
|
-
|
|
512
|
+
ctx = null;
|
|
513
513
|
} catch (e) {
|
|
514
514
|
Logger.printError('WHATAP-231', 'Socket.io end transaction error', e, false);
|
|
515
515
|
TraceContextManager.end(ctx.id);
|
|
@@ -378,7 +378,7 @@ WebsocketObserver.prototype.__endTransaction = function(error, ctx) {
|
|
|
378
378
|
ctx.elapsed = Date.now() - ctx.start_time;
|
|
379
379
|
AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, datas);
|
|
380
380
|
TraceContextManager.end(ctx.id);
|
|
381
|
-
|
|
381
|
+
ctx = null;
|
|
382
382
|
} catch (e) {
|
|
383
383
|
Logger.printError('WHATAP-222', 'WebSocket end transaction error', e, false);
|
|
384
384
|
TraceContextManager.end(ctx.id);
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
var IntKeyMap = require('../util/intkey-map'),
|
|
8
|
-
HashUtil = require('../util/hashutil'),
|
|
9
8
|
TraceContext = require('./trace-context'),
|
|
10
9
|
Logger = require('../logger');
|
|
11
10
|
var Long = require('long');
|
|
@@ -19,7 +18,7 @@ function TraceContextManager() {
|
|
|
19
18
|
this.nextId = 1;
|
|
20
19
|
this.currentId = null;
|
|
21
20
|
this._asyncLocalStorage = new AsyncLocalStorage();
|
|
22
|
-
this.entry = new IntKeyMap(1021,1).setMax(
|
|
21
|
+
this.entry = new IntKeyMap(1021,1).setMax(10000);
|
|
23
22
|
this.node = null;
|
|
24
23
|
this.clock_seq = null;
|
|
25
24
|
}
|
package/lib/util/nodeutil.js
CHANGED
|
@@ -90,8 +90,7 @@ var NodeUtil = {
|
|
|
90
90
|
const major = this.getNodeMajorVersion();
|
|
91
91
|
const minor = this.getNodeMinorVersion();
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
return major >= 18 || (major === 16 && minor >= 7);
|
|
93
|
+
return major >= 17 || (major >= 16 && minor >= 7);
|
|
95
94
|
},
|
|
96
95
|
|
|
97
96
|
// 버전 비교 함수
|
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.5-canary.1",
|
|
5
|
+
"releaseDate": "20251030",
|
|
6
6
|
"description": "Monitoring and Profiling Service",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {},
|