whatap 0.5.26 → 1.0.0-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.
Files changed (198) hide show
  1. package/README.md +78 -32
  2. package/agent/darwin/arm64/whatap_nodejs +0 -0
  3. package/agent/linux/amd64/whatap_nodejs +0 -0
  4. package/agent/linux/arm64/whatap_nodejs +0 -0
  5. package/build.txt +4 -0
  6. package/lib/conf/config-default.js +3 -10
  7. package/lib/conf/configure.js +349 -369
  8. package/lib/conf/license.js +1 -1
  9. package/lib/control/packagectr-helper.js +3 -34
  10. package/lib/core/agent.js +882 -176
  11. package/lib/core/interceptor.js +6 -6
  12. package/lib/core/shimmer.js +36 -82
  13. package/lib/counter/counter-manager.js +8 -79
  14. package/lib/counter/task/activetransaction.js +17 -68
  15. package/lib/io/data-inputx.js +3 -13
  16. package/lib/io/data-outputx.js +206 -268
  17. package/lib/logger.js +6 -6
  18. package/lib/net/security-master.js +20 -139
  19. package/lib/observers/apollo-server-observer.js +27 -33
  20. package/lib/observers/global-observer.js +80 -155
  21. package/lib/observers/http-observer.js +236 -666
  22. package/lib/observers/ioredis-observer.js +294 -0
  23. package/lib/observers/maria-observer.js +362 -204
  24. package/lib/observers/mongodb-observer.js +226 -169
  25. package/lib/observers/mongoose-observer.js +323 -518
  26. package/lib/observers/mssql-observer.js +418 -177
  27. package/lib/observers/mysql-observer.js +449 -342
  28. package/lib/observers/mysql2-observer.js +358 -396
  29. package/lib/observers/oracle-observer.js +384 -559
  30. package/lib/observers/pgsql-observer.js +489 -231
  31. package/lib/observers/prisma-observer.js +92 -303
  32. package/lib/observers/process-observer.js +35 -79
  33. package/lib/observers/redis-observer.js +331 -166
  34. package/lib/observers/socket.io-observer.js +187 -226
  35. package/lib/observers/websocket-observer.js +301 -175
  36. package/lib/pack/counter-pack.js +0 -3
  37. package/lib/pack/log-sink-pack.js +52 -14
  38. package/lib/pack/tagcount-pack.js +4 -4
  39. package/lib/{counter/task → system}/gc-action.js +74 -27
  40. package/lib/trace/trace-context-manager.js +25 -113
  41. package/lib/trace/trace-context.js +7 -21
  42. package/lib/trace/trace-httpc.js +11 -17
  43. package/lib/trace/trace-sql.js +21 -29
  44. package/lib/udp/async_sender.js +119 -0
  45. package/lib/udp/index.js +17 -0
  46. package/lib/udp/packet_enum.js +52 -0
  47. package/lib/udp/packet_queue.js +69 -0
  48. package/lib/udp/packet_type_enum.js +33 -0
  49. package/lib/udp/param_def.js +72 -0
  50. package/lib/udp/udp_session.js +336 -0
  51. package/lib/util/escape-literal-sql.js +5 -5
  52. package/lib/util/hashutil.js +18 -18
  53. package/lib/util/keygen.js +3 -0
  54. package/lib/util/linkedset.js +2 -1
  55. package/lib/util/nodeutil.js +1 -2
  56. package/lib/util/sql-util.js +178 -0
  57. package/lib/util/trace-helper.js +91 -0
  58. package/lib/util/transfer.js +58 -0
  59. package/lib/value/map-value.js +2 -3
  60. package/package.json +5 -10
  61. package/whatap.conf +4 -1
  62. package/lib/conf/conf-sys-mon.js +0 -101
  63. package/lib/control/cmd-config.js +0 -24
  64. package/lib/control/control-handler.js +0 -367
  65. package/lib/core/request-agent.js +0 -27
  66. package/lib/counter/meter/meter-activex.js +0 -67
  67. package/lib/counter/meter/meter-httpc.js +0 -57
  68. package/lib/counter/meter/meter-resource.js +0 -9
  69. package/lib/counter/meter/meter-service.js +0 -168
  70. package/lib/counter/meter/meter-socket.io.js +0 -51
  71. package/lib/counter/meter/meter-sql.js +0 -71
  72. package/lib/counter/meter/meter-users.js +0 -58
  73. package/lib/counter/meter.js +0 -183
  74. package/lib/counter/task/agentinfo.js +0 -107
  75. package/lib/counter/task/gcstat.js +0 -34
  76. package/lib/counter/task/heapmem.js +0 -25
  77. package/lib/counter/task/httpc.js +0 -76
  78. package/lib/counter/task/metering-info.js +0 -125
  79. package/lib/counter/task/proc-cpu.js +0 -29
  80. package/lib/counter/task/realtimeuser.js +0 -31
  81. package/lib/counter/task/res/systemECSTask.js +0 -39
  82. package/lib/counter/task/res/systemKubeTask.js +0 -53
  83. package/lib/counter/task/res/util/awsEcsClientThread.js +0 -218
  84. package/lib/counter/task/res/util/linuxProcStatUtil.js +0 -14
  85. package/lib/counter/task/res-sys-cpu.js +0 -62
  86. package/lib/counter/task/service.js +0 -202
  87. package/lib/counter/task/socketio.js +0 -30
  88. package/lib/counter/task/sql.js +0 -105
  89. package/lib/counter/task/systemperf.js +0 -43
  90. package/lib/data/datapack-sender.js +0 -289
  91. package/lib/data/dataprofile-agent.js +0 -162
  92. package/lib/data/datatext-agent.js +0 -135
  93. package/lib/data/event-level.js +0 -15
  94. package/lib/data/test.js +0 -49
  95. package/lib/data/zipprofile.js +0 -197
  96. package/lib/env/constants.js +0 -21
  97. package/lib/error/error-handler.js +0 -437
  98. package/lib/kube/kube-client.js +0 -144
  99. package/lib/lang/text-types.js +0 -58
  100. package/lib/logsink/line-log-util.js +0 -87
  101. package/lib/logsink/line-log.js +0 -12
  102. package/lib/logsink/log-sender.js +0 -78
  103. package/lib/logsink/log-tracer.js +0 -40
  104. package/lib/logsink/sender-util.js +0 -56
  105. package/lib/logsink/zip/zip-send.js +0 -177
  106. package/lib/net/netflag.js +0 -55
  107. package/lib/net/receiver.js +0 -66
  108. package/lib/net/sender.js +0 -141
  109. package/lib/net/tcp-return.js +0 -18
  110. package/lib/net/tcp-session.js +0 -286
  111. package/lib/net/tcpreq-client-proxy.js +0 -70
  112. package/lib/net/tcprequest-mgr.js +0 -58
  113. package/lib/observers/cluster-observer.js +0 -22
  114. package/lib/observers/express-observer.js +0 -215
  115. package/lib/observers/file-observer.js +0 -184
  116. package/lib/observers/grpc-observer.js +0 -336
  117. package/lib/observers/memcached-observer.js +0 -56
  118. package/lib/observers/mongo-observer.js +0 -317
  119. package/lib/observers/net-observer.js +0 -77
  120. package/lib/observers/promise-observer.js +0 -31
  121. package/lib/observers/schedule-observer.js +0 -67
  122. package/lib/observers/stream-observer.js +0 -19
  123. package/lib/observers/thrift-observer.js +0 -197
  124. package/lib/pack/activestack-pack.js +0 -55
  125. package/lib/pack/apenum.js +0 -8
  126. package/lib/pack/errorsnap-pack.js +0 -69
  127. package/lib/pack/event-pack.js +0 -54
  128. package/lib/pack/hitmap-pack.js +0 -63
  129. package/lib/pack/hitmap-pack1.js +0 -152
  130. package/lib/pack/netstat.js +0 -15
  131. package/lib/pack/otype.js +0 -7
  132. package/lib/pack/profile-pack.js +0 -49
  133. package/lib/pack/realtimeuser-pack.js +0 -41
  134. package/lib/pack/stat-general-pack.js +0 -96
  135. package/lib/pack/staterror-pack.js +0 -120
  136. package/lib/pack/stathttpc-pack.js +0 -66
  137. package/lib/pack/stathttpc-rec.js +0 -78
  138. package/lib/pack/statremote-pack.js +0 -46
  139. package/lib/pack/statservice-pack.js +0 -63
  140. package/lib/pack/statservice-pack1.js +0 -88
  141. package/lib/pack/statservice-rec.js +0 -292
  142. package/lib/pack/statservice-rec_dep.js +0 -151
  143. package/lib/pack/statsql-pack.js +0 -69
  144. package/lib/pack/statsql-rec.js +0 -100
  145. package/lib/pack/statuseragent-pack.js +0 -44
  146. package/lib/pack/tagctr.js +0 -15
  147. package/lib/pack/text-pack.js +0 -50
  148. package/lib/pack/time-count.js +0 -25
  149. package/lib/pack/websocket.js +0 -15
  150. package/lib/pack/zip-pack.js +0 -70
  151. package/lib/pii/pii-item.js +0 -31
  152. package/lib/pii/pii-mask.js +0 -174
  153. package/lib/plugin/plugin-loadermanager.js +0 -57
  154. package/lib/plugin/plugin.js +0 -75
  155. package/lib/service/tx-record.js +0 -332
  156. package/lib/stat/stat-error.js +0 -116
  157. package/lib/stat/stat-httpc.js +0 -98
  158. package/lib/stat/stat-remote-ip.js +0 -46
  159. package/lib/stat/stat-remote-ipurl.js +0 -88
  160. package/lib/stat/stat-sql.js +0 -113
  161. package/lib/stat/stat-tranx.js +0 -58
  162. package/lib/stat/stat-tx-caller.js +0 -160
  163. package/lib/stat/stat-tx-domain.js +0 -111
  164. package/lib/stat/stat-tx-referer.js +0 -112
  165. package/lib/stat/stat-useragent.js +0 -48
  166. package/lib/stat/timingsender.js +0 -76
  167. package/lib/step/activestack-step.js +0 -38
  168. package/lib/step/dbc-step.js +0 -36
  169. package/lib/step/http-stepx.js +0 -67
  170. package/lib/step/message-step.js +0 -40
  171. package/lib/step/method-stepx.js +0 -45
  172. package/lib/step/resultset-step.js +0 -40
  173. package/lib/step/securemsg-step.js +0 -44
  174. package/lib/step/socket-step.js +0 -46
  175. package/lib/step/sql-stepx.js +0 -68
  176. package/lib/step/sqlxtype.js +0 -16
  177. package/lib/step/step.js +0 -66
  178. package/lib/step/stepenum.js +0 -54
  179. package/lib/topology/link.js +0 -63
  180. package/lib/topology/nodeinfo.js +0 -123
  181. package/lib/topology/status-detector.js +0 -111
  182. package/lib/util/anylist.js +0 -103
  183. package/lib/util/cardinality/hyperloglog.js +0 -106
  184. package/lib/util/cardinality/murmurhash.js +0 -31
  185. package/lib/util/cardinality/registerset.js +0 -75
  186. package/lib/util/errordata.js +0 -21
  187. package/lib/util/iputil_x.js +0 -527
  188. package/lib/util/kube-util.js +0 -73
  189. package/lib/util/paramsecurity.js +0 -80
  190. package/lib/util/pre-process.js +0 -13
  191. package/lib/util/process-seq.js +0 -166
  192. package/lib/util/property-util.js +0 -36
  193. package/lib/util/request-queue.js +0 -70
  194. package/lib/util/requestdouble-queue.js +0 -72
  195. package/lib/util/resourceprofile.js +0 -157
  196. package/lib/util/stop-watch.js +0 -30
  197. package/lib/util/system-util.js +0 -10
  198. package/lib/util/userid-util.js +0 -57
@@ -5,211 +5,110 @@
5
5
  */
6
6
 
7
7
  var TraceContextManager = require('../trace/trace-context-manager'),
8
- DataTextAgent = require('../data/datatext-agent'),
9
- ParsedSql = require('../trace/parsed-sql'),
10
- SqlStepX = require('../step/sql-stepx'),
11
- DBCStep = require('../step/dbc-step'),
12
- ResultSetStep = require('../step/resultset-step'),
13
- HashUtil = require('../util/hashutil'),
14
- IntKeyMap = require('../util/intkey-map'),
15
- StatSql = require('../stat/stat-sql'),
16
- StatError = require('../stat/stat-error'),
17
- MeterSql = require('../counter/meter/meter-sql'),
18
- EscapeLiteralSQL = require('../util/escape-literal-sql'),
19
- TextTypes = require('../lang/text-types'),
20
- Long = require('long'),
21
- conf = require('../conf/configure'),
22
- Logger = require('../logger'),
23
- TraceSQL = require('../trace/trace-sql')
24
- const DateUtil = require('../util/dateutil');
25
- const MessageStep = require("../step/message-step");
26
- // const ResourceProfile = require("../util/resourceprofile");
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
+ AsyncResource = require('async_hooks').AsyncResource;
27
20
 
28
21
  var MssqlObserver = function (agent) {
29
22
  this.agent = agent;
30
- this.aop = agent.aop;
31
23
  this.packages = ['mssql'];
32
24
  };
33
- var dbc_hash=0;
34
- MssqlObserver.prototype.inject = function (mod, modName) {
35
25
 
36
- if(mod.__whatap_observe__) {return;}
37
- mod.__whatap_observe__ = true;
38
-
39
- Logger.initPrint("MssqlObserver");
40
-
41
- var self = this;
42
-
43
- var requestCommand = ['_bulk', '_query', '_execute'];
44
-
45
- requestCommand.forEach(function (command) {
46
- self.aop.both(mod.Request.prototype, command,
47
- function (obj, args) {
48
-
49
- var ctx = TraceContextManager.getCurrentContext();
50
- if(ctx == null) { return; }
51
-
52
- var sql_step = new SqlStepX();
53
- var sql = (typeof args[0] === 'string') ? args[0] : JSON.stringify(args[0]),
54
- psql = null;
55
-
56
-
57
- if(dbc_hash===0){
58
- if(obj.parent && obj.parent.config) {
59
- var config = obj.parent.config,
60
- dbc = 'mssql://';
61
- try {
62
- dbc += (config.server || '');
63
- dbc += ':';
64
- dbc += (config.port || '');
65
- dbc += '/';
66
- dbc += (config.database || '');
67
- dbc_hash = HashUtil.hashFromString(dbc);
68
- DataTextAgent.DBC.add(dbc_hash, dbc);
69
- DataTextAgent.METHOD.add(dbc_hash, dbc);
70
- DataTextAgent.ERROR.add(dbc_hash, dbc)
71
- } catch(e) {
72
- }
73
- }
74
- }
75
- var dbc_step = new DBCStep();
76
- dbc_step.hash = dbc_hash;
77
- dbc_step.start_time = ctx.getElapsedTime();
78
- ctx.profile.push(dbc_step);
26
+ var dbc_hash = 0;
27
+ var dbc = 'mssql://';
79
28
 
80
- sql_step.dbc = dbc_hash;
29
+ var hookedInstances = new WeakSet();
81
30
 
82
- try {
83
- psql = escapeLiteral(sql);
84
- } catch(e) {
85
- Logger.printError("WHATAP-192", "MssqlObserver escapeliteral error", e);
86
- }
87
-
88
- if(psql != null) {
89
- DataTextAgent.SQL.add(sql_step.hash, sql);
90
- // = psql.type.charCodeAt(0);
91
- sql_step.hash = psql.sql;
92
- }
93
- sql_step.start_time = ctx.getElapsedTime();
94
- ctx.profile.push(sql_step);
95
- self.aop.functionHook(args, -1, function (obj, args) {
96
- TraceContextManager.resume(ctx);
97
- if(args[0] != null) {
98
- ctx.error_message = args[0].message;
99
- ctx.error_class = args[0].name || args[0].constructor?.name || 'MSSQLError';
100
- if (conf.trace_sql_error_stack && conf.trace_sql_error_depth) {
101
- var traceDepth = conf.trace_sql_error_depth;
102
-
103
- var errorStack = args[0].stack.split("\n");
104
- if (errorStack.length > traceDepth) {
105
- errorStack = errorStack.slice(0, traceDepth + 1);
106
- }
107
- ctx.error_message = errorStack.join("\n");
108
- sql_step.error = ctx.error = StatError.addError('mssql-' + args[0].code, args[0].message, ctx.service_hash, TextTypes.SQL, null);
109
- }
110
- if(conf._is_trace_ignore_err_cls_contains === true && args[0].code.indexOf(conf.trace_ignore_err_cls_contains) < 0){
111
- sql_step.error = StatError.addError( 'mssql-'+args[0].code, args[0].message|| 'mssql error', ctx.service_hash, TextTypes.SQL, sql_step.hash); /*long*/
112
- if (ctx.error.isZero()) { ctx.error = sql_step.error; }
113
- } else if(conf._is_trace_ignore_err_msg_contains === true && args[0].message.indexOf(conf.trace_ignore_err_msg_contains) < 0){
114
- sql_step.error = StatError.addError( 'mssql-'+args[0].code, args[0].message|| 'mssql error', ctx.service_hash, TextTypes.SQL, sql_step.hash); /*long*/
115
- if (ctx.error.isZero()) { ctx.error = sql_step.error; }
116
- } else if(conf._is_trace_ignore_err_cls_contains === false && conf._is_trace_ignore_err_msg_contains === false) {
117
- sql_step.error = StatError.addError( 'mssql-'+args[0].code, args[0].message|| 'mssql error', ctx.service_hash, TextTypes.SQL, sql_step.hash); /*long*/
118
- if (ctx.error.isZero()) { ctx.error = sql_step.error; }
119
- }
120
- }
121
-
122
- sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
123
- TraceSQL.isSlowSQL(ctx);
124
-
125
- MeterSql.add(dbc_hash, sql_step.elapsed, args[0] != null);
126
- StatSql.addSqlTime(ctx.service_hash, sql_step.dbc,
127
- sql_step.hash, sql_step.elapsed, args[0] != null, 0);
128
-
129
- if(psql && psql.type == 'S') {
130
- var result_step = new ResultSetStep();
131
- result_step.dbc = sql_step.dbc;
132
- result_step.sqlhash = sql_step.hash;
133
- try {
134
- result_step.fetch = args[1][0].length;
135
- ctx.rs_count = ctx.rs_count ? ctx.rs_count + args[1][0].length : args[1][0].length;
136
- } catch(e) {
137
- }
138
- ctx.profile.push(result_step);
31
+ var checkedSql = new IntKeyMap(2000).setMax(2000);
32
+ var nonLiteSql = new IntKeyMap(5000).setMax(5000);
33
+ var date = DateUtil.yyyymmdd();
139
34
 
140
- MeterSql.addFetch(dbc_hash, result_step.fetch, 0);
141
- StatSql.addFetch(dbc_hash, result_step.sqlhash, result_step.fetch, 0);
35
+ function handleSqlError(ctx, err) {
36
+ if (!err) return;
142
37
 
143
- TraceSQL.isTooManyRecords(sql_step, result_step.fetch, ctx);
144
- } else if(psql && psql.type == 'U') {
38
+ try {
39
+ var errorClass = err.code || err.name || err.constructor?.name || 'MSSQLError';
40
+ var errorMessage = err.message || 'mssql error';
41
+ var errorStack = '';
145
42
 
146
- }
147
- });
148
- }, function (obj, args, ret, lctx) {
149
- });
150
- });
151
- var conn_dbc_hash=0;
152
- self.aop.both(mod, 'connect',
153
- function (obj, args, lctx) {
154
-
155
- var ctx = TraceContextManager.getCurrentContext();
156
- if(ctx == null) { return; }
157
- lctx.context = ctx;
158
-
159
- var conn = '';
160
- if(args[0]) { //좀더 로직 개선 필요...
161
- conn += args[0]['server'] || '';
162
- conn += args[0]['database'] || '';
43
+ if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && err.stack) {
44
+ var traceDepth = conf.trace_sql_error_depth;
45
+ var stackLines = err.stack.split("\n");
46
+ if (stackLines.length > traceDepth) {
47
+ stackLines = stackLines.slice(0, traceDepth + 1);
163
48
  }
164
- if(conn.length === 0) { return; }
165
- if(conn_dbc_hash==0){ //한번만 전송되게 함.
166
- conn = 'mssql://' + conn;
167
- conn_dbc_hash = HashUtil.hashFromString(conn);
168
- DataTextAgent.DBC.add(conn_dbc_hash, conn);
169
- DataTextAgent.METHOD.add(conn_dbc_hash, dbc);
170
- DataTextAgent.ERROR.add(conn_dbc_hash, dbc)
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);
171
73
  }
172
74
 
173
- var dbc_step = new DBCStep();
174
- dbc_step.hash = conn_dbc_hash;
175
- dbc_step.start_time = ctx.getElapsedTime();
176
-
177
- lctx.step = dbc_step;
178
- },
179
- function (obj, args, ret, lctx) {
180
- var pool = ret;
181
- var ctx = lctx.context,
182
- step = lctx.step;
183
-
184
- if(ctx == null || step == null) { return; }
185
- step.elapsed = ctx.getElapsedTime() - step.start_time;
186
- ctx.profile.push(step);
187
- });
188
- };
75
+ AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
76
+ }
77
+ } catch (e) {
78
+ Logger.printError('WHATAP-209', 'Error handling MSSQL error', e, false);
79
+ }
80
+ }
189
81
 
190
- var checkedSql = new IntKeyMap(2000).setMax(2000);
191
- var nonLiteSql = new IntKeyMap(5000).setMax(5000);
192
- var date = DateUtil.yyyymmdd();
82
+ function setupDbcInfo(config) {
83
+ if (dbc_hash === 0 && config) {
84
+ dbc = 'mssql://';
85
+ dbc += (config.server || '') + ':';
86
+ dbc += (config.port || '') + '/';
87
+ dbc += config.database || '';
88
+ dbc_hash = HashUtil.hashFromString(dbc);
89
+ }
90
+ }
193
91
 
194
92
  function escapeLiteral(sql) {
195
- if(sql == null) { sql = ''; }
93
+ if (sql == null) {
94
+ sql = '';
95
+ }
196
96
 
197
- if(date !== DateUtil.yyyymmdd()) {
97
+ if (date !== DateUtil.yyyymmdd()) {
198
98
  checkedSql.clear();
199
99
  nonLiteSql.clear();
200
100
  date = DateUtil.yyyymmdd();
201
- Logger.print('WHATAP-SQL-CLEAR', 'MssqlObserver CLEAR OK!!!!!!!!!!!!!!!!', false);
202
101
  }
203
102
 
204
103
  var sqlHash = HashUtil.hashFromString(sql);
205
104
  var psql = nonLiteSql.get(sqlHash);
206
105
 
207
- if(psql != null) {
106
+ if (psql != null) {
208
107
  return psql;
209
108
  }
210
109
  psql = checkedSql.get(sqlHash);
211
110
 
212
- if(psql != null) {
111
+ if (psql != null) {
213
112
  return psql;
214
113
  }
215
114
 
@@ -217,9 +116,8 @@ function escapeLiteral(sql) {
217
116
  els.process();
218
117
 
219
118
  var hash = HashUtil.hashFromString(els.getParsedSql());
220
- DataTextAgent.SQL.add(hash, els.getParsedSql());
221
119
 
222
- if(hash === sqlHash) {
120
+ if (hash === sqlHash) {
223
121
  psql = new ParsedSql(els.sqlType, hash, null);
224
122
  nonLiteSql.put(sqlHash, psql);
225
123
  } else {
@@ -229,4 +127,347 @@ function escapeLiteral(sql) {
229
127
  return psql;
230
128
  }
231
129
 
130
+ function createRequestWrapper(agent, dbcUrl, command) {
131
+ return function(original) {
132
+ return function wrappedRequest() {
133
+ var args = Array.prototype.slice.call(arguments);
134
+ var ctx = TraceContextManager.getCurrentContext();
135
+
136
+ if (ctx == null || args[0] == null) {
137
+ return original.apply(this, arguments);
138
+ }
139
+
140
+ if (dbcUrl === 'mssql://' || !dbc_hash) {
141
+ return original.apply(this, arguments);
142
+ }
143
+
144
+ const asyncResource = new AsyncResource('mssql-request');
145
+ const callbackResource = new AsyncResource('mssql-callback');
146
+
147
+ return asyncResource.runInAsyncScope(() => {
148
+ ctx.start_time = Date.now();
149
+ ctx.elapsed = 0;
150
+ AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbcUrl]);
151
+
152
+ var sql_start_time = Date.now();
153
+ ctx.footprint('MsSQL ' + command + ' Start');
154
+ ctx.sql_count++;
155
+
156
+ var sql = args.length > 0 ? args[0] : undefined;
157
+ var finalSql = '';
158
+
159
+ try {
160
+ if (typeof sql === 'string') {
161
+ finalSql = sql;
162
+ } else if (sql !== null && typeof sql === 'object') {
163
+ finalSql = JSON.stringify(sql);
164
+ }
165
+ } catch (formatError) {
166
+ Logger.printError('WHATAP-210', 'Error formatting MSSQL query', formatError, false);
167
+ finalSql = '';
168
+ }
169
+
170
+ if (typeof finalSql !== 'string' || finalSql.length === 0) {
171
+ finalSql = '';
172
+ }
173
+
174
+ var psql = null;
175
+ if (typeof finalSql === 'string' && finalSql.length > 0) {
176
+ try {
177
+ psql = escapeLiteral(finalSql);
178
+ Logger.print('WHATAP-203', 'Processing SQL: ' + finalSql.substring(0, 200), false);
179
+ } catch (e) {
180
+ Logger.printError('WHATAP-211', 'MssqlObserver escapeliteral error', e, false);
181
+ }
182
+ } else {
183
+ psql = escapeLiteral(finalSql);
184
+ }
185
+
186
+ ctx.active_sqlhash = true;
187
+ ctx.active_dbc = dbc_hash;
188
+
189
+ function requestCallback(err, results) {
190
+ var currentCtx = TraceContextManager.getCurrentContext();
191
+ if (currentCtx == null) {
192
+ return;
193
+ }
194
+
195
+ TraceContextManager.resume(currentCtx.id);
196
+
197
+ var sql_elapsed = Date.now() - sql_start_time;
198
+ var resultCount = 0;
199
+
200
+ if (err) {
201
+ handleSqlError(currentCtx, err);
202
+ }
203
+
204
+ if (!err && results) {
205
+ if (Array.isArray(results) && results.length > 0) {
206
+ if (results[0] && Array.isArray(results[0])) {
207
+ resultCount = results[0].length;
208
+ } else if (results[0] && results[0].recordset && Array.isArray(results[0].recordset)) {
209
+ resultCount = results[0].recordset.length;
210
+ }
211
+ } else if (results.recordset && Array.isArray(results.recordset)) {
212
+ resultCount = results.recordset.length;
213
+ } else if (results.rowsAffected && Array.isArray(results.rowsAffected)) {
214
+ resultCount = results.rowsAffected.reduce((sum, count) => sum + count, 0);
215
+ }
216
+ }
217
+
218
+ try {
219
+ TraceSQL.isSlowSQL(currentCtx);
220
+ if (!err && psql != null && psql.type === 'S') {
221
+ TraceSQL.isTooManyRecords(resultCount, currentCtx);
222
+ }
223
+ } catch (e) {
224
+ Logger.printError('WHATAP-212', 'Error in TraceSQL processing', e, false);
225
+ }
226
+
227
+ currentCtx.elapsed = sql_elapsed;
228
+ currentCtx.active_sqlhash = false;
229
+ AsyncSender.send_packet(PacketTypeEnum.TX_SQL, currentCtx, [dbcUrl, finalSql, String(resultCount)]);
230
+
231
+ currentCtx.footprint('MsSQL ' + command + ' Done');
232
+ }
233
+
234
+ var callbackWrapped = false;
235
+ var hasCallback = false;
236
+
237
+ // 콜백 찾기 및 래핑
238
+ for (var i = args.length - 1; i >= 0; i--) {
239
+ if (typeof args[i] === 'function') {
240
+ hasCallback = true;
241
+ var originalCallback = args[i];
242
+ args[i] = callbackResource.bind(function() {
243
+ var callbackArgs = Array.prototype.slice.call(arguments);
244
+ try {
245
+ requestCallback(callbackArgs[0], callbackArgs[1]);
246
+ } catch (e) {
247
+ Logger.printError('WHATAP-213', 'Error in callback hook', e, false);
248
+ }
249
+ if (originalCallback && typeof originalCallback === 'function') {
250
+ return originalCallback.apply(this, callbackArgs);
251
+ }
252
+ });
253
+ callbackWrapped = true;
254
+ break;
255
+ }
256
+ }
257
+
258
+ try {
259
+ const result = original.apply(this, args);
260
+
261
+ // Promise 기반 처리
262
+ if (!hasCallback && result && typeof result.then === 'function') {
263
+ return result.then(function(res) {
264
+ requestCallback(null, res);
265
+ return res;
266
+ }).catch(function(err) {
267
+ requestCallback(err, null);
268
+ throw err;
269
+ });
270
+ }
271
+
272
+ return result;
273
+ } catch (requestError) {
274
+ requestCallback(requestError, null);
275
+ throw requestError;
276
+ }
277
+ });
278
+ };
279
+ };
280
+ }
281
+
282
+ MssqlObserver.prototype.inject = function (mod, moduleName) {
283
+ if (mod.__whatap_observe__) {
284
+ return;
285
+ }
286
+ mod.__whatap_observe__ = true;
287
+ Logger.initPrint("MssqlObserver");
288
+
289
+ if (conf.sql_enabled === false) {
290
+ return;
291
+ }
292
+
293
+ var self = this;
294
+
295
+ // Request 클래스의 메서드들 후킹
296
+ if (mod.Request && mod.Request.prototype) {
297
+ var requestCommands = ['_bulk', '_query', '_execute'];
298
+
299
+ requestCommands.forEach(function(command) {
300
+ if (mod.Request.prototype[command] && !mod.Request.prototype[command].__whatap_wrapped__) {
301
+ shimmer.wrap(mod.Request.prototype, command, function(original) {
302
+ return function wrappedRequestCommand() {
303
+ var args = Array.prototype.slice.call(arguments);
304
+ var ctx = TraceContextManager.getCurrentContext();
305
+
306
+ if (ctx == null) {
307
+ return original.apply(this, arguments);
308
+ }
309
+
310
+ // DBC 정보 설정
311
+ if (dbc_hash === 0 && this.parent && this.parent.config) {
312
+ setupDbcInfo(this.parent.config);
313
+ }
314
+
315
+ return createRequestWrapper(self.agent, dbc, command)(original).apply(this, args);
316
+ };
317
+ });
318
+ mod.Request.prototype[command].__whatap_wrapped__ = true;
319
+ }
320
+ });
321
+ }
322
+
323
+ // connect 함수 후킹
324
+ if (mod.connect && !mod.connect.__whatap_wrapped__) {
325
+ shimmer.wrap(mod, 'connect', function(original) {
326
+ return function wrappedConnect() {
327
+ var args = Array.prototype.slice.call(arguments);
328
+ var ctx = TraceContextManager.getCurrentContext();
329
+
330
+ if (ctx == null) {
331
+ return original.apply(this, arguments);
332
+ }
333
+
334
+ // 연결 정보 설정
335
+ if (args[0]) {
336
+ setupDbcInfo(args[0]);
337
+ }
338
+
339
+ const connectionResource = new AsyncResource('mssql-connect');
340
+
341
+ return connectionResource.runInAsyncScope(() => {
342
+ ctx.start_time = Date.now();
343
+ ctx.db_opening = true;
344
+ ctx.footprint('MsSQL Connecting Start');
345
+
346
+ // 콜백 래핑
347
+ for (var i = args.length - 1; i >= 0; i--) {
348
+ if (typeof args[i] === 'function') {
349
+ var originalCallback = args[i];
350
+ args[i] = connectionResource.bind(function() {
351
+ var callbackArgs = Array.prototype.slice.call(arguments);
352
+ var err = callbackArgs[0];
353
+
354
+ if (ctx) {
355
+ TraceContextManager.resume(ctx.id);
356
+ ctx.elapsed = Date.now() - ctx.start_time;
357
+
358
+ if (err) {
359
+ handleSqlError(ctx, err);
360
+ ctx.footprint('MsSQL Connecting Error');
361
+ } else {
362
+ ctx.footprint('MsSQL Connecting Done');
363
+ }
364
+ }
365
+
366
+ return originalCallback.apply(this, callbackArgs);
367
+ });
368
+ break;
369
+ }
370
+ }
371
+
372
+ var result = original.apply(this, args);
373
+
374
+ // Promise 기반 처리
375
+ if (result && typeof result.then === 'function') {
376
+ return result.then(connectionResource.bind(function(pool) {
377
+ if (ctx) {
378
+ TraceContextManager.resume(ctx.id);
379
+ ctx.elapsed = Date.now() - ctx.start_time;
380
+ ctx.db_opening = false;
381
+ ctx.footprint('MsSQL Connecting Done');
382
+ }
383
+ return pool;
384
+ })).catch(connectionResource.bind(function(err) {
385
+ if (ctx) {
386
+ TraceContextManager.resume(ctx.id);
387
+ ctx.elapsed = Date.now() - ctx.start_time;
388
+ ctx.db_opening = false;
389
+ ctx.footprint('MsSQL Connecting Error');
390
+ handleSqlError(ctx, err);
391
+ }
392
+ throw err;
393
+ }));
394
+ }
395
+
396
+ return result;
397
+ });
398
+ };
399
+ });
400
+ mod.connect.__whatap_wrapped__ = true;
401
+ }
402
+
403
+ // ConnectionPool 클래스 후킹 (있는 경우)
404
+ if (mod.ConnectionPool && !mod.ConnectionPool.__whatap_wrapped__) {
405
+ shimmer.wrap(mod, 'ConnectionPool', function(original) {
406
+ return function wrappedConnectionPool() {
407
+ var args = Array.prototype.slice.call(arguments);
408
+
409
+ // 연결 정보 설정
410
+ if (args[0]) {
411
+ setupDbcInfo(args[0]);
412
+ }
413
+
414
+ var pool = new (Function.prototype.bind.apply(original, [null].concat(args)));
415
+
416
+ if (pool && !hookedInstances.has(pool)) {
417
+ hookedInstances.add(pool);
418
+
419
+ // connect 메서드 후킹
420
+ if (pool.connect && !pool.connect.__whatap_wrapped__) {
421
+ shimmer.wrap(pool, 'connect', function(original) {
422
+ return function wrappedPoolConnect() {
423
+ var args = Array.prototype.slice.call(arguments);
424
+ var ctx = TraceContextManager.getCurrentContext();
425
+
426
+ if (ctx == null) {
427
+ return original.apply(this, arguments);
428
+ }
429
+
430
+ const connectionResource = new AsyncResource('mssql-pool-connect');
431
+
432
+ return connectionResource.runInAsyncScope(() => {
433
+ ctx.start_time = Date.now();
434
+ ctx.footprint('MsSQL Pool Connecting Start');
435
+
436
+ var result = original.apply(this, args);
437
+
438
+ // Promise 기반 처리
439
+ if (result && typeof result.then === 'function') {
440
+ return result.then(connectionResource.bind(function(res) {
441
+ if (ctx) {
442
+ TraceContextManager.resume(ctx.id);
443
+ ctx.elapsed = Date.now() - ctx.start_time;
444
+ ctx.footprint('MsSQL Pool Connecting Done');
445
+ }
446
+ return res;
447
+ })).catch(connectionResource.bind(function(err) {
448
+ if (ctx) {
449
+ TraceContextManager.resume(ctx.id);
450
+ ctx.elapsed = Date.now() - ctx.start_time;
451
+ ctx.footprint('MsSQL Pool Connecting Error');
452
+ handleSqlError(ctx, err);
453
+ }
454
+ throw err;
455
+ }));
456
+ }
457
+
458
+ return result;
459
+ });
460
+ };
461
+ });
462
+ pool.connect.__whatap_wrapped__ = true;
463
+ }
464
+ }
465
+
466
+ return pool;
467
+ };
468
+ });
469
+ mod.ConnectionPool.__whatap_wrapped__ = true;
470
+ }
471
+ };
472
+
232
473
  exports.MssqlObserver = MssqlObserver;