whatap 1.0.1-canary.2 → 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.
Files changed (198) hide show
  1. package/README.md +33 -77
  2. package/lib/conf/conf-sys-mon.js +101 -0
  3. package/lib/conf/config-default.js +10 -3
  4. package/lib/conf/configure.js +369 -349
  5. package/lib/conf/license.js +1 -1
  6. package/lib/control/cmd-config.js +24 -0
  7. package/lib/control/control-handler.js +367 -0
  8. package/lib/control/packagectr-helper.js +34 -3
  9. package/lib/core/agent.js +176 -888
  10. package/lib/core/interceptor.js +6 -6
  11. package/lib/core/request-agent.js +27 -0
  12. package/lib/core/shimmer.js +82 -36
  13. package/lib/counter/counter-manager.js +79 -8
  14. package/lib/counter/meter/meter-activex.js +67 -0
  15. package/lib/counter/meter/meter-httpc.js +57 -0
  16. package/lib/counter/meter/meter-resource.js +9 -0
  17. package/lib/counter/meter/meter-service.js +168 -0
  18. package/lib/counter/meter/meter-socket.io.js +51 -0
  19. package/lib/counter/meter/meter-sql.js +71 -0
  20. package/lib/counter/meter/meter-users.js +58 -0
  21. package/lib/counter/meter.js +183 -0
  22. package/lib/counter/task/activetransaction.js +68 -17
  23. package/lib/counter/task/agentinfo.js +107 -0
  24. package/lib/{system → counter/task}/gc-action.js +27 -74
  25. package/lib/counter/task/gcstat.js +34 -0
  26. package/lib/counter/task/heapmem.js +25 -0
  27. package/lib/counter/task/httpc.js +76 -0
  28. package/lib/counter/task/metering-info.js +125 -0
  29. package/lib/counter/task/proc-cpu.js +29 -0
  30. package/lib/counter/task/realtimeuser.js +31 -0
  31. package/lib/counter/task/res/systemECSTask.js +39 -0
  32. package/lib/counter/task/res/systemKubeTask.js +53 -0
  33. package/lib/counter/task/res/util/awsEcsClientThread.js +218 -0
  34. package/lib/counter/task/res/util/linuxProcStatUtil.js +14 -0
  35. package/lib/counter/task/res-sys-cpu.js +62 -0
  36. package/lib/counter/task/service.js +202 -0
  37. package/lib/counter/task/socketio.js +30 -0
  38. package/lib/counter/task/sql.js +105 -0
  39. package/lib/counter/task/systemperf.js +43 -0
  40. package/lib/data/datapack-sender.js +289 -0
  41. package/lib/data/dataprofile-agent.js +162 -0
  42. package/lib/data/datatext-agent.js +135 -0
  43. package/lib/data/event-level.js +15 -0
  44. package/lib/data/test.js +49 -0
  45. package/lib/data/zipprofile.js +197 -0
  46. package/lib/env/constants.js +21 -0
  47. package/lib/error/error-handler.js +437 -0
  48. package/lib/io/data-inputx.js +13 -3
  49. package/lib/io/data-outputx.js +268 -206
  50. package/lib/kube/kube-client.js +144 -0
  51. package/lib/lang/text-types.js +58 -0
  52. package/lib/logger.js +6 -6
  53. package/lib/logsink/line-log-util.js +87 -0
  54. package/lib/logsink/line-log.js +12 -0
  55. package/lib/logsink/log-sender.js +78 -0
  56. package/lib/logsink/log-tracer.js +40 -0
  57. package/lib/logsink/sender-util.js +56 -0
  58. package/lib/logsink/zip/zip-send.js +177 -0
  59. package/lib/net/netflag.js +55 -0
  60. package/lib/net/receiver.js +66 -0
  61. package/lib/net/security-master.js +139 -20
  62. package/lib/net/sender.js +141 -0
  63. package/lib/net/tcp-return.js +18 -0
  64. package/lib/net/tcp-session.js +286 -0
  65. package/lib/net/tcpreq-client-proxy.js +70 -0
  66. package/lib/net/tcprequest-mgr.js +58 -0
  67. package/lib/observers/apollo-server-observer.js +33 -27
  68. package/lib/observers/cluster-observer.js +22 -0
  69. package/lib/observers/express-observer.js +215 -0
  70. package/lib/observers/file-observer.js +184 -0
  71. package/lib/observers/global-observer.js +155 -80
  72. package/lib/observers/grpc-observer.js +336 -0
  73. package/lib/observers/http-observer.js +666 -236
  74. package/lib/observers/maria-observer.js +204 -362
  75. package/lib/observers/memcached-observer.js +56 -0
  76. package/lib/observers/mongo-observer.js +317 -0
  77. package/lib/observers/mongodb-observer.js +169 -226
  78. package/lib/observers/mongoose-observer.js +518 -323
  79. package/lib/observers/mssql-observer.js +177 -418
  80. package/lib/observers/mysql-observer.js +342 -449
  81. package/lib/observers/mysql2-observer.js +396 -358
  82. package/lib/observers/net-observer.js +77 -0
  83. package/lib/observers/oracle-observer.js +559 -384
  84. package/lib/observers/pgsql-observer.js +231 -489
  85. package/lib/observers/prisma-observer.js +303 -92
  86. package/lib/observers/process-observer.js +79 -35
  87. package/lib/observers/promise-observer.js +31 -0
  88. package/lib/observers/redis-observer.js +166 -331
  89. package/lib/observers/schedule-observer.js +67 -0
  90. package/lib/observers/socket.io-observer.js +226 -187
  91. package/lib/observers/stream-observer.js +19 -0
  92. package/lib/observers/thrift-observer.js +197 -0
  93. package/lib/observers/websocket-observer.js +175 -301
  94. package/lib/pack/activestack-pack.js +55 -0
  95. package/lib/pack/apenum.js +8 -0
  96. package/lib/pack/counter-pack.js +3 -0
  97. package/lib/pack/errorsnap-pack.js +69 -0
  98. package/lib/pack/event-pack.js +54 -0
  99. package/lib/pack/hitmap-pack.js +63 -0
  100. package/lib/pack/hitmap-pack1.js +152 -0
  101. package/lib/pack/log-sink-pack.js +14 -52
  102. package/lib/pack/netstat.js +15 -0
  103. package/lib/pack/otype.js +7 -0
  104. package/lib/pack/profile-pack.js +49 -0
  105. package/lib/pack/realtimeuser-pack.js +41 -0
  106. package/lib/pack/stat-general-pack.js +96 -0
  107. package/lib/pack/staterror-pack.js +120 -0
  108. package/lib/pack/stathttpc-pack.js +66 -0
  109. package/lib/pack/stathttpc-rec.js +78 -0
  110. package/lib/pack/statremote-pack.js +46 -0
  111. package/lib/pack/statservice-pack.js +63 -0
  112. package/lib/pack/statservice-pack1.js +88 -0
  113. package/lib/pack/statservice-rec.js +292 -0
  114. package/lib/pack/statservice-rec_dep.js +151 -0
  115. package/lib/pack/statsql-pack.js +69 -0
  116. package/lib/pack/statsql-rec.js +100 -0
  117. package/lib/pack/statuseragent-pack.js +44 -0
  118. package/lib/pack/tagcount-pack.js +4 -4
  119. package/lib/pack/tagctr.js +15 -0
  120. package/lib/pack/text-pack.js +50 -0
  121. package/lib/pack/time-count.js +25 -0
  122. package/lib/pack/websocket.js +15 -0
  123. package/lib/pack/zip-pack.js +70 -0
  124. package/lib/pii/pii-item.js +31 -0
  125. package/lib/pii/pii-mask.js +174 -0
  126. package/lib/plugin/plugin-loadermanager.js +57 -0
  127. package/lib/plugin/plugin.js +75 -0
  128. package/lib/service/tx-record.js +332 -0
  129. package/lib/stat/stat-error.js +116 -0
  130. package/lib/stat/stat-httpc.js +98 -0
  131. package/lib/stat/stat-remote-ip.js +46 -0
  132. package/lib/stat/stat-remote-ipurl.js +88 -0
  133. package/lib/stat/stat-sql.js +113 -0
  134. package/lib/stat/stat-tranx.js +58 -0
  135. package/lib/stat/stat-tx-caller.js +160 -0
  136. package/lib/stat/stat-tx-domain.js +111 -0
  137. package/lib/stat/stat-tx-referer.js +112 -0
  138. package/lib/stat/stat-useragent.js +48 -0
  139. package/lib/stat/timingsender.js +76 -0
  140. package/lib/step/activestack-step.js +38 -0
  141. package/lib/step/dbc-step.js +36 -0
  142. package/lib/step/http-stepx.js +67 -0
  143. package/lib/step/message-step.js +40 -0
  144. package/lib/step/method-stepx.js +45 -0
  145. package/lib/step/resultset-step.js +40 -0
  146. package/lib/step/securemsg-step.js +44 -0
  147. package/lib/step/socket-step.js +46 -0
  148. package/lib/step/sql-stepx.js +68 -0
  149. package/lib/step/sqlxtype.js +16 -0
  150. package/lib/step/step.js +66 -0
  151. package/lib/step/stepenum.js +54 -0
  152. package/lib/topology/link.js +63 -0
  153. package/lib/topology/nodeinfo.js +123 -0
  154. package/lib/topology/status-detector.js +111 -0
  155. package/lib/trace/trace-context-manager.js +113 -25
  156. package/lib/trace/trace-context.js +21 -7
  157. package/lib/trace/trace-httpc.js +17 -11
  158. package/lib/trace/trace-sql.js +29 -21
  159. package/lib/util/anylist.js +103 -0
  160. package/lib/util/cardinality/hyperloglog.js +106 -0
  161. package/lib/util/cardinality/murmurhash.js +31 -0
  162. package/lib/util/cardinality/registerset.js +75 -0
  163. package/lib/util/errordata.js +21 -0
  164. package/lib/util/escape-literal-sql.js +5 -5
  165. package/lib/util/hashutil.js +18 -18
  166. package/lib/util/iputil_x.js +527 -0
  167. package/lib/util/keygen.js +0 -3
  168. package/lib/util/kube-util.js +73 -0
  169. package/lib/util/linkedset.js +1 -2
  170. package/lib/util/nodeutil.js +2 -1
  171. package/lib/util/paramsecurity.js +80 -0
  172. package/lib/util/pre-process.js +13 -0
  173. package/lib/util/process-seq.js +166 -0
  174. package/lib/util/property-util.js +36 -0
  175. package/lib/util/request-queue.js +70 -0
  176. package/lib/util/requestdouble-queue.js +72 -0
  177. package/lib/util/resourceprofile.js +157 -0
  178. package/lib/util/stop-watch.js +30 -0
  179. package/lib/util/system-util.js +10 -0
  180. package/lib/util/userid-util.js +57 -0
  181. package/lib/value/map-value.js +3 -2
  182. package/package.json +9 -5
  183. package/whatap.conf +1 -4
  184. package/agent/darwin/arm64/whatap_nodejs +0 -0
  185. package/agent/linux/amd64/whatap_nodejs +0 -0
  186. package/agent/linux/arm64/whatap_nodejs +0 -0
  187. package/build.txt +0 -4
  188. package/lib/observers/ioredis-observer.js +0 -294
  189. package/lib/udp/async_sender.js +0 -119
  190. package/lib/udp/index.js +0 -17
  191. package/lib/udp/packet_enum.js +0 -52
  192. package/lib/udp/packet_queue.js +0 -69
  193. package/lib/udp/packet_type_enum.js +0 -33
  194. package/lib/udp/param_def.js +0 -72
  195. package/lib/udp/udp_session.js +0 -336
  196. package/lib/util/sql-util.js +0 -178
  197. package/lib/util/trace-helper.js +0 -91
  198. package/lib/util/transfer.js +0 -58
@@ -5,277 +5,258 @@
5
5
  */
6
6
 
7
7
  var TraceContextManager = require('../trace/trace-context-manager'),
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');
8
+ ParsedSql = require('../trace/parsed-sql'),
9
+ SqlStepX = require('../step/sql-stepx'),
10
+ DBCStep = require('../step/dbc-step'),
11
+ ResultSetStep = require('../step/resultset-step'),
12
+ DataTextAgent = require('../data/datatext-agent'),
13
+ StatSql = require('../stat/stat-sql'),
14
+ MeterSql = require('../counter/meter/meter-sql'),
15
+ conf = require('../conf/configure'),
16
+ IntKeyMap = require('../util/intkey-map'),
17
+ EscapeLiteralSQL = require('../util/escape-literal-sql'),
18
+ HashUtil = require('../util/hashutil'),
19
+ StatError = require('../stat/stat-error'),
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');
20
27
 
21
28
  var MariaObserver = function (agent) {
22
29
  this.agent = agent;
23
30
  this.packages = ['mariadb'];
24
31
  };
25
32
 
26
- var dbc_hash = 0;
27
- var dbc = 'mariadb://';
33
+ var dbc, dbc_hash;
34
+ MariaObserver.prototype.inject = function (mod, moduleName) {
35
+ if (mod.__whatap_observe__) { return; }
36
+ mod.__whatap_observe__ = true;
28
37
 
29
- // 후킹된 객체 추적
30
- var hookedInstances = new WeakSet();
38
+ Logger.initPrint("MariaObserver");
31
39
 
32
- function handleSqlError(ctx, err, sqlHash) {
33
- if (!err) return;
40
+ if (!conf.sql_enabled) return;
34
41
 
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
- }
42
+ // shimmer.wrap(mod, 'createConnection', wrapCreateConnection(mod));
43
+ shimmer.wrap(mod, 'createConnection', wrapConnection(mod));
44
+ shimmer.wrap(mod, 'createPool', wrapCreatePool(mod));
45
+ };
49
46
 
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
- }
47
+ var _finishQuery = function (ctx, sql_step) {
48
+ sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
49
+ TraceSQL.isSlowSQL(ctx);
61
50
 
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;
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
+ };
68
54
 
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
- }
55
+ var _handleError = function (ctx, sql_step, err) {
56
+ sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
57
+ TraceSQL.isSlowSQL(ctx);
82
58
 
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
- }
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
+ };
62
+
63
+ function wrapCreateConnection(agent) {
64
+ return function (original) {
65
+ return async function (...args) {
66
+ const ctx = TraceContextManager.getCurrentContext();
67
+ if (!ctx || ctx.db_opening) return original.apply(this, args);
68
+
69
+ ctx.db_opening = true;
70
+ ctx.footprint('Maria Connecting Start');
71
+
72
+ // const dbc_step = new DBCStep();
73
+ // dbc_step.start_time = ctx.getElapsedTime();
74
+
75
+ const connection = await original.apply(this, args);
76
+ wrapConnectionMethods(connection, agent);
77
+
78
+ ctx.footprint('Maria Connecting Done');
79
+ ctx.db_opening = false;
80
+
81
+ getDBCHash(args);
82
+ // dbc_step.hash = dbc_hash;
83
+ // ctx.profile.push(dbc_step);
84
+
85
+ return connection;
86
+ };
87
+ };
94
88
  }
95
89
 
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);
90
+ function wrapConnection(agent) {
91
+ return function (original) {
92
+ return function (...args) {
93
+ const connectionPromise = original.apply(this, args);
94
+ getDBCHash(args);
100
95
 
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;
96
+ return connectionPromise.then(connection => {
97
+ shimmer.wrap(connection, 'query', createQueryHook(agent));
98
+ return connection;
99
+ });
109
100
  }
110
101
  }
111
102
  }
112
103
 
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();
104
+ function wrapCreatePool(agent) {
105
+ return function (original) {
106
+ return function (...args) {
107
+ const pool = original.apply(this, args);
108
+ getDBCHash(args);
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
+ });
119
117
 
120
- if (ctx == null || args[0] == null) {
121
- return original.apply(this, arguments);
122
- }
118
+ return pool;
119
+ };
120
+ };
121
+ }
123
122
 
124
- if (args[0].sql == null && typeof args[0] != 'string') {
125
- return original.apply(this, arguments);
126
- }
123
+ function wrapConnectionMethods(connection, agent) {
124
+ shimmer.wrap(connection, 'query', createQueryHook(agent));
125
+ shimmer.wrap(connection, 'execute', createQueryHook(agent));
126
+ }
127
127
 
128
- // AsyncResource 생성
129
- const asyncResource = new AsyncResource('mariadb-query');
128
+ function createQueryHook(agent) {
129
+ return function (original) {
130
+ return function (...args) {
131
+ const ctx = TraceContextManager.getCurrentContext();
132
+ if (!ctx || !args[0]) return original.apply(this, args);
130
133
 
131
- return asyncResource.runInAsyncScope(() => {
132
- // HTTP Observer 패턴을 따라 시작 시간 설정
133
- ctx.start_time = Date.now();
134
+ ctx.db_opening = true;
135
+ ctx.footprint('Maria Connecting Start');
134
136
 
135
- // DB 연결 패킷 전송 (elapsed = 0으로 설정)
136
- ctx.elapsed = 0;
137
- AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbcUrl]);
137
+ const dbc_step = new DBCStep();
138
+ ctx.footprint('Maria Connecting Done');
139
+ ctx.db_opening = false;
138
140
 
139
- // SQL 시작 시간 기록
140
- var sql_start_time = Date.now();
141
- ctx.footprint('MariaDB Query Start');
142
- ctx.sql_count++;
141
+ dbc_step.hash = dbc_hash;
142
+ ctx.profile.push(dbc_step);
143
143
 
144
- var sql = args.length > 0 ? args[0] : undefined;
145
- var params = args.length > 1 && Array.isArray(args[1]) ? args[1] : undefined;
144
+ const sql_step = new SqlStepX();
145
+ sql_step.start_time = ctx.getElapsedTime();
146
+ ctx.profile.push(sql_step);
146
147
 
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
- }
148
+ ctx.footprint('Maria Query Start');
149
+ ctx.sql_count++;
153
150
 
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
- }
183
-
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);
195
- }
151
+ var sql = args.length > 0 ? args[0] : undefined,
152
+ psql = null;
196
153
 
197
- var sqlHash = psql ? psql.sql : 0;
198
- ctx.active_sqlhash = true;
154
+ if(typeof sql !== 'string') {
155
+ sql = args[0].sql || undefined;
156
+ }
199
157
 
200
- const result = original.apply(this, args);
158
+ if (typeof sql === 'string' && sql.length > 0) {
159
+ try {
160
+ psql = escapeLiteral(sql);
161
+ } catch (e) {
162
+ Logger.printError('WHATAP-191', 'MariaObserver escapeliteral error', e);
163
+ }
164
+ } else {
165
+ sql = '';
166
+ psql = escapeLiteral(sql);
167
+ }
201
168
 
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
- }
169
+ if(psql != null) {
170
+ sql_step.hash = psql.sql;
171
+ // sql_step.crud = psql.type.charCodeAt(0);
172
+ }
209
173
 
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
- }
222
- }
174
+ var els = new EscapeLiteralSQL(sql);
175
+ els.process();
223
176
 
224
- // TraceSQL 처리
225
- try {
226
- TraceSQL.isSlowSQL(currentCtx);
177
+ ctx.active_sqlhash = sql_step.hash;
227
178
 
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);
179
+ if(conf.profile_sql_param_enabled) {
180
+ var params = args.length > 1 && Array.isArray(args[1]) ? args[1] : undefined;
181
+ sql_step.setTrue(1);
182
+ var crc = {value : 0};
183
+ sql_step.p1 = toParamBytes(psql.param, crc);
184
+ if(params != undefined) {
185
+ const result = params.map((param) => {
186
+ if(typeof param === 'string'){
187
+ return `'${param}'`
234
188
  }
189
+ return param
190
+ }).toString()
191
+ sql_step.p2 = toParamBytes(result, crc);
192
+ }
193
+ sql_step.pcrc = crc.value;
194
+ }
235
195
 
236
- currentCtx.elapsed = sql_elapsed;
237
- currentCtx.active_sqlhash = false;
238
- AsyncSender.send_packet(PacketTypeEnum.TX_SQL, currentCtx, [dbcUrl, finalSql, String(resultCount)]);
239
-
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
- }
196
+ const result = original.apply(this, args);
247
197
 
248
- var sql_elapsed = Date.now() - sql_start_time;
198
+ return result.then(res => {
199
+ if (Array.isArray(res) && psql && psql.type === "S") {
200
+ var result_step = new ResultSetStep();
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);
249
207
 
250
- // 에러 처리
251
- handleSqlError(currentCtx, err, sqlHash);
208
+ ctx.rs_count = ctx.rs_count ? ctx.rs_count + res.length : res.length;
252
209
 
253
- currentCtx.elapsed = sql_elapsed;
254
- currentCtx.active_sqlhash = false;
255
- AsyncSender.send_packet(PacketTypeEnum.TX_SQL, currentCtx, [dbcUrl, finalSql, '0']);
210
+ MeterSql.addFetch(result_step.dbc, result_step.fetch, 0);
211
+ StatSql.addFetch(result_step.dbc, result_step.sqlhash, result_step.fetch, 0);
256
212
 
257
- currentCtx.footprint('MariaDB Query Error');
258
- throw err;
259
- });
213
+ TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
260
214
  }
261
-
262
- return result;
215
+ var isSelectQuery = psql && psql.type === "S"? true : false;
216
+ _finishQuery(ctx, sql_step, isSelectQuery, res);
217
+ return res;
218
+ }).catch(err => {
219
+ _handleError(ctx, sql_step, err)
220
+ if (conf.trace_sql_error_stack && conf.trace_sql_error_depth) {
221
+ var traceDepth = conf.trace_sql_error_depth;
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);
229
+ }
230
+ throw err;
263
231
  });
264
232
  };
265
233
  };
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
+ }
266
245
  };
267
246
 
268
- // 유틸리티 함수들
247
+ function getDBCHash(args) {
248
+ dbc = `mariadb://${(args[0] || {}).user || ''}@${(args[0] || {}).host || ''}/${(args[0] || {}).database || ''}`;
249
+ dbc_hash = HashUtil.hashFromString(dbc);
250
+ }
251
+
269
252
  var checkedSql = new IntKeyMap(2000).setMax(2000);
270
253
  var nonLiteSql = new IntKeyMap(5000).setMax(5000);
271
254
  var date = DateUtil.yyyymmdd();
272
255
 
273
256
  function escapeLiteral(sql) {
274
- if (sql == null) {
275
- sql = '';
276
- }
257
+ if(sql == null) { sql = ''; }
277
258
 
278
- if (date !== DateUtil.yyyymmdd()) {
259
+ if(date !== DateUtil.yyyymmdd()) {
279
260
  checkedSql.clear();
280
261
  nonLiteSql.clear();
281
262
  date = DateUtil.yyyymmdd();
@@ -285,12 +266,12 @@ function escapeLiteral(sql) {
285
266
  var sqlHash = HashUtil.hashFromString(sql);
286
267
  var psql = nonLiteSql.get(sqlHash);
287
268
 
288
- if (psql != null) {
269
+ if(psql != null) {
289
270
  return psql;
290
271
  }
291
272
  psql = checkedSql.get(sqlHash);
292
273
 
293
- if (psql != null) {
274
+ if(psql != null) {
294
275
  return psql;
295
276
  }
296
277
 
@@ -298,7 +279,9 @@ function escapeLiteral(sql) {
298
279
  els.process();
299
280
 
300
281
  var hash = HashUtil.hashFromString(els.getParsedSql());
301
- if (hash === sqlHash) {
282
+ DataTextAgent.SQL.add(hash, els.getParsedSql());
283
+
284
+ if(hash === sqlHash) {
302
285
  psql = new ParsedSql(els.sqlType, hash, null);
303
286
  nonLiteSql.put(sqlHash, psql);
304
287
  } else {
@@ -308,145 +291,4 @@ function escapeLiteral(sql) {
308
291
  return psql;
309
292
  }
310
293
 
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
-
452
294
  exports.MariaObserver = MariaObserver;