whatap 1.0.1 → 1.0.2
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 +32 -78
- package/lib/conf/conf-sys-mon.js +101 -0
- package/lib/conf/config-default.js +10 -3
- package/lib/conf/configure.js +369 -349
- package/lib/conf/license.js +1 -1
- package/lib/control/cmd-config.js +24 -0
- package/lib/control/control-handler.js +367 -0
- package/lib/control/packagectr-helper.js +34 -3
- package/lib/core/agent.js +176 -882
- package/lib/core/interceptor.js +6 -6
- package/lib/core/request-agent.js +27 -0
- package/lib/core/shimmer.js +82 -36
- package/lib/counter/counter-manager.js +79 -8
- package/lib/counter/meter/meter-activex.js +67 -0
- package/lib/counter/meter/meter-httpc.js +57 -0
- package/lib/counter/meter/meter-resource.js +9 -0
- package/lib/counter/meter/meter-service.js +168 -0
- package/lib/counter/meter/meter-socket.io.js +51 -0
- package/lib/counter/meter/meter-sql.js +71 -0
- package/lib/counter/meter/meter-users.js +58 -0
- package/lib/counter/meter.js +183 -0
- package/lib/counter/task/activetransaction.js +68 -17
- package/lib/counter/task/agentinfo.js +107 -0
- package/lib/{system → counter/task}/gc-action.js +27 -74
- package/lib/counter/task/gcstat.js +34 -0
- package/lib/counter/task/heapmem.js +25 -0
- package/lib/counter/task/httpc.js +76 -0
- package/lib/counter/task/metering-info.js +125 -0
- package/lib/counter/task/proc-cpu.js +29 -0
- package/lib/counter/task/realtimeuser.js +31 -0
- package/lib/counter/task/res/systemECSTask.js +39 -0
- package/lib/counter/task/res/systemKubeTask.js +53 -0
- package/lib/counter/task/res/util/awsEcsClientThread.js +218 -0
- package/lib/counter/task/res/util/linuxProcStatUtil.js +14 -0
- package/lib/counter/task/res-sys-cpu.js +62 -0
- package/lib/counter/task/service.js +202 -0
- package/lib/counter/task/socketio.js +30 -0
- package/lib/counter/task/sql.js +105 -0
- package/lib/counter/task/systemperf.js +43 -0
- package/lib/data/datapack-sender.js +289 -0
- package/lib/data/dataprofile-agent.js +162 -0
- package/lib/data/datatext-agent.js +135 -0
- package/lib/data/event-level.js +15 -0
- package/lib/data/test.js +49 -0
- package/lib/data/zipprofile.js +197 -0
- package/lib/env/constants.js +21 -0
- package/lib/error/error-handler.js +437 -0
- package/lib/io/data-inputx.js +13 -3
- package/lib/io/data-outputx.js +268 -206
- package/lib/kube/kube-client.js +144 -0
- package/lib/lang/text-types.js +58 -0
- package/lib/logger.js +6 -6
- package/lib/logsink/line-log-util.js +87 -0
- package/lib/logsink/line-log.js +12 -0
- package/lib/logsink/log-sender.js +78 -0
- package/lib/logsink/log-tracer.js +40 -0
- package/lib/logsink/sender-util.js +56 -0
- package/lib/logsink/zip/zip-send.js +177 -0
- package/lib/net/netflag.js +55 -0
- package/lib/net/receiver.js +66 -0
- package/lib/net/security-master.js +139 -20
- package/lib/net/sender.js +141 -0
- package/lib/net/tcp-return.js +18 -0
- package/lib/net/tcp-session.js +286 -0
- package/lib/net/tcpreq-client-proxy.js +70 -0
- package/lib/net/tcprequest-mgr.js +58 -0
- package/lib/observers/apollo-server-observer.js +33 -27
- package/lib/observers/cluster-observer.js +22 -0
- package/lib/observers/express-observer.js +215 -0
- package/lib/observers/file-observer.js +184 -0
- package/lib/observers/global-observer.js +155 -80
- package/lib/observers/grpc-observer.js +336 -0
- package/lib/observers/http-observer.js +666 -236
- package/lib/observers/maria-observer.js +204 -362
- package/lib/observers/memcached-observer.js +56 -0
- package/lib/observers/mongo-observer.js +317 -0
- package/lib/observers/mongodb-observer.js +169 -226
- package/lib/observers/mongoose-observer.js +518 -323
- package/lib/observers/mssql-observer.js +177 -418
- package/lib/observers/mysql-observer.js +342 -449
- package/lib/observers/mysql2-observer.js +396 -358
- package/lib/observers/net-observer.js +77 -0
- package/lib/observers/oracle-observer.js +559 -384
- package/lib/observers/pgsql-observer.js +231 -489
- package/lib/observers/prisma-observer.js +303 -92
- package/lib/observers/process-observer.js +79 -35
- package/lib/observers/promise-observer.js +31 -0
- package/lib/observers/redis-observer.js +166 -331
- package/lib/observers/schedule-observer.js +67 -0
- package/lib/observers/socket.io-observer.js +226 -187
- package/lib/observers/stream-observer.js +19 -0
- package/lib/observers/thrift-observer.js +197 -0
- package/lib/observers/websocket-observer.js +175 -301
- package/lib/pack/activestack-pack.js +55 -0
- package/lib/pack/apenum.js +8 -0
- package/lib/pack/counter-pack.js +3 -0
- package/lib/pack/errorsnap-pack.js +69 -0
- package/lib/pack/event-pack.js +54 -0
- package/lib/pack/hitmap-pack.js +63 -0
- package/lib/pack/hitmap-pack1.js +152 -0
- package/lib/pack/log-sink-pack.js +14 -52
- package/lib/pack/netstat.js +15 -0
- package/lib/pack/otype.js +7 -0
- package/lib/pack/profile-pack.js +49 -0
- package/lib/pack/realtimeuser-pack.js +41 -0
- package/lib/pack/stat-general-pack.js +96 -0
- package/lib/pack/staterror-pack.js +120 -0
- package/lib/pack/stathttpc-pack.js +66 -0
- package/lib/pack/stathttpc-rec.js +78 -0
- package/lib/pack/statremote-pack.js +46 -0
- package/lib/pack/statservice-pack.js +63 -0
- package/lib/pack/statservice-pack1.js +88 -0
- package/lib/pack/statservice-rec.js +292 -0
- package/lib/pack/statservice-rec_dep.js +151 -0
- package/lib/pack/statsql-pack.js +69 -0
- package/lib/pack/statsql-rec.js +100 -0
- package/lib/pack/statuseragent-pack.js +44 -0
- package/lib/pack/tagcount-pack.js +4 -4
- package/lib/pack/tagctr.js +15 -0
- package/lib/pack/text-pack.js +50 -0
- package/lib/pack/time-count.js +25 -0
- package/lib/pack/websocket.js +15 -0
- package/lib/pack/zip-pack.js +70 -0
- package/lib/pii/pii-item.js +31 -0
- package/lib/pii/pii-mask.js +174 -0
- package/lib/plugin/plugin-loadermanager.js +57 -0
- package/lib/plugin/plugin.js +75 -0
- package/lib/service/tx-record.js +332 -0
- package/lib/stat/stat-error.js +116 -0
- package/lib/stat/stat-httpc.js +98 -0
- package/lib/stat/stat-remote-ip.js +46 -0
- package/lib/stat/stat-remote-ipurl.js +88 -0
- package/lib/stat/stat-sql.js +113 -0
- package/lib/stat/stat-tranx.js +58 -0
- package/lib/stat/stat-tx-caller.js +160 -0
- package/lib/stat/stat-tx-domain.js +111 -0
- package/lib/stat/stat-tx-referer.js +112 -0
- package/lib/stat/stat-useragent.js +48 -0
- package/lib/stat/timingsender.js +76 -0
- package/lib/step/activestack-step.js +38 -0
- package/lib/step/dbc-step.js +36 -0
- package/lib/step/http-stepx.js +67 -0
- package/lib/step/message-step.js +40 -0
- package/lib/step/method-stepx.js +45 -0
- package/lib/step/resultset-step.js +40 -0
- package/lib/step/securemsg-step.js +44 -0
- package/lib/step/socket-step.js +46 -0
- package/lib/step/sql-stepx.js +68 -0
- package/lib/step/sqlxtype.js +16 -0
- package/lib/step/step.js +66 -0
- package/lib/step/stepenum.js +54 -0
- package/lib/topology/link.js +63 -0
- package/lib/topology/nodeinfo.js +123 -0
- package/lib/topology/status-detector.js +111 -0
- package/lib/trace/trace-context-manager.js +113 -25
- package/lib/trace/trace-context.js +21 -7
- package/lib/trace/trace-httpc.js +17 -11
- package/lib/trace/trace-sql.js +29 -21
- package/lib/util/anylist.js +103 -0
- package/lib/util/cardinality/hyperloglog.js +106 -0
- package/lib/util/cardinality/murmurhash.js +31 -0
- package/lib/util/cardinality/registerset.js +75 -0
- package/lib/util/errordata.js +21 -0
- package/lib/util/escape-literal-sql.js +5 -5
- package/lib/util/hashutil.js +18 -18
- package/lib/util/iputil_x.js +527 -0
- package/lib/util/keygen.js +0 -3
- package/lib/util/kube-util.js +73 -0
- package/lib/util/linkedset.js +1 -2
- package/lib/util/nodeutil.js +2 -1
- package/lib/util/paramsecurity.js +80 -0
- package/lib/util/pre-process.js +13 -0
- package/lib/util/process-seq.js +166 -0
- package/lib/util/property-util.js +36 -0
- package/lib/util/request-queue.js +70 -0
- package/lib/util/requestdouble-queue.js +72 -0
- package/lib/util/resourceprofile.js +157 -0
- package/lib/util/stop-watch.js +30 -0
- package/lib/util/system-util.js +10 -0
- package/lib/util/userid-util.js +57 -0
- package/lib/value/map-value.js +3 -2
- package/package.json +9 -4
- package/whatap.conf +1 -4
- package/agent/darwin/arm64/whatap_nodejs +0 -0
- package/agent/linux/amd64/whatap_nodejs +0 -0
- package/agent/linux/arm64/whatap_nodejs +0 -0
- package/build.txt +0 -4
- package/lib/observers/ioredis-observer.js +0 -294
- package/lib/udp/async_sender.js +0 -119
- package/lib/udp/index.js +0 -17
- package/lib/udp/packet_enum.js +0 -52
- package/lib/udp/packet_queue.js +0 -69
- package/lib/udp/packet_type_enum.js +0 -33
- package/lib/udp/param_def.js +0 -72
- package/lib/udp/udp_session.js +0 -336
- package/lib/util/sql-util.js +0 -178
- package/lib/util/trace-helper.js +0 -91
- package/lib/util/transfer.js +0 -58
|
@@ -5,21 +5,32 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
8
|
+
SocketStep = require('../step/socket-step'),
|
|
8
9
|
conf = require('../conf/configure'),
|
|
9
10
|
IPUtil = require('../util/iputil'),
|
|
10
11
|
Logger = require('../logger');
|
|
11
12
|
const {Detector: URLPatternDetector} = require("../trace/serviceurl-pattern-detector");
|
|
13
|
+
const DataTextAgent = require("../data/datatext-agent");
|
|
14
|
+
const ResourceProfile = require("../util/resourceprofile");
|
|
15
|
+
const ProfilePack = require('../pack/profile-pack');
|
|
16
|
+
const TxRecord = require('../service/tx-record');
|
|
17
|
+
const DateUtil = require('../util/dateutil');
|
|
18
|
+
const SecurityMaster = require('../net/security-master');
|
|
19
|
+
const DataProfileAgent = require('../data/dataprofile-agent');
|
|
20
|
+
const MeterUsers = require("../counter/meter/meter-users");
|
|
21
|
+
const MeterService = require('../counter/meter/meter-service').MeterService;
|
|
12
22
|
const shimmer = require('../core/shimmer');
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const os = require('os');
|
|
23
|
+
const MessageStep = require('../step/message-step');
|
|
24
|
+
const HashUtil = require('../util/hashutil');
|
|
16
25
|
|
|
17
26
|
// 설정을 객체로 통합하여 관리 (참조 성능 향상)
|
|
18
27
|
var config = {
|
|
19
28
|
trace_background_socket_enabled: conf.getProperty('trace_background_socket_enabled', true),
|
|
20
29
|
trace_sampling_enabled: conf.getProperty('trace_sampling_enabled', true),
|
|
21
30
|
trace_sampling_tps: conf.getProperty('trace_sampling_tps', 1000),
|
|
22
|
-
resource_sampling_rate: 0.1 // 리소스 프로파일링을 10%만 수행
|
|
31
|
+
resource_sampling_rate: 0.1, // 리소스 프로파일링을 10%만 수행
|
|
32
|
+
profile_batch_size: 20, // 프로파일 배치 처리 크기
|
|
33
|
+
flush_interval: 500 // 프로파일 플러시 간격 (ms)
|
|
23
34
|
};
|
|
24
35
|
|
|
25
36
|
// 설정 변경 감지를 단일 리스너로 통합
|
|
@@ -57,10 +68,48 @@ var SocketIOObserver = function(agent){
|
|
|
57
68
|
}
|
|
58
69
|
};
|
|
59
70
|
|
|
71
|
+
// 프로파일 데이터 버퍼링 (배치 처리)
|
|
72
|
+
this.profileBuffer = [];
|
|
73
|
+
|
|
74
|
+
// 주기적 플러시 설정
|
|
75
|
+
setInterval(() => this.flushProfileBuffer(), config.flush_interval);
|
|
76
|
+
|
|
60
77
|
// IP 주소 캐싱 (성능 최적화)
|
|
61
78
|
this.ipCache = new Map();
|
|
62
79
|
};
|
|
63
80
|
|
|
81
|
+
SocketIOObserver.prototype.flushProfileBuffer = function() {
|
|
82
|
+
if (this.profileBuffer.length === 0) return;
|
|
83
|
+
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
// 100ms 이상 지난 항목만 처리
|
|
86
|
+
const bufferToFlush = this.profileBuffer.filter(item => (now - item.timestamp) >= 100);
|
|
87
|
+
if (bufferToFlush.length === 0) return;
|
|
88
|
+
|
|
89
|
+
// 최대 batch_size까지만 처리
|
|
90
|
+
let batchToProcess;
|
|
91
|
+
if(bufferToFlush.length > config.profile_batch_size)
|
|
92
|
+
batchToProcess = bufferToFlush.slice(0, config.profile_batch_size);
|
|
93
|
+
else
|
|
94
|
+
batchToProcess = bufferToFlush;
|
|
95
|
+
|
|
96
|
+
// 버퍼에서 처리할 항목 제거
|
|
97
|
+
this.profileBuffer = this.profileBuffer.filter(item =>
|
|
98
|
+
!batchToProcess.some(batch => batch.ctx._id === item.ctx._id)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// 배치 처리
|
|
102
|
+
batchToProcess.forEach(item => {
|
|
103
|
+
try {
|
|
104
|
+
DataProfileAgent.sendProfile(item.ctx, item.profile, false);
|
|
105
|
+
// 컨텍스트 정리 (메모리 누수 방지)
|
|
106
|
+
item.ctx = null;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
Logger.printError('WHATAP-615', 'Socket.io buffer flush error', e, false);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
|
|
64
113
|
// IP 주소 처리 최적화 함수
|
|
65
114
|
SocketIOObserver.prototype.getProcessedIp = function(address) {
|
|
66
115
|
if (!address) return null;
|
|
@@ -91,56 +140,6 @@ SocketIOObserver.prototype.getProcessedIp = function(address) {
|
|
|
91
140
|
return result;
|
|
92
141
|
};
|
|
93
142
|
|
|
94
|
-
// 에러 처리 함수
|
|
95
|
-
function handleSocketError(ctx, err) {
|
|
96
|
-
if (!err) return null;
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
var errorClass = err.code || err.name || err.constructor?.name || 'SocketIOError';
|
|
100
|
-
var errorMessage = err.message || 'socket.io error';
|
|
101
|
-
var errorStack = '';
|
|
102
|
-
|
|
103
|
-
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && err.stack) {
|
|
104
|
-
var traceDepth = conf.trace_sql_error_depth;
|
|
105
|
-
var stackLines = err.stack.split("\n");
|
|
106
|
-
if (stackLines.length > traceDepth) {
|
|
107
|
-
stackLines = stackLines.slice(0, traceDepth + 1);
|
|
108
|
-
}
|
|
109
|
-
errorStack = stackLines.join("\n");
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
var shouldAddError = false;
|
|
113
|
-
if (conf._is_trace_ignore_err_cls_contains === true && errorClass &&
|
|
114
|
-
errorClass.indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
115
|
-
shouldAddError = true;
|
|
116
|
-
} else if (conf._is_trace_ignore_err_msg_contains === true && errorMessage &&
|
|
117
|
-
errorMessage.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
|
|
118
|
-
shouldAddError = true;
|
|
119
|
-
} else if (conf._is_trace_ignore_err_cls_contains === false &&
|
|
120
|
-
conf._is_trace_ignore_err_msg_contains === false) {
|
|
121
|
-
shouldAddError = true;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (shouldAddError) {
|
|
125
|
-
if (!ctx.error) ctx.error = 1;
|
|
126
|
-
ctx.status = 500;
|
|
127
|
-
var errors = [errorClass];
|
|
128
|
-
if (errorMessage) {
|
|
129
|
-
errors.push(errorMessage);
|
|
130
|
-
}
|
|
131
|
-
if (errorStack || err.stack) {
|
|
132
|
-
errors.push(errorStack || err.stack);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
136
|
-
return errorClass; // 에러 정보 반환
|
|
137
|
-
}
|
|
138
|
-
} catch (e) {
|
|
139
|
-
Logger.printError('WHATAP-227', 'Error handling Socket.IO error', e, false);
|
|
140
|
-
}
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
143
|
SocketIOObserver.prototype.inject = function (mod, moduleName) {
|
|
145
144
|
if (mod.__whatap_observe__) {
|
|
146
145
|
return;
|
|
@@ -150,6 +149,33 @@ SocketIOObserver.prototype.inject = function (mod, moduleName) {
|
|
|
150
149
|
|
|
151
150
|
var self = this;
|
|
152
151
|
|
|
152
|
+
// 공통 emit 래핑 함수
|
|
153
|
+
const wrapEmitFunction = function(target, emitType, getContextInfo) {
|
|
154
|
+
if (!target || typeof target.emit !== 'function' || target.emit.__wrapped__) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const originalEmit = target.emit;
|
|
159
|
+
target.emit = function(event, ...args) {
|
|
160
|
+
if (!config.trace_background_socket_enabled) {
|
|
161
|
+
return originalEmit.apply(this, [event, ...args]);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const contextInfo = getContextInfo ? getContextInfo.call(this) : {};
|
|
165
|
+
self.__handleSocketEmitEvent(this, event, args, emitType, contextInfo);
|
|
166
|
+
return originalEmit.apply(this, [event, ...args]);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// 원본 함수 속성 보존
|
|
170
|
+
Object.defineProperties(target.emit, {
|
|
171
|
+
length: { value: originalEmit.length },
|
|
172
|
+
name: { value: originalEmit.name },
|
|
173
|
+
__wrapped__: { value: true }
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return true;
|
|
177
|
+
};
|
|
178
|
+
|
|
153
179
|
const wrapSocketIOEvents = function(target) {
|
|
154
180
|
if (!target || typeof target.on !== 'function') {
|
|
155
181
|
return false;
|
|
@@ -362,164 +388,141 @@ SocketIOObserver.prototype.inject = function (mod, moduleName) {
|
|
|
362
388
|
if (mod.Server && mod.Server.prototype) {
|
|
363
389
|
wrapSocketIOEvents(mod.Server.prototype);
|
|
364
390
|
}
|
|
391
|
+
|
|
392
|
+
// 3. 직접 모듈 래핑 (일부 버전에서 필요할 수 있음)
|
|
393
|
+
// if (typeof mod.on === 'function') {
|
|
394
|
+
// wrapSocketIOEvents(mod);
|
|
395
|
+
// }
|
|
365
396
|
};
|
|
366
397
|
|
|
398
|
+
// 소켓 이벤트 처리 최적화 (CPU 및 메모리 사용 감소) - broadcast 지원 추가
|
|
367
399
|
SocketIOObserver.prototype.__handleSocketEmitEvent = function(socket, event, args, emitType, contextInfo) {
|
|
400
|
+
// 빠른 샘플링 체크 (조기 반환으로 성능 향상)
|
|
368
401
|
if (config.trace_sampling_enabled && !this.socketCounter.checkSampling()) {
|
|
402
|
+
MeterService.add(0, 1, 0, SecurityMaster.PCODE, SecurityMaster.OKIND, SecurityMaster.OID);
|
|
369
403
|
return;
|
|
370
404
|
}
|
|
371
405
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (!ctx) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
406
|
+
// 리소스 프로파일링 샘플링 (전체 이벤트의 일부만 측정)
|
|
407
|
+
const shouldProfileResource = Math.random() < config.resource_sampling_rate;
|
|
377
408
|
|
|
409
|
+
// 컨텍스트 생성 및 실행
|
|
410
|
+
TraceContextManager._asyncLocalStorage.run(this.__initCtx(socket, args, shouldProfileResource, emitType, contextInfo), () => {
|
|
378
411
|
try {
|
|
379
|
-
ctx
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
412
|
+
var ctx = TraceContextManager._asyncLocalStorage.getStore();
|
|
413
|
+
if (!ctx) return;
|
|
414
|
+
|
|
415
|
+
// IP 주소 처리 최적화
|
|
416
|
+
var host = null;
|
|
417
|
+
var remoteAddress = contextInfo.remoteAddress || (socket && socket.conn && socket.conn.remoteAddress);
|
|
418
|
+
|
|
419
|
+
if (remoteAddress) {
|
|
420
|
+
const ipInfo = this.getProcessedIp(remoteAddress);
|
|
421
|
+
if (ipInfo) {
|
|
422
|
+
host = ipInfo.host;
|
|
423
|
+
// 이미 처리된 IP 바이트 사용
|
|
424
|
+
var step = new SocketStep();
|
|
425
|
+
step.start_time = ctx.getElapsedTime();
|
|
426
|
+
step.ipaddr = ipInfo.ipBytes;
|
|
427
|
+
step.elapsed = 0; // 즉시 종료 (측정 최소화)
|
|
428
|
+
|
|
429
|
+
// 브로드캐스트 타입 정보 추가
|
|
430
|
+
if (emitType !== 'socket') {
|
|
431
|
+
step.broadcast_type = emitType;
|
|
432
|
+
step.broadcast_info = contextInfo;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
ctx.profile.push(step);
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
const ipBytes = Buffer.from(IPUtil.stringToBytes("0.0.0.0"));
|
|
439
|
+
var step = new SocketStep();
|
|
440
|
+
step.start_time = ctx.getElapsedTime();
|
|
441
|
+
step.ipaddr = ipBytes;
|
|
442
|
+
step.elapsed = 0;
|
|
443
|
+
|
|
444
|
+
ctx.profile.push(step);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// 트랜잭션 종료 및 데이터 전송
|
|
397
448
|
this.__endTransaction(null, ctx);
|
|
449
|
+
|
|
398
450
|
} catch (e) {
|
|
399
|
-
Logger.printError('WHATAP-
|
|
451
|
+
Logger.printError('WHATAP-616', 'socket.io emit transaction error', e, false);
|
|
400
452
|
|
|
401
|
-
|
|
402
|
-
|
|
453
|
+
// 에러 시 컨텍스트 정리 (메모리 누수 방지)
|
|
454
|
+
var ctx = TraceContextManager._asyncLocalStorage.getStore();
|
|
455
|
+
if (ctx) {
|
|
456
|
+
TraceContextManager.end(ctx._id);
|
|
457
|
+
}
|
|
403
458
|
}
|
|
404
459
|
});
|
|
405
460
|
};
|
|
406
461
|
|
|
407
|
-
|
|
462
|
+
// 트랜잭션 종료 최적화 (배치 처리 및 메모리 사용 감소)
|
|
463
|
+
SocketIOObserver.prototype.__endTransaction = function(error, ctx) {
|
|
408
464
|
try {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
465
|
+
// 기본 성능 데이터 수집
|
|
466
|
+
var profile = new ProfilePack();
|
|
467
|
+
var wtx = new TxRecord();
|
|
468
|
+
wtx.endTime = DateUtil.currentTime();
|
|
469
|
+
profile.time = wtx.endTime;
|
|
470
|
+
wtx.elapsed = ctx.getElapsedTime();
|
|
471
|
+
|
|
472
|
+
// 서비스 이름에 브로드캐스트 타입 정보 추가
|
|
473
|
+
let serviceName = ctx.service_name;
|
|
474
|
+
DataTextAgent.SERVICE.add(ctx.service_hash, serviceName);
|
|
475
|
+
|
|
476
|
+
wtx.seq = ctx.txid;
|
|
477
|
+
wtx.service = ctx.service_hash;
|
|
478
|
+
|
|
479
|
+
// 리소스 프로파일링은 샘플링된 경우에만 수행
|
|
480
|
+
if (ctx.shouldProfileResource) {
|
|
481
|
+
wtx.cpuTime = ResourceProfile.getCPUTime() - ctx.start_cpu;
|
|
482
|
+
wtx.malloc = ResourceProfile.getUsedHeapSize() - ctx.start_malloc;
|
|
483
|
+
if(wtx.malloc < 0) { wtx.malloc = 0; }
|
|
484
|
+
} else {
|
|
485
|
+
wtx.cpuTime = 0;
|
|
486
|
+
wtx.malloc = 0;
|
|
431
487
|
}
|
|
432
488
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
Logger.printError('WHATAP-229', 'Socket.io send message error', e, false);
|
|
436
|
-
throw e;
|
|
437
|
-
}
|
|
438
|
-
};
|
|
489
|
+
wtx.status = 2;
|
|
490
|
+
wtx.ipaddr = ctx.remoteIp;
|
|
439
491
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
var start_time = Date.now();
|
|
443
|
-
ctx.start_time = start_time;
|
|
444
|
-
ctx.elapsed = 0;
|
|
445
|
-
ctx.error = 0;
|
|
446
|
-
|
|
447
|
-
// IP 주소 및 포트 처리
|
|
448
|
-
var ipString = "0.0.0.0";
|
|
449
|
-
var port = 0;
|
|
450
|
-
var remoteAddress = contextInfo.remoteAddress || (socket && socket.conn && socket.conn.remoteAddress);
|
|
451
|
-
|
|
452
|
-
if (remoteAddress) {
|
|
453
|
-
const ipInfo = this.getProcessedIp(remoteAddress);
|
|
454
|
-
if (ipInfo) {
|
|
455
|
-
ipString = ipInfo.host;
|
|
456
|
-
ctx.remoteIp = ipInfo.ipInt;
|
|
457
|
-
|
|
458
|
-
if (socket && socket.conn && socket.conn.remotePort) {
|
|
459
|
-
port = Number(socket.conn.remotePort);
|
|
460
|
-
} else if (remoteAddress.includes(':')) {
|
|
461
|
-
// remoteAddress에서 포트 추출 시도
|
|
462
|
-
const parts = remoteAddress.split(':');
|
|
463
|
-
if (parts.length > 1) {
|
|
464
|
-
const portStr = parts[parts.length - 1];
|
|
465
|
-
const parsedPort = parseInt(portStr, 10);
|
|
466
|
-
if (!isNaN(parsedPort)) {
|
|
467
|
-
port = parsedPort;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
492
|
+
// 기본 측정 데이터 기록
|
|
493
|
+
MeterService.add(0, wtx.elapsed, 0, SecurityMaster.PCODE, SecurityMaster.OKIND, SecurityMaster.OID);
|
|
473
494
|
|
|
474
|
-
|
|
475
|
-
|
|
495
|
+
profile.oid = SecurityMaster.OID;
|
|
496
|
+
profile.service = wtx;
|
|
476
497
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
Logger.printError('WHATAP-230', 'Socket.io send event error', e, false);
|
|
481
|
-
throw e;
|
|
482
|
-
}
|
|
483
|
-
};
|
|
498
|
+
// 컨텍스트 ID 보존 후 컨텍스트 종료 (메모리 누수 방지)
|
|
499
|
+
const ctxId = ctx._id;
|
|
500
|
+
TraceContextManager.end(ctxId);
|
|
484
501
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
502
|
+
// 프로파일 데이터 버퍼에 추가 (비동기 처리 최적화)
|
|
503
|
+
this.profileBuffer.push({
|
|
504
|
+
ctx: ctx,
|
|
505
|
+
profile: profile,
|
|
506
|
+
timestamp: Date.now()
|
|
507
|
+
});
|
|
492
508
|
|
|
493
|
-
if (
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
let datas = [
|
|
498
|
-
os.hostname(), // hostname
|
|
499
|
-
ctx.service_name,
|
|
500
|
-
0, // mtid
|
|
501
|
-
0, // mdepth
|
|
502
|
-
0, // mcaller_txid
|
|
503
|
-
0, // mcaller_pcode
|
|
504
|
-
'', // mcaller_spec
|
|
505
|
-
String(0), // mcaller_url_hash
|
|
506
|
-
200
|
|
507
|
-
];
|
|
508
|
-
ctx.elapsed = Date.now() - ctx.start_time;
|
|
509
|
-
AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, datas);
|
|
510
|
-
|
|
511
|
-
TraceContextManager.end(ctx.id);
|
|
509
|
+
if (this.profileBuffer.length > 1000) {
|
|
510
|
+
// 가장 오래된 항목부터 제거
|
|
511
|
+
this.profileBuffer = this.profileBuffer.slice(-500);
|
|
512
|
+
}
|
|
512
513
|
|
|
513
514
|
} catch (e) {
|
|
514
|
-
Logger.printError('WHATAP-
|
|
515
|
-
|
|
515
|
+
Logger.printError('WHATAP-615', 'Socket.io end transaction error', e, false);
|
|
516
|
+
// 에러 시에도 컨텍스트 정리
|
|
517
|
+
TraceContextManager.end(ctx._id);
|
|
516
518
|
ctx = null;
|
|
517
519
|
}
|
|
518
520
|
};
|
|
519
521
|
|
|
520
|
-
|
|
522
|
+
// 컨텍스트 초기화 최적화 - broadcast 정보 추가
|
|
523
|
+
SocketIOObserver.prototype.__initCtx = function(socket, args, shouldProfileResource, emitType, contextInfo) {
|
|
521
524
|
const ctx = TraceContextManager.start();
|
|
522
|
-
if (!ctx) return
|
|
525
|
+
if (!ctx) {return;}
|
|
523
526
|
|
|
524
527
|
var remote_addr;
|
|
525
528
|
var remoteAddress = contextInfo.remoteAddress || (socket && socket.conn && socket.conn.remoteAddress);
|
|
@@ -531,18 +534,54 @@ SocketIOObserver.prototype.__initCtx = function(socket, args, emitType, contextI
|
|
|
531
534
|
}
|
|
532
535
|
|
|
533
536
|
ctx.service_name = "/socket.io";
|
|
537
|
+
ctx.service_hash = HashUtil.hashFromString(ctx.service_name);
|
|
538
|
+
|
|
539
|
+
// MessageStep 생성 - 브로드캐스트 타입별 정보
|
|
540
|
+
var step = new MessageStep();
|
|
541
|
+
var title, message;
|
|
542
|
+
|
|
543
|
+
switch (emitType) {
|
|
544
|
+
case 'broadcast':
|
|
545
|
+
title = "Broadcast";
|
|
546
|
+
message = "Broadcast to all clients except sender";
|
|
547
|
+
break;
|
|
548
|
+
case 'room_broadcast':
|
|
549
|
+
title = "Room Broadcast";
|
|
550
|
+
message = `Broadcast to room: ${contextInfo.room || 'unknown'}`;
|
|
551
|
+
break;
|
|
552
|
+
case 'global_broadcast':
|
|
553
|
+
title = "Global Broadcast";
|
|
554
|
+
message = `Total clients: ${contextInfo.connectedSockets || 0}`;
|
|
555
|
+
break;
|
|
556
|
+
case 'server_room_broadcast':
|
|
557
|
+
title = "Server Room Broadcast";
|
|
558
|
+
message = `Room: ${contextInfo.room || 'unknown'}, Total clients: ${contextInfo.connectedSockets || 0}`;
|
|
559
|
+
break;
|
|
560
|
+
default:
|
|
561
|
+
title = "Socket";
|
|
562
|
+
message = "Direct socket message";
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
step.hash = HashUtil.hashFromString(title);
|
|
566
|
+
step.start_time = ctx.getElapsedTime();
|
|
567
|
+
step.desc = message;
|
|
568
|
+
DataTextAgent.MESSAGE.add(step.hash, title);
|
|
569
|
+
ctx.profile.push(step);
|
|
570
|
+
|
|
571
|
+
// 리소스 측정은 샘플링된 경우에만 수행
|
|
572
|
+
ctx.shouldProfileResource = shouldProfileResource;
|
|
573
|
+
if (shouldProfileResource) {
|
|
574
|
+
ctx.start_malloc = ResourceProfile.getUsedHeapSize();
|
|
575
|
+
ctx.start_cpu = ResourceProfile.getCPUTime();
|
|
576
|
+
}
|
|
534
577
|
|
|
535
578
|
if (remote_addr) {
|
|
536
579
|
remote_addr = IPUtil.checkIp4(remote_addr);
|
|
537
580
|
ctx.remoteIp = IPUtil.stringToInt(remote_addr);
|
|
538
|
-
ctx.userid = ctx.remoteIp;
|
|
581
|
+
ctx.userid = Long.fromNumber(ctx.remoteIp);
|
|
582
|
+
MeterUsers.add(ctx.userid);
|
|
539
583
|
}
|
|
540
584
|
|
|
541
|
-
// 기본값 설정
|
|
542
|
-
ctx.userAgentString = '';
|
|
543
|
-
ctx.referer = '';
|
|
544
|
-
ctx.status = 200;
|
|
545
|
-
|
|
546
585
|
return ctx;
|
|
547
586
|
};
|
|
548
587
|
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
|
|
8
|
+
var StreamObserver = function(agent) {
|
|
9
|
+
this.agent = agent;
|
|
10
|
+
this.aop = agent.aop;
|
|
11
|
+
this.packages = ['stream'];
|
|
12
|
+
};
|
|
13
|
+
StreamObserver.prototype.inject = function (mod, moduleName) {
|
|
14
|
+
if(mod.__whatap_observe__) { return; }
|
|
15
|
+
mod.__whatap_observe__ = true;
|
|
16
|
+
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.StreamObserver = StreamObserver;
|