whatap 1.0.9 → 1.0.10
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/agent/windows/whatap_nodejs.exe +0 -0
- package/lib/conf/config-default.js +3 -1
- package/lib/control/packagectr-helper.js +3 -3
- package/lib/core/agent.js +57 -27
- package/lib/observers/cron-observer.js +279 -0
- package/lib/observers/custom-method-observer.js +10 -0
- package/lib/observers/http-observer.js +5 -11
- package/package.json +2 -2
|
Binary file
|
|
@@ -278,7 +278,9 @@ var ConfigDefault = {
|
|
|
278
278
|
"prisma_read_func_name": str("prisma_read_func_name", "read"),
|
|
279
279
|
"prisma_database_url_name": str("prisma_database_url_name", "DATABASE_URL"),
|
|
280
280
|
|
|
281
|
-
"metering_tagcount_enabled": bool("metering_tagcount_enabled", false)
|
|
281
|
+
"metering_tagcount_enabled": bool("metering_tagcount_enabled", false),
|
|
282
|
+
|
|
283
|
+
"trace_cron_enabled": bool("trace_cron_enabled", true)
|
|
282
284
|
};
|
|
283
285
|
|
|
284
286
|
ConfigDefault._hook_method_ignore_prefix = ConfigDefault.hook_method_ignore_prefixes.split(',');
|
|
@@ -191,15 +191,15 @@ PackageCtrHelper.hookMethod = function(obj, modulePath, methodName, className) {
|
|
|
191
191
|
return originalMethod.apply(this, arguments);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
var startTime = Date.now();
|
|
194
|
+
var startTime = ctx.start_time = Date.now();
|
|
195
195
|
var error = null;
|
|
196
196
|
var result = null;
|
|
197
197
|
|
|
198
198
|
// Capture original arguments once for later use
|
|
199
199
|
var originalArgs = arguments;
|
|
200
200
|
|
|
201
|
-
// Format: "ClassName.methodName" if className exists, otherwise "
|
|
202
|
-
var methodFullPath = className ? className + '.' + methodName :
|
|
201
|
+
// Format: "ClassName.methodName" if className exists, otherwise "NULL.methodName"
|
|
202
|
+
var methodFullPath = className ? className + '.' + methodName : 'NULL.' + methodName;
|
|
203
203
|
|
|
204
204
|
// Convert arguments to string once
|
|
205
205
|
var argsString = '';
|
package/lib/core/agent.js
CHANGED
|
@@ -35,7 +35,8 @@ var Interceptor = require('./interceptor').Interceptor,
|
|
|
35
35
|
ApolloObserver = require('../observers/apollo-server-observer').ApolloServerObserver,
|
|
36
36
|
PrismaObserver = require('../observers/prisma-observer').PrismaObserver,
|
|
37
37
|
OracleObserver = require('../observers/oracle-observer').OracleObserver,
|
|
38
|
-
CustomMethodObserver = require('../observers/custom-method-observer').CustomMethodObserver
|
|
38
|
+
CustomMethodObserver = require('../observers/custom-method-observer').CustomMethodObserver,
|
|
39
|
+
CronObserver = require('../observers/cron-observer').CronObserver;
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
var Configuration = require('./../conf/configure'),
|
|
@@ -965,12 +966,19 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
|
|
|
965
966
|
if (pid) {
|
|
966
967
|
try {
|
|
967
968
|
if (this.isGoAgentRunning(pid)) {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
Logger.print("WHATAP-
|
|
972
|
-
|
|
973
|
-
|
|
969
|
+
// Windows: 기존 프로세스가 실행 중이면 스킵 (Python agent와 동일한 동작)
|
|
970
|
+
// Unix/Linux: 기존 프로세스 종료 후 새로 시작
|
|
971
|
+
if (process.platform === 'win32') {
|
|
972
|
+
Logger.print("WHATAP-106", `Agent already running (PID: ${pid}). Skipping duplicate execution.`, false);
|
|
973
|
+
return;
|
|
974
|
+
} else {
|
|
975
|
+
Logger.print("WHATAP-106", `Found existing agent with PID ${pid}, terminating...`, false);
|
|
976
|
+
try {
|
|
977
|
+
process.kill(parseInt(pid), 'SIGKILL');
|
|
978
|
+
Logger.print("WHATAP-107", `Successfully terminated existing agent with PID ${pid}`, false);
|
|
979
|
+
} catch (killError) {
|
|
980
|
+
Logger.printError("WHATAP-108", `Error terminating process with PID ${pid}`, killError, false);
|
|
981
|
+
}
|
|
974
982
|
}
|
|
975
983
|
}
|
|
976
984
|
} catch (e) {
|
|
@@ -983,10 +991,16 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
|
|
|
983
991
|
|
|
984
992
|
try {
|
|
985
993
|
// 바이너리 경로 설정
|
|
986
|
-
const agentPath = path.join(whatapHome, AGENT_NAME);
|
|
987
994
|
const platform = process.platform;
|
|
988
995
|
const architecture = ARCH[process.arch] || process.arch;
|
|
989
|
-
|
|
996
|
+
|
|
997
|
+
const binaryName = platform === 'win32' ? AGENT_NAME + '.exe' : AGENT_NAME;
|
|
998
|
+
const agentPath = path.join(whatapHome, binaryName);
|
|
999
|
+
|
|
1000
|
+
// Windows는 architecture 하위 디렉토리 없이 단일 바이너리 사용
|
|
1001
|
+
const sourcePath = platform === 'win32'
|
|
1002
|
+
? path.join(__dirname, '..', '..', 'agent', 'windows', binaryName)
|
|
1003
|
+
: path.join(__dirname, '..', '..', 'agent', platform, architecture, AGENT_NAME);
|
|
990
1004
|
|
|
991
1005
|
// sourcePath 존재 여부 확인
|
|
992
1006
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -1004,8 +1018,10 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
|
|
|
1004
1018
|
Logger.print("WHATAP-037", `Symlink failed (${e.code}), copying binary instead`, false);
|
|
1005
1019
|
try {
|
|
1006
1020
|
fs.copyFileSync(sourcePath, agentPath);
|
|
1007
|
-
// 실행 권한 부여
|
|
1008
|
-
|
|
1021
|
+
// 실행 권한 부여 (Windows는 불필요)
|
|
1022
|
+
if (platform !== 'win32') {
|
|
1023
|
+
fs.chmodSync(agentPath, 0o755);
|
|
1024
|
+
}
|
|
1009
1025
|
Logger.print("WHATAP-221", `Binary copied and made executable at ${agentPath}`, false);
|
|
1010
1026
|
} catch (copyErr) {
|
|
1011
1027
|
throw new Error(`Failed to copy agent binary: ${copyErr.message}`);
|
|
@@ -1014,12 +1030,14 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
|
|
|
1014
1030
|
}
|
|
1015
1031
|
}
|
|
1016
1032
|
|
|
1017
|
-
// agentPath 실행 권한 확인
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1033
|
+
// agentPath 실행 권한 확인 (Windows는 스킵)
|
|
1034
|
+
if (platform !== 'win32') {
|
|
1035
|
+
try {
|
|
1036
|
+
fs.accessSync(agentPath, fs.constants.X_OK);
|
|
1037
|
+
} catch (e) {
|
|
1038
|
+
Logger.print("WHATAP-222", `Agent binary not executable, adding execute permission`, false);
|
|
1039
|
+
fs.chmodSync(agentPath, 0o755);
|
|
1040
|
+
}
|
|
1023
1041
|
}
|
|
1024
1042
|
|
|
1025
1043
|
// run 디렉토리 생성
|
|
@@ -1068,16 +1086,27 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
|
|
|
1068
1086
|
Object.assign(newEnv, opts);
|
|
1069
1087
|
|
|
1070
1088
|
// 에이전트 프로세스 시작
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1089
|
+
// Windows: -t 2 foreground (detached 모드)
|
|
1090
|
+
// Unix/Linux: -t 2 -d 1 (daemon 모드)
|
|
1091
|
+
const spawnArgs = platform === 'win32'
|
|
1092
|
+
? ['-t', '2', 'foreground']
|
|
1093
|
+
: ['-t', '2', '-d', '1'];
|
|
1094
|
+
|
|
1095
|
+
const spawnOptions = {
|
|
1096
|
+
cwd: whatapHome,
|
|
1097
|
+
env: newEnv,
|
|
1098
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1099
|
+
detached: platform === 'win32' // Windows에서는 detached 모드
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
// Windows에서는 DETACHED_PROCESS 플래그 추가
|
|
1103
|
+
if (platform === 'win32') {
|
|
1104
|
+
spawnOptions.detached = true;
|
|
1105
|
+
// Windows 전용: 새로운 콘솔 윈도우 생성 방지
|
|
1106
|
+
spawnOptions.windowsHide = true;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const agentProcess = child_process.spawn(agentPath, spawnArgs, spawnOptions);
|
|
1081
1110
|
|
|
1082
1111
|
const MAX_BUFFER_SIZE = 50000; // 50KB - prevent memory leak
|
|
1083
1112
|
let stdout = '';
|
|
@@ -1322,6 +1351,7 @@ NodeAgent.prototype.loadObserves = function() {
|
|
|
1322
1351
|
observes.push(ApolloObserver);
|
|
1323
1352
|
observes.push(PrismaObserver);
|
|
1324
1353
|
observes.push(OracleObserver);
|
|
1354
|
+
observes.push(CronObserver);
|
|
1325
1355
|
|
|
1326
1356
|
var packageToObserve = {};
|
|
1327
1357
|
observes.forEach(function(observeObj) {
|
|
@@ -0,0 +1,279 @@
|
|
|
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
|
+
AsyncSender = require('../udp/async_sender'),
|
|
11
|
+
PacketTypeEnum = require('../udp/packet_type_enum');
|
|
12
|
+
const shimmer = require('../core/shimmer');
|
|
13
|
+
|
|
14
|
+
var CronObserver = function (agent) {
|
|
15
|
+
this.agent = agent;
|
|
16
|
+
this.packages = ['node-cron', 'cron', 'node-schedule'];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
CronObserver.prototype.__createCronJobObserver = function (callback, cronExpression, jobName) {
|
|
20
|
+
var self = this;
|
|
21
|
+
|
|
22
|
+
// callback이 async 함수인지 확인
|
|
23
|
+
const isAsync = callback.constructor.name === 'AsyncFunction';
|
|
24
|
+
|
|
25
|
+
return function wrappedCronCallback() {
|
|
26
|
+
return TraceContextManager._asyncLocalStorage.run(self.__initCtx(cronExpression, jobName), () => {
|
|
27
|
+
var ctx = TraceContextManager._asyncLocalStorage.getStore();
|
|
28
|
+
|
|
29
|
+
if (!ctx) {
|
|
30
|
+
return callback.apply(this, arguments);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
ctx.service_name = jobName || '/';
|
|
35
|
+
let hostname = '0.0.0.0';
|
|
36
|
+
|
|
37
|
+
let startDatas = [
|
|
38
|
+
hostname,
|
|
39
|
+
ctx.service_name,
|
|
40
|
+
'0.0.0.0',
|
|
41
|
+
'',
|
|
42
|
+
'',
|
|
43
|
+
String(0),
|
|
44
|
+
String(false),
|
|
45
|
+
''
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, startDatas);
|
|
49
|
+
|
|
50
|
+
// 원본 callback 실행
|
|
51
|
+
const result = callback.apply(this, arguments);
|
|
52
|
+
|
|
53
|
+
// async 함수인 경우 Promise 처리
|
|
54
|
+
if (isAsync || (result && typeof result.then === 'function')) {
|
|
55
|
+
return Promise.resolve(result)
|
|
56
|
+
.then((res) => {
|
|
57
|
+
self.__endTransaction(null, ctx);
|
|
58
|
+
return res;
|
|
59
|
+
})
|
|
60
|
+
.catch((error) => {
|
|
61
|
+
self.__handleError(error, ctx);
|
|
62
|
+
self.__endTransaction(null, ctx);
|
|
63
|
+
throw error;
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
// 동기 함수인 경우 바로 종료
|
|
67
|
+
self.__endTransaction(null, ctx);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// 동기 에러 처리
|
|
72
|
+
self.__handleError(error, ctx);
|
|
73
|
+
self.__endTransaction(null, ctx);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
CronObserver.prototype.__handleError = function (error, ctx) {
|
|
81
|
+
if (!ctx) return;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
ctx.error = 1;
|
|
85
|
+
ctx.status = 500;
|
|
86
|
+
|
|
87
|
+
var errorClass = error.code || error.name || error.constructor?.name || 'CronJobError';
|
|
88
|
+
var errorMessage = error.message || 'Cron job execution failed';
|
|
89
|
+
var errorStack = '';
|
|
90
|
+
|
|
91
|
+
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && error.stack) {
|
|
92
|
+
var traceDepth = conf.trace_sql_error_depth;
|
|
93
|
+
var stackLines = error.stack.split("\n");
|
|
94
|
+
if (stackLines.length > traceDepth) {
|
|
95
|
+
stackLines = stackLines.slice(0, traceDepth + 1);
|
|
96
|
+
}
|
|
97
|
+
errorStack = stackLines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var errors = [errorClass, errorMessage];
|
|
101
|
+
if (errorStack || error.stack) {
|
|
102
|
+
errors.push(errorStack || error.stack);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
Logger.printError('WHATAP-301', 'Error handling cron job error', e, false);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
CronObserver.prototype.__endTransaction = function (error, ctx) {
|
|
112
|
+
try {
|
|
113
|
+
if (error) {
|
|
114
|
+
TraceContextManager.end(ctx != null ? ctx.id : null);
|
|
115
|
+
ctx = null;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (ctx == null || TraceContextManager.isExist(ctx.id) === false) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let endDatas = [
|
|
124
|
+
'0.0.0.0',
|
|
125
|
+
ctx.service_name,
|
|
126
|
+
0, // mtid
|
|
127
|
+
0, // mdepth
|
|
128
|
+
0, // mcaller_txid
|
|
129
|
+
0, // mcaller_pcode
|
|
130
|
+
'', // mcaller_spec
|
|
131
|
+
String(0), // mcaller_url_hash
|
|
132
|
+
ctx.status || 200
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
ctx.start_time = Date.now();
|
|
136
|
+
// ctx.elapsed = Date.now() - ctx.start_time;
|
|
137
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, endDatas);
|
|
138
|
+
|
|
139
|
+
TraceContextManager.end(ctx.id);
|
|
140
|
+
ctx = null;
|
|
141
|
+
} catch (e) {
|
|
142
|
+
Logger.printError('WHATAP-302', 'End cron transaction error', e, false);
|
|
143
|
+
TraceContextManager.end(ctx != null ? ctx.id : null);
|
|
144
|
+
ctx = null;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
CronObserver.prototype.__initCtx = function (cronExpression, jobName) {
|
|
149
|
+
if (conf.getProperty('profile_enabled', true) === false) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 크론잡 모니터링 비활성화 옵션 체크
|
|
154
|
+
if (conf.getProperty('trace_cron_enabled', true) === false) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
var ctx = TraceContextManager.start();
|
|
159
|
+
if (ctx == null) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
ctx.service_name = jobName || '/';
|
|
164
|
+
ctx.remoteIp = 0;
|
|
165
|
+
ctx.userid = 0;
|
|
166
|
+
ctx.userAgentString = '';
|
|
167
|
+
ctx.referer = '';
|
|
168
|
+
ctx.status = 200;
|
|
169
|
+
ctx.error = 0;
|
|
170
|
+
|
|
171
|
+
return ctx;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* node-cron 라이브러리 후킹
|
|
176
|
+
*/
|
|
177
|
+
CronObserver.prototype.inject = function (mod, moduleName) {
|
|
178
|
+
var self = this;
|
|
179
|
+
|
|
180
|
+
if (mod.__whatap_observe__) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
mod.__whatap_observe__ = true;
|
|
184
|
+
Logger.initPrint("CronObserver");
|
|
185
|
+
|
|
186
|
+
if (conf.getProperty('profile_enabled', true) === false) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// node-cron의 schedule 메서드 후킹
|
|
191
|
+
if (typeof mod.schedule === 'function') {
|
|
192
|
+
shimmer.wrap(mod, 'schedule', function (original) {
|
|
193
|
+
return function wrappedSchedule(cronExpression, callback, options) {
|
|
194
|
+
// 크론잡 이름 추출 (옵션에서 가져오거나 자동 생성)
|
|
195
|
+
var jobName = '/';
|
|
196
|
+
|
|
197
|
+
if (options && options.name) {
|
|
198
|
+
jobName = `/${options.name}`;
|
|
199
|
+
} else if (typeof cronExpression === 'string') {
|
|
200
|
+
jobName = `/${cronExpression.replace(/\s+/g, '-')}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// callback을 래핑
|
|
204
|
+
var wrappedCallback = self.__createCronJobObserver(callback, cronExpression, jobName);
|
|
205
|
+
|
|
206
|
+
// 원본 schedule 호출 (래핑된 callback으로)
|
|
207
|
+
return original.call(this, cronExpression, wrappedCallback, options);
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// node-schedule 라이브러리 지원
|
|
214
|
+
if (mod.scheduleJob && typeof mod.scheduleJob === 'function') {
|
|
215
|
+
shimmer.wrap(mod, 'scheduleJob', function (original) {
|
|
216
|
+
return function wrappedScheduleJob(nameOrSpec, specOrCallback, callback) {
|
|
217
|
+
var jobName = '/';
|
|
218
|
+
var spec, actualCallback;
|
|
219
|
+
|
|
220
|
+
// 오버로딩 처리
|
|
221
|
+
if (typeof nameOrSpec === 'string') {
|
|
222
|
+
jobName = `/${nameOrSpec}`;
|
|
223
|
+
spec = specOrCallback;
|
|
224
|
+
actualCallback = callback;
|
|
225
|
+
} else {
|
|
226
|
+
spec = nameOrSpec;
|
|
227
|
+
actualCallback = specOrCallback;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// callback 래핑
|
|
231
|
+
var wrappedCallback = self.__createCronJobObserver(
|
|
232
|
+
actualCallback,
|
|
233
|
+
JSON.stringify(spec),
|
|
234
|
+
jobName
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
// 원본 scheduleJob 호출
|
|
238
|
+
if (typeof nameOrSpec === 'string') {
|
|
239
|
+
return original.call(this, nameOrSpec, spec, wrappedCallback);
|
|
240
|
+
} else {
|
|
241
|
+
return original.call(this, spec, wrappedCallback);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// cron 라이브러리 지원 (CronJob 클래스)
|
|
248
|
+
if (mod.CronJob && typeof mod.CronJob === 'function') {
|
|
249
|
+
// mod 객체의 'CronJob' 프로퍼티를 래핑
|
|
250
|
+
shimmer.wrap(mod, 'CronJob', function(OriginalCronJob) {
|
|
251
|
+
return function WrappedCronJob(cronTime, onTick, onComplete, start, timezone, context, runOnInit, utcOffset, unrefTimeout) {
|
|
252
|
+
// onTick 콜백 래핑
|
|
253
|
+
var wrappedOnTick = null;
|
|
254
|
+
if (typeof onTick === 'function') {
|
|
255
|
+
wrappedOnTick = self.__createCronJobObserver(
|
|
256
|
+
onTick,
|
|
257
|
+
typeof cronTime === 'string' ? cronTime : 'custom',
|
|
258
|
+
'/'
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 원본 생성자 호출
|
|
263
|
+
return new OriginalCronJob(
|
|
264
|
+
cronTime,
|
|
265
|
+
wrappedOnTick || onTick,
|
|
266
|
+
onComplete,
|
|
267
|
+
start,
|
|
268
|
+
timezone,
|
|
269
|
+
context,
|
|
270
|
+
runOnInit,
|
|
271
|
+
utcOffset,
|
|
272
|
+
unrefTimeout
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
exports.CronObserver = CronObserver;
|
|
@@ -128,6 +128,16 @@ CustomMethodObserver.prototype.inject = function(mod, moduleName) {
|
|
|
128
128
|
Logger.print('WHATAP-224',
|
|
129
129
|
'Hooked class method: ' + className + '.' + methodName,
|
|
130
130
|
false);
|
|
131
|
+
} else if (typeof moduleExports === 'function' && moduleExports.name === className) {
|
|
132
|
+
// CommonJS default export: module.exports = ExternalService
|
|
133
|
+
if (moduleExports.prototype && typeof moduleExports.prototype[methodName] === 'function') {
|
|
134
|
+
PackageCtrHelper.hookMethod(moduleExports.prototype, tryPath, methodName, className);
|
|
135
|
+
} else {
|
|
136
|
+
PackageCtrHelper.hookMethod(moduleExports, tryPath, methodName, className);
|
|
137
|
+
}
|
|
138
|
+
Logger.print('WHATAP-224-CJS',
|
|
139
|
+
'Hooked CommonJS default class method: ' + className + '.' + methodName,
|
|
140
|
+
false);
|
|
131
141
|
} else if (moduleExports.default) {
|
|
132
142
|
// ESM default export
|
|
133
143
|
if (typeof moduleExports.default === 'function' && moduleExports.default.name === className) {
|
|
@@ -128,6 +128,11 @@ HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
ctx.service_name = req.url ? req.url : "";
|
|
131
|
+
ctx.isStaticContents = isStatic(ctx.service_name);
|
|
132
|
+
if(ctx.isStaticContents){
|
|
133
|
+
return callback(req, res);
|
|
134
|
+
}
|
|
135
|
+
|
|
131
136
|
let hostname = ctx.host && ctx.host.includes(':') ? ctx.host.split(':')[0] : '';
|
|
132
137
|
let datas = [
|
|
133
138
|
hostname,
|
|
@@ -247,17 +252,6 @@ function initCtx(req, res) {
|
|
|
247
252
|
// Host
|
|
248
253
|
ctx.host = req.headers.host;
|
|
249
254
|
|
|
250
|
-
/************************************/
|
|
251
|
-
/* Header / param Trace */
|
|
252
|
-
/************************************/
|
|
253
|
-
var header_enabled = false;
|
|
254
|
-
if(conf.profile_http_header_enabled === true && req.headers) {
|
|
255
|
-
header_enabled = true;
|
|
256
|
-
var prefix = conf.profile_header_url_prefix;
|
|
257
|
-
if(prefix && ctx.service_name.indexOf(prefix) < 0) {
|
|
258
|
-
header_enabled = false;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
255
|
/************************************/
|
|
262
256
|
/* Header / param Trace */
|
|
263
257
|
/************************************/
|
package/package.json
CHANGED