whatap 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -78
- package/lib/conf/conf-sys-mon.js +101 -0
- package/lib/conf/config-default.js +10 -3
- package/lib/conf/configure.js +369 -349
- package/lib/conf/license.js +1 -1
- package/lib/control/cmd-config.js +24 -0
- package/lib/control/control-handler.js +367 -0
- package/lib/control/packagectr-helper.js +34 -3
- package/lib/core/agent.js +176 -882
- package/lib/core/interceptor.js +6 -6
- package/lib/core/request-agent.js +27 -0
- package/lib/core/shimmer.js +82 -36
- package/lib/counter/counter-manager.js +79 -8
- package/lib/counter/meter/meter-activex.js +67 -0
- package/lib/counter/meter/meter-httpc.js +57 -0
- package/lib/counter/meter/meter-resource.js +9 -0
- package/lib/counter/meter/meter-service.js +168 -0
- package/lib/counter/meter/meter-socket.io.js +51 -0
- package/lib/counter/meter/meter-sql.js +71 -0
- package/lib/counter/meter/meter-users.js +58 -0
- package/lib/counter/meter.js +183 -0
- package/lib/counter/task/activetransaction.js +68 -17
- package/lib/counter/task/agentinfo.js +107 -0
- package/lib/{system → counter/task}/gc-action.js +27 -74
- package/lib/counter/task/gcstat.js +34 -0
- package/lib/counter/task/heapmem.js +25 -0
- package/lib/counter/task/httpc.js +76 -0
- package/lib/counter/task/metering-info.js +125 -0
- package/lib/counter/task/proc-cpu.js +29 -0
- package/lib/counter/task/realtimeuser.js +31 -0
- package/lib/counter/task/res/systemECSTask.js +39 -0
- package/lib/counter/task/res/systemKubeTask.js +53 -0
- package/lib/counter/task/res/util/awsEcsClientThread.js +218 -0
- package/lib/counter/task/res/util/linuxProcStatUtil.js +14 -0
- package/lib/counter/task/res-sys-cpu.js +62 -0
- package/lib/counter/task/service.js +202 -0
- package/lib/counter/task/socketio.js +30 -0
- package/lib/counter/task/sql.js +105 -0
- package/lib/counter/task/systemperf.js +43 -0
- package/lib/data/datapack-sender.js +289 -0
- package/lib/data/dataprofile-agent.js +162 -0
- package/lib/data/datatext-agent.js +135 -0
- package/lib/data/event-level.js +15 -0
- package/lib/data/test.js +49 -0
- package/lib/data/zipprofile.js +197 -0
- package/lib/env/constants.js +21 -0
- package/lib/error/error-handler.js +437 -0
- package/lib/io/data-inputx.js +13 -3
- package/lib/io/data-outputx.js +268 -206
- package/lib/kube/kube-client.js +144 -0
- package/lib/lang/text-types.js +58 -0
- package/lib/logger.js +6 -6
- package/lib/logsink/line-log-util.js +87 -0
- package/lib/logsink/line-log.js +12 -0
- package/lib/logsink/log-sender.js +78 -0
- package/lib/logsink/log-tracer.js +40 -0
- package/lib/logsink/sender-util.js +56 -0
- package/lib/logsink/zip/zip-send.js +177 -0
- package/lib/net/netflag.js +55 -0
- package/lib/net/receiver.js +66 -0
- package/lib/net/security-master.js +139 -20
- package/lib/net/sender.js +141 -0
- package/lib/net/tcp-return.js +18 -0
- package/lib/net/tcp-session.js +286 -0
- package/lib/net/tcpreq-client-proxy.js +70 -0
- package/lib/net/tcprequest-mgr.js +58 -0
- package/lib/observers/apollo-server-observer.js +33 -27
- package/lib/observers/cluster-observer.js +22 -0
- package/lib/observers/express-observer.js +215 -0
- package/lib/observers/file-observer.js +184 -0
- package/lib/observers/global-observer.js +155 -80
- package/lib/observers/grpc-observer.js +336 -0
- package/lib/observers/http-observer.js +666 -236
- package/lib/observers/maria-observer.js +204 -362
- package/lib/observers/memcached-observer.js +56 -0
- package/lib/observers/mongo-observer.js +317 -0
- package/lib/observers/mongodb-observer.js +169 -226
- package/lib/observers/mongoose-observer.js +518 -323
- package/lib/observers/mssql-observer.js +177 -418
- package/lib/observers/mysql-observer.js +342 -449
- package/lib/observers/mysql2-observer.js +396 -358
- package/lib/observers/net-observer.js +77 -0
- package/lib/observers/oracle-observer.js +559 -384
- package/lib/observers/pgsql-observer.js +231 -489
- package/lib/observers/prisma-observer.js +303 -92
- package/lib/observers/process-observer.js +79 -35
- package/lib/observers/promise-observer.js +31 -0
- package/lib/observers/redis-observer.js +166 -331
- package/lib/observers/schedule-observer.js +67 -0
- package/lib/observers/socket.io-observer.js +226 -187
- package/lib/observers/stream-observer.js +19 -0
- package/lib/observers/thrift-observer.js +197 -0
- package/lib/observers/websocket-observer.js +175 -301
- package/lib/pack/activestack-pack.js +55 -0
- package/lib/pack/apenum.js +8 -0
- package/lib/pack/counter-pack.js +3 -0
- package/lib/pack/errorsnap-pack.js +69 -0
- package/lib/pack/event-pack.js +54 -0
- package/lib/pack/hitmap-pack.js +63 -0
- package/lib/pack/hitmap-pack1.js +152 -0
- package/lib/pack/log-sink-pack.js +14 -52
- package/lib/pack/netstat.js +15 -0
- package/lib/pack/otype.js +7 -0
- package/lib/pack/profile-pack.js +49 -0
- package/lib/pack/realtimeuser-pack.js +41 -0
- package/lib/pack/stat-general-pack.js +96 -0
- package/lib/pack/staterror-pack.js +120 -0
- package/lib/pack/stathttpc-pack.js +66 -0
- package/lib/pack/stathttpc-rec.js +78 -0
- package/lib/pack/statremote-pack.js +46 -0
- package/lib/pack/statservice-pack.js +63 -0
- package/lib/pack/statservice-pack1.js +88 -0
- package/lib/pack/statservice-rec.js +292 -0
- package/lib/pack/statservice-rec_dep.js +151 -0
- package/lib/pack/statsql-pack.js +69 -0
- package/lib/pack/statsql-rec.js +100 -0
- package/lib/pack/statuseragent-pack.js +44 -0
- package/lib/pack/tagcount-pack.js +4 -4
- package/lib/pack/tagctr.js +15 -0
- package/lib/pack/text-pack.js +50 -0
- package/lib/pack/time-count.js +25 -0
- package/lib/pack/websocket.js +15 -0
- package/lib/pack/zip-pack.js +70 -0
- package/lib/pii/pii-item.js +31 -0
- package/lib/pii/pii-mask.js +174 -0
- package/lib/plugin/plugin-loadermanager.js +57 -0
- package/lib/plugin/plugin.js +75 -0
- package/lib/service/tx-record.js +332 -0
- package/lib/stat/stat-error.js +116 -0
- package/lib/stat/stat-httpc.js +98 -0
- package/lib/stat/stat-remote-ip.js +46 -0
- package/lib/stat/stat-remote-ipurl.js +88 -0
- package/lib/stat/stat-sql.js +113 -0
- package/lib/stat/stat-tranx.js +58 -0
- package/lib/stat/stat-tx-caller.js +160 -0
- package/lib/stat/stat-tx-domain.js +111 -0
- package/lib/stat/stat-tx-referer.js +112 -0
- package/lib/stat/stat-useragent.js +48 -0
- package/lib/stat/timingsender.js +76 -0
- package/lib/step/activestack-step.js +38 -0
- package/lib/step/dbc-step.js +36 -0
- package/lib/step/http-stepx.js +67 -0
- package/lib/step/message-step.js +40 -0
- package/lib/step/method-stepx.js +45 -0
- package/lib/step/resultset-step.js +40 -0
- package/lib/step/securemsg-step.js +44 -0
- package/lib/step/socket-step.js +46 -0
- package/lib/step/sql-stepx.js +68 -0
- package/lib/step/sqlxtype.js +16 -0
- package/lib/step/step.js +66 -0
- package/lib/step/stepenum.js +54 -0
- package/lib/topology/link.js +63 -0
- package/lib/topology/nodeinfo.js +123 -0
- package/lib/topology/status-detector.js +111 -0
- package/lib/trace/trace-context-manager.js +113 -25
- package/lib/trace/trace-context.js +21 -7
- package/lib/trace/trace-httpc.js +17 -11
- package/lib/trace/trace-sql.js +29 -21
- package/lib/util/anylist.js +103 -0
- package/lib/util/cardinality/hyperloglog.js +106 -0
- package/lib/util/cardinality/murmurhash.js +31 -0
- package/lib/util/cardinality/registerset.js +75 -0
- package/lib/util/errordata.js +21 -0
- package/lib/util/escape-literal-sql.js +5 -5
- package/lib/util/hashutil.js +18 -18
- package/lib/util/iputil_x.js +527 -0
- package/lib/util/keygen.js +0 -3
- package/lib/util/kube-util.js +73 -0
- package/lib/util/linkedset.js +1 -2
- package/lib/util/nodeutil.js +2 -1
- package/lib/util/paramsecurity.js +80 -0
- package/lib/util/pre-process.js +13 -0
- package/lib/util/process-seq.js +166 -0
- package/lib/util/property-util.js +36 -0
- package/lib/util/request-queue.js +70 -0
- package/lib/util/requestdouble-queue.js +72 -0
- package/lib/util/resourceprofile.js +157 -0
- package/lib/util/stop-watch.js +30 -0
- package/lib/util/system-util.js +10 -0
- package/lib/util/userid-util.js +57 -0
- package/lib/value/map-value.js +3 -2
- package/package.json +9 -4
- package/whatap.conf +1 -4
- package/agent/darwin/arm64/whatap_nodejs +0 -0
- package/agent/linux/amd64/whatap_nodejs +0 -0
- package/agent/linux/arm64/whatap_nodejs +0 -0
- package/build.txt +0 -4
- package/lib/observers/ioredis-observer.js +0 -294
- package/lib/udp/async_sender.js +0 -119
- package/lib/udp/index.js +0 -17
- package/lib/udp/packet_enum.js +0 -52
- package/lib/udp/packet_queue.js +0 -69
- package/lib/udp/packet_type_enum.js +0 -33
- package/lib/udp/param_def.js +0 -72
- package/lib/udp/udp_session.js +0 -336
- package/lib/util/sql-util.js +0 -178
- package/lib/util/trace-helper.js +0 -91
- package/lib/util/transfer.js +0 -58
|
@@ -1,388 +1,583 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2016 the WHATAP project authors. All rights reserved.
|
|
3
|
-
* Use of this source code is governed by a license that
|
|
4
|
-
* can be found in the LICENSE file.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
SqlStepX = require('../step/sql-stepx'),
|
|
3
|
+
DataTextAgent = require('../data/datatext-agent'),
|
|
4
|
+
HashUtil = require('../util/hashutil');
|
|
5
|
+
const DBCStep = require("../step/dbc-step");
|
|
6
|
+
const Logger = require("../logger");
|
|
7
|
+
const ParamSecurity = require("../util/paramsecurity");
|
|
8
|
+
const {Buffer} = require("buffer");
|
|
9
|
+
const conf = require('../conf/configure');
|
|
10
|
+
const shimmer = require('../core/shimmer');
|
|
15
11
|
|
|
16
12
|
var MongooseObserver = function (agent) {
|
|
17
13
|
this.agent = agent;
|
|
18
14
|
this.packages = ['mongoose'];
|
|
19
15
|
};
|
|
20
16
|
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'findOneAndUpdate'
|
|
37
|
-
'findByIdAndUpdate'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'findOneAndDelete'
|
|
41
|
-
'findByIdAndDelete'
|
|
42
|
-
'
|
|
17
|
+
var dbc_step, dbc, conn_dbc_hash;
|
|
18
|
+
|
|
19
|
+
// 단일 필터 메서드 (첫 번째 인자가 filter)
|
|
20
|
+
const collectionMethodsWithFilter = [
|
|
21
|
+
'find',
|
|
22
|
+
// 'findById',
|
|
23
|
+
'findOne',
|
|
24
|
+
'countDocuments',
|
|
25
|
+
'distinct',
|
|
26
|
+
'deleteOne',
|
|
27
|
+
'deleteMany'
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// 이중 필터 메서드 (첫 번째: filter, 두 번째: update)
|
|
31
|
+
const collectionMethodsWithTwoFilters = [
|
|
32
|
+
'findOneAndUpdate',
|
|
33
|
+
// 'findByIdAndUpdate',
|
|
34
|
+
'updateOne',
|
|
35
|
+
'updateMany',
|
|
36
|
+
'findOneAndDelete',
|
|
37
|
+
// 'findByIdAndDelete',
|
|
38
|
+
'replaceOne'
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// 특수 메서드
|
|
42
|
+
const specialMethods = [
|
|
43
|
+
'create',
|
|
44
|
+
'insertMany',
|
|
45
|
+
'aggregate'
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
MongooseObserver.prototype.inject = function (mod, modName) {
|
|
49
|
+
var self = this;
|
|
50
|
+
|
|
51
|
+
// mongoose.connect 후킹 (연결 정보 저장)
|
|
52
|
+
shimmer.wrap(mod, 'connect', function(originalConnect) {
|
|
53
|
+
return function wrappedConnect() {
|
|
54
|
+
if (arguments[0]) {
|
|
55
|
+
dbc = arguments[0];
|
|
56
|
+
conn_dbc_hash = HashUtil.hashFromString(dbc);
|
|
57
|
+
}
|
|
58
|
+
return originalConnect.apply(this, arguments);
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Model 생성 후킹
|
|
63
|
+
shimmer.wrap(mod, 'model', function(originalModel) {
|
|
64
|
+
return function wrappedModel() {
|
|
65
|
+
const model = originalModel.apply(this, arguments);
|
|
66
|
+
|
|
67
|
+
// 생성된 Model에 메서드 패치 적용
|
|
68
|
+
self.patchModelMethods(model);
|
|
69
|
+
|
|
70
|
+
return model;
|
|
71
|
+
};
|
|
72
|
+
});
|
|
43
73
|
};
|
|
44
74
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
dbc_hash = HashUtil.hashFromString(dbc);
|
|
50
|
-
Logger.print('WHATAP-MONGOOSE-DBC', 'DBC setup: ' + dbc, false);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
75
|
+
MongooseObserver.prototype.patchModelMethods = function(Model) {
|
|
76
|
+
if(Model.__whatap_observe__) {return;}
|
|
77
|
+
Model.__whatap_observe__ = true;
|
|
78
|
+
var self = this;
|
|
53
79
|
|
|
54
|
-
//
|
|
55
|
-
function
|
|
56
|
-
|
|
80
|
+
// 단일 필터 메서드 패치
|
|
81
|
+
collectionMethodsWithFilter.forEach(function(methodName) {
|
|
82
|
+
if (Model[methodName]) {
|
|
83
|
+
shimmer.wrap(Model, methodName, function(originalMethod) {
|
|
84
|
+
return self.createSingleFilterWrapper(originalMethod, methodName);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
57
88
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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);
|
|
68
|
-
}
|
|
69
|
-
errorStack = stackLines.join("\n");
|
|
89
|
+
// 이중 필터 메서드 패치
|
|
90
|
+
collectionMethodsWithTwoFilters.forEach(function(methodName) {
|
|
91
|
+
if (Model[methodName]) {
|
|
92
|
+
shimmer.wrap(Model, methodName, function(originalMethod) {
|
|
93
|
+
return self.createDoubleFilterWrapper(originalMethod, methodName);
|
|
94
|
+
});
|
|
70
95
|
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// aggregate 메서드 패치
|
|
99
|
+
if (Model.aggregate) {
|
|
100
|
+
shimmer.wrap(Model, 'aggregate', function(originalAggregate) {
|
|
101
|
+
return self.createAggregateWrapper(originalAggregate);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
71
104
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
105
|
+
// create, insertMany 패치
|
|
106
|
+
['create', 'insertMany'].forEach(function(methodName) {
|
|
107
|
+
if (Model[methodName]) {
|
|
108
|
+
shimmer.wrap(Model, methodName, function(originalMethod) {
|
|
109
|
+
return self.createInsertWrapper(originalMethod, methodName);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
MongooseObserver.prototype.createSingleFilterWrapper = function(originalMethod, methodName) {
|
|
116
|
+
var self = this;
|
|
117
|
+
|
|
118
|
+
return function wrappedSingleFilter() {
|
|
119
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
120
|
+
if (!ctx) {
|
|
121
|
+
return originalMethod.apply(this, arguments);
|
|
82
122
|
}
|
|
123
|
+
ctx.__mongoose_traced__ = true;
|
|
124
|
+
|
|
125
|
+
const dbc_step = self.createDBCStep(ctx);
|
|
126
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
127
|
+
ctx.profile.push(dbc_step);
|
|
128
|
+
|
|
129
|
+
// SQL Step 생성
|
|
130
|
+
const sql_step = new SqlStepX();
|
|
131
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
132
|
+
|
|
133
|
+
const result = originalMethod.apply(this, arguments);
|
|
134
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const filterObj = arguments[0];
|
|
138
|
+
const parseResult = self.parseSingleFilter(methodName, filterObj);
|
|
83
139
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
140
|
+
// SQL 문자열 생성: "ModelName methodName where=[field1,field2]"
|
|
141
|
+
const modelName = this.modelName || 'Unknown';
|
|
142
|
+
let sql = `${modelName} ${methodName}`;
|
|
143
|
+
|
|
144
|
+
if (parseResult.whereFields.length > 0) {
|
|
145
|
+
sql += ` where=[${parseResult.whereFields.join(',')}]`;
|
|
90
146
|
}
|
|
91
|
-
|
|
92
|
-
|
|
147
|
+
|
|
148
|
+
// SQL Step 완성
|
|
149
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
150
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
151
|
+
|
|
152
|
+
// 파라미터 암호화 처리
|
|
153
|
+
if (conf.getProperty('profile_mongodb_param_enabled', false) === true &&
|
|
154
|
+
parseResult.values.length > 0) {
|
|
155
|
+
sql_step.setTrue(1);
|
|
156
|
+
var crc = {value: 0};
|
|
157
|
+
const valuesString = parseResult.values.map(val => {
|
|
158
|
+
if (typeof val === 'string') {
|
|
159
|
+
return `'${val}'`;
|
|
160
|
+
}
|
|
161
|
+
return val;
|
|
162
|
+
}).toString();
|
|
163
|
+
sql_step.p2 = toParamBytes(valuesString, crc);
|
|
164
|
+
sql_step.pcrc = crc.value;
|
|
93
165
|
}
|
|
94
166
|
|
|
95
|
-
|
|
167
|
+
ctx.profile.push(sql_step);
|
|
168
|
+
|
|
169
|
+
} catch (e) {
|
|
170
|
+
Logger.printError("WHATAP-611", "Mongodb single filter query error", e, false);
|
|
96
171
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
172
|
+
|
|
173
|
+
return result;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
MongooseObserver.prototype.createDoubleFilterWrapper = function(originalMethod, methodName) {
|
|
178
|
+
var self = this;
|
|
179
|
+
|
|
180
|
+
return function wrappedDoubleFilter() {
|
|
181
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
182
|
+
if (!ctx) {
|
|
183
|
+
return originalMethod.apply(this, arguments);
|
|
184
|
+
}
|
|
185
|
+
ctx.__mongoose_traced__ = true;
|
|
186
|
+
|
|
187
|
+
// DBC Step 생성
|
|
188
|
+
const dbc_step = self.createDBCStep(ctx);
|
|
189
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
190
|
+
ctx.profile.push(dbc_step);
|
|
191
|
+
|
|
192
|
+
// SQL Step 생성
|
|
193
|
+
const sql_step = new SqlStepX();
|
|
194
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
195
|
+
|
|
196
|
+
const result = originalMethod.apply(this, arguments);
|
|
197
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const filterObj = arguments[0];
|
|
201
|
+
const updateObj = arguments[1];
|
|
202
|
+
const parseResult = self.parseDoubleFilter(methodName, filterObj, updateObj);
|
|
203
|
+
|
|
204
|
+
// SQL 문자열 생성: "ModelName methodName where=[field1] field=[field2,field3]"
|
|
205
|
+
const modelName = this.modelName || 'Unknown';
|
|
206
|
+
let sql = `${modelName} ${methodName}`;
|
|
207
|
+
|
|
208
|
+
if (parseResult.whereFields.length > 0) {
|
|
209
|
+
sql += ` where=[${parseResult.whereFields.join(',')}]`;
|
|
109
210
|
}
|
|
110
211
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const asyncResource = new AsyncResource('mongoose-command');
|
|
116
|
-
|
|
117
|
-
return asyncResource.runInAsyncScope(() => {
|
|
118
|
-
// DB 연결 패킷 전송
|
|
119
|
-
ctx.start_time = Date.now();
|
|
120
|
-
ctx.elapsed = 0;
|
|
121
|
-
AsyncSender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, [dbc]);
|
|
122
|
-
|
|
123
|
-
var command_start_time = Date.now();
|
|
124
|
-
ctx.footprint(`Mongoose ${commandName} Start`);
|
|
125
|
-
|
|
126
|
-
// 쿼리 텍스트 구성
|
|
127
|
-
var queryParts = [commandName, modelName];
|
|
128
|
-
var fieldNames = [];
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
if (methodName === 'aggregate' && Array.isArray(args[0])) {
|
|
132
|
-
// aggregate 파이프라인 처리
|
|
133
|
-
var pipelineFields = [];
|
|
134
|
-
args[0].forEach(function(stage) {
|
|
135
|
-
if (stage.$match) {
|
|
136
|
-
pipelineFields = pipelineFields.concat(Object.keys(stage.$match));
|
|
137
|
-
}
|
|
138
|
-
if (stage.$group) {
|
|
139
|
-
pipelineFields = pipelineFields.concat(Object.keys(stage.$group));
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
if (pipelineFields.length > 0) {
|
|
143
|
-
queryParts.push('field=[' + pipelineFields.join(',') + ']');
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
// 첫 번째 인자에서 필드명 추출
|
|
147
|
-
if (args[0] && typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
148
|
-
fieldNames = Object.keys(args[0]);
|
|
149
|
-
}
|
|
150
|
-
if (fieldNames.length > 0) {
|
|
151
|
-
queryParts.push('field=[' + fieldNames.join(',') + ']');
|
|
152
|
-
}
|
|
212
|
+
if (parseResult.updateFields.length > 0) {
|
|
213
|
+
sql += ` field=[${parseResult.updateFields.join(',')}]`;
|
|
214
|
+
}
|
|
153
215
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
}
|
|
216
|
+
// SQL Step 완성
|
|
217
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
218
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
219
|
+
|
|
220
|
+
// 파라미터 암호화 처리 (where 값 + update 값)
|
|
221
|
+
if (conf.getProperty('profile_mongodb_param_enabled', false) === true && parseResult.values.length > 0) {
|
|
222
|
+
sql_step.setTrue(1);
|
|
223
|
+
var crc = {value: 0};
|
|
224
|
+
const valuesString = parseResult.values.map(val => {
|
|
225
|
+
if (typeof val === 'string') {
|
|
226
|
+
return `'${val}'`;
|
|
167
227
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
228
|
+
return val;
|
|
229
|
+
}).toString();
|
|
230
|
+
sql_step.p2 = toParamBytes(valuesString, crc);
|
|
231
|
+
sql_step.pcrc = crc.value;
|
|
232
|
+
}
|
|
171
233
|
|
|
172
|
-
|
|
234
|
+
ctx.profile.push(sql_step);
|
|
173
235
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
236
|
+
} catch (e) {
|
|
237
|
+
Logger.printError("WHATAP-611", "Mongodb double filter query error", e, false);
|
|
238
|
+
}
|
|
177
239
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
240
|
+
return result;
|
|
241
|
+
};
|
|
242
|
+
};
|
|
181
243
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
ctx.footprint(`Mongoose ${commandName} Done`);
|
|
185
|
-
} catch (e) {
|
|
186
|
-
Logger.printError('WHATAP-247', 'Error in Mongoose callback', e, false);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
244
|
+
MongooseObserver.prototype.createAggregateWrapper = function(originalAggregate) {
|
|
245
|
+
var self = this;
|
|
189
246
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
args[i] = asyncResource.bind(function() {
|
|
198
|
-
var callbackArgs = Array.prototype.slice.call(arguments);
|
|
199
|
-
executeCallback(callbackArgs[0], callbackArgs[1]);
|
|
200
|
-
|
|
201
|
-
if (originalCallback && typeof originalCallback === 'function') {
|
|
202
|
-
return originalCallback.apply(this, callbackArgs);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
247
|
+
return function wrappedAggregate() {
|
|
248
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
249
|
+
if (!ctx) {
|
|
250
|
+
return originalAggregate.apply(this, arguments);
|
|
251
|
+
}
|
|
252
|
+
ctx.__mongoose_traced__ = true;
|
|
208
253
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
254
|
+
const dbc_step = self.createDBCStep(ctx);
|
|
255
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
256
|
+
ctx.profile.push(dbc_step);
|
|
257
|
+
|
|
258
|
+
// SQL Step 생성
|
|
259
|
+
const sql_step = new SqlStepX();
|
|
260
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
261
|
+
|
|
262
|
+
const result = originalAggregate.apply(this, arguments);
|
|
263
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const pipeline = arguments[0];
|
|
267
|
+
const parseResult = self.parseAggregatePipeline(pipeline);
|
|
268
|
+
|
|
269
|
+
// SQL 문자열 생성
|
|
270
|
+
const modelName = this.modelName || 'Unknown';
|
|
271
|
+
let sql = `${modelName} aggregate`;
|
|
222
272
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
273
|
+
if (parseResult.matchFields.length > 0) {
|
|
274
|
+
sql += ` where=[${parseResult.matchFields.join(',')}]`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (parseResult.groupFields.length > 0) {
|
|
278
|
+
sql += ` group=[${parseResult.groupFields.join(',')}]`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (parseResult.projectFields.length > 0) {
|
|
282
|
+
sql += ` field=[${parseResult.projectFields.join(',')}]`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// SQL Step 완성
|
|
286
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
287
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
288
|
+
|
|
289
|
+
// 파라미터 암호화 처리 (주로 $match 조건값들)
|
|
290
|
+
if (conf.getProperty('profile_mongodb_param_enabled', false) === true &&
|
|
291
|
+
parseResult.values.length > 0) {
|
|
292
|
+
sql_step.setTrue(1);
|
|
293
|
+
var crc = {value: 0};
|
|
294
|
+
const valuesString = parseResult.values.map(val => {
|
|
295
|
+
if (typeof val === 'string') {
|
|
296
|
+
return `'${val}'`;
|
|
226
297
|
}
|
|
298
|
+
return val;
|
|
299
|
+
}).toString();
|
|
300
|
+
sql_step.p2 = toParamBytes(valuesString, crc);
|
|
301
|
+
sql_step.pcrc = crc.value;
|
|
302
|
+
}
|
|
227
303
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
304
|
+
ctx.profile.push(sql_step);
|
|
305
|
+
|
|
306
|
+
} catch (e) {
|
|
307
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate query error", e, false);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return result;
|
|
235
311
|
};
|
|
236
|
-
}
|
|
312
|
+
};
|
|
237
313
|
|
|
238
|
-
|
|
239
|
-
var
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
314
|
+
MongooseObserver.prototype.createInsertWrapper = function(originalMethod, methodName) {
|
|
315
|
+
var self = this;
|
|
316
|
+
|
|
317
|
+
return function wrappedInsert() {
|
|
318
|
+
const ctx = TraceContextManager.getCurrentContext();
|
|
319
|
+
if (!ctx) {
|
|
320
|
+
return originalMethod.apply(this, arguments);
|
|
321
|
+
}
|
|
322
|
+
ctx.__mongoose_traced__ = true;
|
|
323
|
+
|
|
324
|
+
const dbc_step = self.createDBCStep(ctx);
|
|
325
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
326
|
+
ctx.profile.push(dbc_step);
|
|
327
|
+
|
|
328
|
+
// SQL Step 생성
|
|
329
|
+
const sql_step = new SqlStepX();
|
|
330
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
331
|
+
|
|
332
|
+
const result = originalMethod.apply(this, arguments);
|
|
333
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
245
334
|
|
|
246
|
-
|
|
335
|
+
try {
|
|
336
|
+
const docs = arguments[0];
|
|
337
|
+
const parseResult = self.parseInsertDocuments(methodName, docs);
|
|
247
338
|
|
|
248
|
-
|
|
249
|
-
|
|
339
|
+
// SQL 문자열 생성
|
|
340
|
+
const modelName = this.modelName || 'Unknown';
|
|
341
|
+
let sql = `${modelName} ${methodName}`;
|
|
342
|
+
|
|
343
|
+
if (parseResult.insertFields.length > 0) {
|
|
344
|
+
sql += ` field=[${parseResult.insertFields.join(',')}]`;
|
|
250
345
|
}
|
|
251
346
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
var callbackArgs = Array.prototype.slice.call(arguments);
|
|
265
|
-
var err = callbackArgs[0];
|
|
266
|
-
|
|
267
|
-
if (ctx) {
|
|
268
|
-
ctx.elapsed = Date.now() - ctx.start_time;
|
|
269
|
-
ctx.db_opening = false;
|
|
270
|
-
|
|
271
|
-
if (err) {
|
|
272
|
-
handleMongooseError(ctx, err);
|
|
273
|
-
ctx.footprint('Mongoose Connecting Error');
|
|
274
|
-
} else {
|
|
275
|
-
ctx.footprint('Mongoose Connecting Done');
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return originalCallback.apply(this, callbackArgs);
|
|
280
|
-
});
|
|
281
|
-
break;
|
|
347
|
+
// SQL Step 완성
|
|
348
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
349
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
350
|
+
|
|
351
|
+
// 파라미터 암호화 처리
|
|
352
|
+
if (conf.getProperty('profile_mongodb_param_enabled', false) === true &&
|
|
353
|
+
parseResult.values.length > 0) {
|
|
354
|
+
sql_step.setTrue(1);
|
|
355
|
+
var crc = {value: 0};
|
|
356
|
+
const valuesString = parseResult.values.map(val => {
|
|
357
|
+
if (typeof val === 'string') {
|
|
358
|
+
return `'${val}'`;
|
|
282
359
|
}
|
|
283
|
-
|
|
360
|
+
return val;
|
|
361
|
+
}).toString();
|
|
362
|
+
sql_step.p2 = toParamBytes(valuesString, crc);
|
|
363
|
+
sql_step.pcrc = crc.value;
|
|
364
|
+
}
|
|
284
365
|
|
|
285
|
-
|
|
366
|
+
ctx.profile.push(sql_step);
|
|
286
367
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (ctx) {
|
|
291
|
-
ctx.elapsed = Date.now() - ctx.start_time;
|
|
292
|
-
ctx.db_opening = false;
|
|
293
|
-
ctx.footprint('Mongoose Connecting Done');
|
|
294
|
-
}
|
|
368
|
+
} catch (e) {
|
|
369
|
+
Logger.printError("WHATAP-611", "Mongodb insert query error", e, false);
|
|
370
|
+
}
|
|
295
371
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
372
|
+
return result;
|
|
373
|
+
};
|
|
374
|
+
};
|
|
300
375
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
handleMongooseError(ctx, err);
|
|
308
|
-
}
|
|
309
|
-
throw err;
|
|
310
|
-
}));
|
|
311
|
-
}
|
|
376
|
+
MongooseObserver.prototype.createDBCStep = function(ctx) {
|
|
377
|
+
if (dbc && conn_dbc_hash) {
|
|
378
|
+
DataTextAgent.DBC.add(conn_dbc_hash, dbc);
|
|
379
|
+
DataTextAgent.METHOD.add(conn_dbc_hash, dbc);
|
|
380
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, dbc);
|
|
381
|
+
}
|
|
312
382
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
383
|
+
var dbc_step = new DBCStep();
|
|
384
|
+
dbc_step.hash = conn_dbc_hash;
|
|
385
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
386
|
+
|
|
387
|
+
return dbc_step;
|
|
317
388
|
};
|
|
318
389
|
|
|
319
|
-
//
|
|
320
|
-
function
|
|
321
|
-
|
|
322
|
-
Object.keys(MONGOOSE_COMMANDS).forEach(function(methodName) {
|
|
323
|
-
if (ModelConstructor.prototype[methodName] &&
|
|
324
|
-
!ModelConstructor.prototype[methodName].__whatap_wrapped__) {
|
|
390
|
+
// 비동기 결과 처리
|
|
391
|
+
MongooseObserver.prototype.handleAsyncResult = function(result, ctx, methodName) {
|
|
392
|
+
ctx.footprint('Mongodb Command Start: ' + methodName);
|
|
325
393
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
394
|
+
// Promise인 경우 처리 (대부분의 Mongoose 메서드가 Promise 반환)
|
|
395
|
+
if (result && typeof result.then === 'function') {
|
|
396
|
+
// 이미 실행은 완료되었으므로 특별한 처리 불필요
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return result;
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// 단일 필터 파싱
|
|
404
|
+
MongooseObserver.prototype.parseSingleFilter = function(methodName, filterObj) {
|
|
405
|
+
const result = {
|
|
406
|
+
whereFields: [],
|
|
407
|
+
values: []
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
if (filterObj && typeof filterObj === 'object') {
|
|
411
|
+
this.extractFieldsAndValues(filterObj, result.whereFields, result.values);
|
|
333
412
|
}
|
|
334
|
-
}
|
|
335
413
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
414
|
+
return result;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// 이중 필터 파싱 - 수정된 버전
|
|
418
|
+
MongooseObserver.prototype.parseDoubleFilter = function(methodName, filterObj, updateObj) {
|
|
419
|
+
const result = {
|
|
420
|
+
whereFields: [],
|
|
421
|
+
updateFields: [],
|
|
422
|
+
values: []
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// where 조건 파싱
|
|
426
|
+
if (filterObj && typeof filterObj === 'object') {
|
|
427
|
+
this.extractFieldsAndValues(filterObj, result.whereFields, result.values);
|
|
339
428
|
}
|
|
340
|
-
mod.__whatap_observe__ = true;
|
|
341
|
-
Logger.initPrint("MongooseObserver");
|
|
342
429
|
|
|
343
|
-
|
|
344
|
-
|
|
430
|
+
// update 조건 파싱 - 수정된 로직
|
|
431
|
+
if (updateObj && typeof updateObj === 'object') {
|
|
432
|
+
this.extractUpdateFieldsOnly(updateObj, result.updateFields, result.values);
|
|
345
433
|
}
|
|
346
434
|
|
|
347
|
-
|
|
435
|
+
return result;
|
|
436
|
+
};
|
|
348
437
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
438
|
+
// Aggregate pipeline 파싱
|
|
439
|
+
MongooseObserver.prototype.parseAggregatePipeline = function(pipeline) {
|
|
440
|
+
const result = {
|
|
441
|
+
matchFields: [],
|
|
442
|
+
groupFields: [],
|
|
443
|
+
projectFields: [],
|
|
444
|
+
values: []
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
if (Array.isArray(pipeline)) {
|
|
448
|
+
pipeline.forEach(stage => {
|
|
449
|
+
if (stage.$match) {
|
|
450
|
+
this.extractFieldsAndValues(stage.$match, result.matchFields, result.values);
|
|
451
|
+
}
|
|
452
|
+
if (stage.$group) {
|
|
453
|
+
this.extractGroupFields(stage.$group, result.groupFields);
|
|
454
|
+
}
|
|
455
|
+
if (stage.$project) {
|
|
456
|
+
this.extractProjectFields(stage.$project, result.projectFields);
|
|
457
|
+
}
|
|
458
|
+
});
|
|
353
459
|
}
|
|
354
460
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
461
|
+
return result;
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
// Insert documents 파싱
|
|
465
|
+
MongooseObserver.prototype.parseInsertDocuments = function(methodName, docs) {
|
|
466
|
+
const result = {
|
|
467
|
+
insertFields: [],
|
|
468
|
+
values: []
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
if (methodName === 'insertMany' && Array.isArray(docs)) {
|
|
472
|
+
// 첫 번째 문서의 필드들을 기준으로 함
|
|
473
|
+
if (docs.length > 0 && typeof docs[0] === 'object') {
|
|
474
|
+
this.extractFieldsAndValues(docs[0], result.insertFields, result.values);
|
|
475
|
+
}
|
|
476
|
+
} else if (docs && typeof docs === 'object') {
|
|
477
|
+
this.extractFieldsAndValues(docs, result.insertFields, result.values);
|
|
358
478
|
}
|
|
359
479
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
480
|
+
return result;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// 필드와 값 추출 (기본)
|
|
484
|
+
MongooseObserver.prototype.extractFieldsAndValues = function(obj, fieldsArray, valuesArray) {
|
|
485
|
+
if (!obj || typeof obj !== 'object') return;
|
|
486
|
+
|
|
487
|
+
Object.keys(obj).forEach(key => {
|
|
488
|
+
if (key.startsWith('$')) {
|
|
489
|
+
// MongoDB 연산자는 중첩 처리
|
|
490
|
+
if (typeof obj[key] === 'object') {
|
|
491
|
+
this.extractFieldsAndValues(obj[key], fieldsArray, valuesArray);
|
|
492
|
+
} else {
|
|
493
|
+
valuesArray.push(obj[key]);
|
|
494
|
+
}
|
|
495
|
+
} else {
|
|
496
|
+
fieldsArray.push(key);
|
|
497
|
+
if (obj[key] !== null && obj[key] !== undefined) {
|
|
498
|
+
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
|
|
499
|
+
// 중첩 객체의 값들도 추출
|
|
500
|
+
this.extractNestedValues(obj[key], valuesArray);
|
|
501
|
+
} else {
|
|
502
|
+
valuesArray.push(obj[key]);
|
|
503
|
+
}
|
|
375
504
|
}
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
};
|
|
376
508
|
|
|
377
|
-
|
|
378
|
-
|
|
509
|
+
// Update 필드만 추출 (수정된 버전) - where 필드 중복 방지
|
|
510
|
+
MongooseObserver.prototype.extractUpdateFieldsOnly = function(updateObj, fieldsArray, valuesArray) {
|
|
511
|
+
if (!updateObj || typeof updateObj !== 'object') return;
|
|
512
|
+
|
|
513
|
+
Object.keys(updateObj).forEach(key => {
|
|
514
|
+
if (key.startsWith('$')) {
|
|
515
|
+
// $set: {name: 'new', email: 'new'} 처리
|
|
516
|
+
if (key === '$set' || key === '$inc' || key === '$push' || key === '$pull' || key === '$unset') {
|
|
517
|
+
if (typeof updateObj[key] === 'object') {
|
|
518
|
+
Object.keys(updateObj[key]).forEach(field => {
|
|
519
|
+
fieldsArray.push(field);
|
|
520
|
+
const value = updateObj[key][field];
|
|
521
|
+
if (value !== null && value !== undefined) {
|
|
522
|
+
valuesArray.push(value);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// 다른 연산자들도 필요시 추가
|
|
528
|
+
} else {
|
|
529
|
+
// 직접 업데이트: {name: "new"} 형태
|
|
530
|
+
fieldsArray.push(key);
|
|
531
|
+
if (updateObj[key] !== null && updateObj[key] !== undefined) {
|
|
532
|
+
valuesArray.push(updateObj[key]);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
};
|
|
379
537
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
538
|
+
// Group 필드 추출
|
|
539
|
+
MongooseObserver.prototype.extractGroupFields = function(groupObj, fieldsArray) {
|
|
540
|
+
if (!groupObj || typeof groupObj !== 'object') return;
|
|
541
|
+
|
|
542
|
+
Object.keys(groupObj).forEach(key => {
|
|
543
|
+
if (key !== '_id') {
|
|
544
|
+
fieldsArray.push(key);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
// Project 필드 추출
|
|
550
|
+
MongooseObserver.prototype.extractProjectFields = function(projectObj, fieldsArray) {
|
|
551
|
+
if (!projectObj || typeof projectObj !== 'object') return;
|
|
384
552
|
|
|
385
|
-
|
|
553
|
+
Object.keys(projectObj).forEach(key => {
|
|
554
|
+
fieldsArray.push(key);
|
|
555
|
+
});
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
// 중첩 값 추출
|
|
559
|
+
MongooseObserver.prototype.extractNestedValues = function(obj, valuesArray) {
|
|
560
|
+
if (!obj || typeof obj !== 'object') return;
|
|
561
|
+
|
|
562
|
+
Object.values(obj).forEach(value => {
|
|
563
|
+
if (value !== null && value !== undefined) {
|
|
564
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
565
|
+
this.extractNestedValues(value, valuesArray);
|
|
566
|
+
} else {
|
|
567
|
+
valuesArray.push(value);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
var toParamBytes = function (p, crc) {
|
|
574
|
+
if (p == null || p.length === 0) {
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
try {
|
|
578
|
+
return ParamSecurity.encrypt(Buffer.from(p, 'utf8'), crc);
|
|
579
|
+
} catch (e) {
|
|
580
|
+
return null;
|
|
386
581
|
}
|
|
387
582
|
};
|
|
388
583
|
|