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.
Files changed (198) hide show
  1. package/README.md +32 -78
  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 -882
  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 -4
  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
@@ -4,41 +4,66 @@
4
4
  * can be found in the LICENSE file.
5
5
  */
6
6
 
7
+ const { reqlog_x_txid } = require('../conf/config-default');
8
+ const controlHandler = require('../control/control-handler');
9
+ const RequestLog = require('../requestlog');
7
10
  var TraceContextManager = require('../trace/trace-context-manager'),
8
- URLPatternDetector = require('../trace/serviceurl-pattern-detector').Detector,
9
- conf = require('../conf/configure'),
10
- HashUtil = require('../util/hashutil'),
11
- Hexa32 = require('../util/hexa32'),
12
- KeyGen = require('../util/keygen'),
13
- TraceHelper = require('../util/trace-helper'),
14
- Logger = require('../logger'),
15
- AsyncSender = require('../udp/async_sender'),
16
- PacketTypeEnum = require('../udp/packet_type_enum'),
17
- TraceHttpc = require('../trace/trace-httpc');
11
+ URLPatternDetector = require('../trace/serviceurl-pattern-detector').Detector,
12
+ DataTextAgent = require('../data/datatext-agent'),
13
+ DataProfileAgent = require('../data/dataprofile-agent'),
14
+ EventLevel = require('../data/event-level'),
15
+ HttpStepX = require('../step/http-stepx'),
16
+ TxRecord = require('../service/tx-record'),
17
+ StatError = require('../stat/stat-error'),
18
+ StatHttpc = require('../stat/stat-httpc'),
19
+ StatTranxMtCaller = require('../stat/stat-tx-caller'),
20
+ ProfilePack = require('../pack/profile-pack'),
21
+ DataInputX = require('../io/data-inputx'),
22
+ SecurityMaster = require('../net/security-master'),
23
+ MeterService = require('../counter/meter/meter-service').MeterService,
24
+ MeterUsers = require('../counter/meter/meter-users'),
25
+ MeterHttpC = require('../counter/meter/meter-httpc'),
26
+ conf = require('../conf/configure'),
27
+ HashUtil = require('../util/hashutil'),
28
+ UserIdUtil = require('../util/userid-util'),
29
+ DateUtil = require('../util/dateutil'),
30
+ IPUtil = require('../util/iputil'),
31
+ Hexa32 = require('../util/hexa32'),
32
+ ResourceProfile = require('../util/resourceprofile'),
33
+ TextTypes = require('../lang/text-types'),
34
+ MessageStep = require('../step/message-step'),
35
+ SecureMsgStep = require('../step/securemsg-step'),
36
+ PluginLoaderManager = require('../plugin/plugin-loadermanager'),
37
+ Long = require('long'),
38
+ KeyGen = require('../util/keygen'),
39
+ Logger = require('../logger'),
40
+ IntKeyLinkedMap = require("../util/intkey-linkedmap");
41
+ const ParamSecurity = require("../util/paramsecurity");
18
42
  const {Buffer} = require("buffer");
19
43
  const shimmer = require('../core/shimmer');
20
- const os = require('os');
21
- const Transfer = require('../util/transfer');
44
+ const TraceHttpc = require('../trace/trace-httpc');
22
45
 
23
- var _exts = new Set([".css", ".js", ".png", ".htm", ".html", ".gif", ".jpg", ".css", ".txt", ".ico"]);
46
+ var _exts=new Set([".css",".js",".png", ".htm", ".html", ".gif", ".jpg", ".css", ".txt", ".ico"]);
24
47
 
25
48
  var configIpHeaderKey = conf.getProperty('trace_http_client_ip_header_key', 'x-forwarded-for');
26
49
  var configUserAgentKey = conf.getProperty('trace_user_agent_header_key', '');
27
50
  var configRefererKey = conf.getProperty('trace_referer_header_key', '');
51
+ var trace_origin_url = conf.getProperty('trace_origin_url', false);
28
52
  var ignore_http_method = conf.getProperty('ignore_http_method', 'PATCH,OPTIONS,HEAD,TRACE');
29
53
  var transaction_status_error_enable = conf.getProperty('transaction_status_error_enable', true);
30
54
  var status_ignore = conf.getProperty('status_ignore', '');
31
55
  var httpc_status_ignore = conf.getProperty('httpc_status_ignore', '');
32
56
  var status_ignore_set = conf.getProperty('status_ignore_set', '');
33
57
  var httpc_status_ignore_set = conf.getProperty('httpc_status_ignore_set', '');
58
+ var profile_error_step_enabled = conf.getProperty('profile_error_step_enabled', '');
59
+ var httpc_not_found_ignore = conf.getProperty('httpc_not_found_ignore', false);
60
+ var httpc_not_found_ignore_time = conf.getProperty('httpc_not_found_ignore_time', 300000);
34
61
  var profile_http_header_ignore_keys = conf.getProperty('profile_http_header_ignore_keys', 'Cookie,cookie,accept,user-agent,referer');
35
62
  var profile_http_parameter_enabled = conf.getProperty('profile_http_parameter_enabled', true);
36
63
  var profile_http_parameter_keys = conf.getProperty('profile_http_parameter_keys', '');
37
64
  var ignore_build_file_enabled = conf.getProperty('ignore_build_file_enabled', true);
38
65
  var ignore_build_file_path = conf.getProperty('ignore_build_file_path', '/_next/');
39
-
40
- // Configuration event handlers
41
- conf.on('trace_http_client_ip_header_key', function (newProperty) {
66
+ conf.on('trace_http_client_ip_header_key', function(newProperty) {
42
67
  configIpHeaderKey = newProperty;
43
68
  });
44
69
  conf.on('trace_normalize_urls', function (newProps) {
@@ -56,6 +81,9 @@ conf.on('trace_user_agent_header_key', function (newProps) {
56
81
  conf.on('trace_referer_header_key', function (newProps) {
57
82
  configRefererKey = newProps;
58
83
  });
84
+ conf.on('trace_origin_url', function (newProps) {
85
+ trace_origin_url = newProps;
86
+ })
59
87
  conf.on('ignore_http_method', function (newProps) {
60
88
  ignore_http_method = newProps;
61
89
  })
@@ -74,6 +102,15 @@ conf.on('status_ignore_set', function (newProps) {
74
102
  conf.on('httpc_status_ignore_set', function (newProps) {
75
103
  httpc_status_ignore_set = newProps;
76
104
  })
105
+ conf.on('profile_error_step_enabled', function (newProps) {
106
+ profile_error_step_enabled = newProps;
107
+ })
108
+ conf.on('httpc_not_found_ignore', function (newProps) {
109
+ httpc_not_found_ignore = newProps;
110
+ })
111
+ conf.on('httpc_not_found_ignore_time', function (newProps) {
112
+ httpc_not_found_ignore_time = newProps;
113
+ })
77
114
  conf.on('profile_http_header_ignore_keys', function (newProps) {
78
115
  profile_http_header_ignore_keys = newProps;
79
116
  })
@@ -90,66 +127,127 @@ conf.on('ignore_build_file_path', function (newProps) {
90
127
  ignore_build_file_path = newProps;
91
128
  })
92
129
 
130
+ let _trace_mtrace_traceparent_key = conf.getProperty('trace_mtrace_traceparent_key', 'traceparent');
131
+ let custom_trace_header_enabled = conf.getProperty('custom_trace_header_enabled', false);
132
+ let custom_trace_header_key = conf.getProperty('custom_trace_header_key', null);
133
+
134
+ // conf 리스너 추가
135
+ conf.on('trace_mtrace_traceparent_key', function(newProperty) {
136
+ _trace_mtrace_traceparent_key = newProperty;
137
+ });
138
+
139
+ conf.on('custom_trace_header_enabled', function(newProperty) {
140
+ custom_trace_header_enabled = newProperty;
141
+ });
142
+
143
+ conf.on('custom_trace_header_key', function(newProperty) {
144
+ custom_trace_header_key = newProperty;
145
+ });
93
146
  var staticConents = function (newProps) {
94
- var x = new Set();
95
- var words = !newProps ? [] : newProps.split(',');
96
- for (var i = 0; i < words.length; i++) {
147
+ var x=new Set();
148
+ var words = !newProps?[]:newProps.split(',');
149
+ for(var i = 0 ; i < words.length ; i++) {
97
150
  var ex = words[i].trim();
98
- if (ex.length > 0) {
99
- if (ex.startsWith(".")) {
151
+ if(ex.length>0){
152
+ if(ex.startsWith(".")){
100
153
  x.add(ex);
101
- } else {
102
- x.add("." + ex);
154
+ }else{
155
+ x.add("."+ex );
103
156
  }
104
157
  }
105
158
  }
106
- _exts = x;
159
+
160
+ _exts =x;
107
161
  };
108
162
  conf.on('web_static_content_extensions', staticConents);
109
163
  staticConents(conf["web_static_content_extensions"]);
110
164
 
111
- var HttpObserver = function (agent) {
165
+ var httpc_not_found_ignore_map = null;
166
+ var httpc_not_found_ignore_url = new Set();
167
+
168
+ var HttpObserver = function(agent){
112
169
  this.agent = agent;
113
- this.packages = ['http', 'https'];
170
+ this.packages = ['http','https'];
114
171
  URLPatternDetector.build(true);
115
172
  };
116
173
 
117
- HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps, server) {
174
+ HttpObserver.prototype.__createTransactionObserver = function(callback, isHttps, server) {
118
175
  var self = this;
119
176
  var aop = this.agent.aop;
120
177
 
121
178
  return function (req, res) {
122
179
  TraceContextManager._asyncLocalStorage.run(initCtx(req, res), () => {
123
180
  var ctx = TraceContextManager._asyncLocalStorage.getStore();
124
- if (!ctx) {
181
+ if(!ctx) {
125
182
  return callback(req, res);
126
183
  }
127
184
 
128
- ctx.service_name = req.url ? req.url : "";
129
- let hostname = ctx.host && ctx.host.includes(':') ? ctx.host.split(':')[0] : '';
130
- let datas = [
131
- hostname,
132
- ctx.service_name,
133
- ctx.remoteIp,
134
- ctx.userAgentString,
135
- ctx.referer,
136
- String(ctx.userid),
137
- String(ctx.isStaticContents),
138
- req.method
139
- ];
140
-
141
- aop.after(res, 'end', function (obj, args) {
142
- if (ctx == null) {
143
- return;
185
+ PluginLoaderManager.do('httpservicestart', ctx, req, res);
186
+ if(trace_origin_url === true){
187
+ var originUrlHash = HashUtil.hashFromString('Origin url');
188
+ var step = new MessageStep();
189
+ step.hash = originUrlHash;
190
+ step.start_time = ctx.getElapsedTime();
191
+ // step.desc = req.url;
192
+
193
+ DataTextAgent.MESSAGE.add(originUrlHash, 'Origin url');
194
+ ctx.profile.add(step);
195
+ }
196
+
197
+ // res.on('aborted', () => {
198
+ // self.__endTransaction(null, ctx, req, res)
199
+ // })
200
+
201
+ res.on('close', () => {
202
+ // 강제로 종료할 경우
203
+ self.__endTransaction(null, ctx, req, res)
204
+ });
205
+
206
+ aop.after(res, 'end', function(obj, args) {
207
+ if(ctx == null) { return; }
208
+ PluginLoaderManager.do('httpserviceend', ctx, req, res);
209
+
210
+ var not_found_ignore = httpc_not_found_ignore_url.has(req.url);
211
+ if (httpc_not_found_ignore && !not_found_ignore && obj.statusCode === 404) {
212
+ const url_hash = HashUtil.hashFromString(req.url);
213
+ const currentTime = new Date().getTime();
214
+
215
+ if (!httpc_not_found_ignore_map) {
216
+ httpc_not_found_ignore_map = new IntKeyLinkedMap(500, 1).setMax(500);
217
+ }
218
+ updateNotFoundIgnoreMap(req.url, url_hash, currentTime);
219
+ }
220
+
221
+ ctx.isStaticContents = isStatic(req.url);
222
+ ctx.http_method = req.method;
223
+ if(conf.profile_http_querystring_enabled){
224
+ ctx.http_query = JSON.stringify(req.query);
225
+ }
226
+ ctx.http_content_type = (req.headers['content_type'] || '');
227
+ ctx.status = Math.floor(obj.statusCode / 100);
228
+
229
+ // 에러가 발생했지만 스택수집안했을 경우
230
+ if (transaction_status_error_enable && ctx.status >= 4) {
231
+ if(ctx.error.isZero())
232
+ ctx.error = StatError.addError(obj.statusCode, obj.statusMessage, ctx.service_hash);
233
+ ctx.statusCode = obj.statusCode;
234
+ ctx.statusTitle = obj.statusMessage;
235
+ ctx.statusMessage = ctx.error_message;
236
+ }
237
+
238
+ var shouldEndTransaction = shouldEndCurrentTransaction(not_found_ignore, ctx, res, req.route ? req.route.path : '');
239
+ if (shouldEndTransaction) {
240
+ self.__endTransaction(null, ctx, req, res);
241
+ } else {
242
+ TraceContextManager.end(ctx._id);
243
+ ctx = null;
144
244
  }
145
- self.__endTransaction(null, ctx, req, res);
146
245
  });
147
246
 
148
247
  try {
149
- AsyncSender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
150
248
  return callback.apply(this, arguments);
151
249
  } catch (e) {
152
- Logger.printError("WHATAP-235", 'Hooking request failed..', e, false);
250
+ Logger.printError("WHATAP-606", 'Hooking request failed..', e, false);
153
251
  self.__endTransaction(e, ctx, req, res);
154
252
  throw e;
155
253
  }
@@ -157,14 +255,13 @@ HttpObserver.prototype.__createTransactionObserver = function (callback, isHttps
157
255
  };
158
256
  };
159
257
 
160
- function isStatic(u) {
258
+ function isStatic(u){
161
259
  var x = u.lastIndexOf('.');
162
- if (x <= 0) return false;
260
+ if(x<=0) return false;
163
261
 
164
262
  var ext = u.substring(x);
165
263
  return _exts.has(ext);
166
264
  }
167
-
168
265
  function initCtx(req, res) {
169
266
  /*url이 없으면 추적하지 않는다*/
170
267
  if(!req.url) { return null; }
@@ -177,11 +274,70 @@ function initCtx(req, res) {
177
274
  }
178
275
 
179
276
  var ctx = TraceContextManager.start();
180
- if (ctx == null) {
181
- return null;
277
+ if(ctx == null) { return null; }
278
+
279
+ req.__ctx_id__ = ctx._id;
280
+
281
+ var url = req.url,
282
+ index = url.indexOf('?');
283
+ if(index >= 0) {
284
+ url = url.slice(0, index);
285
+ }
286
+ ctx.service_name = URLPatternDetector.normalize(url);
287
+ try {
288
+ if(conf.trace_service_port_enabled === true && server.address()) {
289
+ ctx.service_name += ' {' + server.address().port + '}';
290
+ }
291
+ } catch(e){
292
+ }
293
+
294
+ try {
295
+ if(conf.trace_transaction_name_header_key != null) {
296
+ ctx.service_name = req.headers[conf.trace_transaction_name_header_key] + ctx.service_name;
297
+ }
298
+ } catch(e) {
299
+ }
300
+
301
+ ctx.service_hash = HashUtil.hashFromString(ctx.service_name);
302
+ // DataTextAgent.SERVICE.add(ctx.service_hash, ctx.service_name);
303
+
304
+ ctx.isStaticContents = isStatic(req.url);
305
+
306
+ var referer = undefined;
307
+ if(configRefererKey && req.headers[configRefererKey]){
308
+ referer = req.headers[configRefererKey];
309
+ }else if(req.headers.referer){
310
+ referer = req.headers.referer;
311
+ }
312
+ if (referer) {
313
+ ctx.referer = HashUtil.hashFromString(referer);
314
+ DataTextAgent.REFERER.add(ctx.referer, referer);
315
+ }
316
+
317
+ if(configUserAgentKey && req.headers[configUserAgentKey]){
318
+ ctx.userAgentString = req.headers[configUserAgentKey];
319
+ }else if(req.headers['user-agent']){
320
+ ctx.userAgentString = req.headers['user-agent'];
321
+ }
322
+ if(ctx.userAgentString){
323
+ ctx.userAgent = HashUtil.hashFromString(ctx.userAgentString);
324
+ DataTextAgent.USERAGENT.add(ctx.userAgent, ctx.userAgentString);
325
+ }
326
+
327
+ ctx.http_host=req.headers.host;
328
+ if (ctx.http_host) {
329
+ ctx.http_host_hash = HashUtil.hashFromString(ctx.http_host);
330
+ DataTextAgent.HTTP_DOMAIN.add(ctx.http_host_hash, ctx.http_host);
182
331
  }
183
332
 
184
- // RemoteIP
333
+ ctx.originUrl = req.url;
334
+ ctx.start_malloc = ResourceProfile.getUsedHeapSize();
335
+ ctx.start_cpu = ResourceProfile.getCPUTime();
336
+ ctx.http_method = req.method;
337
+ if(conf.profile_http_querystring_enabled){
338
+ ctx.http_query = JSON.stringify(req.query);
339
+ }
340
+ ctx.http_content_type = (req.headers['content_type'] || '');
185
341
  var remote_addr;
186
342
  try {
187
343
  remote_addr = req.headers[configIpHeaderKey] || req.connection.remoteAddress || "0.0.0.0";
@@ -203,27 +359,9 @@ function initCtx(req, res) {
203
359
  MeterUsers.add(ctx.userid);
204
360
  break;
205
361
  }
206
- } catch (e) {
207
- }
208
362
 
209
- // Referer
210
- var referer = undefined;
211
- if(configRefererKey && req.headers[configRefererKey]){
212
- ctx.referer = req.headers[configRefererKey];
213
- }else if(req.headers.referer){
214
- ctx.referer = req.headers.referer;
215
- }
216
-
217
- // UserAgent
218
- if(configUserAgentKey && req.headers[configUserAgentKey]){
219
- ctx.userAgentString = req.headers[configUserAgentKey];
220
- }else if(req.headers['user-agent']){
221
- ctx.userAgentString = req.headers['user-agent'];
363
+ } catch (e) {
222
364
  }
223
-
224
- // Host
225
- ctx.host = req.headers.host;
226
-
227
365
  /************************************/
228
366
  /* Header / param Trace */
229
367
  /************************************/
@@ -235,26 +373,19 @@ function initCtx(req, res) {
235
373
  header_enabled = false;
236
374
  }
237
375
  }
238
- /************************************/
239
- /* Header / param Trace */
240
- /************************************/
241
- var header_enabled = false;
242
- if (conf.profile_http_header_enabled === true && req.headers) {
243
- header_enabled = true;
244
- var prefix = conf.profile_header_url_prefix;
245
- if (prefix && ctx.service_name.indexOf(prefix) < 0) {
246
- header_enabled = false;
247
- }
248
- }
249
376
 
250
- if (header_enabled) {
377
+ if(header_enabled) {
378
+ var step = new MessageStep();
379
+ step.hash = HashUtil.hashFromString("HTTP-HEADERS");
380
+ step.start_time = ctx.getElapsedTime();
381
+
251
382
  var header_ignore_key_set = new Set();
252
- if (profile_http_header_ignore_keys) {
383
+ if(profile_http_header_ignore_keys) {
253
384
  header_ignore_key_set = new Set(profile_http_header_ignore_keys.split(','));
254
385
  }
255
386
 
256
- try {
257
- var headerDesc = Object.keys(req.headers).map(function (key) {
387
+ try{
388
+ step.desc = Object.keys(req.headers).map(function (key) {
258
389
  if (!header_ignore_key_set.has(key)) {
259
390
  return `${key}=${req.headers[key]}`;
260
391
  }
@@ -262,40 +393,81 @@ function initCtx(req, res) {
262
393
  if (element) return element
263
394
  }).join('\n');
264
395
 
265
- if (headerDesc) {
266
- let headerDatas = ['HTTP-HEADERS', 'HTTP-HEADERS', headerDesc];
267
- ctx.start_time = Date.now();
268
- AsyncSender.send_packet(PacketTypeEnum.TX_MSG, ctx, headerDatas);
269
- }
270
- } catch (e) {
271
- Logger.printError('WHATAP-236', 'Header parsing error', e, false);
396
+ DataTextAgent.MESSAGE.add(step.hash, "HTTP-HEADERS");
397
+ ctx.profile.push(step);
398
+ }catch (e) {
399
+ step = null;
400
+ header_ignore_key_set = null;
401
+ Logger.printError('WHATAP-614', 'Header parsing error', e, false);
272
402
  }
273
403
  }
274
-
275
404
  /************************************/
276
405
  /* Multi Server Transaction Trace */
277
406
  /************************************/
278
- if (conf.getProperty('mtrace_enabled', false)) {
279
- var poid = req.headers['x-wtap-po'];
407
+ if(conf.getProperty('mtrace_enabled', false)) {
408
+ // traceparent 헤더 처리 (W3C Trace Context 표준)
409
+ const traceparentKey = req.headers[conf._trace_mtrace_traceparent_key];
410
+ let hasTraceparentKey = false;
411
+ let traceparentStepId = 0;
412
+
413
+ if (traceparentKey) {
414
+ hasTraceparentKey = true;
415
+ const parts = traceparentKey.trim().split('-');
416
+
417
+ if (parts.length >= 4) {
418
+ // parts[0]: version (00)
419
+ // parts[1]: 32자리 16진수 trace ID
420
+ // parts[2]: 16자리 16진수 parent ID (span ID)
421
+ // parts[3]: 2자리 16진수 trace flags
422
+
423
+ const mcallerTraceIdValue = parts[1];
424
+ ctx.mcallerTraceparentValue = mcallerTraceIdValue;
425
+
426
+ try {
427
+ // trace ID의 뒤 16자리를 가져와서 long으로 변환
428
+ const mtidHex = mcallerTraceIdValue.substring(16);
429
+ const mtidLong = Long.fromString(mtidHex, true, 16);
430
+ ctx.mtid = mtidLong;
431
+
432
+ if (!ctx.mtid.isZero()) {
433
+ ctx.mtid_build_checked = true;
434
+ }
435
+ } catch (e) {
436
+ Logger.printError('WHATAP-851', 'traceparent parse error', e, true);
437
+ }
438
+
439
+ try {
440
+ // parent span ID 추출
441
+ const parentSpanId = Long.fromString(parts[2], true, 16);
442
+ ctx.mcaller_stepId = parentSpanId;
443
+ traceparentStepId = parentSpanId;
444
+ } catch (e) {
445
+ Logger.printError('WHATAP-851', 'traceparent span id parse error', e, true);
446
+ }
447
+ }
448
+ }
449
+
450
+ // WhaTap 고유 헤더 처리
451
+ const poid = req.headers['x-wtap-po'];
280
452
  if (poid != null) {
281
453
  ctx.setCallerPOID(poid);
454
+
282
455
  try {
283
- var mt_caller = req.headers[conf._trace_mtrace_caller_key];
284
- if (mt_caller) {
285
- var x = mt_caller.indexOf(',');
456
+ const mt_caller = req.headers[conf._trace_mtrace_caller_key];
457
+ if(mt_caller) {
458
+ const x = mt_caller.indexOf(',');
286
459
  if (x > 0) {
287
460
  ctx.mtid = Hexa32.toLong32(mt_caller.substring(0, x));
288
461
  ctx.mtid_build_checked = true;
289
- var y = mt_caller.indexOf(',', x + 1);
462
+ const y = mt_caller.indexOf(',', x + 1);
290
463
  if (y > 0) {
291
464
  ctx.mdepth = parseInt(mt_caller.substring(x + 1, y));
292
- var z = mt_caller.indexOf(',', y + 1);
465
+ const z = mt_caller.indexOf(',', y + 1);
293
466
  if (z < 0) {
294
467
  ctx.mcaller_txid = Hexa32.toLong32(mt_caller.substring(y + 1));
295
468
  } else {
296
469
  ctx.mcaller_txid = Hexa32.toLong32(mt_caller.substring(y + 1, z));
297
-
298
- var z2 = mt_caller.indexOf(',', z + 1);
470
+ const z2 = mt_caller.indexOf(',', z + 1);
299
471
  if (z2 < 0) {
300
472
  ctx.mcaller_stepId = Hexa32.toLong32(mt_caller.substring(z + 1));
301
473
  } else {
@@ -305,57 +477,91 @@ function initCtx(req, res) {
305
477
  }
306
478
  }
307
479
  }
480
+
308
481
  if (conf.stat_mtrace_enabled) {
309
- var inf = req.headers[conf._trace_mtrace_spec_key1];
310
- if (inf != null && inf.length > 0) {
311
- var px = inf.indexOf(',');
482
+ const inf = req.headers[conf._trace_mtrace_spec_key1];
483
+ if(inf != null && inf.length > 0) {
484
+ const px = inf.indexOf(',');
312
485
  ctx.mcaller_spec = inf.substring(0, px);
313
486
  ctx.mcaller_url = inf.substring(px + 1);
314
- ctx.mcaller_url_hash = HashUtil.hashFromString(ctx.mcaller_url);
315
487
  }
316
488
  }
317
- } catch (e) {
318
- Logger.printError('WHATAP-237', 'Multi Server Transaction ', e, true);
489
+ } catch(e) {
490
+ Logger.printError('WHATAP-850', 'Multi Server Transaction', e, true);
491
+ }
492
+ }
493
+
494
+ // Gateway가 header를 그대로 전달하는 경우 처리
495
+ if (hasTraceparentKey) {
496
+ if (!traceparentStepId.equals(ctx.mcaller_stepId)) {
497
+ ctx.mcaller_stepId = traceparentStepId;
498
+ ctx.mcaller_txid = Long.ZERO;
319
499
  }
320
500
  }
321
501
  }
322
502
 
323
- return ctx;
324
- };
503
+ var poid=req.headers['x-wtap-po'];
504
+ if (poid != null) {
505
+ ctx.setCallerPOID(poid);
506
+ try{
507
+ var mt_caller=req.headers[conf._trace_mtrace_caller_key];
508
+ if(mt_caller){
509
+ var x = mt_caller.indexOf(',');
510
+ if (x > 0) {
511
+ ctx.mtid = Hexa32.toLong32(mt_caller.substring(0, x));
512
+ ctx.mtid_build_checked = true;
513
+ var y = mt_caller.indexOf(',', x + 1);
514
+ if (y > 0) {
515
+ ctx.mdepth = parseInt(mt_caller.substring(x + 1, y));
516
+ var z = mt_caller.indexOf(',', y + 1);
517
+ if (z < 0) {
518
+ ctx.mcaller_txid = Hexa32.toLong32(mt_caller.substring(y + 1));
519
+ } else {
520
+ ctx.mcaller_txid = Hexa32.toLong32(mt_caller.substring(y + 1, z));
325
521
 
326
- function interceptorError(statusCode, error, ctx) {
327
- if (!ctx) {
328
- return;
522
+ var z2 = mt_caller.indexOf(',', z + 1);
523
+ if (z2 < 0) {
524
+ ctx.mcaller_stepId = Hexa32.toLong32(mt_caller.substring(z + 1));
525
+ } else {
526
+ ctx.mcaller_stepId = Hexa32.toLong32(mt_caller.substring(z + 1, z2));
527
+ }
528
+ }
529
+ }
530
+ }
531
+ }
532
+ if (conf.stat_mtrace_enabled) {
533
+ var inf=req.headers[conf._trace_mtrace_spec_key1];
534
+ if(inf != null && inf.length > 0){
535
+ var px = inf.indexOf(',');
536
+ ctx.mcaller_spec = inf.substring(0, px);
537
+ ctx.mcaller_url = inf.substring(px + 1);
538
+ }
539
+ }
540
+ } catch(e) {
541
+ Logger.printError('WHATAP-850', 'Multi Server Transaction ', e, true);
542
+ }
329
543
  }
330
544
 
331
- ctx.status = statusCode;
332
- let errors = [];
333
- let error_message = 'Request failed with status code ';
334
- if (statusCode >= 400 && !ctx.error) {
335
- ctx.error = 1;
336
-
337
- errors.push(error.class)
338
- if(error.message)
339
- errors.push(error.message)
340
- else
341
- errors.push(error_message + statusCode);
545
+ return ctx;
546
+ };
342
547
 
343
- AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
344
- }
345
- }
548
+ HttpObserver.prototype.__endTransaction = function(error, ctx, req, res) {
549
+ if(ctx == null || TraceContextManager.isExist(ctx._id) === false) { return; }
346
550
 
347
- HttpObserver.prototype.__endTransaction = function (error, ctx, req, res) {
348
551
  var param_enabled = false;
349
- if (conf.profile_http_parameter_enabled === true) {
552
+ if(conf.profile_http_parameter_enabled === true) {
350
553
  param_enabled = true;
351
554
  var prefix = conf.profile_http_parameter_url_prefix;
352
- if (prefix && ctx.service_name.indexOf(prefix) < 0) {
555
+ if(prefix && ctx.service_name.indexOf(prefix) < 0) {
353
556
  param_enabled = false;
354
557
  }
355
558
  }
356
559
 
357
560
  if (param_enabled && req.query && Object.keys(req.query).length > 0) {
358
561
  const query = req.query;
562
+ let secureMsgStep = new SecureMsgStep(ctx.getElapsedTime());
563
+ secureMsgStep.hash = HashUtil.hashFromString("HTTP-PARAMETERS");
564
+
359
565
  const profileHttpParameterKeysSet = profile_http_parameter_keys ? new Set(profile_http_parameter_keys.split(',')) : null;
360
566
 
361
567
  try {
@@ -365,67 +571,218 @@ HttpObserver.prototype.__endTransaction = function (error, ctx, req, res) {
365
571
  .join('\n');
366
572
 
367
573
  if (desc) {
368
- let paramDatas = ['HTTP-PARAMETERS', req.method, desc];
369
- AsyncSender.send_packet(PacketTypeEnum.TX_SECURE_MSG, ctx, paramDatas);
574
+ const crc = { value: 0 };
575
+ secureMsgStep.value = toParamBytes(desc, crc);
576
+ secureMsgStep.crc = crc.value;
577
+
578
+ DataTextAgent.MESSAGE.add(secureMsgStep.hash, "HTTP-PARAMETERS");
579
+ ctx.profile.push(secureMsgStep);
580
+ } else {
581
+ secureMsgStep = null;
370
582
  }
371
583
  } catch (e) {
372
- Logger.printError('WHATAP-238', 'Parameter parsing error', e, false);
584
+ secureMsgStep = null;
585
+ Logger.printError('WHATAP-613', 'Parameter parsing error', e, false);
373
586
  }
374
587
  }
375
588
 
376
- if (error) {
377
- TraceContextManager.end(ctx != null ? ctx.id : null);
378
- ctx = null;
379
- return;
589
+ if(profile_error_step_enabled && ctx.statusMessage){
590
+ var step = new MessageStep();
591
+ var title = ctx.statusTitle ? ctx.statusTitle : "EXCEPTION";
592
+ step.hash = HashUtil.hashFromString(title);
593
+ step.start_time = ctx.getElapsedTime();
594
+ step.desc = ctx.statusMessage;
595
+ DataTextAgent.MESSAGE.add(step.hash, title);
596
+ ctx.profile.push(step);
380
597
  }
381
598
 
382
- if (ctx == null || TraceContextManager.isExist(ctx.id) === false) {
599
+ if(error) {
600
+ TraceContextManager.end(ctx != null ? ctx._id : null);
601
+ ctx = null;
383
602
  return;
384
603
  }
385
604
 
386
- if (ctx.isStaticContents !== true && conf._trace_ignore_url_set[ctx.service_hash]) {
605
+ // if(ctx == null || TraceContextManager.isExist(ctx._id) === false) { return; }
606
+
607
+ if(ctx.isStaticContents !== true && conf._trace_ignore_url_set[ctx.service_hash]){
387
608
  ctx.isStaticContents = true;
388
609
  }
389
610
 
390
- if (conf._is_trace_ignore_url_prefix === true && ctx.service_name.startsWith(conf.trace_ignore_url_prefix) === true) {
611
+ if(conf._is_trace_ignore_url_prefix === true && ctx.service_name.startsWith(conf.trace_ignore_url_prefix) === true){
391
612
  ctx.isStaticContents = true;
392
613
  }
393
614
 
394
- if (ctx.isStaticContents) {
395
- TraceContextManager.end(ctx.id);
615
+ if(ctx.isStaticContents){
616
+ TraceContextManager.end(ctx._id);
396
617
  ctx = null;
397
618
  return;
398
619
  }
399
620
 
400
621
  try {
401
- ctx.start_time = Date.now();
402
- let datas = [os.hostname(), ctx.service_name, ctx.mtid, ctx.mdepth, ctx.mcaller_txid,
403
- ctx.mcaller_pcode, ctx.mcaller_spec, String(ctx.mcaller_url_hash), ctx.status];
404
- ctx.elapsed = Date.now() - ctx.start_time;
405
- AsyncSender.send_packet(PacketTypeEnum.TX_END, ctx, datas);
622
+ var profile = new ProfilePack();
623
+ var wtx = new TxRecord();
624
+ // profile.time = ctx.start_time;
625
+ wtx.endTime = DateUtil.currentTime();
626
+ profile.time = wtx.endTime;
627
+ wtx.elapsed = ctx.getElapsedTime();
628
+
629
+ ctx.service_hash = HashUtil.hashFromString(ctx.service_name);
630
+ DataTextAgent.SERVICE.add(ctx.service_hash, ctx.service_name);
631
+
632
+ wtx.service = ctx.service_hash;
633
+ wtx.cpuTime = ResourceProfile.getCPUTime() - ctx.start_cpu;
634
+ wtx.malloc = ResourceProfile.getUsedHeapSize()-ctx.start_malloc;
635
+ if(wtx.malloc < 0) { wtx.malloc = 0; }
636
+ wtx.originUrl = ctx.originUrl;
637
+
638
+ wtx.cipher = HashUtil.hash(ParamSecurity.key);
639
+ wtx.seq = ctx.txid;
640
+ wtx.sqlCount = ctx.sql_count;
641
+ wtx.sqlTime = ctx.sql_time;
642
+ wtx.sqlFetchCount = ctx.rs_count;
643
+ wtx.sqlFetchTime = parseInt(ctx.rs_time);
644
+ wtx.ipaddr = ctx.remoteIp;
645
+ wtx.userid = ctx.userid;
646
+
647
+ if (ctx.error.isZero() === false) {
648
+ wtx.error = ctx.error;
649
+ wtx.errorLevel = EventLevel.WARNING;
650
+ }
651
+ wtx.userAgent = ctx.userAgent;
652
+ wtx.referer = ctx.referer;
653
+
654
+ wtx.httpcCount = ctx.httpc_count;
655
+ wtx.httpcTime = ctx.httpc_time;
656
+ wtx.status = ctx.status;
657
+
658
+ wtx.http_method=TxRecord.HTTP_METHOD[ctx.http_method] || TxRecord.WEB_GET;
659
+ wtx.http_host = ctx.http_host;
660
+ wtx.mtid=ctx.mtid;
661
+ wtx.mdepth=ctx.mdepth;
662
+ wtx.mcaller=ctx.mcaller_txid;
663
+ wtx.mcallerStepId = ctx.mcaller_stepId;
664
+ wtx.mcaller_pcode = ctx.mcaller_pcode;
665
+ wtx.mcaller_okind = ctx.mcaller_okind;
666
+ wtx.mcaller_oid = ctx.mcaller_oid;
667
+
668
+ wtx.appctx = "";
669
+ wtx.txName = ctx.service_name;
670
+ if(ctx.error_class) wtx.error_class = ctx.error_class;
671
+ if(ctx.error_message) wtx.error_message = ctx.error_message;
672
+
673
+ if(conf.getProperty('txtext_txname_enabled', true)){
674
+ wtx.txName = ctx.service_name;
675
+ }
676
+
677
+ MeterService.add(wtx.service, wtx.elapsed,
678
+ wtx.errorLevel, ctx.mcaller_pcode, ctx.mcaller_okind, ctx.mcaller_oid);
679
+
680
+ profile.oid = SecurityMaster.OID;
681
+ profile.service = wtx;
682
+ if(Boolean(conf.reqlog_enabled) == true) {
683
+ ctx.endTime = wtx.endTime;
684
+ ctx.elapsed = wtx.elapsed;
685
+ RequestLog.setRecord(ctx);
686
+ }
687
+ //duplicated executed... so end() first
688
+ TraceContextManager.end(ctx._id);
689
+ setTimeout(function () {
690
+ DataProfileAgent.sendProfile(ctx, profile, false);
691
+ TraceContextManager.end(ctx._id);
692
+ ctx = null;
693
+ }, 100);
406
694
 
407
- TraceContextManager.end(ctx.id);
408
695
  } catch (e) {
409
- Logger.printError('WHATAP-239', 'End transaction error..', e, false);
410
- TraceContextManager.end(ctx.id);
696
+ Logger.printError('WHATAP-607', 'End transaction error..', e, false);
697
+ TraceContextManager.end(ctx._id);
411
698
  ctx = null;
412
699
  }
700
+
413
701
  };
414
702
 
415
- // interTxTraceAutoOn function moved to util/trace-helper.js
703
+ var transfer_poid;
704
+ function transferPOID(ctx) {
705
+ if (transfer_poid)
706
+ return transfer_poid;
707
+ transfer_poid=Hexa32.toString32(SecurityMaster.PCODE)+','
708
+ +Hexa32.toString32(SecurityMaster.OKIND)+','+Hexa32.toString32(SecurityMaster.OID);
709
+ return transfer_poid;
710
+ }
416
711
 
417
- HttpObserver.prototype.inject = function (mod, moduleName) {
712
+ function transferMTID_CALLERTX(ctx) {
713
+ if (ctx.transfer_id)
714
+ return ctx.transfer_id;
715
+ var x = Hexa32.toString32(ctx.mtid) + ',' + (ctx.mdepth + 1) + ',' + Hexa32.toString32(ctx.txid);
716
+ ctx.transfer_id = x;
717
+ return ctx.transfer_id;
718
+ }
719
+ function transferSPEC_URL(ctx) {
720
+ if (ctx.transfer_info)
721
+ return ctx.transfer_info;
722
+ var x = conf.mtrace_spec + ',' + ctx.service_hash;
723
+ ctx.transfer_info = x;
724
+ return ctx.transfer_info;
725
+ }
726
+ var check_seq = 1;
727
+ function interTxTraceAutoOn(ctx) {
728
+ if (conf.mtrace_enabled ==false || ctx.httpc_checked || ctx.mtid.isZero()===false)
729
+ return;
730
+ ctx.httpc_checked = true;
731
+ if(conf.mtrace_rate>=100){
732
+ ctx.mtid = KeyGen.next();
733
+ return;
734
+ }
735
+ check_seq++;
736
+ switch (Math.floor(conf.mtrace_rate / 10)) {
737
+ case 10:
738
+ ctx.mtid = KeyGen.next();
739
+ break;
740
+ case 9:
741
+ if (check_seq % 10 !== 0)
742
+ ctx.mtid = KeyGen.next();
743
+ break;
744
+ case 8:
745
+ if (check_seq % 5 !== 0)
746
+ ctx.mtid = KeyGen.next();
747
+ break;
748
+ case 7:
749
+ if (check_seq % 4 !== 0)
750
+ ctx.mtid = KeyGen.next();
751
+ break;
752
+ case 6:
753
+ if (check_seq % 3 !== 0)
754
+ ctx.mtid = KeyGen.next();
755
+ break;
756
+ case 5:
757
+ if (check_seq % 2 === 0)
758
+ ctx.mtid = KeyGen.next();
759
+ break;
760
+ case 4:
761
+ if (check_seq % 3 === 0 || check_seq % 5 === 0)
762
+ ctx.mtid = KeyGen.next();
763
+ break;
764
+ case 3:
765
+ if (check_seq % 4 === 0 || check_seq % 5 === 0)
766
+ ctx.mtid = KeyGen.next();
767
+ break;
768
+ case 2:
769
+ if (check_seq % 5 === 0)
770
+ ctx.mtid = KeyGen.next();
771
+ break;
772
+ case 1:
773
+ if (check_seq % 10 === 0)
774
+ ctx.mtid = KeyGen.next();
775
+ break;
776
+ }
777
+ }
778
+ HttpObserver.prototype.inject = function( mod, moduleName ) {
418
779
  var self = this;
419
780
  var aop = self.agent.aop;
420
781
 
421
- if (mod.__whatap_observe__) {
422
- return;
423
- }
782
+ if(mod.__whatap_observe__) { return; }
424
783
  mod.__whatap_observe__ = true;
425
784
  Logger.initPrint("HttpObserver");
426
- if (conf.getProperty('profile_enabled', true) === false) {
427
- return;
428
- }
785
+ if( conf.getProperty('profile_enabled', true) === false ) { return; }
429
786
 
430
787
  aop.after(mod, 'createServer', function (obj, args, ret) {
431
788
  aop.before(ret, 'listen', function (obj, args) {
@@ -448,83 +805,102 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
448
805
  }
449
806
  );
450
807
 
451
- if (conf.getProperty('httpc_enabled', true) === false) {
452
- return;
453
- }
808
+ if( conf.getProperty('httpc_enabled', true) === false ) { return; }
454
809
 
455
810
  shimmer.wrap(mod, 'request', function (original) {
456
811
  return function wrappedRequest(options, callback) {
457
812
  var ctx = TraceContextManager.getCurrentContext();
458
- if (!ctx || (!options.host && !options.hostname)) {
813
+ if(!ctx || (!options.host && !options.hostname)){
459
814
  return original.apply(this, arguments);
460
815
  }
461
816
 
462
817
  var isHttpRepeat = false;
463
- if (moduleName === 'https') {
818
+ if(moduleName === 'https'){
464
819
  options.__isHttps = true;
465
820
  }
466
- if (moduleName === 'http' && options.__isHttps) {
821
+ if(moduleName === 'http' && options.__isHttps){
467
822
  isHttpRepeat = true;
468
823
  }
469
- ctx.start_time = Date.now();
470
824
 
471
- if (!isHttpRepeat) {
472
- if (options.method === 'OPTION') {
825
+ var step = new HttpStepX();
826
+ step.start_time = ctx.getElapsedTime();
827
+
828
+ if(!isHttpRepeat){
829
+ if(options.method === 'OPTION'){
473
830
  return original.apply(this, arguments);
474
831
  }
475
- try {
476
- TraceHelper.interTxTraceAutoOn(ctx);
477
- if (conf.getProperty('mtrace_enabled', false)) {
478
- if (options.headers) {
479
- options.headers['x-wtap-po'] = Transfer.POID();
480
- } else {
481
- options.headers = {'x-wtap-po': Transfer.POID()};
832
+ try{
833
+ interTxTraceAutoOn(ctx);
834
+ if(conf.getProperty('mtrace_enabled', false)){
835
+ if(options.headers){
836
+ options.headers['x-wtap-po'] = transferPOID(ctx);
837
+ }else{
838
+ options.headers = {'x-wtap-po': transferPOID(ctx)};
482
839
  }
483
- if (conf.stat_mtrace_enabled) {
484
- options.headers[conf._trace_mtrace_spec_key1] = Transfer.SPEC_URL(ctx);
840
+ if(conf.stat_mtrace_enabled){
841
+ options.headers[conf._trace_mtrace_spec_key1]=transferSPEC_URL(ctx);
485
842
  }
486
- if (!ctx.mtid.isZero()) {
487
- options.headers[conf._trace_mtrace_caller_key] = Transfer.MTID_CALLERTX(ctx);
843
+ if(ctx.mtid.isZero()===false){
844
+ options.headers[conf._trace_mtrace_caller_key]=transferMTID_CALLERTX(ctx);
488
845
  }
489
-
490
- ctx.mcallee = KeyGen.next();
491
- options.headers[conf._trace_mtrace_callee_key] = Hexa32.toString32(ctx.mcallee);
492
846
  }
493
847
 
494
848
  ctx.httpc_url = options.path || '/';
495
849
  ctx.httpc_host = options.host || options.hostname || '';
496
850
  ctx.httpc_port = options.port || -1;
497
- ctx.active_httpc_hash = true;
498
-
499
- if (ctx.httpc_port < 0) {
500
- ctx.httpc_port = 80
851
+
852
+ ctx.footprint('Http Call Start');
853
+
854
+ if (ctx.httpc_port < 0) { ctx.httpc_port = 80 };
855
+
856
+ if(conf.getProperty('profile_httpc_start_step_enabled', false)){
857
+ step.elapsed = ctx.getElapsedTime() - step.start_time;
858
+ step.url = HashUtil.hashFromString(ctx.httpc_url);
859
+ DataTextAgent.HTTPC_URL.add(step.url, ctx.httpc_url);
860
+ step.host = HashUtil.hashFromString(ctx.httpc_host);
861
+ DataTextAgent.HTTPC_HOST.add(step.host, ctx.httpc_host);
862
+ step.port = ctx.httpc_port;
863
+
864
+ ctx.active_httpc_hash = step.url;
865
+ ctx.profile.push(step);
866
+ endHttpc(ctx, step);
501
867
  }
502
- } catch (e) {
503
- Logger.printError('WHATAP-240', 'Http Setup Error', e, true);
868
+ }catch (e) {
869
+ Logger.printError('WHATAP-852', 'Http Repeat ', e, true);
504
870
  return original.apply(this, arguments);
505
871
  }
506
- } else {
872
+ }else{
507
873
  return original.apply(this, arguments);
508
874
  }
509
875
 
510
876
  var wrappedCallback;
511
877
  if (typeof callback === 'function') {
512
- wrappedCallback = function (response) {
513
- if (TraceContextManager.resume(ctx.id) === null) {
878
+ wrappedCallback = function(response) {
879
+ if (TraceContextManager.resume(ctx._id) === null) {
514
880
  return callback.apply(this, arguments);
515
881
  }
516
882
 
517
- response.on('end', function () {
518
- // HTTP 클라이언트 에러 처리 - Python 스타일로 단순화
883
+ response.on('end', function() {
884
+ step.elapsed = ctx.getElapsedTime() - step.start_time;
885
+ step.url = HashUtil.hashFromString(ctx.httpc_url);
886
+ DataTextAgent.HTTPC_URL.add(step.url, ctx.httpc_url);
887
+ step.host = HashUtil.hashFromString(ctx.httpc_host);
888
+ DataTextAgent.HTTPC_HOST.add(step.host, ctx.httpc_host);
889
+ step.port = ctx.httpc_port;
890
+
519
891
  if (response.statusCode >= 400 && transaction_status_error_enable) {
520
- let error = {
521
- class: response.statusMessage,
522
- message: ''
892
+ step.error = StatError.addError(response.statusCode, response.statusMessage,
893
+ ctx.service_hash, TextTypes.HTTPC_URL, step.url);
894
+ if (ctx.error.isZero()) {
895
+ ctx.error = step.error;
896
+ ctx.statusCode = response.statusCode;
897
+ ctx.statusMessage = response.statusMessage;
523
898
  }
524
- interceptorError(response.statusCode, error, ctx);
525
899
  }
526
900
 
527
- endHttpc(ctx);
901
+ ctx.active_httpc_hash = step.url;
902
+ ctx.profile.push(step);
903
+ endHttpc(ctx, step);
528
904
  });
529
905
 
530
906
  return callback.apply(this, arguments);
@@ -532,32 +908,36 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
532
908
  }
533
909
 
534
910
  var req = original.apply(this, [options, wrappedCallback]);
911
+ var httpc_url = options.path
535
912
 
536
913
  req.on('error', function (err) {
537
- if (TraceContextManager.resume(ctx.id) === null) {
538
- return;
539
- }
540
-
541
- const isIgnoreHttpc = shouldIgnoreError(err.code, ctx.httpc_url, httpc_status_ignore, httpc_status_ignore_set);
542
-
543
- const networkErrorToStatusCode = {
544
- 'ECONNREFUSED': 503,
545
- 'ETIMEDOUT': 504,
546
- 'ENOTFOUND': 502,
547
- 'ECONNRESET': 503,
548
- 'EPIPE': 503,
549
- 'EHOSTUNREACH': 503,
550
- };
551
- const statusCode = networkErrorToStatusCode[err.code] || 500;
914
+ if (TraceContextManager.resume(ctx._id) === null) { return; }
915
+ const isIgnoreHttpc = shouldIgnoreError(
916
+ err.code,
917
+ httpc_url,
918
+ httpc_status_ignore,
919
+ httpc_status_ignore_set);
920
+
921
+ if (!isIgnoreHttpc && transaction_status_error_enable && step.error.isZero()) {
922
+ ctx.is_httpc_error = true;
923
+
924
+ step.error = StatError.addError(
925
+ err.code,
926
+ err.message,
927
+ ctx.service_hash,
928
+ TextTypes.HTTPC_URL,
929
+ step.url
930
+ );
931
+
932
+ if (ctx.error.isZero()) {
933
+ ctx.error = step.error;
934
+ ctx.statusCode = err.code;
935
+ ctx.statusMessage = ctx.error_message = err.message;
552
936
 
553
- if (!isIgnoreHttpc && transaction_status_error_enable) {
554
- let error = {
555
- class: err.code,
556
- message: err.message || ''
557
937
  }
558
- interceptorError(statusCode, error, ctx);
559
938
  }
560
- endHttpc(ctx);
939
+
940
+ endHttpc(ctx, step);
561
941
  });
562
942
 
563
943
  shimmer.wrap(req, 'write', function (original) {
@@ -573,15 +953,18 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
573
953
  if (arguments[0] instanceof Buffer) {
574
954
  bodyData = arguments[0].toString('utf8');
575
955
  }
576
- if (bodyData) {
577
- console.log(`body Data: ${bodyData}`)
578
- let paramDatas = ['HTTP-PARAMETERS', options.method, bodyData];
579
- AsyncSender.send_packet(PacketTypeEnum.TX_SECURE_MSG, ctx, paramDatas);
956
+ if(bodyData){
957
+ var step = new MessageStep();
958
+ step.hash = HashUtil.hashFromString("HTTPC-REQUEST-BODY");
959
+ step.start_time = ctx.getElapsedTime();
960
+ step.desc = bodyData;
961
+ DataTextAgent.MESSAGE.add(step.hash, "HTTPC-REQUEST-BODY");
962
+ ctx.profile.push(step);
580
963
  }
581
964
  }
582
965
  }
583
966
  } catch (e) {
584
- Logger.printError('WHATAP-241', 'HTTP Write hook failed', e, false);
967
+ Logger.printError('WHATAP-615', 'HTTP Write hook failed', e, false);
585
968
  }
586
969
  return original.apply(this, arguments);
587
970
  }
@@ -591,18 +974,18 @@ HttpObserver.prototype.inject = function (mod, moduleName) {
591
974
  }
592
975
  });
593
976
 
594
- // HTTP 클라이언트 종료 처리 - 단순화
595
- function endHttpc(ctx) {
596
- if (ctx == null) {
597
- return;
598
- }
977
+ function endHttpc(ctx, step) {
978
+ if(ctx == null || step == null) { return; }
599
979
 
600
- ctx.active_httpc_hash = false;
601
- let urls = `${ctx.httpc_host}:${ctx.httpc_port}${ctx.httpc_url}`;
602
- let httpcDatas = [urls, ctx.mcallee];
603
- ctx.elapsed = Date.now() - ctx.start_time;
604
- TraceHttpc.isSlowHttpc(ctx);
605
- AsyncSender.send_packet(PacketTypeEnum.TX_HTTPC, ctx, httpcDatas);
980
+ step.elapsed = ctx.getElapsedTime() - step.start_time;
981
+ TraceHttpc.isSlowHttpc(ctx, step);
982
+
983
+ ctx.httpc_count++;
984
+ ctx.httpc_time += step.elapsed;
985
+
986
+ MeterHttpC.add(step.host, step.elapsed, step.error.isZero()===false);
987
+ StatHttpc.addHttpcTime(ctx.service_hash, step.url, step.host, step.port, step.elapsed, step.error.isZero()===false);
988
+ ctx.footprint('Http Call Done');
606
989
  }
607
990
  };
608
991
 
@@ -625,4 +1008,51 @@ function shouldIgnoreError(statusCode, url, statusCodeIgnore, statusIgnoreSet) {
625
1008
  return false;
626
1009
  }
627
1010
 
1011
+ function updateNotFoundIgnoreMap(url, url_hash, currentTime) {
1012
+ var ignore_value = httpc_not_found_ignore_map.get(url_hash) || {
1013
+ count: 0, start_time: currentTime, last_time: currentTime, url: url
1014
+ };
1015
+
1016
+ ignore_value.count++;
1017
+ ignore_value.last_time = currentTime;
1018
+
1019
+ if ((ignore_value.last_time - ignore_value.start_time) > httpc_not_found_ignore_time) {
1020
+ ignore_value = { count: 1, start_time: currentTime, last_time: currentTime, url: url };
1021
+ }
1022
+
1023
+ if (ignore_value.count >= 50) {
1024
+ httpc_not_found_ignore_url.add(url);
1025
+ httpc_not_found_ignore_map.remove(url_hash);
1026
+ Logger.print('WHATAP-610', "The ignore option for URL " + url + " is applied.", false);
1027
+ }
1028
+
1029
+ httpc_not_found_ignore_map.put(url_hash, ignore_value);
1030
+ }
1031
+
1032
+ function shouldEndCurrentTransaction(not_found_ignore, ctx, res, requestPath) {
1033
+ if (not_found_ignore) return false;
1034
+ const is_ignore = shouldIgnoreError(res.statusCode, requestPath, status_ignore, status_ignore_set);
1035
+ return !is_ignore;
1036
+ }
1037
+
1038
+ var toParamBytes = function (p, crc) {
1039
+ if (p == null || p.length === 0) {
1040
+ return null;
1041
+ }
1042
+ try {
1043
+ return ParamSecurity.encrypt(Buffer.from(p, 'utf8'), crc);
1044
+ } catch (e) {
1045
+ return null;
1046
+ }
1047
+ };
1048
+
1049
+ function createMtraceId(userAgentString) {
1050
+ // MTraceHelper.createId 구현
1051
+ if (userAgentString) {
1052
+ // userAgent 기반으로 ID 생성
1053
+ return KeyGen.next();
1054
+ }
1055
+ return KeyGen.next();
1056
+ }
1057
+
628
1058
  exports.HttpObserver = HttpObserver;