whatap 0.5.26 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -0
- package/lib/conf/config-default.js +3 -10
- package/lib/conf/configure.js +349 -369
- package/lib/conf/license.js +1 -1
- package/lib/control/packagectr-helper.js +3 -34
- package/lib/core/agent.js +882 -176
- package/lib/core/interceptor.js +6 -6
- package/lib/core/shimmer.js +36 -82
- package/lib/counter/counter-manager.js +8 -79
- package/lib/counter/task/activetransaction.js +17 -68
- package/lib/io/data-inputx.js +3 -13
- package/lib/io/data-outputx.js +206 -268
- package/lib/logger.js +6 -6
- package/lib/net/security-master.js +20 -139
- package/lib/observers/apollo-server-observer.js +27 -33
- package/lib/observers/global-observer.js +80 -155
- package/lib/observers/http-observer.js +236 -666
- package/lib/observers/ioredis-observer.js +294 -0
- package/lib/observers/maria-observer.js +362 -204
- package/lib/observers/mongodb-observer.js +226 -169
- package/lib/observers/mongoose-observer.js +323 -518
- package/lib/observers/mssql-observer.js +418 -177
- package/lib/observers/mysql-observer.js +449 -342
- package/lib/observers/mysql2-observer.js +358 -396
- package/lib/observers/oracle-observer.js +384 -559
- package/lib/observers/pgsql-observer.js +489 -231
- package/lib/observers/prisma-observer.js +92 -303
- package/lib/observers/process-observer.js +35 -79
- package/lib/observers/redis-observer.js +331 -166
- package/lib/observers/socket.io-observer.js +187 -226
- package/lib/observers/websocket-observer.js +301 -175
- package/lib/pack/counter-pack.js +0 -3
- package/lib/pack/log-sink-pack.js +52 -14
- package/lib/pack/tagcount-pack.js +4 -4
- package/lib/{counter/task → system}/gc-action.js +74 -27
- package/lib/trace/trace-context-manager.js +25 -113
- package/lib/trace/trace-context.js +7 -21
- package/lib/trace/trace-httpc.js +11 -17
- package/lib/trace/trace-sql.js +21 -29
- package/lib/udp/async_sender.js +119 -0
- package/lib/udp/index.js +17 -0
- package/lib/udp/packet_enum.js +52 -0
- package/lib/udp/packet_queue.js +69 -0
- package/lib/udp/packet_type_enum.js +33 -0
- package/lib/udp/param_def.js +72 -0
- package/lib/udp/udp_session.js +336 -0
- package/lib/util/escape-literal-sql.js +5 -5
- package/lib/util/hashutil.js +18 -18
- package/lib/util/keygen.js +3 -0
- package/lib/util/linkedset.js +2 -1
- package/lib/util/nodeutil.js +1 -2
- package/lib/util/sql-util.js +178 -0
- package/lib/util/trace-helper.js +91 -0
- package/lib/util/transfer.js +58 -0
- package/lib/value/map-value.js +2 -3
- package/package.json +5 -10
- package/lib/conf/conf-sys-mon.js +0 -101
- package/lib/control/cmd-config.js +0 -24
- package/lib/control/control-handler.js +0 -367
- package/lib/core/request-agent.js +0 -27
- package/lib/counter/meter/meter-activex.js +0 -67
- package/lib/counter/meter/meter-httpc.js +0 -57
- package/lib/counter/meter/meter-resource.js +0 -9
- package/lib/counter/meter/meter-service.js +0 -168
- package/lib/counter/meter/meter-socket.io.js +0 -51
- package/lib/counter/meter/meter-sql.js +0 -71
- package/lib/counter/meter/meter-users.js +0 -58
- package/lib/counter/meter.js +0 -183
- package/lib/counter/task/agentinfo.js +0 -107
- package/lib/counter/task/gcstat.js +0 -34
- package/lib/counter/task/heapmem.js +0 -25
- package/lib/counter/task/httpc.js +0 -76
- package/lib/counter/task/metering-info.js +0 -125
- package/lib/counter/task/proc-cpu.js +0 -29
- package/lib/counter/task/realtimeuser.js +0 -31
- package/lib/counter/task/res/systemECSTask.js +0 -39
- package/lib/counter/task/res/systemKubeTask.js +0 -53
- package/lib/counter/task/res/util/awsEcsClientThread.js +0 -218
- package/lib/counter/task/res/util/linuxProcStatUtil.js +0 -14
- package/lib/counter/task/res-sys-cpu.js +0 -62
- package/lib/counter/task/service.js +0 -202
- package/lib/counter/task/socketio.js +0 -30
- package/lib/counter/task/sql.js +0 -105
- package/lib/counter/task/systemperf.js +0 -43
- package/lib/data/datapack-sender.js +0 -289
- package/lib/data/dataprofile-agent.js +0 -162
- package/lib/data/datatext-agent.js +0 -135
- package/lib/data/event-level.js +0 -15
- package/lib/data/test.js +0 -49
- package/lib/data/zipprofile.js +0 -197
- package/lib/env/constants.js +0 -21
- package/lib/error/error-handler.js +0 -437
- package/lib/kube/kube-client.js +0 -144
- package/lib/lang/text-types.js +0 -58
- package/lib/logsink/line-log-util.js +0 -87
- package/lib/logsink/line-log.js +0 -12
- package/lib/logsink/log-sender.js +0 -78
- package/lib/logsink/log-tracer.js +0 -40
- package/lib/logsink/sender-util.js +0 -56
- package/lib/logsink/zip/zip-send.js +0 -177
- package/lib/net/netflag.js +0 -55
- package/lib/net/receiver.js +0 -66
- package/lib/net/sender.js +0 -141
- package/lib/net/tcp-return.js +0 -18
- package/lib/net/tcp-session.js +0 -286
- package/lib/net/tcpreq-client-proxy.js +0 -70
- package/lib/net/tcprequest-mgr.js +0 -58
- package/lib/observers/cluster-observer.js +0 -22
- package/lib/observers/express-observer.js +0 -215
- package/lib/observers/file-observer.js +0 -184
- package/lib/observers/grpc-observer.js +0 -336
- package/lib/observers/memcached-observer.js +0 -56
- package/lib/observers/mongo-observer.js +0 -317
- package/lib/observers/net-observer.js +0 -77
- package/lib/observers/promise-observer.js +0 -31
- package/lib/observers/schedule-observer.js +0 -67
- package/lib/observers/stream-observer.js +0 -19
- package/lib/observers/thrift-observer.js +0 -197
- package/lib/pack/activestack-pack.js +0 -55
- package/lib/pack/apenum.js +0 -8
- package/lib/pack/errorsnap-pack.js +0 -69
- package/lib/pack/event-pack.js +0 -54
- package/lib/pack/hitmap-pack.js +0 -63
- package/lib/pack/hitmap-pack1.js +0 -152
- package/lib/pack/netstat.js +0 -15
- package/lib/pack/otype.js +0 -7
- package/lib/pack/profile-pack.js +0 -49
- package/lib/pack/realtimeuser-pack.js +0 -41
- package/lib/pack/stat-general-pack.js +0 -96
- package/lib/pack/staterror-pack.js +0 -120
- package/lib/pack/stathttpc-pack.js +0 -66
- package/lib/pack/stathttpc-rec.js +0 -78
- package/lib/pack/statremote-pack.js +0 -46
- package/lib/pack/statservice-pack.js +0 -63
- package/lib/pack/statservice-pack1.js +0 -88
- package/lib/pack/statservice-rec.js +0 -292
- package/lib/pack/statservice-rec_dep.js +0 -151
- package/lib/pack/statsql-pack.js +0 -69
- package/lib/pack/statsql-rec.js +0 -100
- package/lib/pack/statuseragent-pack.js +0 -44
- package/lib/pack/tagctr.js +0 -15
- package/lib/pack/text-pack.js +0 -50
- package/lib/pack/time-count.js +0 -25
- package/lib/pack/websocket.js +0 -15
- package/lib/pack/zip-pack.js +0 -70
- package/lib/pii/pii-item.js +0 -31
- package/lib/pii/pii-mask.js +0 -174
- package/lib/plugin/plugin-loadermanager.js +0 -57
- package/lib/plugin/plugin.js +0 -75
- package/lib/service/tx-record.js +0 -332
- package/lib/stat/stat-error.js +0 -116
- package/lib/stat/stat-httpc.js +0 -98
- package/lib/stat/stat-remote-ip.js +0 -46
- package/lib/stat/stat-remote-ipurl.js +0 -88
- package/lib/stat/stat-sql.js +0 -113
- package/lib/stat/stat-tranx.js +0 -58
- package/lib/stat/stat-tx-caller.js +0 -160
- package/lib/stat/stat-tx-domain.js +0 -111
- package/lib/stat/stat-tx-referer.js +0 -112
- package/lib/stat/stat-useragent.js +0 -48
- package/lib/stat/timingsender.js +0 -76
- package/lib/step/activestack-step.js +0 -38
- package/lib/step/dbc-step.js +0 -36
- package/lib/step/http-stepx.js +0 -67
- package/lib/step/message-step.js +0 -40
- package/lib/step/method-stepx.js +0 -45
- package/lib/step/resultset-step.js +0 -40
- package/lib/step/securemsg-step.js +0 -44
- package/lib/step/socket-step.js +0 -46
- package/lib/step/sql-stepx.js +0 -68
- package/lib/step/sqlxtype.js +0 -16
- package/lib/step/step.js +0 -66
- package/lib/step/stepenum.js +0 -54
- package/lib/topology/link.js +0 -63
- package/lib/topology/nodeinfo.js +0 -123
- package/lib/topology/status-detector.js +0 -111
- package/lib/util/anylist.js +0 -103
- package/lib/util/cardinality/hyperloglog.js +0 -106
- package/lib/util/cardinality/murmurhash.js +0 -31
- package/lib/util/cardinality/registerset.js +0 -75
- package/lib/util/errordata.js +0 -21
- package/lib/util/iputil_x.js +0 -527
- package/lib/util/kube-util.js +0 -73
- package/lib/util/paramsecurity.js +0 -80
- package/lib/util/pre-process.js +0 -13
- package/lib/util/process-seq.js +0 -166
- package/lib/util/property-util.js +0 -36
- package/lib/util/request-queue.js +0 -70
- package/lib/util/requestdouble-queue.js +0 -72
- package/lib/util/resourceprofile.js +0 -157
- package/lib/util/stop-watch.js +0 -30
- package/lib/util/system-util.js +0 -10
- package/lib/util/userid-util.js +0 -57
|
@@ -5,31 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const TraceContextManager = require("../trace/trace-context-manager");
|
|
8
|
-
const ParsedSql = require("../trace/parsed-sql");
|
|
9
|
-
const SqlStepX = require("../step/sql-stepx");
|
|
10
|
-
const DBCStep = require("../step/dbc-step");
|
|
11
|
-
const ResultSetStep = require("../step/resultset-step");
|
|
12
|
-
const DataTextAgent = require("../data/datatext-agent");
|
|
13
|
-
const StatSql = require("../stat/stat-sql");
|
|
14
|
-
const MeterSql = require("../counter/meter/meter-sql");
|
|
15
8
|
const conf = require("../conf/configure");
|
|
16
|
-
const IntKeyMap = require("../util/intkey-map");
|
|
17
|
-
const EscapeLiteralSQL = require("../util/escape-literal-sql");
|
|
18
9
|
const HashUtil = require("../util/hashutil");
|
|
19
|
-
const StatError = require("../stat/stat-error");
|
|
20
|
-
const TextTypes = require("../lang/text-types");
|
|
21
|
-
const ParamSecurity = require("../util/paramsecurity");
|
|
22
10
|
const Logger = require("../logger");
|
|
23
|
-
const Buffer = require("buffer").Buffer;
|
|
24
|
-
const DateUtil = require("../util/dateutil");
|
|
25
|
-
const TraceSQL = require("../trace/trace-sql");
|
|
26
11
|
const shimmer = require("../core/shimmer");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
var prisma_database_url_name = conf.getProperty('prisma_database_url_name', 'DATABASE_URL')
|
|
30
|
-
conf.on('prisma_database_url_name', function (newProps) {
|
|
31
|
-
prisma_database_url_name = newProps;
|
|
32
|
-
})
|
|
12
|
+
const AsyncSender = require('../udp/async_sender');
|
|
13
|
+
const PacketTypeEnum = require('../udp/packet_type_enum');
|
|
33
14
|
|
|
34
15
|
var PrismaObserver = function(agent) {
|
|
35
16
|
this.agent = agent;
|
|
@@ -55,40 +36,20 @@ PrismaObserver.prototype.inject = function(mod, moduleName) {
|
|
|
55
36
|
|
|
56
37
|
// Prisma Client 초기화 메서드 후킹
|
|
57
38
|
if (mod.PrismaClient) {
|
|
58
|
-
// 직접 PrismaClient 생성자 후킹
|
|
59
39
|
shimmer.wrap(mod, 'PrismaClient', function(originalConstructor) {
|
|
60
40
|
return function(...args) {
|
|
61
|
-
|
|
62
|
-
const instance =
|
|
63
|
-
|
|
64
|
-
const prismaServicePrototype = Object.getPrototypeOf(this);
|
|
65
|
-
Object.getOwnPropertyNames(prismaServicePrototype).forEach((method) => {
|
|
66
|
-
if (typeof prismaServicePrototype[method] === "function" && !instance[method]) {
|
|
67
|
-
instance[method] = prismaServicePrototype[method].bind(instance);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
Object.getOwnPropertyNames(originalInstance).forEach((prop) => {
|
|
72
|
-
if (!instance.hasOwnProperty(prop)) {
|
|
73
|
-
instance[prop] = originalInstance[prop];
|
|
74
|
-
}
|
|
75
|
-
});
|
|
41
|
+
// 원래 생성자 호출
|
|
42
|
+
const instance = originalConstructor.apply(this, args);
|
|
76
43
|
|
|
44
|
+
// 패치 적용
|
|
77
45
|
self.patchPrismaInstance(instance);
|
|
78
46
|
|
|
79
|
-
if (!instance[prisma_read_func_name]) {
|
|
80
|
-
instance[prisma_read_func_name] = function () {
|
|
81
|
-
return this;
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
47
|
return instance;
|
|
86
48
|
};
|
|
87
49
|
});
|
|
88
50
|
}
|
|
89
51
|
};
|
|
90
52
|
|
|
91
|
-
// 각 Prisma 인스턴스에 패치 적용
|
|
92
53
|
PrismaObserver.prototype.patchPrismaInstance = function(prismaInstance) {
|
|
93
54
|
if (prismaInstance.__whatap_observe__) {
|
|
94
55
|
return;
|
|
@@ -96,71 +57,56 @@ PrismaObserver.prototype.patchPrismaInstance = function(prismaInstance) {
|
|
|
96
57
|
prismaInstance.__whatap_observe__ = true;
|
|
97
58
|
|
|
98
59
|
this.setupConnectionInfo(prismaInstance);
|
|
99
|
-
|
|
100
60
|
this.hookUseMiddleware(prismaInstance);
|
|
101
61
|
};
|
|
102
62
|
|
|
103
|
-
// 연결 정보 설정
|
|
104
63
|
PrismaObserver.prototype.setupConnectionInfo = function(prismaInstance) {
|
|
105
64
|
try {
|
|
106
65
|
// 연결 정보 가져오기 시도
|
|
107
66
|
const url = prismaInstance._engineConfig?.overrideDatasources?.db?.url ||
|
|
108
|
-
prismaInstance.
|
|
109
|
-
|
|
67
|
+
prismaInstance._engineConfig?.datasources?.db?.url ||
|
|
68
|
+
prismaInstance._baseDmmf?.datamodel?.datasources?.[0]?.url?.value ||
|
|
69
|
+
process.env.DATABASE_URL ||
|
|
110
70
|
'prisma:unknown';
|
|
111
71
|
|
|
112
72
|
if (url && url !== "prisma:unknown" && !dbc_hash) {
|
|
113
73
|
const dbUrl = new URL(url);
|
|
114
74
|
const protocol = dbUrl.protocol.replace(':', '');
|
|
115
75
|
|
|
116
|
-
// 프로토콜에 따라 접두사 설정 (postgresql -> pgsql로 변환할 수도 있음)
|
|
117
|
-
const dbProtocol = protocol === 'pgsql' ? 'postgresql' : protocol;
|
|
118
|
-
|
|
119
76
|
// MySQL 관찰자와 동일한 형식으로 구성
|
|
120
|
-
dbc = `${
|
|
77
|
+
dbc = `${protocol}://`;
|
|
121
78
|
dbc += dbUrl.username || '';
|
|
122
79
|
dbc += "@";
|
|
123
80
|
dbc += dbUrl.hostname || '';
|
|
124
81
|
dbc += '/';
|
|
125
82
|
dbc += dbUrl.pathname.replace('/', '') || '';
|
|
126
83
|
dbc_hash = HashUtil.hashFromString(dbc);
|
|
127
|
-
|
|
128
|
-
DataTextAgent.DBC.add(dbc_hash, dbc);
|
|
129
|
-
DataTextAgent.METHOD.add(dbc_hash, dbc);
|
|
130
|
-
DataTextAgent.ERROR.add(dbc_hash, dbc);
|
|
131
84
|
}
|
|
132
85
|
|
|
133
86
|
} catch (e) {
|
|
134
|
-
Logger.printError("WHATAP-
|
|
87
|
+
Logger.printError("WHATAP-223", "Failed to extract connection info", e, false);
|
|
135
88
|
dbc = "prisma:unknown";
|
|
136
89
|
dbc_hash = HashUtil.hashFromString(dbc);
|
|
137
90
|
}
|
|
138
91
|
};
|
|
139
92
|
|
|
140
93
|
PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
141
|
-
const
|
|
142
|
-
|
|
94
|
+
const self = this;
|
|
95
|
+
|
|
96
|
+
if (typeof prismaInstance.$use === 'function') {
|
|
143
97
|
prismaInstance.$use(async (params, next) => {
|
|
144
|
-
var result;
|
|
145
98
|
const ctx = TraceContextManager.getCurrentContext();
|
|
146
99
|
if (!ctx) {
|
|
147
100
|
return next(params);
|
|
148
101
|
}
|
|
149
102
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
DataTextAgent.ERROR.add(dbc_hash, dbc)
|
|
155
|
-
|
|
156
|
-
dbc_step.hash = dbc_hash;
|
|
157
|
-
dbc_step.start_time = ctx.getElapsedTime();
|
|
158
|
-
ctx.profile.push(dbc_step);
|
|
103
|
+
// DB 연결 패킷 전송 (mysql2-observer와 동일한 패턴)
|
|
104
|
+
ctx.start_time = Date.now();
|
|
105
|
+
ctx.elapsed = 0;
|
|
106
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbc]);
|
|
159
107
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
sql_step.elapsed = 0;
|
|
163
|
-
ctx.profile.push(sql_step);
|
|
108
|
+
// SQL 시작 시간 기록
|
|
109
|
+
var sql_start_time = Date.now();
|
|
164
110
|
|
|
165
111
|
const modelName = params.model || 'unknown';
|
|
166
112
|
const action = params.action || 'unknown';
|
|
@@ -168,161 +114,21 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
168
114
|
ctx.footprint(`Prisma ${modelName}.${action} Start`);
|
|
169
115
|
ctx.sql_count = (ctx.sql_count || 0) + 1;
|
|
170
116
|
|
|
171
|
-
//
|
|
117
|
+
// 쿼리 정보 생성
|
|
172
118
|
const queryInfo = `Prisma ${modelName}.${action}`;
|
|
173
|
-
const queryHash = HashUtil.hashFromString(queryInfo);
|
|
174
|
-
|
|
175
|
-
DataTextAgent.SQL.add(queryHash, queryInfo);
|
|
176
|
-
sql_step.hash = queryHash;
|
|
177
|
-
sql_step.dbc = dbc_hash;
|
|
178
|
-
|
|
179
|
-
ctx.active_sqlhash = sql_step.hash;
|
|
180
|
-
ctx.active_dbc = sql_step.dbc;
|
|
181
|
-
|
|
182
|
-
// 쿼리 파라미터 정보 추출
|
|
183
|
-
if (conf.profile_sql_param_enabled) {
|
|
184
|
-
const paramsString = JSON.stringify(params.args || {});
|
|
185
|
-
sql_step.setTrue(1);
|
|
186
|
-
var crc = { value: 0 };
|
|
187
|
-
sql_step.p1 = toParamBytes(paramsString, crc);
|
|
188
|
-
sql_step.pcrc = crc.value;
|
|
189
|
-
}
|
|
190
119
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (params.args && params.args.length > 0) {
|
|
195
|
-
if (params.args[0] && params.args[0].strings && Array.isArray(params.args[0].strings)) {
|
|
196
|
-
sqlString = params.args[0].strings.join('').trim();
|
|
197
|
-
} else if (params.args[0] && params.args[0] && Array.isArray(params.args[0])){
|
|
198
|
-
sqlString = params.args[0].join('').trim();
|
|
199
|
-
} else if (typeof params.args[0] === 'string') {
|
|
200
|
-
sqlString = params.args[0];
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// SQL 문자열이 있으면 처리
|
|
205
|
-
if (sqlString && sqlString.length > 0) {
|
|
206
|
-
try {
|
|
207
|
-
var psql = escapeLiteral(sqlString);
|
|
208
|
-
if (psql != null) {
|
|
209
|
-
sql_step.hash = psql.sql;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// 추가 SQL 정보 처리
|
|
213
|
-
var els = new EscapeLiteralSQL(sqlString);
|
|
214
|
-
els.process();
|
|
215
|
-
|
|
216
|
-
// SQL 파라미터 처리
|
|
217
|
-
if (conf.profile_sql_param_enabled) {
|
|
218
|
-
var params = params.args.slice(1);
|
|
219
|
-
sql_step.setTrue(1);
|
|
220
|
-
var crc = { value: 0 };
|
|
221
|
-
sql_step.p1 = toParamBytes(psql.param, crc);
|
|
222
|
-
|
|
223
|
-
if (params && params.length > 0) {
|
|
224
|
-
const result = params.map((param) => {
|
|
225
|
-
if (typeof param === 'string') {
|
|
226
|
-
return `'${param}'`;
|
|
227
|
-
}
|
|
228
|
-
return param;
|
|
229
|
-
}).toString();
|
|
230
|
-
sql_step.p2 = toParamBytes(result, crc);
|
|
231
|
-
}
|
|
232
|
-
sql_step.pcrc = crc.value;
|
|
233
|
-
}
|
|
234
|
-
} catch (e) {
|
|
235
|
-
Logger.printError("WHATAP-305", "escapeLiteral error", e, false);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
120
|
+
ctx.active_sqlhash = HashUtil.hashFromString(queryInfo);
|
|
121
|
+
ctx.active_dbc = dbc_hash;
|
|
122
|
+
|
|
239
123
|
try {
|
|
240
|
-
result = await next(params);
|
|
241
|
-
|
|
242
|
-
// Raw 쿼리 처리
|
|
243
|
-
if (action === "queryRaw" || action === "executeRaw" || action === "queryRawUnsafe" || action === "executeRawUnsafe") {
|
|
244
|
-
// Raw 쿼리 결과셋 처리
|
|
245
|
-
if ((action === "queryRaw" || action === "queryRawUnsafe") && result) {
|
|
246
|
-
let recordCount = 0;
|
|
247
|
-
|
|
248
|
-
if (Array.isArray(result)) {
|
|
249
|
-
recordCount = result.length;
|
|
250
|
-
} else if (result && typeof result === "object") {
|
|
251
|
-
recordCount = 1;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if(psql && psql.sql){
|
|
255
|
-
const sqlHashToUse = psql.sql;
|
|
256
|
-
|
|
257
|
-
var result_step = new ResultSetStep();
|
|
258
|
-
result_step.start_time = ctx.getElapsedTime();
|
|
259
|
-
result_step.elapsed = 0;
|
|
260
|
-
result_step.fetch = recordCount;
|
|
261
|
-
result_step.sqlhash = sqlHashToUse;
|
|
262
|
-
result_step.dbc = dbc_hash;
|
|
263
|
-
ctx.profile.push(result_step);
|
|
264
|
-
|
|
265
|
-
ctx.rs_count = ctx.rs_count ? ctx.rs_count + recordCount : recordCount;
|
|
266
|
-
ctx.rs_time = ctx.rs_time ? ctx.rs_time + sql_step.elapsed : sql_step.elapsed;
|
|
267
|
-
|
|
268
|
-
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
269
|
-
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
270
|
-
|
|
271
|
-
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// 결과셋 처리 (findMany, findFirst, findUnique 등)
|
|
277
|
-
if (["findMany", "findFirst", "findUnique"].includes(action)) {
|
|
278
|
-
let recordCount = 0;
|
|
279
|
-
|
|
280
|
-
if (Array.isArray(result)) {
|
|
281
|
-
recordCount = result.length;
|
|
282
|
-
} else if (result && typeof result === "object") {
|
|
283
|
-
recordCount = 1;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
var result_step = new ResultSetStep();
|
|
287
|
-
result_step.start_time = ctx.getElapsedTime();
|
|
288
|
-
result_step.elapsed = 0;
|
|
289
|
-
result_step.fetch = recordCount;
|
|
290
|
-
result_step.sqlhash = queryHash;
|
|
291
|
-
result_step.dbc = dbc_hash;
|
|
292
|
-
ctx.profile.push(result_step);
|
|
293
|
-
|
|
294
|
-
ctx.rs_count = ctx.rs_count ? ctx.rs_count + recordCount : recordCount;
|
|
295
|
-
ctx.rs_time = ctx.rs_time ? ctx.rs_time + sql_step.elapsed : sql_step.elapsed;
|
|
296
|
-
|
|
297
|
-
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
298
|
-
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
299
|
-
|
|
300
|
-
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// 수정된 레코드 수 처리 (create, update, delete 등)
|
|
304
|
-
if (["create", "createMany", "update", "updateMany", "delete", "deleteMany"].includes(action)) {
|
|
305
|
-
if (result && result.count !== undefined) {
|
|
306
|
-
sql_step.updated = result.count;
|
|
307
|
-
} else if (result && typeof result === "object") {
|
|
308
|
-
sql_step.updated = 1;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// UPSERT 처리 추가
|
|
313
|
-
if (action === "upsert") {
|
|
314
|
-
sql_step.updated = 1; // upsert는 항상 1개의 레코드에 영향을 미침
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
this._finishQuery(ctx, sql_step);
|
|
124
|
+
const result = await next(params);
|
|
318
125
|
|
|
126
|
+
self._finishQuery(ctx, sql_start_time, result, queryInfo);
|
|
319
127
|
ctx.footprint(`Prisma ${modelName}.${action} Done`);
|
|
320
128
|
|
|
321
129
|
return result;
|
|
322
130
|
} catch (err) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
this._handleError(ctx, sql_step, err);
|
|
131
|
+
self._handleError(ctx, sql_start_time, err, queryInfo);
|
|
326
132
|
ctx.footprint(`Prisma ${modelName}.${action} Error`);
|
|
327
133
|
throw err;
|
|
328
134
|
}
|
|
@@ -330,106 +136,89 @@ PrismaObserver.prototype.hookUseMiddleware = function(prismaInstance) {
|
|
|
330
136
|
}
|
|
331
137
|
};
|
|
332
138
|
|
|
333
|
-
PrismaObserver.prototype._finishQuery = function(ctx,
|
|
334
|
-
|
|
335
|
-
ctx.sql_time = (ctx.sql_time || 0) +
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
139
|
+
PrismaObserver.prototype._finishQuery = function(ctx, sql_start_time, result, queryInfo) {
|
|
140
|
+
var sql_elapsed = Date.now() - sql_start_time;
|
|
141
|
+
ctx.sql_time = (ctx.sql_time || 0) + sql_elapsed;
|
|
142
|
+
|
|
143
|
+
// 결과 개수 계산
|
|
144
|
+
let resultCount = 0;
|
|
145
|
+
if (result) {
|
|
146
|
+
if (Array.isArray(result)) {
|
|
147
|
+
resultCount = result.length;
|
|
148
|
+
} else if (result && typeof result === "object" && result.count !== undefined) {
|
|
149
|
+
resultCount = result.count;
|
|
150
|
+
} else if (result && typeof result === "object") {
|
|
151
|
+
resultCount = 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
341
154
|
|
|
342
|
-
|
|
155
|
+
// SQL 패킷 전송 (mysql2-observer와 동일한 패턴)
|
|
156
|
+
ctx.elapsed = sql_elapsed;
|
|
157
|
+
ctx.active_sqlhash = false;
|
|
158
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_SQL, ctx, [dbc, queryInfo, String(resultCount)]);
|
|
343
159
|
};
|
|
344
160
|
|
|
345
|
-
PrismaObserver.prototype._handleError = function(ctx,
|
|
346
|
-
|
|
347
|
-
ctx.sql_time = (ctx.sql_time || 0) +
|
|
348
|
-
|
|
349
|
-
TraceSQL.isSlowSQL(ctx);
|
|
350
|
-
|
|
351
|
-
MeterSql.add(dbc_hash, sql_step.elapsed, true);
|
|
352
|
-
StatSql.addSqlTime(ctx.service_hash, sql_step.dbc, sql_step.hash, sql_step.elapsed, true, 0);
|
|
161
|
+
PrismaObserver.prototype._handleError = function(ctx, sql_start_time, err, queryInfo) {
|
|
162
|
+
var sql_elapsed = Date.now() - sql_start_time;
|
|
163
|
+
ctx.sql_time = (ctx.sql_time || 0) + sql_elapsed;
|
|
353
164
|
|
|
354
165
|
try {
|
|
355
166
|
const errorClassName = err.name || err.constructor?.name || "UnknownError";
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
sql_step.error = StatError.addError(errorClassName, err.message, ctx.service_hash, TextTypes.SQL, sql_step.hash);
|
|
167
|
+
const errorMessage = err.message || 'Prisma error';
|
|
168
|
+
let errorStack = '';
|
|
359
169
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
170
|
+
ctx.error_class = errorClassName;
|
|
171
|
+
ctx.error_message = errorMessage;
|
|
363
172
|
|
|
364
|
-
|
|
173
|
+
// 스택 트레이스 처리
|
|
174
|
+
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && err.stack) {
|
|
365
175
|
var traceDepth = conf.trace_sql_error_depth;
|
|
366
|
-
var
|
|
176
|
+
var stackLines = err.stack.split("\n");
|
|
367
177
|
|
|
368
|
-
if (
|
|
369
|
-
|
|
178
|
+
if (stackLines.length > traceDepth) {
|
|
179
|
+
stackLines = stackLines.slice(0, traceDepth + 1);
|
|
370
180
|
}
|
|
371
|
-
|
|
181
|
+
errorStack = stackLines.join("\n");
|
|
182
|
+
ctx.error_message = errorStack;
|
|
372
183
|
}
|
|
373
|
-
} catch (e) {
|
|
374
|
-
Logger.printError("WHATAP-309", "Error handling failed", e, false);
|
|
375
|
-
}
|
|
376
184
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
var checkedSql = new IntKeyMap(2000).setMax(2000);
|
|
392
|
-
var nonLiteSql = new IntKeyMap(5000).setMax(5000);
|
|
393
|
-
var date = DateUtil.yyyymmdd();
|
|
394
|
-
|
|
395
|
-
function escapeLiteral(sql) {
|
|
396
|
-
if (sql == null) {
|
|
397
|
-
sql = "";
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (date !== DateUtil.yyyymmdd()) {
|
|
401
|
-
checkedSql.clear();
|
|
402
|
-
nonLiteSql.clear();
|
|
403
|
-
date = DateUtil.yyyymmdd();
|
|
404
|
-
Logger.print("WHATAP-SQL-CLEAR", "PrismaObserver CLEAR OK!!!!!!!!!!!!!!!!", false);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
var sqlHash = HashUtil.hashFromString(sql);
|
|
408
|
-
var psql = nonLiteSql.get(sqlHash);
|
|
409
|
-
|
|
410
|
-
if (psql != null) {
|
|
411
|
-
return psql;
|
|
412
|
-
}
|
|
413
|
-
psql = checkedSql.get(sqlHash);
|
|
185
|
+
// 에러 무시 조건 확인 (mysql2-observer와 동일한 로직)
|
|
186
|
+
var shouldAddError = false;
|
|
187
|
+
if (conf._is_trace_ignore_err_cls_contains === true && errorClassName &&
|
|
188
|
+
errorClassName.indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
189
|
+
shouldAddError = true;
|
|
190
|
+
} else if (conf._is_trace_ignore_err_msg_contains === true && errorMessage &&
|
|
191
|
+
errorMessage.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
|
|
192
|
+
shouldAddError = true;
|
|
193
|
+
} else if (conf._is_trace_ignore_err_cls_contains === false &&
|
|
194
|
+
conf._is_trace_ignore_err_msg_contains === false) {
|
|
195
|
+
shouldAddError = true;
|
|
196
|
+
}
|
|
414
197
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
198
|
+
if (shouldAddError) {
|
|
199
|
+
if(!ctx.error) ctx.error = 1;
|
|
200
|
+
ctx.status = 500;
|
|
201
|
+
ctx.errClass = errorClassName;
|
|
202
|
+
ctx.errMessage = errorMessage;
|
|
418
203
|
|
|
419
|
-
|
|
420
|
-
|
|
204
|
+
var errors = [errorClassName];
|
|
205
|
+
if (errorMessage) {
|
|
206
|
+
errors.push(errorMessage);
|
|
207
|
+
}
|
|
208
|
+
if (errorStack || err.stack) {
|
|
209
|
+
errors.push(errorStack || err.stack);
|
|
210
|
+
}
|
|
211
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
212
|
+
}
|
|
421
213
|
|
|
422
|
-
|
|
423
|
-
|
|
214
|
+
// SQL 패킷 전송 (에러 발생시에도)
|
|
215
|
+
ctx.elapsed = sql_elapsed;
|
|
216
|
+
ctx.active_sqlhash = false;
|
|
217
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_SQL, ctx, [dbc, queryInfo, "0"]);
|
|
424
218
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
nonLiteSql.put(sqlHash, psql);
|
|
428
|
-
} else {
|
|
429
|
-
psql = new ParsedSql(els.sqlType, hash, els.getParameter());
|
|
430
|
-
checkedSql.put(sqlHash, psql);
|
|
219
|
+
} catch (e) {
|
|
220
|
+
Logger.printError("WHATAP-224", "Error handling failed", e, false);
|
|
431
221
|
}
|
|
432
|
-
|
|
433
|
-
}
|
|
222
|
+
};
|
|
434
223
|
|
|
435
224
|
exports.PrismaObserver = PrismaObserver;
|
|
@@ -6,28 +6,26 @@
|
|
|
6
6
|
|
|
7
7
|
const TraceContextManager = require('../trace/trace-context-manager');
|
|
8
8
|
const conf = require('../conf/configure');
|
|
9
|
-
const
|
|
10
|
-
const
|
|
9
|
+
const AsyncSender = require('../udp/async_sender');
|
|
10
|
+
const DataOuputX = require('../io/data-outputx');
|
|
11
|
+
const SecurityMaster = require('../net/security-master');
|
|
12
|
+
const LogSinkPack = require('../pack/log-sink-pack');
|
|
11
13
|
|
|
12
14
|
let logsink_enabled = conf.getProperty('logsink_enabled', false);
|
|
13
|
-
let logTracer = logsink_enabled ? new LogTracer() : null;
|
|
14
15
|
|
|
15
|
-
conf.on('logsink_enabled', function
|
|
16
|
+
conf.on('logsink_enabled', function(newProperty) {
|
|
16
17
|
logsink_enabled = newProperty;
|
|
17
|
-
logTracer = logsink_enabled ? new LogTracer() : null;
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
const ProcessObserver = function (agent) {
|
|
21
21
|
this.agent = agent;
|
|
22
22
|
this.packages = ['process'];
|
|
23
|
-
this.exitHandlersRegistered = false;
|
|
24
23
|
};
|
|
25
24
|
|
|
26
25
|
ProcessObserver.prototype.inject = function (mod, moduleName) {
|
|
27
26
|
this._hookNextTick(mod);
|
|
28
27
|
this._hookStdOutWrite();
|
|
29
28
|
this._hookStdErrWrite();
|
|
30
|
-
this._hookProcessExit(mod);
|
|
31
29
|
};
|
|
32
30
|
|
|
33
31
|
ProcessObserver.prototype._hookNextTick = function (mod) {
|
|
@@ -41,6 +39,26 @@ ProcessObserver.prototype._hookNextTick = function (mod) {
|
|
|
41
39
|
});
|
|
42
40
|
};
|
|
43
41
|
|
|
42
|
+
ProcessObserver.prototype._sendLogPack = function (content, category) {
|
|
43
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
44
|
+
const tags = ctx && ctx.id ? {'@txid': ctx.id.toString()} : {};
|
|
45
|
+
|
|
46
|
+
const fields = {"filename": null};
|
|
47
|
+
|
|
48
|
+
const p = new LogSinkPack();
|
|
49
|
+
p.Category = category;
|
|
50
|
+
p.time = Date.now();
|
|
51
|
+
p.line = Date.now();
|
|
52
|
+
p.content = content;
|
|
53
|
+
|
|
54
|
+
p.pcode = SecurityMaster.PCODE;
|
|
55
|
+
const bout = new DataOuputX();
|
|
56
|
+
bout.writePack(p, null);
|
|
57
|
+
const packbytes = bout.toByteArray();
|
|
58
|
+
|
|
59
|
+
AsyncSender.send_relaypack(packbytes);
|
|
60
|
+
};
|
|
61
|
+
|
|
44
62
|
ProcessObserver.prototype._hookStdOutWrite = function () {
|
|
45
63
|
this.agent.aop.after(process.stdout, 'write', (obj, args) => {
|
|
46
64
|
if (conf.getProperty('logsink_enabled', false) && args[0]) {
|
|
@@ -49,9 +67,12 @@ ProcessObserver.prototype._hookStdOutWrite = function () {
|
|
|
49
67
|
const parsedContent = JSON.parse(content);
|
|
50
68
|
content = parsedContent.message ? parsedContent.message : JSON.stringify(parsedContent);
|
|
51
69
|
} catch (e) {
|
|
70
|
+
// JSON 파싱 실패 시 원본 content 사용
|
|
52
71
|
}
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
|
|
73
|
+
if (content && content.trim()) {
|
|
74
|
+
const category = conf.getProperty('logsink_category_stdout', 'AppStdOut');
|
|
75
|
+
this._sendLogPack(content, category);
|
|
55
76
|
}
|
|
56
77
|
}
|
|
57
78
|
});
|
|
@@ -65,80 +86,15 @@ ProcessObserver.prototype._hookStdErrWrite = function () {
|
|
|
65
86
|
const parsedContent = JSON.parse(content);
|
|
66
87
|
content = parsedContent.message ? parsedContent.message : JSON.stringify(parsedContent);
|
|
67
88
|
} catch (e) {
|
|
89
|
+
// JSON 파싱 실패 시 원본 content 사용
|
|
68
90
|
}
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
|
|
92
|
+
if (content && content.trim()) {
|
|
93
|
+
const category = conf.getProperty('logsink_category_stderr', 'AppStdErr');
|
|
94
|
+
this._sendLogPack(content, category);
|
|
71
95
|
}
|
|
72
96
|
}
|
|
73
97
|
});
|
|
74
98
|
};
|
|
75
99
|
|
|
76
|
-
ProcessObserver.prototype._hookProcessExit = function (mod) {
|
|
77
|
-
if (this.exitHandlersRegistered) {
|
|
78
|
-
Logger.print("WHATAP-901", "[ProcessObserver] Exit handlers already registered, skipping...", false)
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const self = this;
|
|
82
|
-
|
|
83
|
-
// SIGTERM (graceful shutdown)
|
|
84
|
-
process.on('SIGTERM', function () {
|
|
85
|
-
const message = 'Process termination requested by system or process manager (SIGTERM) - Usually from service stop or container shutdown';
|
|
86
|
-
Logger.print('WHATAP-902', message, false);
|
|
87
|
-
setTimeout(() => process.exit(0), 100);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// SIGINT (Ctrl+C)
|
|
91
|
-
process.on('SIGINT', function () {
|
|
92
|
-
const message = 'Process interrupted by user (SIGINT) - Typically Ctrl+C or kill command';
|
|
93
|
-
Logger.print('WHATAP-903', message, false);
|
|
94
|
-
setTimeout(() => process.exit(0), 100);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// SIGHUP (hang up)
|
|
98
|
-
process.on('SIGHUP', function () {
|
|
99
|
-
const message = 'Process hangup signal received (SIGHUP) - Terminal disconnection or parent process terminated';
|
|
100
|
-
Logger.print('WHATAP-904', message, false);
|
|
101
|
-
setTimeout(() => process.exit(0), 100);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// SIGUSR1 (user-defined signal 1)
|
|
105
|
-
process.on('SIGUSR1', function () {
|
|
106
|
-
const message = 'User-defined signal 1 received (SIGUSR1) - Custom application signal';
|
|
107
|
-
Logger.print('WHATAP-905', message, false);
|
|
108
|
-
setTimeout(() => process.exit(0), 100);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// SIGUSR2 (user-defined signal 2)
|
|
112
|
-
process.on('SIGUSR2', function () {
|
|
113
|
-
const message = 'User-defined signal 2 received (SIGUSR2) - Custom application signal';
|
|
114
|
-
Logger.print('WHATAP-906', message, false);
|
|
115
|
-
setTimeout(() => process.exit(0), 100);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// 처리되지 않은 예외
|
|
119
|
-
// process.on('uncaughtException', function (err) {
|
|
120
|
-
// const message = `Unhandled exception caused process crash - Error: ${err.message}, File: ${err.stack ? err.stack.split('\n')[1] || 'unknown' : 'unknown'}`;
|
|
121
|
-
// Logger.print('WHATAP-907', message, err, false);
|
|
122
|
-
//
|
|
123
|
-
// // 로그 남긴 후 프로세스 종료
|
|
124
|
-
// setTimeout(() => {
|
|
125
|
-
// process.exit(1);
|
|
126
|
-
// }, 100);
|
|
127
|
-
// });
|
|
128
|
-
//
|
|
129
|
-
// // 처리되지 않은 Promise rejection
|
|
130
|
-
// process.on('unhandledRejection', function (reason, promise) {
|
|
131
|
-
// const message = `Unhandled Promise rejection may cause process termination - Reason: ${reason instanceof Error ? reason.message : String(reason)}`;
|
|
132
|
-
// const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
133
|
-
// Logger.print('WHATAP-908', message, err, false);
|
|
134
|
-
//
|
|
135
|
-
// // 로그 남긴 후 프로세스 종료
|
|
136
|
-
// setTimeout(() => {
|
|
137
|
-
// process.exit(1);
|
|
138
|
-
// }, 100);
|
|
139
|
-
// });
|
|
140
|
-
|
|
141
|
-
this.exitHandlersRegistered = true;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
100
|
module.exports.ProcessObserver = ProcessObserver;
|