whatap 1.0.2 → 1.0.3-canary.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/README.md +77 -33
- 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 +888 -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 -9
- package/whatap.conf +4 -1
- 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,258 +5,277 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
8
|
-
ParsedSql
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
TextTypes = require('../lang/text-types'),
|
|
21
|
-
ParamSecurity = require('../util/paramsecurity'),
|
|
22
|
-
Logger = require('../logger'),
|
|
23
|
-
DateUtil = require('../util/dateutil'),
|
|
24
|
-
Buffer = require('buffer').Buffer,
|
|
25
|
-
shimmer = require('../core/shimmer'),
|
|
26
|
-
TraceSQL = require('../trace/trace-sql');
|
|
8
|
+
ParsedSql = require('../trace/parsed-sql'),
|
|
9
|
+
conf = require('../conf/configure'),
|
|
10
|
+
IntKeyMap = require('../util/intkey-map'),
|
|
11
|
+
EscapeLiteralSQL = require('../util/escape-literal-sql'),
|
|
12
|
+
HashUtil = require('../util/hashutil'),
|
|
13
|
+
Logger = require('../logger'),
|
|
14
|
+
DateUtil = require('../util/dateutil'),
|
|
15
|
+
AsyncSender = require('../udp/async_sender'),
|
|
16
|
+
PacketTypeEnum = require('../udp/packet_type_enum'),
|
|
17
|
+
shimmer = require('../core/shimmer'),
|
|
18
|
+
TraceSQL = require('../trace/trace-sql');
|
|
19
|
+
const { AsyncResource } = require('async_hooks');
|
|
27
20
|
|
|
28
21
|
var MariaObserver = function (agent) {
|
|
29
22
|
this.agent = agent;
|
|
30
23
|
this.packages = ['mariadb'];
|
|
31
24
|
};
|
|
32
25
|
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
if (mod.__whatap_observe__) { return; }
|
|
36
|
-
mod.__whatap_observe__ = true;
|
|
37
|
-
|
|
38
|
-
Logger.initPrint("MariaObserver");
|
|
39
|
-
|
|
40
|
-
if (!conf.sql_enabled) return;
|
|
41
|
-
|
|
42
|
-
// shimmer.wrap(mod, 'createConnection', wrapCreateConnection(mod));
|
|
43
|
-
shimmer.wrap(mod, 'createConnection', wrapConnection(mod));
|
|
44
|
-
shimmer.wrap(mod, 'createPool', wrapCreatePool(mod));
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
var _finishQuery = function (ctx, sql_step) {
|
|
48
|
-
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
49
|
-
TraceSQL.isSlowSQL(ctx);
|
|
50
|
-
|
|
51
|
-
MeterSql.add(sql_step.hash, sql_step.elapsed, false);
|
|
52
|
-
StatSql.addSqlTime(ctx, ctx.service_hash, sql_step.dbc, sql_step.hash, sql_step.elapsed, false, 0);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
var _handleError = function (ctx, sql_step, err) {
|
|
56
|
-
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
57
|
-
TraceSQL.isSlowSQL(ctx);
|
|
58
|
-
|
|
59
|
-
MeterSql.add(sql_step.hash, sql_step.elapsed, false);
|
|
60
|
-
StatSql.addSqlTime(ctx, ctx.service_hash, sql_step.dbc, sql_step.hash, sql_step.elapsed, true, 0);
|
|
61
|
-
};
|
|
26
|
+
var dbc_hash = 0;
|
|
27
|
+
var dbc = 'mariadb://';
|
|
62
28
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return async function (...args) {
|
|
66
|
-
const ctx = TraceContextManager.getCurrentContext();
|
|
67
|
-
if (!ctx || ctx.db_opening) return original.apply(this, args);
|
|
29
|
+
// 후킹된 객체 추적
|
|
30
|
+
var hookedInstances = new WeakSet();
|
|
68
31
|
|
|
69
|
-
|
|
70
|
-
|
|
32
|
+
function handleSqlError(ctx, err, sqlHash) {
|
|
33
|
+
if (!err) return;
|
|
71
34
|
|
|
72
|
-
|
|
73
|
-
|
|
35
|
+
try {
|
|
36
|
+
var errorClass = err.code || err.name || err.constructor?.name || 'MariaDBError';
|
|
37
|
+
var errorMessage = err.message || err.sqlMessage || 'mariadb error';
|
|
38
|
+
var errorStack = '';
|
|
39
|
+
|
|
40
|
+
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && err.stack) {
|
|
41
|
+
var traceDepth = conf.trace_sql_error_depth;
|
|
42
|
+
var stackLines = err.stack.split("\n");
|
|
43
|
+
if (stackLines.length > traceDepth) {
|
|
44
|
+
stackLines = stackLines.slice(0, traceDepth + 1);
|
|
45
|
+
}
|
|
46
|
+
errorStack = stackLines.join("\n");
|
|
47
|
+
ctx.error_message = errorStack;
|
|
48
|
+
}
|
|
74
49
|
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
var shouldAddError = false;
|
|
51
|
+
if (conf._is_trace_ignore_err_cls_contains === true && errorClass &&
|
|
52
|
+
errorClass.indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
53
|
+
shouldAddError = true;
|
|
54
|
+
} else if (conf._is_trace_ignore_err_msg_contains === true && errorMessage &&
|
|
55
|
+
errorMessage.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
|
|
56
|
+
shouldAddError = true;
|
|
57
|
+
} else if (conf._is_trace_ignore_err_cls_contains === false &&
|
|
58
|
+
conf._is_trace_ignore_err_msg_contains === false) {
|
|
59
|
+
shouldAddError = true;
|
|
60
|
+
}
|
|
77
61
|
|
|
78
|
-
|
|
79
|
-
ctx.
|
|
62
|
+
if (shouldAddError) {
|
|
63
|
+
if(!ctx.error) ctx.error = 1;
|
|
64
|
+
ctx.status = 500;
|
|
65
|
+
ctx.error_message = errorMessage;
|
|
66
|
+
ctx.errClass = errorClass;
|
|
67
|
+
ctx.errMessage = errorMessage;
|
|
80
68
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
var errors = [errorClass];
|
|
70
|
+
if (errorMessage) {
|
|
71
|
+
errors.push(errorMessage);
|
|
72
|
+
}
|
|
73
|
+
if (errorStack || err.stack) {
|
|
74
|
+
errors.push(errorStack || err.stack);
|
|
75
|
+
}
|
|
76
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
Logger.printError('WHATAP-214', 'Error handling MariaDB error', e, false);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
function setupDbcInfo(args) {
|
|
84
|
+
if (dbc_hash === 0 && args.length > 0) {
|
|
85
|
+
var info = args[0] || {};
|
|
86
|
+
dbc = 'mariadb://';
|
|
87
|
+
dbc += info.user || '';
|
|
88
|
+
dbc += "@";
|
|
89
|
+
dbc += info.host || '';
|
|
90
|
+
dbc += '/';
|
|
91
|
+
dbc += info.database || '';
|
|
92
|
+
dbc_hash = HashUtil.hashFromString(dbc);
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
getDBCHash(args);
|
|
96
|
+
function hookConnectionMethods(connection, agent) {
|
|
97
|
+
if (connection && !hookedInstances.has(connection)) {
|
|
98
|
+
hookedInstances.add(connection);
|
|
99
|
+
Logger.print('WHATAP-MARIADB-CONNECTION', 'Hooking new connection object', false);
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
// query와 execute 메서드 후킹
|
|
102
|
+
if (connection.query && !connection.query.__whatap_wrapped__) {
|
|
103
|
+
shimmer.wrap(connection, 'query', createQueryWrapper(agent, dbc));
|
|
104
|
+
connection.query.__whatap_wrapped__ = true;
|
|
105
|
+
}
|
|
106
|
+
if (connection.execute && !connection.execute.__whatap_wrapped__) {
|
|
107
|
+
shimmer.wrap(connection, 'execute', createQueryWrapper(agent, dbc));
|
|
108
|
+
connection.execute.__whatap_wrapped__ = true;
|
|
100
109
|
}
|
|
101
110
|
}
|
|
102
111
|
}
|
|
103
112
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
shimmer.wrap(pool, 'getConnection', (originalGetConnection) => {
|
|
111
|
-
return async function (...connArgs) {
|
|
112
|
-
const connection = await originalGetConnection.apply(this, connArgs);
|
|
113
|
-
wrapConnectionMethods(connection, agent);
|
|
114
|
-
return connection;
|
|
115
|
-
};
|
|
116
|
-
});
|
|
113
|
+
// 쿼리 래핑 함수
|
|
114
|
+
var createQueryWrapper = function(agent, dbcUrl) {
|
|
115
|
+
return function(original) {
|
|
116
|
+
return function wrappedQuery() {
|
|
117
|
+
var args = Array.prototype.slice.call(arguments);
|
|
118
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
117
119
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function wrapConnectionMethods(connection, agent) {
|
|
124
|
-
shimmer.wrap(connection, 'query', createQueryHook(agent));
|
|
125
|
-
shimmer.wrap(connection, 'execute', createQueryHook(agent));
|
|
126
|
-
}
|
|
120
|
+
if (ctx == null || args[0] == null) {
|
|
121
|
+
return original.apply(this, arguments);
|
|
122
|
+
}
|
|
127
123
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const ctx = TraceContextManager.getCurrentContext();
|
|
132
|
-
if (!ctx || !args[0]) return original.apply(this, args);
|
|
124
|
+
if (args[0].sql == null && typeof args[0] != 'string') {
|
|
125
|
+
return original.apply(this, arguments);
|
|
126
|
+
}
|
|
133
127
|
|
|
134
|
-
|
|
135
|
-
|
|
128
|
+
// AsyncResource 생성
|
|
129
|
+
const asyncResource = new AsyncResource('mariadb-query');
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
131
|
+
return asyncResource.runInAsyncScope(() => {
|
|
132
|
+
// HTTP Observer 패턴을 따라 시작 시간 설정
|
|
133
|
+
ctx.start_time = Date.now();
|
|
140
134
|
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
// DB 연결 패킷 전송 (elapsed = 0으로 설정)
|
|
136
|
+
ctx.elapsed = 0;
|
|
137
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbcUrl]);
|
|
143
138
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
// SQL 시작 시간 기록
|
|
140
|
+
var sql_start_time = Date.now();
|
|
141
|
+
ctx.footprint('MariaDB Query Start');
|
|
142
|
+
ctx.sql_count++;
|
|
147
143
|
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
var sql = args.length > 0 ? args[0] : undefined;
|
|
145
|
+
var params = args.length > 1 && Array.isArray(args[1]) ? args[1] : undefined;
|
|
150
146
|
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
if (typeof sql !== 'string') {
|
|
148
|
+
sql = args[0].sql || undefined;
|
|
149
|
+
if (args[0].values && Array.isArray(args[0].values)) {
|
|
150
|
+
params = args[0].values;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
// 최종 SQL 생성 (파라미터 바인딩)
|
|
155
|
+
var finalSql = sql || '';
|
|
156
|
+
if (typeof sql === 'string' && sql.length > 0 && params && params.length > 0) {
|
|
157
|
+
try {
|
|
158
|
+
// MariaDB는 mysql2 스타일의 파라미터 바인딩 지원
|
|
159
|
+
const result = params.map((param) => {
|
|
160
|
+
if(typeof param === 'string'){
|
|
161
|
+
return `'${param.replace(/'/g, "''")}'` // SQL injection 방지
|
|
162
|
+
}
|
|
163
|
+
return param
|
|
164
|
+
}).join(', ');
|
|
165
|
+
|
|
166
|
+
// 간단한 파라미터 치환 (? 기준)
|
|
167
|
+
var paramIndex = 0;
|
|
168
|
+
finalSql = sql.replace(/\?/g, function() {
|
|
169
|
+
if (paramIndex < params.length) {
|
|
170
|
+
var param = params[paramIndex++];
|
|
171
|
+
if (typeof param === 'string') {
|
|
172
|
+
return `'${param.replace(/'/g, "''")}'`;
|
|
173
|
+
}
|
|
174
|
+
return param;
|
|
175
|
+
}
|
|
176
|
+
return '?';
|
|
177
|
+
});
|
|
178
|
+
} catch (e) {
|
|
179
|
+
Logger.printError('WHATAP-SQL-BINDING', 'Error binding parameters', e, false);
|
|
180
|
+
finalSql = sql; // 바인딩 실패 시 원본 사용
|
|
181
|
+
}
|
|
182
|
+
}
|
|
157
183
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
184
|
+
var psql = null;
|
|
185
|
+
if (typeof finalSql === 'string' && finalSql.length > 0) {
|
|
186
|
+
try {
|
|
187
|
+
psql = escapeLiteral(finalSql);
|
|
188
|
+
// Logger.print('WHATAP-SQL-DEBUG', 'Processing SQL: ' + finalSql.substring(0, 200), false);
|
|
189
|
+
} catch (e) {
|
|
190
|
+
Logger.printError('WHATAP-215', 'MariaObserver escapeliteral error', e, false);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
finalSql = '';
|
|
194
|
+
psql = escapeLiteral(finalSql);
|
|
163
195
|
}
|
|
164
|
-
} else {
|
|
165
|
-
sql = '';
|
|
166
|
-
psql = escapeLiteral(sql);
|
|
167
|
-
}
|
|
168
196
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// sql_step.crud = psql.type.charCodeAt(0);
|
|
172
|
-
}
|
|
197
|
+
var sqlHash = psql ? psql.sql : 0;
|
|
198
|
+
ctx.active_sqlhash = true;
|
|
173
199
|
|
|
174
|
-
|
|
175
|
-
els.process();
|
|
200
|
+
const result = original.apply(this, args);
|
|
176
201
|
|
|
177
|
-
|
|
202
|
+
// Promise 기반 처리
|
|
203
|
+
if (result && typeof result.then === 'function') {
|
|
204
|
+
return result.then(res => {
|
|
205
|
+
var currentCtx = TraceContextManager.getCurrentContext();
|
|
206
|
+
if (currentCtx == null) {
|
|
207
|
+
currentCtx = ctx;
|
|
208
|
+
}
|
|
178
209
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
210
|
+
var sql_elapsed = Date.now() - sql_start_time;
|
|
211
|
+
var resultCount = 0;
|
|
212
|
+
|
|
213
|
+
// 결과 개수 계산
|
|
214
|
+
if (res) {
|
|
215
|
+
if (Array.isArray(res)) {
|
|
216
|
+
resultCount = res.length;
|
|
217
|
+
} else if (res.affectedRows !== undefined) {
|
|
218
|
+
resultCount = res.affectedRows;
|
|
219
|
+
} else if (res.changedRows !== undefined) {
|
|
220
|
+
resultCount = res.changedRows;
|
|
221
|
+
}
|
|
188
222
|
}
|
|
189
|
-
return param
|
|
190
|
-
}).toString()
|
|
191
|
-
sql_step.p2 = toParamBytes(result, crc);
|
|
192
|
-
}
|
|
193
|
-
sql_step.pcrc = crc.value;
|
|
194
|
-
}
|
|
195
223
|
|
|
196
|
-
|
|
224
|
+
// TraceSQL 처리
|
|
225
|
+
try {
|
|
226
|
+
TraceSQL.isSlowSQL(currentCtx);
|
|
227
|
+
|
|
228
|
+
// ResultSet 처리 (SELECT 쿼리)
|
|
229
|
+
if (res && psql && psql.type === 'S') {
|
|
230
|
+
TraceSQL.isTooManyRecords(resultCount, currentCtx);
|
|
231
|
+
}
|
|
232
|
+
} catch (e) {
|
|
233
|
+
Logger.printError('WHATAP-TRACESQL', 'Error in TraceSQL processing', e, false);
|
|
234
|
+
}
|
|
197
235
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
result_step.start_time = ctx.getElapsedTime();
|
|
202
|
-
result_step.elapsed = 0;
|
|
203
|
-
result_step.fetch = res.length;
|
|
204
|
-
result_step.sqlhash = psql.sql;
|
|
205
|
-
result_step.dbc = dbc_hash;
|
|
206
|
-
ctx.profile.push(result_step);
|
|
236
|
+
currentCtx.elapsed = sql_elapsed;
|
|
237
|
+
currentCtx.active_sqlhash = false;
|
|
238
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_SQL, currentCtx, [dbcUrl, finalSql, String(resultCount)]);
|
|
207
239
|
|
|
208
|
-
|
|
240
|
+
currentCtx.footprint('MariaDB Query Done');
|
|
241
|
+
return res;
|
|
242
|
+
}).catch(err => {
|
|
243
|
+
var currentCtx = TraceContextManager.getCurrentContext();
|
|
244
|
+
if (currentCtx == null) {
|
|
245
|
+
currentCtx = ctx;
|
|
246
|
+
}
|
|
209
247
|
|
|
210
|
-
|
|
211
|
-
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
248
|
+
var sql_elapsed = Date.now() - sql_start_time;
|
|
212
249
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
var errorStack = err.stack.split("\n");
|
|
224
|
-
if (errorStack.length > traceDepth) {
|
|
225
|
-
errorStack = errorStack.slice(0, traceDepth + 1);
|
|
226
|
-
}
|
|
227
|
-
ctx.error_message = errorStack.join("\n");
|
|
228
|
-
sql_step.error = ctx.error = StatError.addError('pgsql -' + err.code, err.message, ctx.service_hash, TextTypes.SQL, null);
|
|
250
|
+
// 에러 처리
|
|
251
|
+
handleSqlError(currentCtx, err, sqlHash);
|
|
252
|
+
|
|
253
|
+
currentCtx.elapsed = sql_elapsed;
|
|
254
|
+
currentCtx.active_sqlhash = false;
|
|
255
|
+
AsyncSender.send_packet(PacketTypeEnum.TX_SQL, currentCtx, [dbcUrl, finalSql, '0']);
|
|
256
|
+
|
|
257
|
+
currentCtx.footprint('MariaDB Query Error');
|
|
258
|
+
throw err;
|
|
259
|
+
});
|
|
229
260
|
}
|
|
230
|
-
|
|
261
|
+
|
|
262
|
+
return result;
|
|
231
263
|
});
|
|
232
264
|
};
|
|
233
265
|
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
var toParamBytes = function (p, crc) {
|
|
237
|
-
if (p == null || p.length === 0) {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
try {
|
|
241
|
-
return ParamSecurity.encrypt(Buffer.from(p, 'utf8'), crc);
|
|
242
|
-
} catch (e) {
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
266
|
};
|
|
246
267
|
|
|
247
|
-
|
|
248
|
-
dbc = `mariadb://${(args[0] || {}).user || ''}@${(args[0] || {}).host || ''}/${(args[0] || {}).database || ''}`;
|
|
249
|
-
dbc_hash = HashUtil.hashFromString(dbc);
|
|
250
|
-
}
|
|
251
|
-
|
|
268
|
+
// 유틸리티 함수들
|
|
252
269
|
var checkedSql = new IntKeyMap(2000).setMax(2000);
|
|
253
270
|
var nonLiteSql = new IntKeyMap(5000).setMax(5000);
|
|
254
271
|
var date = DateUtil.yyyymmdd();
|
|
255
272
|
|
|
256
273
|
function escapeLiteral(sql) {
|
|
257
|
-
if(sql == null) {
|
|
274
|
+
if (sql == null) {
|
|
275
|
+
sql = '';
|
|
276
|
+
}
|
|
258
277
|
|
|
259
|
-
if(date !== DateUtil.yyyymmdd()) {
|
|
278
|
+
if (date !== DateUtil.yyyymmdd()) {
|
|
260
279
|
checkedSql.clear();
|
|
261
280
|
nonLiteSql.clear();
|
|
262
281
|
date = DateUtil.yyyymmdd();
|
|
@@ -266,12 +285,12 @@ function escapeLiteral(sql) {
|
|
|
266
285
|
var sqlHash = HashUtil.hashFromString(sql);
|
|
267
286
|
var psql = nonLiteSql.get(sqlHash);
|
|
268
287
|
|
|
269
|
-
if(psql != null) {
|
|
288
|
+
if (psql != null) {
|
|
270
289
|
return psql;
|
|
271
290
|
}
|
|
272
291
|
psql = checkedSql.get(sqlHash);
|
|
273
292
|
|
|
274
|
-
if(psql != null) {
|
|
293
|
+
if (psql != null) {
|
|
275
294
|
return psql;
|
|
276
295
|
}
|
|
277
296
|
|
|
@@ -279,9 +298,7 @@ function escapeLiteral(sql) {
|
|
|
279
298
|
els.process();
|
|
280
299
|
|
|
281
300
|
var hash = HashUtil.hashFromString(els.getParsedSql());
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if(hash === sqlHash) {
|
|
301
|
+
if (hash === sqlHash) {
|
|
285
302
|
psql = new ParsedSql(els.sqlType, hash, null);
|
|
286
303
|
nonLiteSql.put(sqlHash, psql);
|
|
287
304
|
} else {
|
|
@@ -291,4 +308,145 @@ function escapeLiteral(sql) {
|
|
|
291
308
|
return psql;
|
|
292
309
|
}
|
|
293
310
|
|
|
311
|
+
// 메인 inject 함수
|
|
312
|
+
MariaObserver.prototype.inject = function (mod, moduleName) {
|
|
313
|
+
if (mod.__whatap_observe__) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
mod.__whatap_observe__ = true;
|
|
317
|
+
Logger.initPrint("MariaObserver");
|
|
318
|
+
|
|
319
|
+
if (conf.sql_enabled === false) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
var self = this;
|
|
324
|
+
|
|
325
|
+
// createConnection 래핑
|
|
326
|
+
if (mod.createConnection && !mod.createConnection.__whatap_wrapped__) {
|
|
327
|
+
shimmer.wrap(mod, 'createConnection', function(original) {
|
|
328
|
+
return function wrappedCreateConnection() {
|
|
329
|
+
var args = Array.prototype.slice.call(arguments);
|
|
330
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
331
|
+
|
|
332
|
+
setupDbcInfo(args);
|
|
333
|
+
|
|
334
|
+
if (ctx && !ctx.db_opening) {
|
|
335
|
+
ctx.db_opening = true;
|
|
336
|
+
ctx.footprint('MariaDB Connecting Start');
|
|
337
|
+
ctx.start_time = Date.now();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const result = original.apply(this, args);
|
|
341
|
+
|
|
342
|
+
// Promise 기반 처리
|
|
343
|
+
if (result && typeof result.then === 'function') {
|
|
344
|
+
return result.then(connection => {
|
|
345
|
+
hookConnectionMethods(connection, self.agent);
|
|
346
|
+
|
|
347
|
+
if (ctx) {
|
|
348
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
349
|
+
ctx.footprint('MariaDB Connecting Done');
|
|
350
|
+
ctx.db_opening = false;
|
|
351
|
+
}
|
|
352
|
+
return connection;
|
|
353
|
+
}).catch(error => {
|
|
354
|
+
if (ctx) {
|
|
355
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
356
|
+
ctx.footprint('MariaDB Connecting Error');
|
|
357
|
+
ctx.db_opening = false;
|
|
358
|
+
handleSqlError(ctx, error, 0);
|
|
359
|
+
}
|
|
360
|
+
throw error;
|
|
361
|
+
});
|
|
362
|
+
} else {
|
|
363
|
+
// 동기 처리
|
|
364
|
+
hookConnectionMethods(result, self.agent);
|
|
365
|
+
|
|
366
|
+
if (ctx) {
|
|
367
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
368
|
+
ctx.footprint('MariaDB Connecting Done');
|
|
369
|
+
ctx.db_opening = false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return result;
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
mod.createConnection.__whatap_wrapped__ = true;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// createPool 래핑
|
|
380
|
+
if (mod.createPool && !mod.createPool.__whatap_wrapped__) {
|
|
381
|
+
shimmer.wrap(mod, 'createPool', function(original) {
|
|
382
|
+
return function wrappedCreatePool() {
|
|
383
|
+
var args = Array.prototype.slice.call(arguments);
|
|
384
|
+
setupDbcInfo(args);
|
|
385
|
+
|
|
386
|
+
var pool = original.apply(this, args);
|
|
387
|
+
|
|
388
|
+
if (pool && !hookedInstances.has(pool)) {
|
|
389
|
+
hookedInstances.add(pool);
|
|
390
|
+
|
|
391
|
+
// Pool의 직접 쿼리 메서드들 후킹
|
|
392
|
+
if (pool.query && !pool.query.__whatap_wrapped__) {
|
|
393
|
+
shimmer.wrap(pool, 'query', createQueryWrapper(self.agent, dbc));
|
|
394
|
+
pool.query.__whatap_wrapped__ = true;
|
|
395
|
+
}
|
|
396
|
+
if (pool.execute && !pool.execute.__whatap_wrapped__) {
|
|
397
|
+
shimmer.wrap(pool, 'execute', createQueryWrapper(self.agent, dbc));
|
|
398
|
+
pool.execute.__whatap_wrapped__ = true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// getConnection 메서드 후킹
|
|
402
|
+
if (pool.getConnection && !pool.getConnection.__whatap_wrapped__) {
|
|
403
|
+
shimmer.wrap(pool, 'getConnection', function(original) {
|
|
404
|
+
return function wrappedGetConnection() {
|
|
405
|
+
var args = Array.prototype.slice.call(arguments);
|
|
406
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
407
|
+
|
|
408
|
+
if (ctx == null) {
|
|
409
|
+
return original.apply(this, args);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const connectionResource = new AsyncResource('mariadb-getConnection');
|
|
413
|
+
|
|
414
|
+
return connectionResource.runInAsyncScope(() => {
|
|
415
|
+
ctx.start_time = Date.now();
|
|
416
|
+
|
|
417
|
+
const result = original.apply(this, args);
|
|
418
|
+
|
|
419
|
+
// Promise 기반 처리
|
|
420
|
+
if (result && typeof result.then === 'function') {
|
|
421
|
+
return result.then(connectionResource.bind(function(connection) {
|
|
422
|
+
TraceContextManager.resume(ctx.id);
|
|
423
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
424
|
+
|
|
425
|
+
if (connection && !connection.__query_hook__) {
|
|
426
|
+
connection.__query_hook__ = true;
|
|
427
|
+
hookConnectionMethods(connection, self.agent);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return connection;
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 동기 처리
|
|
435
|
+
hookConnectionMethods(result, self.agent);
|
|
436
|
+
ctx.elapsed = Date.now() - ctx.start_time;
|
|
437
|
+
return result;
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
});
|
|
441
|
+
pool.getConnection.__whatap_wrapped__ = true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return pool;
|
|
446
|
+
};
|
|
447
|
+
});
|
|
448
|
+
mod.createPool.__whatap_wrapped__ = true;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
294
452
|
exports.MariaObserver = MariaObserver;
|