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,196 +5,253 @@
5
5
  */
6
6
 
7
7
  var TraceContextManager = require('../trace/trace-context-manager'),
8
- SqlStepX = require('../step/sql-stepx'),
9
- ResultSetStep = require('../step/resultset-step'),
10
- DataTextAgent = require('../data/datatext-agent'),
11
- StatError = require('../stat/stat-error'),
12
- TextTypes = require('../lang/text-types'),
13
- hashUtil = require('../util/hashutil'),
14
- Logger = require('../logger');
15
-
16
- var MongodbObserver = function(agent){
8
+ HashUtil = require('../util/hashutil'),
9
+ Logger = require('../logger'),
10
+ conf = require('../conf/configure'),
11
+ AsyncSender = require('../udp/async_sender'),
12
+ PacketTypeEnum = require('../udp/packet_type_enum'),
13
+ shimmer = require('../core/shimmer'),
14
+ AsyncResource = require('async_hooks').AsyncResource;
15
+
16
+ var MongodbObserver = function (agent) {
17
17
  this.agent = agent;
18
18
  this.packages = ['mongodb'];
19
- }
19
+ };
20
20
 
21
- MongodbObserver.prototype.inject = function( mod, moduleName ) {
22
- var self = this;
23
- var aop = self.agent.aop;
21
+ var dbc_hash = 0;
22
+ var dbc = '';
24
23
 
25
- if('instrument' in mod == false) {
26
- return;
27
- }
24
+ var hookedConnections = new WeakSet();
28
25
 
29
- if(mod.__whatap_observe__) { return; }
30
- mod.__whatap_observe__ = true;
26
+ // MongoDB 명령어 매핑
27
+ var MONGODB_COMMANDS = {
28
+ 'insert': 'INSERT',
29
+ 'insertOne': 'INSERTONE',
30
+ 'insertMany': 'INSERTMANY',
31
+ 'find': 'FIND',
32
+ // 'findOne': 'FINDONE',
33
+ 'count': 'COUNT',
34
+ 'countDocuments': 'COUNTDOCUMENTS',
35
+ 'update': 'UPDATE',
36
+ 'updateOne': 'UPDATEONE',
37
+ 'updateMany': 'UPDATEMANY',
38
+ 'delete': 'DELETE',
39
+ 'deleteOne': 'DELETEONE',
40
+ 'deleteMany': 'DELETEMANY',
41
+ 'remove': 'REMOVE',
42
+ 'removeOne': 'REMOVEONE',
43
+ 'removeMany': 'REMOVEMANY',
44
+ 'replaceOne': 'REPLACEONE',
45
+ 'findAndReplace': 'FINDANDREPLACE',
46
+ 'findAndUpdate': 'FINDANDUPDATE',
47
+ 'findAndDelete': 'FINDANDDELETE',
48
+ 'findOneAndUpdate': 'FINDONEANDUPDATE',
49
+ 'findOneAndReplace': 'FINDONEANDREPLACE',
50
+ 'findOneAndDelete': 'FINDONEANDDELETE',
51
+ 'findAndModify': 'FINDANDMODIFY'
52
+ };
31
53
 
32
- Logger.initPrint("MongodbObserver");
33
-
34
- var requestTable = {},
35
- nextRequest,
36
- listener = mod.instrument({}, function(err, instrumentations) {});
37
-
38
- listener.on('started', function (event) {
39
- var requestId = event.requestId, request;
40
- var ctx = TraceContextManager.getCurrentContext();
41
- if(ctx == null) { return; }
42
-
43
- if(nextRequest) {
44
- requestTable[requestId] = { step : nextRequest.step, ctx : nextRequest.ctx };
45
- nextRequest.requestId = requestId;
46
- nextRequest = null;
47
- } else if(event.commandName === 'findandmodify') {
48
- var sql_step = new SqlStepX();
49
- sql_step.start_time = ctx.getElapsedTime();
50
- ctx.profile.add(sql_step);
51
- requestTable[requestId] = {step : sql_step, ctx : ctx};
52
- } else if( requestTable[requestId] == null ) {
53
- return;
54
- }
54
+ // MongoDB 에러 처리
55
+ function handleMongoError(ctx, err) {
56
+ if (!err) return;
55
57
 
56
- var dbc = '',
57
- dbc_hash = 0;
58
- if(event.connectionId) {
59
- var conn = event.connectionId;
60
- dbc = 'mongodb://' + (conn.host || '') + ':' + (conn.port || '') + '/' + (event.databaseName || '');
61
- dbc_hash = hashUtil.hashFromString(dbc);
62
- DataTextAgent.DBC.add(dbc_hash, dbc);
63
- }
64
- request = requestTable[requestId];
65
- request.step.dbc = dbc_hash;
66
-
67
- var dbName = event.databaseName,
68
- collection = event.command[event.commandName],
69
- command = Object.keys(event.command).reduce(function (result, key) {
70
- if(key != event.commandName && key != 'filter' && key != 'documents') {
71
- result[key] = event.command[key];
72
- }
73
- return result;
74
- }, {});
75
- command = JSON.stringify(command).slice(0, 1000);
76
-
77
- var ctx = request.ctx;
78
- ctx.sql_count++;
79
-
80
- var command_string = '', queryKey = '', sql ='', sql_hash = '', crud ='';
81
- if(event.commandName === 'find') {
82
- queryKey = Object.keys(event.command.filter).toString().slice(0, 1000);
83
- command_string = ',key='+queryKey + ',command=' + command;
84
- crud = 'S';
85
- ctx.sql_select++;
86
- } else if(event.commandName === 'insert') {
87
- queryKey = Object.keys(event.command.documents[0]).toString().slice(0, 1000);
88
- command_string = ',documents='+queryKey + ',command=' + command;
89
- crud = 'I';
90
- ctx.sql_insert++;
91
- } else if(event.commandName === 'delete') {
92
- command_string = ',command=' + command;
93
- crud = 'D';
94
- ctx.sql_delete++;
95
- } else if(event.commandName === 'findandmodify') {
96
- command_string = ',command=' + command;
97
- crud = 'U';
98
- ctx.sql_update++;
99
- } else if(event.commandName === 'update') {
100
- command_string = ',command=' + command;
101
- crud = 'U';
102
- ctx.sql_update++;
103
- } else {
104
- ctx.sql_others++;
105
- }
58
+ try {
59
+ var errorClass = err.code || err.name || 'MongoError';
60
+ var errorMessage = err.message || 'mongodb error';
61
+ var errorStack = '';
106
62
 
107
- sql = event.commandName + ' : databaseName=' + dbName +',collection=' + collection + command_string;
108
- sql_hash = hashUtil.hashFromString(sql);
109
- DataTextAgent.SQL.add(sql_hash, sql);
110
- request.step.hash = sql_hash;
111
- request.step.crud = crud.charCodeAt(0);
112
- });
113
-
114
- listener.on('succeeded', function (event) {
115
- var requestId = event.requestId,
116
- request = requestTable[event.requestId];
117
-
118
- if(request == null) {
119
- delete requestTable[requestId];
120
- return;
121
- }
122
-
123
- TraceContextManager.resume(request.ctx._id);
124
- request.step.elapsed = event.duration;
125
- request.ctx.sql_time += request.step.elapsed;
126
-
127
- var command = event.commandName || '';
128
- if(command === 'find' && event.reply) {
129
- var cursor = event.reply.cursor;
130
- if(cursor != null) {
131
- var fetch = cursor.firstBatch.length;
132
- var rs_step = new ResultSetStep();
133
- rs_step.elapsed = 0;
134
- rs_step.dbc = request.step.dbc;
135
- rs_step.sqlhash = request.step.hash;
136
- rs_step.fetch = fetch;
137
- request.ctx.profile.add(rs_step);
63
+ if (conf.trace_sql_error_stack && conf.trace_sql_error_depth && err.stack) {
64
+ var traceDepth = conf.trace_sql_error_depth;
65
+ var stackLines = err.stack.split("\n");
66
+ if (stackLines.length > traceDepth) {
67
+ stackLines = stackLines.slice(0, traceDepth + 1);
138
68
  }
69
+ errorStack = stackLines.join("\n");
139
70
  }
140
71
 
141
- if(command === 'update' && event.reply) {
142
- request.step.updated = event.reply.nModified;
72
+ var shouldAddError = false;
73
+ if (conf._is_trace_ignore_err_cls_contains === true && errorClass &&
74
+ errorClass.toString().indexOf(conf.trace_ignore_err_cls_contains) < 0) {
75
+ shouldAddError = true;
76
+ } else if (conf._is_trace_ignore_err_msg_contains === true && errorMessage &&
77
+ errorMessage.indexOf(conf.trace_ignore_err_msg_contains) < 0) {
78
+ shouldAddError = true;
79
+ } else if (conf._is_trace_ignore_err_cls_contains === false &&
80
+ conf._is_trace_ignore_err_msg_contains === false) {
81
+ shouldAddError = true;
143
82
  }
144
83
 
145
- if(command === 'findandmodify' && event.reply) {
146
- var lastErrorObject = event.reply.lastErrorObject;
147
- request.step.updated = lastErrorObject.n || 0;
84
+ if (shouldAddError) {
85
+ if (!ctx.error) ctx.error = 1;
86
+ ctx.status = 500;
87
+ var errors = [errorClass];
88
+ if (errorMessage) {
89
+ errors.push(errorMessage);
90
+ }
91
+ if (errorStack || err.stack) {
92
+ errors.push(errorStack || err.stack);
93
+ }
94
+
95
+ AsyncSender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors);
148
96
  }
97
+ } catch (e) {
98
+ Logger.printError('WHATAP-242', 'Error handling MongoDB error', e, false);
99
+ }
100
+ }
149
101
 
150
- delete requestTable[requestId];
151
- });
102
+ // Collection 메서드 래퍼 생성
103
+ function createCollectionMethodWrapper(methodName) {
104
+ return function(original) {
105
+ return function wrappedMethod() {
106
+ var ctx = TraceContextManager.getCurrentContext();
107
+ if (!ctx) {
108
+ return original.apply(this, arguments);
109
+ }
152
110
 
153
- listener.on('failed', function (event) {
154
- var requestId = event.requestId,
155
- request = requestTable[event.requestId];
156
- if(request == null) {
157
- delete requestTable[requestId];
158
- return;
159
- }
160
- TraceContextManager.resume(request.ctx._id);
161
- request.step.elapsed = event.duration;
162
- request.ctx.sql_time += request.step.elapsed;
163
-
164
- request.ctx.error_class = event.failure.name || (event.failure.constructor && event.failure.constructor.name) || 'MongoDBError';
165
- request.ctx.error_message = event.failure.message || 'MongoDB error';
166
-
167
- var msgObj = { 'class': event.failure.message, 'msg': event.failure.message };
168
- request.step.error = StatError.addError("mongodb", event.failure.message,
169
- request.ctx.service_hash, TextTypes.SQL, request.step.hash);
170
- if (request.ctx.error.isZero()) {
171
- request.ctx.error = request.step.error;
172
- }
173
-
174
- delete requestTable[requestId];
175
- });
111
+ var args = Array.prototype.slice.call(arguments);
112
+ var collectionName = this.collectionName || this.s?.name || 'unknown';
113
+ var commandName = MONGODB_COMMANDS[methodName] || methodName.toUpperCase();
114
+ var _dbc = this.dbName && dbc.indexOf(this.dbName) === -1 ? dbc + '/' + this.dbName : dbc;
176
115
 
177
- ['cursor', 'insert', 'update', 'remove'].forEach( function(command) {
178
- aop.before(mod.Server.prototype, command, function (obj, args) {
179
- // Select but... DB name undefined return
180
- if(command === 'cursor' && !args[1].find) return;
116
+ const asyncResource = new AsyncResource('mongodb-command');
181
117
 
182
- var ctx = TraceContextManager.getCurrentContext();
183
- if(ctx == null) { return; }
118
+ return asyncResource.runInAsyncScope(() => {
119
+ // DB 연결 패킷 전송
120
+ ctx.start_time = Date.now();
121
+ ctx.elapsed = 0;
122
+ ctx.active_sqlhash = true;
123
+ AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [_dbc]);
184
124
 
185
- var step = new SqlStepX();
186
- step.start_time = ctx.getElapsedTime();
187
- ctx.profile.add(step);
125
+ var command_start_time = Date.now();
126
+ ctx.footprint(`MongoDB ${commandName} Start`);
188
127
 
189
- var req = nextRequest = {step : step, ctx : ctx};
190
- aop.functionHook(args, -1, function (obj, args) {
191
- TraceContextManager.resume(ctx._id);
192
- var requestId = req.requestId;
193
- requestTable[requestId] = undefined;
128
+ // 쿼리 텍스트 구성
129
+ var queryParts = [commandName, collectionName];
130
+ var fieldNames = [];
131
+
132
+ try {
133
+ // 첫 번째 인자에서 필드명 추출 (filter)
134
+ if (args[0] && typeof args[0] === 'object' && !Array.isArray(args[0])) {
135
+ fieldNames = Object.keys(args[0]);
136
+ }
137
+ if (fieldNames.length > 0) {
138
+ queryParts.push('field=[' + fieldNames.join(',') + ']');
139
+ }
140
+ } catch (e) {
141
+ Logger.printError('WHATAP-243', 'Error extracting field names', e, false);
142
+ }
143
+
144
+ var commandText = 'MongoDB ' + queryParts.join(' ');
145
+
146
+ function executeCallback(err, result) {
147
+ try {
148
+ var command_elapsed = Date.now() - command_start_time;
149
+
150
+ if (err) {
151
+ handleMongoError(ctx, err);
152
+ }
153
+
154
+ ctx.elapsed = command_elapsed;
155
+ ctx.active_sqlhash = false;
156
+ AsyncSender.send_packet(PacketTypeEnum.TX_SQL, ctx, [dbc, commandText, '0']);
157
+ ctx.footprint(`MongoDB ${commandName} Done`);
158
+ } catch (e) {
159
+ Logger.printError('WHATAP-244', 'Error in MongoDB callback', e, false);
160
+ }
161
+ }
162
+
163
+ // 콜백 처리
164
+ var hasCallback = false;
165
+ for (var i = args.length - 1; i >= 0; i--) {
166
+ if (typeof args[i] === 'function') {
167
+ hasCallback = true;
168
+ var originalCallback = args[i];
169
+
170
+ args[i] = asyncResource.bind(function() {
171
+ var callbackArgs = Array.prototype.slice.call(arguments);
172
+ executeCallback(callbackArgs[0], callbackArgs[1]);
173
+
174
+ if (originalCallback && typeof originalCallback === 'function') {
175
+ return originalCallback.apply(this, callbackArgs);
176
+ }
177
+ });
178
+ break;
179
+ }
180
+ }
181
+
182
+ try {
183
+ var result = original.apply(this, args);
184
+
185
+ // Promise 기반 처리
186
+ if (!hasCallback && result && typeof result.then === 'function') {
187
+ return result.then(function(res) {
188
+ executeCallback(null, res);
189
+ return res;
190
+ }).catch(function(err) {
191
+ executeCallback(err, null);
192
+ throw err;
193
+ });
194
+ }
195
+
196
+ // 동기적 결과 처리
197
+ if (!hasCallback) {
198
+ executeCallback(null, result);
199
+ }
200
+
201
+ return result;
202
+ } catch (executeError) {
203
+ executeCallback(executeError, null);
204
+ throw executeError;
205
+ }
194
206
  });
195
- });
196
- });
207
+ };
208
+ };
209
+ }
210
+
211
+ // Connection wrapper 함수
212
+ var createConnectionWrapper = function() {
213
+ return function(original) {
214
+ return function wrappedConnect() {
215
+ dbc = this.s && this.s.url ? this.s.url : 'mongodb://localhost:27017';
216
+ dbc_hash = HashUtil.hashFromString(dbc);
217
+ return original.apply(this, arguments);
218
+ };
219
+ };
197
220
  };
198
221
 
199
- exports.MongodbObserver = MongodbObserver;
222
+ MongodbObserver.prototype.inject = function(mod, moduleName) {
223
+ if (mod.__whatap_observe__) {
224
+ return;
225
+ }
226
+ mod.__whatap_observe__ = true;
227
+ Logger.initPrint("MongodbObserver");
228
+
229
+ if (conf.sql_enabled === false) {
230
+ return;
231
+ }
232
+
233
+ var self = this;
234
+
235
+ if (mod.MongoClient && !mod.MongoClient.__whatap_wrapped__) {
236
+ // 정적 connect 메서드 래핑
237
+ if (mod.MongoClient.prototype.connect && !mod.MongoClient.prototype.connect.__whatap_wrapped__) {
238
+ shimmer.wrap(mod.MongoClient.prototype, 'connect', createConnectionWrapper());
239
+ mod.MongoClient.connect.__whatap_wrapped__ = true;
240
+ }
241
+
242
+ mod.MongoClient.__whatap_wrapped__ = true;
243
+ }
244
+
245
+ // Collection 메서드들 래핑
246
+ if (mod.Collection && mod.Collection.prototype && !mod.Collection.__whatap_wrapped__) {
247
+ Object.keys(MONGODB_COMMANDS).forEach(function(methodName) {
248
+ if (mod.Collection.prototype[methodName] && !mod.Collection.prototype[methodName].__whatap_wrapped__) {
249
+ shimmer.wrap(mod.Collection.prototype, methodName, createCollectionMethodWrapper(methodName));
250
+ mod.Collection.prototype[methodName].__whatap_wrapped__ = true;
251
+ }
252
+ });
253
+ mod.Collection.__whatap_wrapped__ = true;
254
+ }
255
+ };
200
256
 
257
+ exports.MongoObserver = MongodbObserver