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
package/lib/core/agent.js
CHANGED
|
@@ -6,60 +6,63 @@
|
|
|
6
6
|
|
|
7
7
|
var os = require('os'),
|
|
8
8
|
fs = require('fs'),
|
|
9
|
-
path = require('path')
|
|
10
|
-
child_process = require('child_process'),
|
|
11
|
-
properLock = require('proper-lockfile'),
|
|
12
|
-
crypto = require('crypto');
|
|
9
|
+
path = require('path');
|
|
13
10
|
|
|
14
11
|
const RequestLog = require('../requestlog');
|
|
15
12
|
|
|
16
13
|
var Interceptor = require('./interceptor').Interceptor,
|
|
17
14
|
HttpObserver = require('../observers/http-observer').HttpObserver,
|
|
15
|
+
NetObserver = require('../observers/net-observer').NetObserver,
|
|
16
|
+
ClusterObserver = require('../observers/cluster-observer').ClusterObserver,
|
|
17
|
+
ExpressObserver = require('../observers/express-observer').ExpressObserver,
|
|
18
18
|
GlobalObserver = require('../observers/global-observer').GlobalObserver,
|
|
19
19
|
MysqlObserver = require('../observers/mysql-observer').MysqlObserver,
|
|
20
20
|
Mysql2Observer = require('../observers/mysql2-observer').Mysql2Observer,
|
|
21
21
|
MariaObserver = require('../observers/maria-observer').MariaObserver,
|
|
22
22
|
SocketioObserver = require('../observers/socket.io-observer').SocketIOObserver,
|
|
23
23
|
WebsocketObserver = require('../observers/websocket-observer').WebsocketObserver,
|
|
24
|
-
// WsObserver = require('../observers/websocket-observer').WsObserver,
|
|
25
24
|
ProcessObserver = require('../observers/process-observer').ProcessObserver,
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
FileObserver = require('../observers/file-observer').FileObserver,
|
|
26
|
+
MongoObserver = require('../observers/mongo-observer').MongoObserver,
|
|
27
|
+
MongooseObserver = require('../observers/mongoose-observer').MongooseObserver,
|
|
28
28
|
RedisObserver = require('../observers/redis-observer').RedisObserver,
|
|
29
|
-
IORedisObserver = require('../observers/ioredis-observer').IORedisObserver,
|
|
30
29
|
MssqlObserver = require('../observers/mssql-observer').MssqlObserver,
|
|
30
|
+
ThriftObserver = require('../observers/thrift-observer').ThriftObserver,
|
|
31
|
+
PromiseObserver = require('../observers/promise-observer').PromiseObserver,
|
|
31
32
|
PgSqlObserver = require('../observers/pgsql-observer').PgSqlObserver,
|
|
33
|
+
ScheduleObserver = require('../observers/schedule-observer').ScheduleObserver,
|
|
32
34
|
// GRpcObserver = require('../observers/grpc-observer').GRpcObserver,
|
|
33
35
|
ApolloObserver = require('../observers/apollo-server-observer').ApolloServerObserver,
|
|
34
36
|
PrismaObserver = require('../observers/prisma-observer').PrismaObserver,
|
|
35
37
|
OracleObserver = require('../observers/oracle-observer').OracleObserver;
|
|
36
38
|
|
|
37
39
|
|
|
40
|
+
|
|
38
41
|
var Configuration = require('./../conf/configure'),
|
|
39
42
|
SecurityMaster = require('./../net/security-master'),
|
|
43
|
+
TcpSession = require('./../net/tcp-session'),
|
|
44
|
+
PackageCtrHelper = require('./../control/packagectr-helper'),
|
|
45
|
+
DataPackSender = require('../data/datapack-sender'),
|
|
40
46
|
CounterManager = require('./../counter/counter-manager'),
|
|
41
47
|
NodeUtil = require('./../util/nodeutil'),
|
|
42
48
|
DateUtil = require('./../util/dateutil'),
|
|
43
49
|
WhatapUtil = require('./../util'),
|
|
50
|
+
ParamPack = require('../pack/param-pack').ParamPack,
|
|
51
|
+
PluginLoaderManager = require('../plugin/plugin-loadermanager'),
|
|
44
52
|
TraceContextManager = require('../trace/trace-context-manager'),
|
|
53
|
+
DataTextAgent = require('../data/datatext-agent').agent,
|
|
54
|
+
TextTypes = require('../lang/text-types'),
|
|
45
55
|
HashUtil = require('../util/hashutil'),
|
|
56
|
+
MessageStep = require('../step/message-step'),
|
|
46
57
|
Logger = require('../logger');
|
|
47
58
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
'x64': 'amd64',
|
|
56
|
-
'ia32': '386',
|
|
57
|
-
'arm': 'arm',
|
|
58
|
-
'arm64': 'arm64'
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Agent binary name
|
|
62
|
-
const AGENT_NAME = 'whatap_nodejs';
|
|
59
|
+
require('../stat/stat-tranx');
|
|
60
|
+
require('../stat/stat-sql');
|
|
61
|
+
require('../stat/stat-httpc');
|
|
62
|
+
require('../stat/stat-remote-ip');
|
|
63
|
+
require('../stat/stat-remote-ipurl');
|
|
64
|
+
require('../stat/stat-useragent');
|
|
65
|
+
require('../stat/timingsender');
|
|
63
66
|
|
|
64
67
|
var NodeAgent = function(opt) {
|
|
65
68
|
this._userOpt = opt;
|
|
@@ -67,6 +70,7 @@ var NodeAgent = function(opt) {
|
|
|
67
70
|
this.aop = new Interceptor(this);
|
|
68
71
|
this._conf = Configuration;
|
|
69
72
|
this._securityMaster = SecurityMaster;
|
|
73
|
+
this._tcpsession = null;
|
|
70
74
|
this._counterManager = null;
|
|
71
75
|
this.setLoopTime = 5000;
|
|
72
76
|
this.connectCount = 0;
|
|
@@ -103,837 +107,179 @@ NodeAgent.prototype.findRoot = function () {
|
|
|
103
107
|
root = path.join(root, '..');
|
|
104
108
|
}
|
|
105
109
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
pid = parseInt(pid);
|
|
111
|
-
const platform = process.platform;
|
|
112
|
-
let processCommand = '';
|
|
113
|
-
|
|
114
|
-
if (platform === 'linux') {
|
|
115
|
-
// On Linux, use /proc filesystem - same approach as Python
|
|
116
|
-
try {
|
|
117
|
-
const cmdlineFile = path.join('/proc', pid.toString(), 'cmdline');
|
|
118
|
-
if (fs.existsSync(cmdlineFile)) {
|
|
119
|
-
processCommand = fs.readFileSync(cmdlineFile, 'utf8');
|
|
120
|
-
// Log for debugging
|
|
121
|
-
Logger.print("WHATAP-PROCESS", `Process ${pid} command line: ${processCommand}`, false);
|
|
122
|
-
}
|
|
123
|
-
} catch (e) {
|
|
124
|
-
Logger.printError("WHATAP-101", "Error reading Linux process info", e, false);
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
} else if (platform === 'darwin') {
|
|
128
|
-
// On macOS, use ps command
|
|
129
|
-
try {
|
|
130
|
-
processCommand = child_process.execSync(`ps -p ${pid} -o command=`, { encoding: 'utf8' }).trim();
|
|
131
|
-
Logger.print("WHATAP-PROCESS", `Process ${pid} command line: ${processCommand}`, false);
|
|
132
|
-
} catch (e) {
|
|
133
|
-
Logger.printError("WHATAP-102", "Error reading MacOS process info", e, false);
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
} else if (platform === 'win32') {
|
|
137
|
-
// On Windows, use tasklist command
|
|
138
|
-
try {
|
|
139
|
-
const output = child_process.execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: 'utf8' });
|
|
140
|
-
// Windows output has quotes, e.g.: "whatap_nodejs.exe","1234","Console","1","12,345 K"
|
|
141
|
-
const match = output.match(/"([^"]+)"/);
|
|
142
|
-
if (match && match[1]) {
|
|
143
|
-
processCommand = match[1];
|
|
144
|
-
Logger.print("WHATAP-PROCESS", `Process ${pid} command line: ${processCommand}`, false);
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
Logger.printError("WHATAP-103", "Error reading Windows process info", e, false);
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
// On other platforms, try generic ps command
|
|
152
|
-
try {
|
|
153
|
-
processCommand = child_process.execSync(`ps -p ${pid} -o command=`, { encoding: 'utf8' }).trim();
|
|
154
|
-
Logger.print("WHATAP-PROCESS", `Process ${pid} command line: ${processCommand}`, false);
|
|
155
|
-
} catch (e) {
|
|
156
|
-
Logger.printError("WHATAP-104", "Error reading other os process info", e, false);
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Check if the command contains the agent name (equivalent to Python's find('whatap_python') >= 0)
|
|
162
|
-
const isAgentProcess = processCommand.indexOf(AGENT_NAME) >= 0;
|
|
163
|
-
Logger.print("WHATAP-PROCESS", `Process ${pid} is ${isAgentProcess ? '' : 'not '}a WhaTap agent`, false);
|
|
164
|
-
return isAgentProcess;
|
|
165
|
-
} catch (e) {
|
|
166
|
-
Logger.printError("WHATAP-AGENT", "Error in isNodejsAgentProcess", e, false);
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Function to read PID from file
|
|
172
|
-
NodeAgent.prototype.readPidFile = function(home, fileName) {
|
|
173
|
-
try {
|
|
174
|
-
const filePath = path.join(process.env[home], fileName);
|
|
175
|
-
if (fs.existsSync(filePath)) {
|
|
176
|
-
return fs.readFileSync(filePath, 'utf8').trim();
|
|
177
|
-
}
|
|
178
|
-
} catch (e) {
|
|
179
|
-
Logger.printError("WHATAP-PID", "Error reading PID file", e, false);
|
|
180
|
-
}
|
|
181
|
-
return '';
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Function to write to file
|
|
185
|
-
NodeAgent.prototype.writeToFile = function(home, fileName, value) {
|
|
186
|
-
try {
|
|
187
|
-
const filePath = path.join(process.env[home], fileName);
|
|
188
|
-
fs.writeFileSync(filePath, value);
|
|
189
|
-
return true;
|
|
190
|
-
} catch (e) {
|
|
191
|
-
Logger.printError("WHATAP-FILE", `Error writing to file ${fileName}`, e, false);
|
|
192
|
-
Logger.print("WHATAP-FILE", `Try to execute command: \`sudo chmod -R 777 $WHATAP_HOME\``, false);
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// Modified isGoAgentRunning to check PID +-1 range
|
|
198
|
-
NodeAgent.prototype.isGoAgentRunning = function(pid) {
|
|
199
|
-
try {
|
|
200
|
-
if (!pid) return false;
|
|
201
|
-
|
|
202
|
-
// 원래 PID와 +1, -1된 PID 모두 확인
|
|
203
|
-
const pidsToCheck = [
|
|
204
|
-
parseInt(pid),
|
|
205
|
-
parseInt(pid) + 1,
|
|
206
|
-
parseInt(pid) - 1
|
|
207
|
-
];
|
|
208
|
-
|
|
209
|
-
Logger.print("WHATAP-AGENT", `Checking PIDs: ${pidsToCheck.join(', ')} (original: ${pid})`, false);
|
|
210
|
-
|
|
211
|
-
for (const pidToCheck of pidsToCheck) {
|
|
212
|
-
try {
|
|
213
|
-
// 프로세스 존재 여부 확인
|
|
214
|
-
process.kill(pidToCheck, 0);
|
|
215
|
-
|
|
216
|
-
// whatap_nodejs 프로세스인지 확인
|
|
217
|
-
if (this.isNodejsAgentProcess(pidToCheck)) {
|
|
218
|
-
Logger.print("WHATAP-AGENT",
|
|
219
|
-
`Found agent process at PID ${pidToCheck} (original PID in file: ${pid})`,
|
|
220
|
-
false);
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
} catch (e) {
|
|
224
|
-
// ESRCH error means process doesn't exist
|
|
225
|
-
if (e.code !== 'ESRCH') {
|
|
226
|
-
throw e;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
Logger.print("WHATAP-AGENT", `No agent process found for PID ${pid} or adjacent PIDs`, false);
|
|
232
|
-
return false;
|
|
233
|
-
} catch (e) {
|
|
234
|
-
Logger.printError("WHATAP-AGENT", "Error checking if agent is running", e, false);
|
|
235
|
-
return false;
|
|
110
|
+
NodeAgent.prototype.init = function(cb) {
|
|
111
|
+
var self = this;
|
|
112
|
+
if(self._initialized) {
|
|
113
|
+
return;
|
|
236
114
|
}
|
|
237
|
-
|
|
115
|
+
self._initialized = true;
|
|
116
|
+
self.starttime = Date.now();
|
|
238
117
|
|
|
239
|
-
|
|
240
|
-
* Read content from a file - similar to Python's read_file
|
|
241
|
-
* @param {string} home - Environment variable name for home directory
|
|
242
|
-
* @param {string} fileName - Name of the file to read
|
|
243
|
-
* @returns {string} - Content of the file, or empty string on error
|
|
244
|
-
*/
|
|
245
|
-
NodeAgent.prototype.readFile = function(home, fileName) {
|
|
246
|
-
try {
|
|
247
|
-
const filePath = path.join(process.env[home], fileName);
|
|
248
|
-
if (fs.existsSync(filePath)) {
|
|
249
|
-
return fs.readFileSync(filePath, 'utf8').toString().trim();
|
|
250
|
-
}
|
|
251
|
-
} catch (e) {
|
|
252
|
-
Logger.printError("WHATAP-FILE", `Error reading file ${fileName}`, e, false);
|
|
253
|
-
}
|
|
254
|
-
return '';
|
|
255
|
-
};
|
|
118
|
+
self.findRoot();
|
|
256
119
|
|
|
257
|
-
|
|
258
|
-
* Write content to a file - similar to Python's write_file
|
|
259
|
-
* @param {string} home - Environment variable name for home directory
|
|
260
|
-
* @param {string} fileName - Name of the file to write
|
|
261
|
-
* @param {string} value - Content to write to the file
|
|
262
|
-
* @returns {boolean} - True if successful, false otherwise
|
|
263
|
-
*/
|
|
264
|
-
NodeAgent.prototype.writeFile = function(home, fileName, value) {
|
|
265
|
-
try {
|
|
266
|
-
const filePath = path.join(process.env[home], fileName);
|
|
267
|
-
fs.writeFileSync(filePath, value);
|
|
268
|
-
return true;
|
|
269
|
-
} catch (e) {
|
|
270
|
-
Logger.printError("WHATAP-FILE", `Error writing to file ${fileName}`, e, false);
|
|
271
|
-
Logger.print("WHATAP-FILE", `Try to execute command: \`sudo chmod -R 777 $WHATAP_HOME\``, false);
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
120
|
+
Logger.initializer.process();
|
|
275
121
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
NodeAgent.prototype.findWhatapConf = function() {
|
|
281
|
-
// 1. Check current directory
|
|
282
|
-
const scriptDir = path.dirname(__filename);
|
|
283
|
-
const parentDir = path.dirname(scriptDir);
|
|
284
|
-
let confPath = path.join(parentDir, 'whatap.conf');
|
|
122
|
+
// 최초 1회 실행 후 1시간마다 실행
|
|
123
|
+
const ONE_HOUR = 60 * 60 * 1000;
|
|
124
|
+
Logger.clearOldLog();
|
|
125
|
+
setInterval(Logger.clearOldLog, ONE_HOUR);
|
|
285
126
|
|
|
286
|
-
|
|
287
|
-
process.env.WHATAP_HOME = parentDir;
|
|
288
|
-
return confPath;
|
|
289
|
-
}
|
|
127
|
+
Logger.print('WHATAP-001', 'Start initialize WhaTap Agent... Root[' + self._conf['app.root'] + ']', true);
|
|
290
128
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
while (current !== '/' && current !== path.parse(current).root) {
|
|
294
|
-
confPath = path.join(current, 'whatap.conf');
|
|
295
|
-
if (fs.existsSync(confPath)) {
|
|
296
|
-
process.env.WHATAP_HOME = current;
|
|
297
|
-
return confPath;
|
|
298
|
-
}
|
|
299
|
-
current = path.dirname(current);
|
|
129
|
+
if(self._conf['app.root'] == null || self._conf['app.root'].length == 0) {
|
|
130
|
+
return Logger.print("WHATAP-001", "Can not find application root directory", true);
|
|
300
131
|
}
|
|
301
132
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Open and lock the port file - similar to Python's openPortFile
|
|
307
|
-
* @param {string} filepath - Path to the lock file
|
|
308
|
-
* @returns {object|null} - File descriptor or null if failed
|
|
309
|
-
*/
|
|
310
|
-
NodeAgent.prototype.openPortFile = function(filepath) {
|
|
311
|
-
filepath = filepath || process.env.WHATAP_LOCK_FILE || '/tmp/whatap-nodejs.lock';
|
|
312
|
-
|
|
313
|
-
let fileHandle = null;
|
|
314
|
-
let attempts = 0;
|
|
315
|
-
|
|
316
|
-
// Try to open the file, similar to Python's while loop
|
|
317
|
-
while (!fileHandle && attempts < 100) {
|
|
318
|
-
try {
|
|
319
|
-
// Try to open file for reading and writing
|
|
320
|
-
if (fs.existsSync(filepath)) {
|
|
321
|
-
fileHandle = fs.openSync(filepath, 'r+');
|
|
322
|
-
} else {
|
|
323
|
-
// If file doesn't exist, create the directory if needed
|
|
324
|
-
const dirPath = path.dirname(filepath);
|
|
325
|
-
if (!fs.existsSync(dirPath)) {
|
|
326
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
327
|
-
}
|
|
328
|
-
// Create the file
|
|
329
|
-
fileHandle = fs.openSync(filepath, 'w+');
|
|
330
|
-
}
|
|
331
|
-
} catch (e) {
|
|
332
|
-
Logger.printError("WHATAP-PORT", `Error opening port file (attempt ${attempts})`, e, false);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Similar to Python, add a delay after 50 attempts
|
|
336
|
-
if (attempts > 50) {
|
|
337
|
-
setTimeout(() => {}, 100); // 0.1 second delay
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
attempts++;
|
|
341
|
-
}
|
|
133
|
+
NodeUtil.getPackageJson();
|
|
134
|
+
PackageCtrHelper.dynamicHook();
|
|
342
135
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return
|
|
348
|
-
} catch (e) {
|
|
349
|
-
Logger.printError("WHATAP-PORT", "Failed to lock port file", e, false);
|
|
350
|
-
try {
|
|
351
|
-
fs.closeSync(fileHandle);
|
|
352
|
-
} catch (closeErr) {}
|
|
353
|
-
return null;
|
|
136
|
+
self._conf.init(this._userOpt , function(e) {
|
|
137
|
+
if(e) {
|
|
138
|
+
Logger.printError("WHATAP-002", "Configuataion initialize error. " + e.message,
|
|
139
|
+
e, true);
|
|
140
|
+
return;
|
|
354
141
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Get available port number for the agent - similar to Python's get_port_number
|
|
361
|
-
* @param {number} defaultPort - Default port to start with
|
|
362
|
-
* @param {string} home - WHATAP_HOME directory
|
|
363
|
-
* @returns {number|null} - Allocated port number or null if failed
|
|
364
|
-
*/
|
|
365
|
-
NodeAgent.prototype.getPortNumber = function(port, home) {
|
|
366
|
-
port = port || 6600;
|
|
367
|
-
home = home || process.env.WHATAP_HOME;
|
|
368
|
-
|
|
369
|
-
// Return null if home is not defined
|
|
370
|
-
if (!home) {
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Open the port file
|
|
375
|
-
const fileInfo = this.openPortFile();
|
|
376
|
-
if (!fileInfo) {
|
|
377
|
-
return port; // Return default port if we couldn't open the file
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const { fileHandle, filepath } = fileInfo;
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
// Get file size
|
|
384
|
-
const stats = fs.fstatSync(fileHandle);
|
|
385
|
-
let content = '';
|
|
386
|
-
|
|
387
|
-
// Only read if file is not empty
|
|
388
|
-
if (stats.size > 0) {
|
|
389
|
-
const buffer = Buffer.alloc(stats.size);
|
|
390
|
-
fs.readSync(fileHandle, buffer, 0, buffer.length, 0);
|
|
391
|
-
content = buffer.toString().trim();
|
|
142
|
+
Logger.print('WHATAP-101', 'Finish initialize configuration... ' + Boolean(self._conf['reqlog_enabled']) , false);
|
|
143
|
+
if(Boolean(self._conf['reqlog_enabled']) == true ) {
|
|
144
|
+
Logger.print("WHATAP-REQLOG" , "ReqLog Init Start !!!! " , false);
|
|
145
|
+
RequestLog.initializer.process();
|
|
392
146
|
}
|
|
393
147
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
for (const line of lines) {
|
|
400
|
-
const trimmedLine = line.trim();
|
|
401
|
-
if (!trimmedLine) continue;
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
// Parse the line "port home"
|
|
405
|
-
const parts = trimmedLine.split(/\s+/, 2);
|
|
406
|
-
if (parts.length < 2) continue;
|
|
407
|
-
|
|
408
|
-
const portStr = parts[0];
|
|
409
|
-
const portHome = parts[1];
|
|
410
|
-
const currentPort = parseInt(portStr, 10);
|
|
411
|
-
|
|
412
|
-
if (isNaN(currentPort)) continue;
|
|
413
|
-
|
|
414
|
-
// If home matches, return the port
|
|
415
|
-
if (home === portHome) {
|
|
416
|
-
// Clean up before returning
|
|
417
|
-
properLock.unlockSync(filepath);
|
|
418
|
-
fs.closeSync(fileHandle);
|
|
419
|
-
return currentPort;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Track the highest port number
|
|
423
|
-
if (!lastPortFound || lastPortFound < currentPort) {
|
|
424
|
-
lastPortFound = currentPort;
|
|
425
|
-
}
|
|
426
|
-
} catch (e) {
|
|
427
|
-
continue; // Skip lines that can't be parsed
|
|
428
|
-
}
|
|
148
|
+
self._securityMaster.run( function (err) {
|
|
149
|
+
if(err) {
|
|
150
|
+
Logger.printError('WHATAP-104', 'Failed to connect to whatap server', err, false);
|
|
151
|
+
if(self._counterManager) self._counterManager.stop();
|
|
152
|
+
return;
|
|
429
153
|
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Determine the new port number
|
|
433
|
-
const newPort = lastPortFound ? lastPortFound + 1 : port;
|
|
434
|
-
|
|
435
|
-
// Clear the file completely
|
|
436
|
-
fs.ftruncateSync(fileHandle, 0);
|
|
437
154
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
// Unlock and close the file
|
|
442
|
-
properLock.unlockSync(filepath);
|
|
443
|
-
fs.closeSync(fileHandle);
|
|
444
|
-
|
|
445
|
-
return newPort;
|
|
446
|
-
} catch (e) {
|
|
447
|
-
Logger.printError("WHATAP-PORT", "Error processing port file", e, false);
|
|
448
|
-
|
|
449
|
-
try {
|
|
450
|
-
properLock.unlockSync(filepath);
|
|
451
|
-
fs.closeSync(fileHandle);
|
|
452
|
-
} catch (closeErr) {
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return port;
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Configure the port for the agent and update the configuration
|
|
461
|
-
* @returns {number|null} - The configured port or null if failed
|
|
462
|
-
*/
|
|
463
|
-
NodeAgent.prototype.configurePort = function() {
|
|
464
|
-
const port = this.getPortNumber();
|
|
465
|
-
if (port) {
|
|
466
|
-
this.updateConfig('WHATAP_HOME', 'net_udp_port', port.toString());
|
|
467
|
-
return port;
|
|
468
|
-
}
|
|
469
|
-
return null;
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Update configuration file with new option value - similar to Python's update_config
|
|
474
|
-
* @param {string} home - Environment variable name for WhaTap home
|
|
475
|
-
* @param {string} optKey - Option key to update
|
|
476
|
-
* @param {string} optValue - Option value to set
|
|
477
|
-
*/
|
|
478
|
-
NodeAgent.prototype.updateConfig = function(home, optKey, optValue) {
|
|
479
|
-
const homePath = process.env[home];
|
|
480
|
-
if (!homePath) {
|
|
481
|
-
Logger.print("WHATAP-CONFIG", `${home} environment variable not set`, true);
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const configFile = path.join(homePath, 'whatap.conf');
|
|
486
|
-
|
|
487
|
-
try {
|
|
488
|
-
let content = '';
|
|
489
|
-
let isUpdated = false;
|
|
490
|
-
|
|
491
|
-
if (fs.existsSync(configFile)) {
|
|
492
|
-
const lines = fs.readFileSync(configFile, 'utf8').split('\n');
|
|
493
|
-
|
|
494
|
-
// Look for the option key and update if found
|
|
495
|
-
for (let line of lines) {
|
|
496
|
-
if (line.trim()) {
|
|
497
|
-
const parts = line.split('=');
|
|
498
|
-
const key = parts[0].trim();
|
|
499
|
-
|
|
500
|
-
if (key === optKey) {
|
|
501
|
-
line = `${key}=${optValue}`;
|
|
502
|
-
isUpdated = true;
|
|
503
|
-
}
|
|
155
|
+
self.connect(function (err) {
|
|
156
|
+
if(!err) {
|
|
157
|
+
self.initOK(cb);
|
|
504
158
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
content += `\n${optKey}=${optValue}\n`;
|
|
511
|
-
}
|
|
512
|
-
} else {
|
|
513
|
-
// If config file doesn't exist, create with just this option
|
|
514
|
-
content = `${optKey}=${optValue}\n`;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// Write updated content back to file
|
|
518
|
-
fs.writeFileSync(configFile, content);
|
|
519
|
-
Logger.print("WHATAP-CONFIG", `Updated configuration: ${optKey}=${optValue}`, false);
|
|
520
|
-
} catch (e) {
|
|
521
|
-
Logger.printError("WHATAP-CONFIG", `Error updating configuration: ${optKey}=${optValue}`, e, false);
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
|
|
525
|
-
NodeAgent.prototype.getApplicationIdentifier = function() {
|
|
526
|
-
// 1. 명시적 그룹 지정 (환경 변수)
|
|
527
|
-
if (process.env.WHATAP_APP_GROUP) {
|
|
528
|
-
return process.env.WHATAP_APP_GROUP;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// 2. 설정 파일에서 그룹 지정
|
|
532
|
-
if (this._conf['app_group']) {
|
|
533
|
-
return this._conf['app_group'];
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// 3. 자동 생성
|
|
537
|
-
const appRoot = this._conf['app.root'] || process.cwd();
|
|
538
|
-
const appName = this.getApplicationName();
|
|
539
|
-
|
|
540
|
-
const identifier = crypto
|
|
541
|
-
.createHash('md5')
|
|
542
|
-
.update(`${appRoot}:${appName}`)
|
|
543
|
-
.digest('hex')
|
|
544
|
-
.substr(0, 8);
|
|
545
|
-
|
|
546
|
-
Logger.print("WHATAP-AGENT",
|
|
547
|
-
`Application identifier: ${appName} at ${appRoot} => ${identifier}`,
|
|
548
|
-
false);
|
|
549
|
-
|
|
550
|
-
return identifier;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
NodeAgent.prototype.getApplicationName = function() {
|
|
554
|
-
// 1. PM2 실행 시
|
|
555
|
-
if (process.env.PM2_APP_NAME || process.env.name) {
|
|
556
|
-
return process.env.PM2_APP_NAME || process.env.name;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// 2. 설정 파일에서
|
|
560
|
-
if (this._conf['app_name']) {
|
|
561
|
-
return this._conf['app_name'];
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// 3. 명령행 인수에서 --name 옵션 찾기
|
|
565
|
-
const nameArgIndex = process.argv.indexOf('--name');
|
|
566
|
-
if (nameArgIndex !== -1 && nameArgIndex < process.argv.length - 1) {
|
|
567
|
-
return process.argv[nameArgIndex + 1];
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// 4. 환경 변수로 직접 설정
|
|
571
|
-
if (process.env.APP_NAME) {
|
|
572
|
-
return process.env.APP_NAME;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// 5. 기본값: 실행 파일명
|
|
576
|
-
return path.basename(process.argv[1], '.js');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
self.loadObserves();
|
|
163
|
+
return this;
|
|
577
164
|
};
|
|
578
165
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const self = this;
|
|
582
|
-
const home = 'WHATAP_HOME';
|
|
583
|
-
const pidFileName = `${AGENT_NAME}.pid`;
|
|
584
|
-
const whatapHome = process.env[home];
|
|
585
|
-
|
|
586
|
-
if (!whatapHome) {
|
|
587
|
-
Logger.printError("WHATAP-105", "WHATAP_HOME environment variable is not set", true);
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// 1. 애플리케이션 식별자 생성 (포트 제외)
|
|
592
|
-
const appIdentifier = this.getApplicationIdentifier();
|
|
593
|
-
const sharedLockFile = path.join(whatapHome, `agent-${appIdentifier}.lock`);
|
|
594
|
-
const sharedPidFile = path.join(whatapHome, `agent-${appIdentifier}.pid`);
|
|
166
|
+
NodeAgent.prototype.initOK = function(cb) {
|
|
167
|
+
var self = this;
|
|
595
168
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
169
|
+
Logger.ONAME = self._securityMaster.ONAME;
|
|
170
|
+
Logger.initializer.reset();
|
|
171
|
+
|
|
172
|
+
TraceContextManager.initialized = true;
|
|
173
|
+
DataTextAgent.reset();
|
|
174
|
+
|
|
175
|
+
var param = new ParamPack();
|
|
176
|
+
param.putString("whatap.version", NodeUtil.getVersion()+' '+ NodeUtil.getReleaseDate());
|
|
177
|
+
param.putString("os.name", os.platform());
|
|
178
|
+
param.putString("os.arch", os.arch());
|
|
179
|
+
param.putString('os.release', os.release());
|
|
180
|
+
param.putString('node.version', process.version);
|
|
181
|
+
param.putString('node.uptime', (new Date()).toString());
|
|
182
|
+
param.putString('node.name', NodeUtil.getName());
|
|
183
|
+
param.putString('user.timezone', NodeUtil.getTimeZone());
|
|
184
|
+
param.putString('user.home', os.homedir());
|
|
185
|
+
param.putString('user.hostname', os.hostname());
|
|
186
|
+
// CLOUD PLATFORM INFO
|
|
187
|
+
param.putString('CLOUD_PLATFORM', WhatapUtil.cloudPlatformCheck());
|
|
188
|
+
DataPackSender.sendBoot(param);
|
|
189
|
+
|
|
190
|
+
if(self._counterManager === null) {
|
|
191
|
+
self._counterManager = new CounterManager(self);
|
|
192
|
+
self._counterManager.run();
|
|
193
|
+
PluginLoaderManager.start();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
WhatapUtil.printWhatap();
|
|
197
|
+
self.connectCount = 0;
|
|
198
|
+
self.setLoopTime = 5000;
|
|
199
|
+
if(cb) cb();
|
|
200
|
+
}
|
|
614
201
|
|
|
615
|
-
// 잠금 획득 시도
|
|
616
|
-
let lockAcquired = false;
|
|
617
|
-
try {
|
|
618
|
-
if (!fs.existsSync(sharedLockFile)) {
|
|
619
|
-
fs.writeFileSync(sharedLockFile, process.pid.toString());
|
|
620
|
-
lockAcquired = true;
|
|
621
|
-
}
|
|
622
|
-
} catch (e) {
|
|
623
|
-
Logger.printError("WHATAP-AGENT", "Error acquiring lock", e, false);
|
|
624
|
-
}
|
|
625
202
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
203
|
+
NodeAgent.prototype.context = function(cb) {
|
|
204
|
+
return TraceContextManager.getCurrentContext();
|
|
205
|
+
}
|
|
630
206
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
207
|
+
NodeAgent.prototype.connect = function (cb) {
|
|
208
|
+
var self = this;
|
|
209
|
+
if(self.connectCount >0 && self.connectCount % 10 == 0 ) {
|
|
210
|
+
Logger.print("WHATAP-171",
|
|
211
|
+
"[WhaTap Agent] Can not find server port.\n" +
|
|
212
|
+
"Did you add requre('whatap') as the first line of the app's main module?\n" +
|
|
213
|
+
"https://service.whatap.io/project/" + self._securityMaster.PCODE + "/install",
|
|
214
|
+
true);
|
|
215
|
+
if(self.setLoopTime == 5000) {
|
|
216
|
+
self.setLoopTime += 25000;
|
|
217
|
+
Logger.print("WHATAP-150", "[WhaTap Agent] setLoopTime Up -> " + self.setLoopTime , false)
|
|
218
|
+
}else if(self.setLoopTime == 30000) {
|
|
219
|
+
self.setLoopTime += 30000;
|
|
220
|
+
Logger.print("WHATAP-150", "[WhaTap Agent] setLoopTime Up -> " + self.setLoopTime , false)
|
|
221
|
+
} else if(self.setLoopTime == 60000) {
|
|
222
|
+
self.setLoopTime += 300000;
|
|
223
|
+
Logger.print("WHATAP-150", "[WhaTap Agent] setLoopTime Up -> " + self.setLoopTime , false)
|
|
646
224
|
}
|
|
647
225
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
// 바이너리 경로 설정
|
|
660
|
-
const agentPath = path.join(whatapHome, AGENT_NAME);
|
|
661
|
-
const platform = process.platform;
|
|
662
|
-
const architecture = ARCH[process.arch] || process.arch;
|
|
663
|
-
const sourcePath = path.join(__dirname, '..', '..', 'agent', platform, architecture, AGENT_NAME);
|
|
664
|
-
|
|
665
|
-
// 심볼릭 링크 생성
|
|
666
|
-
if (!fs.existsSync(agentPath)) {
|
|
667
|
-
try {
|
|
668
|
-
fs.symlinkSync(sourcePath, agentPath);
|
|
669
|
-
Logger.print("WHATAP-AGENT", `Created symbolic link for ${AGENT_NAME}`, false);
|
|
670
|
-
} catch (e) {
|
|
671
|
-
if (e.code !== 'EEXIST') {
|
|
672
|
-
if (platform === 'win32') {
|
|
673
|
-
Logger.print("WHATAP-AGENT", "Symlink failed, copying binary instead", false);
|
|
674
|
-
fs.copyFileSync(sourcePath, agentPath);
|
|
675
|
-
} else {
|
|
676
|
-
throw e;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// run 디렉토리 생성
|
|
683
|
-
const sockfilePath = path.join(whatapHome, 'run');
|
|
684
|
-
if (!fs.existsSync(sockfilePath)) {
|
|
685
|
-
fs.mkdirSync(sockfilePath, { recursive: true });
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// 환경 변수 설정
|
|
689
|
-
const newEnv = Object.assign({}, process.env);
|
|
690
|
-
newEnv['whatap.start'] = Date.now().toString();
|
|
691
|
-
newEnv['node.uptime'] = new Date().toString();
|
|
692
|
-
newEnv['node.version'] = process.version;
|
|
693
|
-
newEnv['node.tzname'] = new Date().toLocaleString('en', {timeZoneName: 'short'}).split(' ').pop();
|
|
694
|
-
newEnv['os.release'] = os.release();
|
|
695
|
-
newEnv['whatap.enabled'] = 'True';
|
|
696
|
-
newEnv['WHATAP_PID_FILE'] = sharedPidFile; // 공유 PID 파일 사용
|
|
697
|
-
newEnv['NODEJS_PARENT_APP_PID'] = process.pid.toString();
|
|
698
|
-
newEnv['net_udp_port'] = port.toString();
|
|
699
|
-
newEnv['APP_IDENTIFIER'] = appIdentifier;
|
|
700
|
-
newEnv['APP_NAME'] = this.getApplicationName();
|
|
701
|
-
|
|
702
|
-
// PM2 정보 추가
|
|
703
|
-
const isPM2 = typeof process.env.PM2_HOME !== 'undefined' ||
|
|
704
|
-
typeof process.env.pm_id !== 'undefined' ||
|
|
705
|
-
typeof process.env.PM2_JSON_PROCESSING !== 'undefined';
|
|
706
|
-
|
|
707
|
-
if (isPM2) {
|
|
708
|
-
newEnv['PM2_APP_NAME'] = process.env.name || '';
|
|
709
|
-
newEnv['PM2_ID'] = process.env.pm_id || '';
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
Object.assign(newEnv, opts);
|
|
713
|
-
|
|
714
|
-
// 에이전트 프로세스 시작
|
|
715
|
-
const agentProcess = child_process.spawn(
|
|
716
|
-
agentPath,
|
|
717
|
-
['-t', '2', '-d', '1'],
|
|
718
|
-
{
|
|
719
|
-
cwd: whatapHome,
|
|
720
|
-
env: newEnv,
|
|
721
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
722
|
-
detached: true
|
|
723
|
-
}
|
|
724
|
-
);
|
|
725
|
-
|
|
726
|
-
let stdout = '';
|
|
727
|
-
let stderr = '';
|
|
728
|
-
|
|
729
|
-
agentProcess.stdout.on('data', (data) => {
|
|
730
|
-
stdout += data.toString();
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
agentProcess.stderr.on('data', (data) => {
|
|
734
|
-
stderr += data.toString();
|
|
226
|
+
Logger.print("WHATAP-170", "[WhaTap Agent] now waiting for starting......", false)
|
|
227
|
+
self._tcpsession = TcpSession;
|
|
228
|
+
setTimeout(function () {
|
|
229
|
+
Logger.print("WHATAP-011" , "Connecton Retry....")
|
|
230
|
+
self.connectCount++;
|
|
231
|
+
self._tcpsession.open(function(err) {
|
|
232
|
+
if(err) {
|
|
233
|
+
Logger.printError("WHTAP-11", "TCP SESSION OPEN ERROR", err ,false);
|
|
234
|
+
return self.connect(cb);
|
|
235
|
+
};
|
|
236
|
+
if(cb) cb();
|
|
735
237
|
});
|
|
736
|
-
|
|
737
|
-
// PID 추적을 위한 추가 로직
|
|
738
|
-
agentProcess.on('spawn', () => {
|
|
739
|
-
Logger.print("WHATAP-AGENT", `Agent process spawned with PID: ${agentProcess.pid}`, false);
|
|
740
|
-
|
|
741
|
-
// detached 프로세스에서 실제 PID가 다를 수 있으므로 잠시 대기 후 확인
|
|
742
|
-
setTimeout(() => {
|
|
743
|
-
try {
|
|
744
|
-
// ps 명령으로 실제 PID 찾기
|
|
745
|
-
const psCommand = process.platform === 'win32'
|
|
746
|
-
? `tasklist /FI "IMAGENAME eq ${AGENT_NAME}*" /FO CSV /NH`
|
|
747
|
-
: `ps -ef | grep ${AGENT_NAME} | grep -v grep`;
|
|
748
|
-
|
|
749
|
-
const psOutput = child_process.execSync(psCommand, { encoding: 'utf8' });
|
|
750
|
-
const lines = psOutput.trim().split('\n');
|
|
751
|
-
|
|
752
|
-
for (const line of lines) {
|
|
753
|
-
let foundPid = null;
|
|
754
|
-
|
|
755
|
-
if (process.platform === 'win32') {
|
|
756
|
-
// Windows CSV format: "image","pid","session","#","mem"
|
|
757
|
-
const match = line.match(/"[^"]+","(\d+)"/);
|
|
758
|
-
if (match) foundPid = match[1];
|
|
759
|
-
} else {
|
|
760
|
-
// Unix format: uid pid ppid ...
|
|
761
|
-
const parts = line.split(/\s+/);
|
|
762
|
-
if (parts.length > 1) foundPid = parts[1];
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (foundPid) {
|
|
766
|
-
const pidNum = parseInt(foundPid);
|
|
767
|
-
// spawn된 PID와 비슷한 범위인지 확인
|
|
768
|
-
if (Math.abs(pidNum - agentProcess.pid) <= 2) {
|
|
769
|
-
Logger.print("WHATAP-AGENT",
|
|
770
|
-
`Found actual agent PID: ${foundPid} (spawn returned: ${agentProcess.pid})`,
|
|
771
|
-
false);
|
|
772
|
-
|
|
773
|
-
// 실제 PID로 파일 업데이트
|
|
774
|
-
fs.writeFileSync(sharedPidFile, foundPid);
|
|
775
|
-
this.writeToFile(home, pidFileName, foundPid);
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
// 실제 PID를 찾지 못한 경우 spawn이 반환한 PID 사용
|
|
782
|
-
Logger.print("WHATAP-AGENT",
|
|
783
|
-
`Using spawn PID: ${agentProcess.pid} (actual PID not found)`,
|
|
784
|
-
false);
|
|
785
|
-
|
|
786
|
-
fs.writeFileSync(sharedPidFile, agentProcess.pid.toString());
|
|
787
|
-
this.writeToFile(home, pidFileName, agentProcess.pid.toString());
|
|
788
|
-
|
|
789
|
-
} catch (e) {
|
|
790
|
-
Logger.printError("WHATAP-AGENT", "Error finding actual PID", e, false);
|
|
791
|
-
// 에러 발생 시 spawn이 반환한 PID 사용
|
|
792
|
-
fs.writeFileSync(sharedPidFile, agentProcess.pid.toString());
|
|
793
|
-
this.writeToFile(home, pidFileName, agentProcess.pid.toString());
|
|
794
|
-
}
|
|
795
|
-
}, 1000); // 1초 대기
|
|
796
|
-
});
|
|
797
|
-
|
|
798
|
-
agentProcess.on('close', (code) => {
|
|
799
|
-
if (code !== 0) {
|
|
800
|
-
Logger.printError("WHATAP-AGENT", `Agent process exited with code ${code}`, null, true);
|
|
801
|
-
Logger.print("WHATAP-AGENT", `STDOUT: ${stdout}`, false);
|
|
802
|
-
Logger.print("WHATAP-AGENT", `STDERR: ${stderr}`, false);
|
|
803
|
-
// 에이전트가 비정상 종료되면 파일 제거
|
|
804
|
-
try { fs.unlinkSync(sharedLockFile); } catch (e) {}
|
|
805
|
-
try { fs.unlinkSync(sharedPidFile); } catch (e) {}
|
|
806
|
-
} else {
|
|
807
|
-
Logger.print("WHATAP-AGENT", "Agent started successfully", false);
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
agentProcess.unref();
|
|
812
|
-
|
|
813
|
-
Logger.print("WHATAP-AGENT",
|
|
814
|
-
`AGENT UP! (process name: ${AGENT_NAME}, using port: ${port}, app: ${appIdentifier})`,
|
|
815
|
-
false);
|
|
816
|
-
|
|
817
|
-
// 잠금 해제
|
|
818
|
-
try { fs.unlinkSync(sharedLockFile); } catch (e) {}
|
|
819
|
-
|
|
820
|
-
} catch (e) {
|
|
821
|
-
Logger.printError("WHATAP-AGENT", "Error starting agent", e, true);
|
|
822
|
-
// 에러 발생 시 파일 정리
|
|
823
|
-
try { fs.unlinkSync(sharedLockFile); } catch (e) {}
|
|
824
|
-
try { fs.unlinkSync(sharedPidFile); } catch (e) {}
|
|
825
|
-
}
|
|
238
|
+
}, self.setLoopTime);
|
|
826
239
|
};
|
|
827
240
|
|
|
828
|
-
|
|
829
|
-
process.on('exit', () => {
|
|
830
|
-
if (!process.env.WHATAP_HOME || !NodeAgent.prototype.getApplicationIdentifier) {
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
try {
|
|
835
|
-
const appIdentifier = NodeAgent.prototype.getApplicationIdentifier.call(NodeAgent);
|
|
836
|
-
const sharedPidFile = path.join(process.env.WHATAP_HOME, `agent-${appIdentifier}.pid`);
|
|
837
|
-
|
|
838
|
-
if (fs.existsSync(sharedPidFile)) {
|
|
839
|
-
const pid = fs.readFileSync(sharedPidFile, 'utf8').trim();
|
|
840
|
-
// 현재 프로세스가 기록된 PID의 부모 프로세스인 경우에만 제거
|
|
841
|
-
if (pid === process.env.NODEJS_PARENT_APP_PID) {
|
|
842
|
-
fs.unlinkSync(sharedPidFile);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
} catch (e) {
|
|
846
|
-
// 에러 무시
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
// graceful shutdown 처리 추가
|
|
851
|
-
['SIGTERM', 'SIGINT'].forEach((signal) => {
|
|
852
|
-
process.on(signal, () => {
|
|
853
|
-
Logger.print("WHATAP-AGENT", `Received ${signal}, cleaning up...`, false);
|
|
854
|
-
process.exit(0);
|
|
855
|
-
});
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
// Updated init method to incorporate configuration setup similar to Python agent
|
|
859
|
-
NodeAgent.prototype.init = function(cb) {
|
|
241
|
+
NodeAgent.prototype.connectCB = function (cb) {
|
|
860
242
|
var self = this;
|
|
861
|
-
if
|
|
862
|
-
return
|
|
243
|
+
if(self.connectCount >0 && self.connectCount % 5 == 0 ) {
|
|
244
|
+
return cb(new Error());
|
|
863
245
|
}
|
|
864
|
-
self._initialized = true;
|
|
865
|
-
self.starttime = Date.now();
|
|
866
|
-
|
|
867
|
-
self.findRoot();
|
|
868
|
-
|
|
869
|
-
Logger.initializer.process();
|
|
870
|
-
Logger.print('WHATAP-110', 'Start initialize WhaTap Agent... Root[' + self._conf['app.root'] + ']', true);
|
|
871
|
-
|
|
872
|
-
if (self._conf['app.root'] == null || self._conf['app.root'].length == 0) {
|
|
873
|
-
return Logger.print("WHATAP-111", "Can not find application root directory", true);
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// Initialize configuration with proper home directory
|
|
877
|
-
if (!self.initConfig('WHATAP_HOME')) {
|
|
878
|
-
Logger.printError("WHATAP-CONFIG", "Failed to initialize configuration", null, true);
|
|
879
|
-
return self;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
NodeUtil.getPackageJson();
|
|
883
|
-
|
|
884
|
-
self._conf.init(this._userOpt, function(e) {
|
|
885
|
-
if (e) {
|
|
886
|
-
Logger.printError("WHATAP-112", "Configuration initialize error. " + e.message,
|
|
887
|
-
e, true);
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
Logger.print('WHATAP-113', 'Finish initialize configuration... ' + Boolean(self._conf['reqlog_enabled']), false);
|
|
891
|
-
if (Boolean(self._conf['reqlog_enabled']) == true) {
|
|
892
|
-
Logger.print("WHATAP-REQLOG", "ReqLog Init Start !!!!", false);
|
|
893
|
-
RequestLog.initializer.process();
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
if(!self._counterManager){
|
|
897
|
-
self._counterManager = new CounterManager();
|
|
898
|
-
self._counterManager.run();
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// Set Oname,Oid
|
|
902
|
-
self._securityMaster.decideAgentOnameOid();
|
|
903
246
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
247
|
+
Logger.print("WHATAP-970", "[WhaTap Agent] now waiting for starting......", true)
|
|
248
|
+
self._tcpsession = TcpSession;
|
|
249
|
+
setTimeout(function () {
|
|
250
|
+
self._tcpsession.open(function(err) {
|
|
251
|
+
if(err) {
|
|
252
|
+
Logger.printError("WHTAP-911", "TCP SESSION OPEN ERROR", err ,true);
|
|
253
|
+
self.connectCB(cb);
|
|
254
|
+
return;
|
|
255
|
+
};
|
|
256
|
+
if(cb) cb();
|
|
257
|
+
});
|
|
258
|
+
}, self.setLoopTime);
|
|
914
259
|
};
|
|
915
260
|
|
|
916
|
-
NodeAgent.prototype.context = function(cb) {
|
|
917
|
-
return TraceContextManager.getCurrentContext();
|
|
918
|
-
}
|
|
919
|
-
|
|
920
261
|
NodeAgent.prototype.loadObserves = function() {
|
|
921
262
|
var agent = this;
|
|
922
263
|
var observes = [];
|
|
923
264
|
|
|
924
265
|
observes.push(HttpObserver);
|
|
266
|
+
observes.push(NetObserver);
|
|
267
|
+
observes.push(ClusterObserver);
|
|
925
268
|
observes.push(MysqlObserver);
|
|
926
269
|
observes.push(Mysql2Observer);
|
|
927
270
|
observes.push(MariaObserver);
|
|
928
271
|
observes.push(SocketioObserver);
|
|
929
272
|
observes.push(WebsocketObserver);
|
|
930
|
-
|
|
273
|
+
observes.push(ExpressObserver);
|
|
274
|
+
observes.push(FileObserver);
|
|
931
275
|
observes.push(MongoObserver);
|
|
932
|
-
|
|
276
|
+
observes.push(MongooseObserver);
|
|
933
277
|
observes.push(RedisObserver);
|
|
934
|
-
observes.push(IORedisObserver);
|
|
935
278
|
observes.push(MssqlObserver);
|
|
279
|
+
observes.push(ThriftObserver);
|
|
280
|
+
observes.push(PromiseObserver);
|
|
936
281
|
observes.push(PgSqlObserver);
|
|
282
|
+
observes.push(ScheduleObserver);
|
|
937
283
|
// observes.push(GRpcObserver);
|
|
938
284
|
observes.push(ApolloObserver);
|
|
939
285
|
observes.push(PrismaObserver);
|
|
@@ -975,83 +321,31 @@ NodeAgent.prototype.setServicePort = function (port) {
|
|
|
975
321
|
Configuration['whatap.port'] = port || 0;
|
|
976
322
|
}
|
|
977
323
|
|
|
978
|
-
NodeAgent.prototype.
|
|
324
|
+
NodeAgent.prototype.profile = function(desc, value){
|
|
979
325
|
var self = this;
|
|
980
|
-
Logger.print('WHATAP-UDP', 'Initializing UDP connection...', false);
|
|
981
|
-
|
|
982
|
-
// Initialize the UDP session
|
|
983
|
-
UdpSession.udp(self._conf);
|
|
984
|
-
|
|
985
|
-
// Initialize the async sender
|
|
986
|
-
AsyncSender.startWhatapThread();
|
|
987
|
-
|
|
988
|
-
Logger.print('WHATAP-UDP', 'UDP connection initialized', false);
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* Check if WHATAP_HOME is set - similar to Python's check_whatap_home
|
|
993
|
-
* @param {string} target - Environment variable name to check
|
|
994
|
-
* @returns {string|null} - Value of the environment variable or null
|
|
995
|
-
*/
|
|
996
|
-
NodeAgent.prototype.checkWhatapHome = function(target) {
|
|
997
|
-
let whatapHome = process.env[target];
|
|
998
|
-
if (!whatapHome) {
|
|
999
|
-
whatapHome = this.findWhatapConf();
|
|
1000
|
-
}
|
|
1001
|
-
if (!whatapHome) {
|
|
1002
|
-
Logger.print("WHATAP-HOME", `${target} is empty`, true);
|
|
1003
|
-
}
|
|
1004
|
-
return whatapHome;
|
|
1005
|
-
};
|
|
1006
326
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
* @param {string} home - Environment variable name for home directory
|
|
1010
|
-
* @returns {boolean} - True if successful, false otherwise
|
|
1011
|
-
*/
|
|
1012
|
-
NodeAgent.prototype.initConfig = function(home) {
|
|
1013
|
-
let whatapHome = process.env[home];
|
|
1014
|
-
if (!whatapHome) {
|
|
1015
|
-
whatapHome = this.findWhatapConf();
|
|
1016
|
-
}
|
|
1017
|
-
if (!whatapHome) {
|
|
1018
|
-
whatapHome = this.readFile(home, home.toLowerCase());
|
|
1019
|
-
if (!whatapHome) {
|
|
1020
|
-
whatapHome = process.cwd();
|
|
1021
|
-
process.env[home] = whatapHome;
|
|
327
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
328
|
+
if(ctx == null) { return; }
|
|
1022
329
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
Logger.print("WHATAP-HOME", `CURRENT_WORKING_DIRECTORY is ${whatapHome}`, true);
|
|
1026
|
-
}
|
|
330
|
+
if( self.userProfileHash === 0){
|
|
331
|
+
self.userProfileHash = HashUtil.hashFromString('CustomProfileStep');
|
|
1027
332
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
333
|
+
DataTextAgent.add(TextTypes.MESSAGE,self.userProfileHash, 'CustomProfileStep');
|
|
334
|
+
var step = new MessageStep();
|
|
335
|
+
step.hash = self.userProfileHash;
|
|
336
|
+
step.start_time = ctx.getElapsedTime();
|
|
337
|
+
step.desc = desc;
|
|
338
|
+
if(value){
|
|
339
|
+
step.value=false;
|
|
1031
340
|
}
|
|
341
|
+
ctx.profile.add(step);
|
|
1032
342
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const content = fs.readFileSync(defaultConfigPath, 'utf8');
|
|
1042
|
-
fs.writeFileSync(configFile, content);
|
|
1043
|
-
} else {
|
|
1044
|
-
// Create empty config file
|
|
1045
|
-
fs.writeFileSync(configFile, '# WhaTap Node.js Agent Configuration\n');
|
|
1046
|
-
}
|
|
1047
|
-
} catch (e) {
|
|
1048
|
-
Logger.printError("WHATAP-CONFIG", "Permission error creating config file", e, true);
|
|
1049
|
-
Logger.print("WHATAP-CONFIG", 'Try to execute command: `sudo chmod -R 777 $WHATAP_HOME`', true);
|
|
1050
|
-
return false;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
return true;
|
|
1055
|
-
};
|
|
1056
|
-
|
|
343
|
+
}
|
|
344
|
+
// var plugins={};
|
|
345
|
+
// NodeAgent.prototype.plugin = function(name, func){
|
|
346
|
+
// if(func){
|
|
347
|
+
// plugins[name]=func;
|
|
348
|
+
// }
|
|
349
|
+
// return plugins[name];
|
|
350
|
+
// }
|
|
1057
351
|
exports.NodeAgent = new NodeAgent();
|