whatap 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -78
- package/lib/conf/conf-sys-mon.js +101 -0
- package/lib/conf/config-default.js +10 -3
- package/lib/conf/configure.js +369 -349
- package/lib/conf/license.js +1 -1
- package/lib/control/cmd-config.js +24 -0
- package/lib/control/control-handler.js +367 -0
- package/lib/control/packagectr-helper.js +34 -3
- package/lib/core/agent.js +176 -882
- package/lib/core/interceptor.js +6 -6
- package/lib/core/request-agent.js +27 -0
- package/lib/core/shimmer.js +82 -36
- package/lib/counter/counter-manager.js +79 -8
- package/lib/counter/meter/meter-activex.js +67 -0
- package/lib/counter/meter/meter-httpc.js +57 -0
- package/lib/counter/meter/meter-resource.js +9 -0
- package/lib/counter/meter/meter-service.js +168 -0
- package/lib/counter/meter/meter-socket.io.js +51 -0
- package/lib/counter/meter/meter-sql.js +71 -0
- package/lib/counter/meter/meter-users.js +58 -0
- package/lib/counter/meter.js +183 -0
- package/lib/counter/task/activetransaction.js +68 -17
- package/lib/counter/task/agentinfo.js +107 -0
- package/lib/{system → counter/task}/gc-action.js +27 -74
- package/lib/counter/task/gcstat.js +34 -0
- package/lib/counter/task/heapmem.js +25 -0
- package/lib/counter/task/httpc.js +76 -0
- package/lib/counter/task/metering-info.js +125 -0
- package/lib/counter/task/proc-cpu.js +29 -0
- package/lib/counter/task/realtimeuser.js +31 -0
- package/lib/counter/task/res/systemECSTask.js +39 -0
- package/lib/counter/task/res/systemKubeTask.js +53 -0
- package/lib/counter/task/res/util/awsEcsClientThread.js +218 -0
- package/lib/counter/task/res/util/linuxProcStatUtil.js +14 -0
- package/lib/counter/task/res-sys-cpu.js +62 -0
- package/lib/counter/task/service.js +202 -0
- package/lib/counter/task/socketio.js +30 -0
- package/lib/counter/task/sql.js +105 -0
- package/lib/counter/task/systemperf.js +43 -0
- package/lib/data/datapack-sender.js +289 -0
- package/lib/data/dataprofile-agent.js +162 -0
- package/lib/data/datatext-agent.js +135 -0
- package/lib/data/event-level.js +15 -0
- package/lib/data/test.js +49 -0
- package/lib/data/zipprofile.js +197 -0
- package/lib/env/constants.js +21 -0
- package/lib/error/error-handler.js +437 -0
- package/lib/io/data-inputx.js +13 -3
- package/lib/io/data-outputx.js +268 -206
- package/lib/kube/kube-client.js +144 -0
- package/lib/lang/text-types.js +58 -0
- package/lib/logger.js +6 -6
- package/lib/logsink/line-log-util.js +87 -0
- package/lib/logsink/line-log.js +12 -0
- package/lib/logsink/log-sender.js +78 -0
- package/lib/logsink/log-tracer.js +40 -0
- package/lib/logsink/sender-util.js +56 -0
- package/lib/logsink/zip/zip-send.js +177 -0
- package/lib/net/netflag.js +55 -0
- package/lib/net/receiver.js +66 -0
- package/lib/net/security-master.js +139 -20
- package/lib/net/sender.js +141 -0
- package/lib/net/tcp-return.js +18 -0
- package/lib/net/tcp-session.js +286 -0
- package/lib/net/tcpreq-client-proxy.js +70 -0
- package/lib/net/tcprequest-mgr.js +58 -0
- package/lib/observers/apollo-server-observer.js +33 -27
- package/lib/observers/cluster-observer.js +22 -0
- package/lib/observers/express-observer.js +215 -0
- package/lib/observers/file-observer.js +184 -0
- package/lib/observers/global-observer.js +155 -80
- package/lib/observers/grpc-observer.js +336 -0
- package/lib/observers/http-observer.js +666 -236
- package/lib/observers/maria-observer.js +204 -362
- package/lib/observers/memcached-observer.js +56 -0
- package/lib/observers/mongo-observer.js +317 -0
- package/lib/observers/mongodb-observer.js +169 -226
- package/lib/observers/mongoose-observer.js +518 -323
- package/lib/observers/mssql-observer.js +177 -418
- package/lib/observers/mysql-observer.js +342 -449
- package/lib/observers/mysql2-observer.js +396 -358
- package/lib/observers/net-observer.js +77 -0
- package/lib/observers/oracle-observer.js +559 -384
- package/lib/observers/pgsql-observer.js +231 -489
- package/lib/observers/prisma-observer.js +303 -92
- package/lib/observers/process-observer.js +79 -35
- package/lib/observers/promise-observer.js +31 -0
- package/lib/observers/redis-observer.js +166 -331
- package/lib/observers/schedule-observer.js +67 -0
- package/lib/observers/socket.io-observer.js +226 -187
- package/lib/observers/stream-observer.js +19 -0
- package/lib/observers/thrift-observer.js +197 -0
- package/lib/observers/websocket-observer.js +175 -301
- package/lib/pack/activestack-pack.js +55 -0
- package/lib/pack/apenum.js +8 -0
- package/lib/pack/counter-pack.js +3 -0
- package/lib/pack/errorsnap-pack.js +69 -0
- package/lib/pack/event-pack.js +54 -0
- package/lib/pack/hitmap-pack.js +63 -0
- package/lib/pack/hitmap-pack1.js +152 -0
- package/lib/pack/log-sink-pack.js +14 -52
- package/lib/pack/netstat.js +15 -0
- package/lib/pack/otype.js +7 -0
- package/lib/pack/profile-pack.js +49 -0
- package/lib/pack/realtimeuser-pack.js +41 -0
- package/lib/pack/stat-general-pack.js +96 -0
- package/lib/pack/staterror-pack.js +120 -0
- package/lib/pack/stathttpc-pack.js +66 -0
- package/lib/pack/stathttpc-rec.js +78 -0
- package/lib/pack/statremote-pack.js +46 -0
- package/lib/pack/statservice-pack.js +63 -0
- package/lib/pack/statservice-pack1.js +88 -0
- package/lib/pack/statservice-rec.js +292 -0
- package/lib/pack/statservice-rec_dep.js +151 -0
- package/lib/pack/statsql-pack.js +69 -0
- package/lib/pack/statsql-rec.js +100 -0
- package/lib/pack/statuseragent-pack.js +44 -0
- package/lib/pack/tagcount-pack.js +4 -4
- package/lib/pack/tagctr.js +15 -0
- package/lib/pack/text-pack.js +50 -0
- package/lib/pack/time-count.js +25 -0
- package/lib/pack/websocket.js +15 -0
- package/lib/pack/zip-pack.js +70 -0
- package/lib/pii/pii-item.js +31 -0
- package/lib/pii/pii-mask.js +174 -0
- package/lib/plugin/plugin-loadermanager.js +57 -0
- package/lib/plugin/plugin.js +75 -0
- package/lib/service/tx-record.js +332 -0
- package/lib/stat/stat-error.js +116 -0
- package/lib/stat/stat-httpc.js +98 -0
- package/lib/stat/stat-remote-ip.js +46 -0
- package/lib/stat/stat-remote-ipurl.js +88 -0
- package/lib/stat/stat-sql.js +113 -0
- package/lib/stat/stat-tranx.js +58 -0
- package/lib/stat/stat-tx-caller.js +160 -0
- package/lib/stat/stat-tx-domain.js +111 -0
- package/lib/stat/stat-tx-referer.js +112 -0
- package/lib/stat/stat-useragent.js +48 -0
- package/lib/stat/timingsender.js +76 -0
- package/lib/step/activestack-step.js +38 -0
- package/lib/step/dbc-step.js +36 -0
- package/lib/step/http-stepx.js +67 -0
- package/lib/step/message-step.js +40 -0
- package/lib/step/method-stepx.js +45 -0
- package/lib/step/resultset-step.js +40 -0
- package/lib/step/securemsg-step.js +44 -0
- package/lib/step/socket-step.js +46 -0
- package/lib/step/sql-stepx.js +68 -0
- package/lib/step/sqlxtype.js +16 -0
- package/lib/step/step.js +66 -0
- package/lib/step/stepenum.js +54 -0
- package/lib/topology/link.js +63 -0
- package/lib/topology/nodeinfo.js +123 -0
- package/lib/topology/status-detector.js +111 -0
- package/lib/trace/trace-context-manager.js +113 -25
- package/lib/trace/trace-context.js +21 -7
- package/lib/trace/trace-httpc.js +17 -11
- package/lib/trace/trace-sql.js +29 -21
- package/lib/util/anylist.js +103 -0
- package/lib/util/cardinality/hyperloglog.js +106 -0
- package/lib/util/cardinality/murmurhash.js +31 -0
- package/lib/util/cardinality/registerset.js +75 -0
- package/lib/util/errordata.js +21 -0
- package/lib/util/escape-literal-sql.js +5 -5
- package/lib/util/hashutil.js +18 -18
- package/lib/util/iputil_x.js +527 -0
- package/lib/util/keygen.js +0 -3
- package/lib/util/kube-util.js +73 -0
- package/lib/util/linkedset.js +1 -2
- package/lib/util/nodeutil.js +2 -1
- package/lib/util/paramsecurity.js +80 -0
- package/lib/util/pre-process.js +13 -0
- package/lib/util/process-seq.js +166 -0
- package/lib/util/property-util.js +36 -0
- package/lib/util/request-queue.js +70 -0
- package/lib/util/requestdouble-queue.js +72 -0
- package/lib/util/resourceprofile.js +157 -0
- package/lib/util/stop-watch.js +30 -0
- package/lib/util/system-util.js +10 -0
- package/lib/util/userid-util.js +57 -0
- package/lib/value/map-value.js +3 -2
- package/package.json +9 -4
- package/whatap.conf +1 -4
- package/agent/darwin/arm64/whatap_nodejs +0 -0
- package/agent/linux/amd64/whatap_nodejs +0 -0
- package/agent/linux/arm64/whatap_nodejs +0 -0
- package/build.txt +0 -4
- package/lib/observers/ioredis-observer.js +0 -294
- package/lib/udp/async_sender.js +0 -119
- package/lib/udp/index.js +0 -17
- package/lib/udp/packet_enum.js +0 -52
- package/lib/udp/packet_queue.js +0 -69
- package/lib/udp/packet_type_enum.js +0 -33
- package/lib/udp/param_def.js +0 -72
- package/lib/udp/udp_session.js +0 -336
- package/lib/util/sql-util.js +0 -178
- package/lib/util/trace-helper.js +0 -91
- package/lib/util/transfer.js +0 -58
|
@@ -5,18 +5,25 @@
|
|
|
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
|
-
|
|
8
|
+
ParsedSql = require('../trace/parsed-sql'),
|
|
9
|
+
SqlStepX = require('../step/sql-stepx'),
|
|
10
|
+
DBCStep = require('../step/dbc-step'),
|
|
11
|
+
DataTextAgent = require('../data/datatext-agent'),
|
|
12
|
+
StatSql = require('../stat/stat-sql'),
|
|
13
|
+
MeterSql = require('../counter/meter/meter-sql'),
|
|
14
|
+
conf = require('../conf/configure'),
|
|
15
|
+
IntKeyMap = require('../util/intkey-map'),
|
|
16
|
+
EscapeLiteralSQL = require('../util/escape-literal-sql'),
|
|
17
|
+
HashUtil = require('../util/hashutil'),
|
|
18
|
+
StatError = require('../stat/stat-error'),
|
|
19
|
+
TextTypes = require('../lang/text-types'),
|
|
20
|
+
ParamSecurity = require('../util/paramsecurity'),
|
|
21
|
+
Logger = require('../logger'),
|
|
22
|
+
Buffer = require('buffer').Buffer,
|
|
23
|
+
DateUtil = require('../util/dateutil'),
|
|
24
|
+
TraceSQL = require('../trace/trace-sql');
|
|
25
|
+
const shimmer = require('../core/shimmer');
|
|
26
|
+
const ResultSetStep = require("../step/resultset-step");
|
|
20
27
|
|
|
21
28
|
var PgSqlObserver = function (agent) {
|
|
22
29
|
this.agent = agent;
|
|
@@ -24,539 +31,274 @@ var PgSqlObserver = function (agent) {
|
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
var dbc_hash = 0;
|
|
27
|
-
var dbc
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
var dbc, dbc_step;
|
|
35
|
+
PgSqlObserver.prototype.inject = function (mod, moduleName) {
|
|
36
|
+
if (mod.__whatap_observe__) { return; }
|
|
37
|
+
mod.__whatap_observe__ = true;
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
var nonLiteSql = new IntKeyMap(5000).setMax(5000);
|
|
33
|
-
var date = DateUtil.yyyymmdd();
|
|
39
|
+
Logger.initPrint("PgSqlObserver");
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
var self = this;
|
|
42
|
+
var aop = self.agent.aop;
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
var errorClass = err.code || err.name || err.constructor?.name || 'PostgreSQLError';
|
|
40
|
-
var errorMessage = err.message || 'postgresql error';
|
|
41
|
-
var errorStack = '';
|
|
44
|
+
if (conf.sql_enabled === false) { return; }
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
errorStack = stackLines.join("\n");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
var shouldAddError = false;
|
|
53
|
-
if (conf._is_trace_ignore_err_cls_contains === true && errorClass &&
|
|
54
|
-
errorClass.indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
55
|
-
shouldAddError = true;
|
|
56
|
-
} else if (conf._is_trace_ignore_err_msg_contains === true && errorMessage &&
|
|
57
|
-
errorMessage.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
|
|
58
|
-
shouldAddError = true;
|
|
59
|
-
} else if (conf._is_trace_ignore_err_cls_contains === false &&
|
|
60
|
-
conf._is_trace_ignore_err_msg_contains === false) {
|
|
61
|
-
shouldAddError = true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (shouldAddError) {
|
|
65
|
-
if (!ctx.error) ctx.error = 1;
|
|
66
|
-
ctx.status = 500;
|
|
67
|
-
var errors = [errorClass];
|
|
68
|
-
if (errorMessage) {
|
|
69
|
-
errors.push(errorMessage);
|
|
70
|
-
}
|
|
71
|
-
if (errorStack || err.stack) {
|
|
72
|
-
errors.push(errorStack || err.stack);
|
|
46
|
+
shimmer.wrap(mod.Client.prototype, 'connect', function (original) {
|
|
47
|
+
return function () {
|
|
48
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
49
|
+
if (!ctx || ctx.db_opening) {
|
|
50
|
+
return original.apply(this, arguments);
|
|
73
51
|
}
|
|
74
52
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} catch (e) {
|
|
78
|
-
Logger.printError('WHATAP-204', 'Error handling PgSQL error', e, false);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function setupDbcInfo(args) {
|
|
83
|
-
if (dbc_hash === 0 && args.length > 0) {
|
|
84
|
-
var info = args[0] || {};
|
|
85
|
-
dbc = 'postgresql://';
|
|
86
|
-
dbc += (info.user || '') + '@';
|
|
87
|
-
dbc += (info.host || '') + '/';
|
|
88
|
-
dbc += info.database || '';
|
|
89
|
-
dbc_hash = HashUtil.hashFromString(dbc);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function hookConnectionMethods(connection, agent) {
|
|
94
|
-
if (connection && !hookedInstances.has(connection)) {
|
|
95
|
-
hookedInstances.add(connection);
|
|
96
|
-
Logger.print('WHATAP-201', 'Hooking new connection object', false);
|
|
97
|
-
|
|
98
|
-
if (dbc_hash === 0 && connection.connectionParameters) {
|
|
99
|
-
var info = connection.connectionParameters;
|
|
100
|
-
dbc = 'postgresql://';
|
|
101
|
-
dbc += (info.user || '') + '@';
|
|
102
|
-
dbc += (info.host || '') + '/';
|
|
103
|
-
dbc += info.database || '';
|
|
104
|
-
dbc_hash = HashUtil.hashFromString(dbc);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (connection.query && !connection.query.__whatap_wrapped__) {
|
|
108
|
-
shimmer.wrap(connection, 'query', createQueryWrapper(agent, dbc));
|
|
109
|
-
connection.query.__whatap_wrapped__ = true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function escapeLiteral(sql) {
|
|
115
|
-
if (sql == null) {
|
|
116
|
-
sql = '';
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (date !== DateUtil.yyyymmdd()) {
|
|
120
|
-
checkedSql.clear();
|
|
121
|
-
nonLiteSql.clear();
|
|
122
|
-
date = DateUtil.yyyymmdd();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
var sqlHash = HashUtil.hashFromString(sql);
|
|
126
|
-
var psql = nonLiteSql.get(sqlHash);
|
|
53
|
+
ctx.pg_opening = true;
|
|
54
|
+
ctx.footprint('PgSql Connecting Start');
|
|
127
55
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
psql = checkedSql.get(sqlHash);
|
|
132
|
-
|
|
133
|
-
if (psql != null) {
|
|
134
|
-
return psql;
|
|
135
|
-
}
|
|
56
|
+
dbc_step = new DBCStep();
|
|
57
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
136
58
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
59
|
+
const finishConnect = function (param) {
|
|
60
|
+
if (ctx) {
|
|
61
|
+
if (dbc_hash === 0) {
|
|
62
|
+
const info = param.connectionParameters;
|
|
63
|
+
dbc = 'postgresql://';
|
|
64
|
+
dbc += (info.user || '') + '@';
|
|
65
|
+
dbc += (info.host || '') + '/';
|
|
66
|
+
dbc += info.database || '';
|
|
67
|
+
|
|
68
|
+
dbc_hash = HashUtil.hashFromString(dbc);
|
|
69
|
+
|
|
70
|
+
// DataTextAgent.DBC.add(dbc_hash, dbc);
|
|
71
|
+
// DataTextAgent.METHOD.add(dbc_hash, dbc);
|
|
72
|
+
// DataTextAgent.ERROR.add(dbc_hash, dbc);
|
|
73
|
+
}
|
|
74
|
+
//
|
|
75
|
+
// dbc_step.hash = dbc_hash;
|
|
76
|
+
// dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
77
|
+
//
|
|
78
|
+
// ctx.db_opening = false;
|
|
79
|
+
// ctx.footprint('PgSql Connecting Done');
|
|
80
|
+
// ctx.profile.push(dbc_step);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
141
83
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
nonLiteSql.put(sqlHash, psql);
|
|
145
|
-
} else {
|
|
146
|
-
psql = new ParsedSql(els.sqlType, hash, els.getParameter());
|
|
147
|
-
checkedSql.put(sqlHash, psql);
|
|
148
|
-
}
|
|
149
|
-
return psql;
|
|
150
|
-
}
|
|
84
|
+
try {
|
|
85
|
+
const result = original.apply(this, arguments);
|
|
151
86
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
87
|
+
if (result && result.then) {
|
|
88
|
+
result.then(finishConnect(this));
|
|
89
|
+
} else {
|
|
90
|
+
finishConnect(this);
|
|
91
|
+
}
|
|
157
92
|
|
|
158
|
-
|
|
159
|
-
|
|
93
|
+
} catch (err) {
|
|
94
|
+
ctx.db_opening = false;
|
|
95
|
+
Logger.printError('PgSqlObserver', 'Connect Error', err);
|
|
96
|
+
throw err;
|
|
160
97
|
}
|
|
98
|
+
};
|
|
99
|
+
});
|
|
161
100
|
|
|
162
|
-
|
|
101
|
+
shimmer.wrap(mod.Client.prototype, 'query', function (original) {
|
|
102
|
+
return function () {
|
|
103
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
104
|
+
if (!ctx) {
|
|
163
105
|
return original.apply(this, arguments);
|
|
164
106
|
}
|
|
165
107
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbcUrl]);
|
|
108
|
+
if(dbc && dbc_hash){
|
|
109
|
+
if(!dbc_step){
|
|
110
|
+
dbc_step = new DBCStep();
|
|
111
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
112
|
+
}
|
|
113
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
114
|
+
dbc_step.hash = dbc_hash;
|
|
174
115
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
116
|
+
DataTextAgent.DBC.add(dbc_hash, dbc);
|
|
117
|
+
DataTextAgent.METHOD.add(dbc_hash, dbc);
|
|
118
|
+
DataTextAgent.ERROR.add(dbc_hash, dbc);
|
|
178
119
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
120
|
+
ctx.pg_opening = false;
|
|
121
|
+
ctx.footprint('PgSql Connecting Done');
|
|
122
|
+
ctx.profile.push(dbc_step);
|
|
123
|
+
}
|
|
124
|
+
dbc_step = null;
|
|
182
125
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
} else if (typeof sql === 'string') {
|
|
188
|
-
finalSql = sql;
|
|
189
|
-
params = args.length > 1 && Array.isArray(args[1]) ? args[1] : null;
|
|
190
|
-
}
|
|
126
|
+
var sql_step = new SqlStepX();
|
|
127
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
128
|
+
ctx.profile.push(sql_step);
|
|
129
|
+
ctx.footprint('PgSql Query Start');
|
|
191
130
|
|
|
192
|
-
|
|
193
|
-
params.forEach((param, index) => {
|
|
194
|
-
const placeholder = '$' + (index + 1);
|
|
195
|
-
const value = param === null ? 'NULL' :
|
|
196
|
-
typeof param === 'string' ? `'${param.replace(/'/g, "''")}'` :
|
|
197
|
-
String(param);
|
|
198
|
-
finalSql = finalSql.replace(new RegExp('\\' + placeholder + '\\b', 'g'), value);
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
} catch (formatError) {
|
|
202
|
-
Logger.printError('WHATAP-205', 'Error formatting PostgreSQL query', formatError, false);
|
|
203
|
-
if (typeof sql === 'string') {
|
|
204
|
-
finalSql = sql;
|
|
205
|
-
} else if (sql && sql.text) {
|
|
206
|
-
finalSql = sql.text;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
131
|
+
ctx.vvv++;
|
|
209
132
|
|
|
210
|
-
|
|
211
|
-
|
|
133
|
+
let sql = arguments[0];
|
|
134
|
+
let psql = null;
|
|
135
|
+
if (typeof sql === 'string' && sql.length > 0) {
|
|
136
|
+
try {
|
|
137
|
+
psql = escapeLiteral(sql);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
Logger.printError('WHATAP-191', 'PgSqlObserver escapeliteral error', e);
|
|
212
140
|
}
|
|
141
|
+
} else {
|
|
142
|
+
sql = '';
|
|
143
|
+
psql = escapeLiteral(sql);
|
|
144
|
+
}
|
|
213
145
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
146
|
+
if(psql != null) {
|
|
147
|
+
sql_step.hash = psql.sql;
|
|
148
|
+
}
|
|
149
|
+
sql_step.dbc = dbc_hash;
|
|
150
|
+
|
|
151
|
+
var els = new EscapeLiteralSQL(sql);
|
|
152
|
+
els.process();
|
|
153
|
+
ctx.active_sqlhash = sql_step.hash;
|
|
154
|
+
ctx.active_dbc = sql_step.dbc;
|
|
155
|
+
//ctx.active_crud = sql_step.crud;
|
|
156
|
+
|
|
157
|
+
if(conf.profile_sql_param_enabled) {
|
|
158
|
+
var params = arguments.length > 1 && Array.isArray(arguments[1]) ? arguments[1] : undefined;
|
|
159
|
+
sql_step.setTrue(1);
|
|
160
|
+
var crc = {value : 0};
|
|
161
|
+
sql_step.p1 = toParamBytes(psql.param, crc);
|
|
162
|
+
if(params != undefined) {
|
|
163
|
+
const result = params.map((param) => {
|
|
164
|
+
if(typeof param === 'string'){
|
|
165
|
+
return `'${param}'`
|
|
166
|
+
}
|
|
167
|
+
return param
|
|
168
|
+
}).toString()
|
|
169
|
+
sql_step.p2 = toParamBytes(result, crc);
|
|
224
170
|
}
|
|
171
|
+
sql_step.pcrc = crc.value;
|
|
172
|
+
}
|
|
225
173
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
ctx.active_dbc = dbc_hash;
|
|
229
|
-
|
|
230
|
-
function queryCallback(err, results) {
|
|
231
|
-
var currentCtx = TraceContextManager.getCurrentContext();
|
|
232
|
-
if (currentCtx == null) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
TraceContextManager.resume(currentCtx.id);
|
|
174
|
+
try {
|
|
175
|
+
const result = original.apply(this, arguments);
|
|
237
176
|
|
|
238
|
-
|
|
239
|
-
|
|
177
|
+
if (result && result.then) {
|
|
178
|
+
return result.then(res => {
|
|
179
|
+
if(res.command && res.command === 'SELECT'){
|
|
180
|
+
var result_step = new ResultSetStep();
|
|
181
|
+
result_step.start_time = ctx.getElapsedTime();
|
|
182
|
+
result_step.elapsed = 0;
|
|
183
|
+
result_step.fetch = res.rowCount;
|
|
184
|
+
result_step.sqlhash = psql.sql;
|
|
185
|
+
result_step.dbc = dbc_hash;
|
|
186
|
+
ctx.profile.push(result_step);
|
|
240
187
|
|
|
241
|
-
|
|
242
|
-
handleSqlError(currentCtx, err);
|
|
243
|
-
}
|
|
188
|
+
ctx.rs_count = ctx.rs_count ? ctx.rs_count + res.rowCount : res.rowCount;
|
|
244
189
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
resultCount = results.rowCount;
|
|
248
|
-
} else if (results.rows && Array.isArray(results.rows)) {
|
|
249
|
-
resultCount = results.rows.length;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
190
|
+
MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
|
|
191
|
+
StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
|
|
252
192
|
|
|
253
|
-
|
|
254
|
-
TraceSQL.isSlowSQL(currentCtx);
|
|
255
|
-
if (results && results.command && results.command === 'SELECT' && psql != null && psql.type === 'S') {
|
|
256
|
-
TraceSQL.isTooManyRecords(resultCount, currentCtx);
|
|
193
|
+
TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
|
|
257
194
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
var callbackWrapped = false;
|
|
270
|
-
var hasCallback = false;
|
|
271
|
-
|
|
272
|
-
for (var i = args.length - 1; i >= 0; i--) {
|
|
273
|
-
if (typeof args[i] === 'function') {
|
|
274
|
-
hasCallback = true;
|
|
275
|
-
var originalCallback = args[i];
|
|
276
|
-
args[i] = callbackResource.bind(function() {
|
|
277
|
-
var callbackArgs = Array.prototype.slice.call(arguments);
|
|
278
|
-
try {
|
|
279
|
-
queryCallback(callbackArgs[0], callbackArgs[1]);
|
|
280
|
-
} catch (e) {
|
|
281
|
-
Logger.printError('WHATAP-208', 'Error in callback hook', e, false);
|
|
195
|
+
self._finishQuery(ctx, sql_step);
|
|
196
|
+
return res;
|
|
197
|
+
}).catch(err => {
|
|
198
|
+
self._handleError(ctx, sql_step, err)
|
|
199
|
+
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth) {
|
|
200
|
+
var traceDepth = conf.trace_sql_error_depth;
|
|
201
|
+
|
|
202
|
+
var errorStack = err.stack.split("\n");
|
|
203
|
+
if (errorStack.length > traceDepth) {
|
|
204
|
+
errorStack = errorStack.slice(0, traceDepth + 1);
|
|
282
205
|
}
|
|
283
|
-
|
|
284
|
-
|
|
206
|
+
ctx.error_message = errorStack.join("\n");
|
|
207
|
+
sql_step.error = ctx.error = StatError.addError('pgsql -' + err.code, err.message, ctx.service_hash, TextTypes.SQL, null);
|
|
208
|
+
}
|
|
209
|
+
throw err;
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
const callback = arguments[arguments.length - 1];
|
|
213
|
+
if (typeof callback === 'function') {
|
|
214
|
+
arguments[arguments.length - 1] = function (err, res) {
|
|
215
|
+
if (err) {
|
|
216
|
+
self._handleError(ctx, sql_step, err);
|
|
217
|
+
} else {
|
|
218
|
+
self._finishQuery(ctx, sql_step);
|
|
285
219
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
const result = original.apply(this, args);
|
|
294
|
-
|
|
295
|
-
// Promise 기반 처리
|
|
296
|
-
if (!hasCallback && result && typeof result.then === 'function') {
|
|
297
|
-
return result.then(function(res) {
|
|
298
|
-
queryCallback(null, res);
|
|
299
|
-
return res;
|
|
300
|
-
}).catch(function(err) {
|
|
301
|
-
queryCallback(err, null);
|
|
302
|
-
throw err;
|
|
303
|
-
});
|
|
220
|
+
return callback.apply(this, arguments);
|
|
221
|
+
};
|
|
304
222
|
}
|
|
305
|
-
|
|
306
223
|
return result;
|
|
307
|
-
} catch (queryError) {
|
|
308
|
-
queryCallback(queryError, null);
|
|
309
|
-
throw queryError;
|
|
310
224
|
}
|
|
311
|
-
})
|
|
225
|
+
} catch (err) {
|
|
226
|
+
self._handleError(ctx, sql_step, err);
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
312
229
|
};
|
|
313
|
-
};
|
|
230
|
+
});
|
|
314
231
|
};
|
|
315
232
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
var args = Array.prototype.slice.call(arguments);
|
|
320
|
-
var ctx = TraceContextManager.getCurrentContext();
|
|
321
|
-
|
|
322
|
-
if (ctx == null) {
|
|
323
|
-
return original.apply(this, args);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// AsyncResource로 connect 컨텍스트 유지
|
|
327
|
-
const connectionResource = new AsyncResource('pg-pool-connect');
|
|
328
|
-
return connectionResource.runInAsyncScope(() => {
|
|
329
|
-
ctx.start_time = Date.now();
|
|
330
|
-
|
|
331
|
-
// 콜백 래핑
|
|
332
|
-
for (var i = args.length - 1; i >= 0; i--) {
|
|
333
|
-
if (typeof args[i] === 'function') {
|
|
334
|
-
var originalCallback = args[i];
|
|
335
|
-
// AsyncResource로 콜백 바인딩
|
|
336
|
-
args[i] = connectionResource.bind(function() {
|
|
337
|
-
var callbackArgs = Array.prototype.slice.call(arguments);
|
|
338
|
-
var err = callbackArgs[0];
|
|
339
|
-
var client = callbackArgs[1];
|
|
340
|
-
|
|
341
|
-
TraceContextManager.resume(ctx.id);
|
|
342
|
-
ctx.elapsed = Date.now() - ctx.start_time;
|
|
343
|
-
|
|
344
|
-
if (!err && client && !client.__query_hook__) {
|
|
345
|
-
client.__query_hook__ = true;
|
|
346
|
-
hookConnectionMethods(client, agent);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return originalCallback.apply(this, callbackArgs);
|
|
350
|
-
});
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
var result = original.apply(this, args);
|
|
233
|
+
PgSqlObserver.prototype._finishQuery = function (ctx, sql_step) {
|
|
234
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
235
|
+
TraceSQL.isSlowSQL(ctx);
|
|
356
236
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
TraceContextManager.resume(ctx.id);
|
|
361
|
-
ctx.elapsed = Date.now() - ctx.start_time;
|
|
237
|
+
MeterSql.add(sql_step.hash, sql_step.elapsed, false);
|
|
238
|
+
StatSql.addSqlTime(ctx, ctx.service_hash, sql_step.dbc, sql_step.hash, sql_step.elapsed, false, 0);
|
|
239
|
+
};
|
|
362
240
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
241
|
+
PgSqlObserver.prototype._handleError = function (ctx, sql_step, err) {
|
|
242
|
+
ctx.error_message = err.message;
|
|
243
|
+
ctx.error_class = err.name || err.constructor?.name || 'PgsqlError';
|
|
244
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
245
|
+
TraceSQL.isSlowSQL(ctx);
|
|
367
246
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return result;
|
|
373
|
-
});
|
|
374
|
-
};
|
|
375
|
-
};
|
|
247
|
+
MeterSql.add(sql_step.hash, sql_step.elapsed, false);
|
|
248
|
+
StatSql.addSqlTime(ctx, ctx.service_hash, sql_step.dbc, sql_step.hash, sql_step.elapsed, true, 0);
|
|
376
249
|
};
|
|
377
250
|
|
|
378
|
-
|
|
379
|
-
if
|
|
380
|
-
return;
|
|
251
|
+
var toParamBytes = function(p, crc) {
|
|
252
|
+
if(p == null || p.length === 0) {
|
|
253
|
+
return null;
|
|
381
254
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return;
|
|
255
|
+
try{
|
|
256
|
+
return ParamSecurity.encrypt(Buffer.from(p), crc);
|
|
257
|
+
} catch(e) {
|
|
258
|
+
return null;
|
|
387
259
|
}
|
|
260
|
+
};
|
|
388
261
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (mod.Client && !mod.Client.__whatap_wrapped__) {
|
|
393
|
-
shimmer.wrap(mod, 'Client', function(original) {
|
|
394
|
-
return function wrappedClient() {
|
|
395
|
-
var args = Array.prototype.slice.call(arguments);
|
|
396
|
-
var ctx = TraceContextManager.getCurrentContext();
|
|
397
|
-
|
|
398
|
-
setupDbcInfo(args);
|
|
399
|
-
|
|
400
|
-
// if (ctx && !ctx.db_opening) {
|
|
401
|
-
// ctx.db_opening = true;
|
|
402
|
-
// ctx.footprint('PgSql Connecting Start');
|
|
403
|
-
// ctx.start_time = Date.now();
|
|
404
|
-
// }
|
|
405
|
-
|
|
406
|
-
var client = new (Function.prototype.bind.apply(original, [null].concat(args)));
|
|
407
|
-
|
|
408
|
-
hookConnectionMethods(client, self.agent);
|
|
409
|
-
|
|
410
|
-
if (client && client.connect && !client.connect.__whatap_wrapped__) {
|
|
411
|
-
shimmer.wrap(client, 'connect', function(original) {
|
|
412
|
-
return function wrappedConnect() {
|
|
413
|
-
var args = Array.prototype.slice.call(arguments);
|
|
414
|
-
var ctx = TraceContextManager.getCurrentContext();
|
|
415
|
-
|
|
416
|
-
if (ctx) {
|
|
417
|
-
ctx.start_time = Date.now();
|
|
418
|
-
ctx.footprint('PgSql Connecting Start');
|
|
419
|
-
ctx.db_opening = true;
|
|
420
|
-
|
|
421
|
-
// 콜백 래핑
|
|
422
|
-
for (var i = args.length - 1; i >= 0; i--) {
|
|
423
|
-
if (typeof args[i] === 'function') {
|
|
424
|
-
var originalCallback = args[i];
|
|
425
|
-
args[i] = function() {
|
|
426
|
-
var callbackArgs = Array.prototype.slice.call(arguments);
|
|
427
|
-
var err = callbackArgs[0];
|
|
428
|
-
|
|
429
|
-
if (err) {
|
|
430
|
-
handleSqlError(ctx, err);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
ctx.db_opening = false;
|
|
434
|
-
ctx.footprint('PgSql Connecting Done');
|
|
435
|
-
TraceContextManager.resume(ctx.id);
|
|
436
|
-
|
|
437
|
-
return originalCallback.apply(this, callbackArgs);
|
|
438
|
-
};
|
|
439
|
-
break;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
var result = original.apply(this, args);
|
|
445
|
-
|
|
446
|
-
// Promise 기반 처리
|
|
447
|
-
if (result && typeof result.then === 'function') {
|
|
448
|
-
return result.then(function() {
|
|
449
|
-
if (ctx) {
|
|
450
|
-
ctx.db_opening = false;
|
|
451
|
-
ctx.footprint('PgSql Connecting Done');
|
|
452
|
-
}
|
|
453
|
-
return result;
|
|
454
|
-
}).catch(function(err) {
|
|
455
|
-
if (ctx) {
|
|
456
|
-
ctx.db_opening = false;
|
|
457
|
-
ctx.footprint('PgSql Connecting Error');
|
|
458
|
-
handleSqlError(ctx, err);
|
|
459
|
-
}
|
|
460
|
-
throw err;
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return result;
|
|
465
|
-
};
|
|
466
|
-
});
|
|
467
|
-
client.connect.__whatap_wrapped__ = true;
|
|
468
|
-
}
|
|
262
|
+
var checkedSql = new IntKeyMap(2000).setMax(2000);
|
|
263
|
+
var nonLiteSql = new IntKeyMap(5000).setMax(5000);
|
|
264
|
+
var date = DateUtil.yyyymmdd();
|
|
469
265
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
ctx.footprint('PgSql Client Created');
|
|
473
|
-
ctx.db_opening = false;
|
|
474
|
-
}
|
|
266
|
+
function escapeLiteral(sql) {
|
|
267
|
+
if(sql == null) { sql = ''; }
|
|
475
268
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
269
|
+
if(date !== DateUtil.yyyymmdd()) {
|
|
270
|
+
checkedSql.clear();
|
|
271
|
+
nonLiteSql.clear();
|
|
272
|
+
date = DateUtil.yyyymmdd();
|
|
273
|
+
Logger.print('WHATAP-SQL-CLEAR', 'PgSqlObserver CLEAR OK!!!!!!!!!!!!!!!!', false);
|
|
480
274
|
}
|
|
481
275
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
return function wrappedPool() {
|
|
485
|
-
var args = Array.prototype.slice.call(arguments);
|
|
486
|
-
setupDbcInfo(args);
|
|
487
|
-
|
|
488
|
-
var pool = new (Function.prototype.bind.apply(original, [null].concat(args)));
|
|
489
|
-
|
|
490
|
-
if (pool && !hookedInstances.has(pool)) {
|
|
491
|
-
hookedInstances.add(pool);
|
|
492
|
-
|
|
493
|
-
// Pool의 query 메서드 후킹
|
|
494
|
-
if (pool.query && !pool.query.__whatap_wrapped__) {
|
|
495
|
-
shimmer.wrap(pool, 'query', createQueryWrapper(self.agent, dbc));
|
|
496
|
-
pool.query.__whatap_wrapped__ = true;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// Pool의 connect 메서드는 수동 연결 시에만 후킹
|
|
500
|
-
// pool.query() 내부에서 자동으로 연결을 가져올 때는 후킹하지 않음
|
|
501
|
-
if (pool.connect && !pool.connect.__whatap_wrapped__) {
|
|
502
|
-
shimmer.wrap(pool, 'connect', function(original) {
|
|
503
|
-
return function wrappedConnect() {
|
|
504
|
-
var args = Array.prototype.slice.call(arguments);
|
|
505
|
-
var result = original.apply(this, args);
|
|
506
|
-
|
|
507
|
-
// Promise 기반 처리 - 연결 객체에만 후킹 (query는 후킹하지 않음)
|
|
508
|
-
if (result && typeof result.then === 'function') {
|
|
509
|
-
return result.then(function(client) {
|
|
510
|
-
// client에는 query 후킹하지 않음 (pool.query()에서 이미 추적됨)
|
|
511
|
-
return client;
|
|
512
|
-
});
|
|
513
|
-
} else if (result && typeof result === 'object') {
|
|
514
|
-
// 동기적으로 반환된 client에도 query 후킹하지 않음
|
|
515
|
-
return result;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return result;
|
|
519
|
-
};
|
|
520
|
-
});
|
|
521
|
-
pool.connect.__whatap_wrapped__ = true;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
276
|
+
var sqlHash = HashUtil.hashFromString(sql);
|
|
277
|
+
var psql = nonLiteSql.get(sqlHash);
|
|
524
278
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
});
|
|
528
|
-
mod.Pool.__whatap_wrapped__ = true;
|
|
279
|
+
if(psql != null) {
|
|
280
|
+
return psql;
|
|
529
281
|
}
|
|
282
|
+
psql = checkedSql.get(sqlHash);
|
|
530
283
|
|
|
531
|
-
if
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
var args = Array.prototype.slice.call(arguments);
|
|
535
|
-
var ctx = TraceContextManager.getCurrentContext();
|
|
536
|
-
|
|
537
|
-
if (ctx == null || args[0] == null) {
|
|
538
|
-
return original.apply(this, arguments);
|
|
539
|
-
}
|
|
284
|
+
if(psql != null) {
|
|
285
|
+
return psql;
|
|
286
|
+
}
|
|
540
287
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
dbc = 'postgresql://';
|
|
544
|
-
dbc += (info.user || '') + '@';
|
|
545
|
-
dbc += (info.host || '') + '/';
|
|
546
|
-
dbc += info.database || '';
|
|
547
|
-
dbc_hash = HashUtil.hashFromString(dbc);
|
|
548
|
-
}
|
|
288
|
+
var els = new EscapeLiteralSQL(sql);
|
|
289
|
+
els.process();
|
|
549
290
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
});
|
|
553
|
-
mod.Client.prototype.query.__whatap_wrapped__ = true;
|
|
554
|
-
}
|
|
291
|
+
var hash = HashUtil.hashFromString(els.getParsedSql());
|
|
292
|
+
DataTextAgent.SQL.add(hash, els.getParsedSql());
|
|
555
293
|
|
|
556
|
-
if
|
|
557
|
-
|
|
558
|
-
|
|
294
|
+
if(hash === sqlHash) {
|
|
295
|
+
psql = new ParsedSql(els.sqlType, hash, null);
|
|
296
|
+
nonLiteSql.put(sqlHash, psql);
|
|
297
|
+
} else {
|
|
298
|
+
psql = new ParsedSql(els.sqlType, hash, els.getParameter());
|
|
299
|
+
checkedSql.put(sqlHash, psql);
|
|
559
300
|
}
|
|
560
|
-
|
|
301
|
+
return psql;
|
|
302
|
+
}
|
|
561
303
|
|
|
562
304
|
exports.PgSqlObserver = PgSqlObserver;
|