whatap 0.5.19 → 0.5.21
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/lib/conf/config-default.js +7 -0
- package/lib/control/control-handler.js +21 -12
- package/lib/core/agent.js +2 -0
- package/lib/error/error-handler.js +437 -0
- package/lib/observers/apollo-server-observer.js +10 -2
- package/lib/observers/global-observer.js +17 -7
- package/lib/observers/grpc-observer.js +9 -9
- package/lib/observers/http-observer.js +145 -15
- package/lib/observers/maria-observer.js +0 -1
- package/lib/observers/mongodb-observer.js +4 -1
- package/lib/observers/mongoose-observer.js +414 -114
- package/lib/observers/mssql-observer.js +2 -0
- package/lib/observers/mysql-observer.js +5 -2
- package/lib/observers/mysql2-observer.js +703 -0
- package/lib/observers/oracle-observer.js +4 -1
- package/lib/observers/pgsql-observer.js +2 -0
- package/lib/observers/prisma-observer.js +3 -2
- package/lib/service/tx-record.js +92 -54
- package/lib/trace/trace-context.js +2 -0
- package/package.json +2 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
var TraceContextManager = require('../trace/trace-context-manager'),
|
|
3
2
|
SqlStepX = require('../step/sql-stepx'),
|
|
4
3
|
DataTextAgent = require('../data/datatext-agent'),
|
|
5
4
|
HashUtil = require('../util/hashutil');
|
|
6
|
-
const DBCStep = require("
|
|
7
|
-
const Logger = require("
|
|
5
|
+
const DBCStep = require("../step/dbc-step");
|
|
6
|
+
const Logger = require("../logger");
|
|
7
|
+
const shimmer = require('../core/shimmer');
|
|
8
8
|
|
|
9
9
|
var MongooseObserver = function (agent) {
|
|
10
10
|
this.agent = agent;
|
|
@@ -12,8 +12,8 @@ var MongooseObserver = function (agent) {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
var dbc_step, dbc, conn_dbc_hash;
|
|
15
|
-
MongooseObserver.prototype.inject = function (mod, modName) {
|
|
16
15
|
|
|
16
|
+
MongooseObserver.prototype.inject = function (mod, modName) {
|
|
17
17
|
var self = this;
|
|
18
18
|
var hookCommand = [
|
|
19
19
|
"create", // Create: Create a new document
|
|
@@ -34,133 +34,433 @@ MongooseObserver.prototype.inject = function (mod, modName) {
|
|
|
34
34
|
"findByIdAndDelete" // Delete: Find a document by its ID and delete it
|
|
35
35
|
];
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
// mongoose.connect 함수를 shimmer로 래핑
|
|
38
|
+
shimmer.wrap(mod, 'connect', function(original) {
|
|
39
|
+
return function wrappedConnect() {
|
|
40
|
+
var args = Array.prototype.slice.call(arguments);
|
|
41
|
+
|
|
42
|
+
if(!args[0]) {
|
|
43
|
+
return original.apply(this, arguments);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if(dbc) {
|
|
47
|
+
return original.apply(this, arguments);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
dbc = args[0];
|
|
51
|
+
conn_dbc_hash = HashUtil.hashFromString(dbc);
|
|
52
|
+
|
|
53
|
+
var result = original.apply(this, arguments);
|
|
54
|
+
|
|
55
|
+
// Promise 체인으로 연결 성공 후 Model을 hook
|
|
56
|
+
result.then(connection => {
|
|
57
|
+
// Model 생성 시점을 intercept하기 위해 mongoose.model을 hook
|
|
58
|
+
self.hookModelCreation(mod);
|
|
59
|
+
|
|
60
|
+
}).catch(e => {
|
|
61
|
+
Logger.printError("WHATAP-612", "Mongodb connection error", e, false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// 이미 생성된 모델들도 처리하기 위해 mongoose.model 함수를 hook
|
|
69
|
+
this.hookModelCreation(mod);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Model 생성을 intercept하여 각 Model에 hook을 적용
|
|
73
|
+
MongooseObserver.prototype.hookModelCreation = function(mongoose) {
|
|
74
|
+
var self = this;
|
|
75
|
+
|
|
76
|
+
// mongoose.model 함수를 wrap하여 새로 생성되는 모델들을 intercept
|
|
77
|
+
if (!mongoose._whatapHooked) {
|
|
78
|
+
shimmer.wrap(mongoose, 'model', function(original) {
|
|
79
|
+
return function wrappedModel() {
|
|
80
|
+
var result = original.apply(this, arguments);
|
|
81
|
+
|
|
82
|
+
// 새로 생성된 Model에 hook 적용
|
|
83
|
+
if (result && typeof result === 'function') {
|
|
84
|
+
self.wrapModelMethods(result);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
mongoose._whatapHooked = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 이미 존재하는 모델들에도 hook 적용
|
|
94
|
+
var modelNames = mongoose.modelNames();
|
|
95
|
+
modelNames.forEach(function(modelName) {
|
|
96
|
+
var Model = mongoose.model(modelName);
|
|
97
|
+
self.wrapModelMethods(Model);
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Model의 메서드들을 wrap
|
|
102
|
+
MongooseObserver.prototype.wrapModelMethods = function(Model) {
|
|
103
|
+
var self = this;
|
|
104
|
+
|
|
105
|
+
if (Model._whatapHooked) {
|
|
106
|
+
return; // 이미 hook된 경우 스킵
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// aggregate 메서드 hook (Model에 직접 정의됨)
|
|
110
|
+
if (typeof Model.aggregate === 'function') {
|
|
111
|
+
shimmer.wrap(Model, 'aggregate', function(original) {
|
|
112
|
+
return function wrappedAggregate() {
|
|
113
|
+
return self.wrapAggregateExecution(original, this, arguments);
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// CRUD 메서드들 hook (대부분 Model에 직접 정의됨)
|
|
119
|
+
var hookCommand = [
|
|
120
|
+
"create", "insertMany", "find", "findById", "findOne",
|
|
121
|
+
"countDocuments", "distinct", "updateMany", "updateOne",
|
|
122
|
+
"replaceOne", "findOneAndUpdate", "findByIdAndUpdate",
|
|
123
|
+
"deleteOne", "deleteMany", "findOneAndDelete", "findByIdAndDelete"
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
hookCommand.forEach(function(methodName) {
|
|
127
|
+
if (typeof Model[methodName] === 'function') {
|
|
128
|
+
shimmer.wrap(Model, methodName, function(original) {
|
|
129
|
+
return function wrappedMethod() {
|
|
130
|
+
return self.wrapMethodExecution(original, this, arguments, methodName);
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
Model._whatapHooked = true;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// aggregate 실행을 wrap하는 함수
|
|
140
|
+
MongooseObserver.prototype.wrapAggregateExecution = function(original, thisArg, args) {
|
|
141
|
+
var argsArray = Array.prototype.slice.call(args);
|
|
142
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
143
|
+
|
|
144
|
+
if(!ctx) {
|
|
145
|
+
return original.apply(thisArg, argsArray);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// DBC 정보 등록
|
|
149
|
+
if(dbc && conn_dbc_hash){
|
|
150
|
+
DataTextAgent.DBC.add(conn_dbc_hash, dbc);
|
|
151
|
+
DataTextAgent.METHOD.add(conn_dbc_hash, dbc);
|
|
152
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, dbc);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// DBC Step 생성
|
|
156
|
+
var dbc_step = new DBCStep();
|
|
157
|
+
dbc_step.hash = conn_dbc_hash;
|
|
158
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
159
|
+
|
|
160
|
+
// SQL Step 생성
|
|
161
|
+
var sql_step = new SqlStepX();
|
|
162
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
163
|
+
|
|
164
|
+
var result;
|
|
165
|
+
var hasError = false;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
// 원본 함수 실행
|
|
169
|
+
result = original.apply(thisArg, argsArray);
|
|
170
|
+
|
|
171
|
+
// Query 객체인 경우 exec 메서드를 wrap하여 실행 시점의 에러를 캐치
|
|
172
|
+
if (result && typeof result.exec === 'function') {
|
|
173
|
+
// Query 객체의 exec 메서드를 wrap
|
|
174
|
+
var originalExec = result.exec;
|
|
175
|
+
result.exec = function(callback) {
|
|
176
|
+
var execResult = originalExec.call(this, callback);
|
|
177
|
+
|
|
178
|
+
// Promise 체인에 catch 추가
|
|
179
|
+
if (execResult && typeof execResult.catch === 'function') {
|
|
180
|
+
execResult = execResult.catch(function(error) {
|
|
181
|
+
// 에러 정보를 컨텍스트에 설정
|
|
182
|
+
ctx.error_message = error.message || error.toString();
|
|
183
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseAggregateError';
|
|
184
|
+
|
|
185
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
186
|
+
if (conn_dbc_hash) {
|
|
187
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate execution error", error, false);
|
|
191
|
+
throw error; // 에러를 다시 던져서 원래 동작 유지
|
|
192
|
+
});
|
|
52
193
|
}
|
|
53
194
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
sql += ' field=['+param+']';
|
|
95
|
-
|
|
96
|
-
sql_step.hash = HashUtil.hashFromString(sql);
|
|
97
|
-
sql_step.start_time = ctx.getElapsedTime();
|
|
98
|
-
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
99
|
-
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
100
|
-
ctx.profile.push(sql_step);
|
|
101
|
-
} catch(e) {
|
|
102
|
-
Logger.printError("WHATAP-611", "Mongodb query error", e, false);
|
|
103
|
-
sql_step = null;
|
|
195
|
+
return execResult;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// then 메서드도 wrap (Promise 체인 사용 시)
|
|
199
|
+
var originalThen = result.then;
|
|
200
|
+
if (originalThen) {
|
|
201
|
+
result.then = function(onResolve, onReject) {
|
|
202
|
+
return originalThen.call(this, onResolve, function(error) {
|
|
203
|
+
// 에러 정보를 컨텍스트에 설정
|
|
204
|
+
ctx.error_message = error.message || error.toString();
|
|
205
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseAggregateError';
|
|
206
|
+
|
|
207
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
208
|
+
if (conn_dbc_hash) {
|
|
209
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate execution error", error, false);
|
|
213
|
+
|
|
214
|
+
// 원래 reject 핸들러가 있으면 호출, 없으면 에러를 다시 던짐
|
|
215
|
+
if (onReject) {
|
|
216
|
+
return onReject(error);
|
|
217
|
+
} else {
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Promise인 경우 에러 처리를 위해 catch 추가 (직접 Promise를 반환하는 경우)
|
|
226
|
+
else if (result && typeof result.then === 'function') {
|
|
227
|
+
result = result.catch(function(error) {
|
|
228
|
+
// 에러 정보를 컨텍스트에 설정
|
|
229
|
+
ctx.error_message = error.message || error.toString();
|
|
230
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseAggregateError';
|
|
231
|
+
|
|
232
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
233
|
+
if (conn_dbc_hash) {
|
|
234
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
104
235
|
}
|
|
236
|
+
|
|
237
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate execution error", error, false);
|
|
238
|
+
throw error; // 에러를 다시 던져서 원래 동작 유지
|
|
105
239
|
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
} catch(error) {
|
|
243
|
+
hasError = true;
|
|
244
|
+
// 동기 에러 처리
|
|
245
|
+
ctx.error_message = error.message || error.toString();
|
|
246
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseAggregateError';
|
|
247
|
+
|
|
248
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
249
|
+
if (conn_dbc_hash) {
|
|
250
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate execution error", error, false);
|
|
254
|
+
throw error; // 에러를 다시 던져서 원래 동작 유지
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 결과 처리
|
|
258
|
+
try {
|
|
259
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
260
|
+
ctx.profile.push(dbc_step);
|
|
261
|
+
|
|
262
|
+
// aggregate의 경우 op 속성이 없을 수 있음
|
|
263
|
+
var operation = result && result.op ? result.op : 'aggregate';
|
|
264
|
+
ctx.footprint('Mongodb Command Start: ' + operation);
|
|
106
265
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
266
|
+
// Model 이름 가져오기
|
|
267
|
+
var modelName = thisArg.modelName || 'Unknown';
|
|
268
|
+
|
|
269
|
+
var sql = modelName + ' aggregate';
|
|
270
|
+
var param = "";
|
|
271
|
+
|
|
272
|
+
if(Array.isArray(argsArray[0])) {
|
|
273
|
+
argsArray[0].forEach(function (val, i) {
|
|
274
|
+
if(i > 0 && param.length > 0) {
|
|
275
|
+
param += ",";
|
|
276
|
+
}
|
|
277
|
+
if(val && val.hasOwnProperty('$match')) {
|
|
278
|
+
var keys = Object.keys(val['$match']);
|
|
279
|
+
param += keys.join(',');
|
|
115
280
|
}
|
|
281
|
+
if(val && val.hasOwnProperty('$group')) {
|
|
282
|
+
var keys = Object.keys(val['$group']);
|
|
283
|
+
param += keys.join(',');
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
sql += ' field=['+param+']';
|
|
288
|
+
|
|
289
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
290
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
291
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
292
|
+
ctx.profile.push(sql_step);
|
|
293
|
+
|
|
294
|
+
} catch(e) {
|
|
295
|
+
Logger.printError("WHATAP-611", "Mongodb aggregate query processing error", e, false);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return result;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// 일반 CRUD 메서드 실행을 wrap하는 함수
|
|
302
|
+
MongooseObserver.prototype.wrapMethodExecution = function(original, thisArg, args, methodName) {
|
|
303
|
+
var argsArray = Array.prototype.slice.call(args);
|
|
304
|
+
|
|
305
|
+
// 첫 번째 인자가 객체가 아니면 무시 (일부 메서드 제외)
|
|
306
|
+
if(argsArray[0] && typeof argsArray[0] !== "object" &&
|
|
307
|
+
!['findById', 'findByIdAndUpdate', 'findByIdAndDelete'].includes(methodName)) {
|
|
308
|
+
return original.apply(thisArg, argsArray);
|
|
309
|
+
}
|
|
116
310
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
311
|
+
var ctx = TraceContextManager.getCurrentContext();
|
|
312
|
+
if(!ctx) {
|
|
313
|
+
return original.apply(thisArg, argsArray);
|
|
314
|
+
}
|
|
120
315
|
|
|
121
|
-
|
|
316
|
+
// DBC 정보 등록
|
|
317
|
+
if(dbc && conn_dbc_hash){
|
|
318
|
+
DataTextAgent.DBC.add(conn_dbc_hash, dbc);
|
|
319
|
+
DataTextAgent.METHOD.add(conn_dbc_hash, dbc);
|
|
320
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, dbc);
|
|
321
|
+
}
|
|
122
322
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
var ctx = _lctx.context;
|
|
128
|
-
var dbc_step = _lctx.dbc_step;
|
|
129
|
-
var sql_step = _lctx.sql_step;
|
|
130
|
-
if(!ctx || !dbc_step || !sql_step) {return null;}
|
|
323
|
+
// DBC Step 생성
|
|
324
|
+
var dbc_step = new DBCStep();
|
|
325
|
+
dbc_step.hash = conn_dbc_hash;
|
|
326
|
+
dbc_step.start_time = ctx.getElapsedTime();
|
|
131
327
|
|
|
132
|
-
|
|
133
|
-
|
|
328
|
+
// SQL Step 생성
|
|
329
|
+
var sql_step = new SqlStepX();
|
|
330
|
+
sql_step.start_time = ctx.getElapsedTime();
|
|
134
331
|
|
|
135
|
-
|
|
332
|
+
var result;
|
|
333
|
+
var hasError = false;
|
|
136
334
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
335
|
+
try {
|
|
336
|
+
// 원본 함수 실행
|
|
337
|
+
result = original.apply(thisArg, argsArray);
|
|
338
|
+
|
|
339
|
+
// Query 객체인 경우 exec 메서드를 wrap하여 실행 시점의 에러를 캐치
|
|
340
|
+
if (result && typeof result.exec === 'function') {
|
|
341
|
+
// Query 객체의 exec 메서드를 wrap
|
|
342
|
+
var originalExec = result.exec;
|
|
343
|
+
result.exec = function(callback) {
|
|
344
|
+
var execResult = originalExec.call(this, callback);
|
|
345
|
+
|
|
346
|
+
// Promise 체인에 catch 추가
|
|
347
|
+
if (execResult && typeof execResult.catch === 'function') {
|
|
348
|
+
execResult = execResult.catch(function(error) {
|
|
349
|
+
// 에러 정보를 컨텍스트에 설정
|
|
350
|
+
ctx.error_message = error.message || error.toString();
|
|
351
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseError';
|
|
352
|
+
|
|
353
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
354
|
+
if (conn_dbc_hash) {
|
|
355
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
Logger.printError("WHATAP-611", "Mongodb " + methodName + " execution error", error, false);
|
|
359
|
+
throw error; // 에러를 다시 던져서 원래 동작 유지
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return execResult;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// then 메서드도 wrap (Promise 체인 사용 시)
|
|
367
|
+
var originalThen = result.then;
|
|
368
|
+
if (originalThen) {
|
|
369
|
+
result.then = function(onResolve, onReject) {
|
|
370
|
+
return originalThen.call(this, onResolve, function(error) {
|
|
371
|
+
// 에러 정보를 컨텍스트에 설정
|
|
372
|
+
ctx.error_message = error.message || error.toString();
|
|
373
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseError';
|
|
374
|
+
|
|
375
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
376
|
+
if (conn_dbc_hash) {
|
|
377
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
143
378
|
}
|
|
144
|
-
|
|
145
|
-
|
|
379
|
+
|
|
380
|
+
Logger.printError("WHATAP-611", "Mongodb " + methodName + " execution error", error, false);
|
|
381
|
+
|
|
382
|
+
// 원래 reject 핸들러가 있으면 호출, 없으면 에러를 다시 던짐
|
|
383
|
+
if (onReject) {
|
|
384
|
+
return onReject(error);
|
|
385
|
+
} else {
|
|
386
|
+
throw error;
|
|
146
387
|
}
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
} else if (result && typeof result.then === 'function') {
|
|
392
|
+
// Promise인 경우 에러 처리를 위해 catch 추가 (직접 Promise를 반환하는 경우)
|
|
393
|
+
result = result.catch(function(error) {
|
|
394
|
+
// 에러 정보를 컨텍스트에 설정
|
|
395
|
+
ctx.error_message = error.message || error.toString();
|
|
396
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseError';
|
|
147
397
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
152
|
-
ctx.profile.push(sql_step);
|
|
153
|
-
}
|
|
154
|
-
} catch(e) {
|
|
155
|
-
Logger.printError("WHATAP-611", "Mongodb query error", e, false);
|
|
156
|
-
sql_step = null;
|
|
398
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
399
|
+
if (conn_dbc_hash) {
|
|
400
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
157
401
|
}
|
|
158
|
-
})
|
|
159
|
-
}).catch(e => {
|
|
160
|
-
Logger.printError("WHATAP-612", "Mongodb connection error", e, false);
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
402
|
|
|
403
|
+
Logger.printError("WHATAP-611", "Mongodb " + methodName + " execution error", error, false);
|
|
404
|
+
throw error; // 에러를 다시 던져서 원래 동작 유지
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
} catch(error) {
|
|
409
|
+
hasError = true;
|
|
410
|
+
// 동기 에러 처리
|
|
411
|
+
ctx.error_message = error.message || error.toString();
|
|
412
|
+
ctx.error_class = error.name || error.constructor?.name || 'MongooseError';
|
|
413
|
+
|
|
414
|
+
// 에러 정보를 DataTextAgent에도 추가
|
|
415
|
+
if (conn_dbc_hash) {
|
|
416
|
+
DataTextAgent.ERROR.add(conn_dbc_hash, ctx.error_message);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
Logger.printError("WHATAP-611", "Mongodb " + methodName + " execution error", error, false);
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// 결과 처리
|
|
424
|
+
try {
|
|
425
|
+
dbc_step.elapsed = ctx.getElapsedTime() - dbc_step.start_time;
|
|
426
|
+
ctx.profile.push(dbc_step);
|
|
427
|
+
|
|
428
|
+
// operation 이름 가져오기
|
|
429
|
+
var operation = (result && result.op) ? result.op : methodName;
|
|
430
|
+
ctx.footprint('Mongodb Command Start: ' + operation);
|
|
431
|
+
|
|
432
|
+
// Model 이름 가져오기
|
|
433
|
+
var modelName = thisArg.modelName || 'Unknown';
|
|
434
|
+
|
|
435
|
+
var sql = modelName + ' ' + operation;
|
|
436
|
+
|
|
437
|
+
if (argsArray[0]) {
|
|
438
|
+
try {
|
|
439
|
+
var keys = typeof argsArray[0] === 'object' ? Object.keys(argsArray[0]) : [argsArray[0]];
|
|
440
|
+
sql += ' field=' + JSON.stringify(keys);
|
|
441
|
+
} catch(e) {
|
|
442
|
+
sql += ' field=[unknown]';
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (argsArray[1]) {
|
|
446
|
+
try {
|
|
447
|
+
var keys = typeof argsArray[1] === 'object' ? Object.keys(argsArray[1]) : [argsArray[1]];
|
|
448
|
+
sql += ' value=' + JSON.stringify(keys);
|
|
449
|
+
} catch(e) {
|
|
450
|
+
sql += ' value=[unknown]';
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
sql_step.hash = HashUtil.hashFromString(sql);
|
|
455
|
+
sql_step.elapsed = ctx.getElapsedTime() - sql_step.start_time;
|
|
456
|
+
DataTextAgent.SQL.add(sql_step.hash, sql);
|
|
457
|
+
ctx.profile.push(sql_step);
|
|
458
|
+
|
|
459
|
+
} catch(e) {
|
|
460
|
+
Logger.printError("WHATAP-611", "Mongodb query processing error", e, false);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return result;
|
|
164
464
|
};
|
|
165
465
|
|
|
166
466
|
exports.MongooseObserver = MongooseObserver;
|
|
@@ -95,6 +95,8 @@ MssqlObserver.prototype.inject = function (mod, modName) {
|
|
|
95
95
|
self.aop.functionHook(args, -1, function (obj, args) {
|
|
96
96
|
TraceContextManager.resume(ctx);
|
|
97
97
|
if(args[0] != null) {
|
|
98
|
+
ctx.error_message = args[0].message;
|
|
99
|
+
ctx.error_class = args[0].name || args[0].constructor?.name || 'MSSQLError';
|
|
98
100
|
if (conf.trace_sql_error_stack && conf.trace_sql_error_depth) {
|
|
99
101
|
var traceDepth = conf.trace_sql_error_depth;
|
|
100
102
|
|
|
@@ -12,7 +12,6 @@ var TraceContextManager = require('../trace/trace-context-manager'),
|
|
|
12
12
|
DataTextAgent = require('../data/datatext-agent'),
|
|
13
13
|
StatSql = require('../stat/stat-sql'),
|
|
14
14
|
MeterSql = require('../counter/meter/meter-sql'),
|
|
15
|
-
conf = require('../conf/configure'),
|
|
16
15
|
IntKeyMap = require('../util/intkey-map'),
|
|
17
16
|
EscapeLiteralSQL = require('../util/escape-literal-sql'),
|
|
18
17
|
HashUtil = require('../util/hashutil'),
|
|
@@ -27,7 +26,7 @@ var TraceContextManager = require('../trace/trace-context-manager'),
|
|
|
27
26
|
|
|
28
27
|
var MysqlObserver = function (agent) {
|
|
29
28
|
this.agent = agent;
|
|
30
|
-
this.packages = ['mysql'
|
|
29
|
+
this.packages = ['mysql'];
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
var queryHook = function (dbc, agent) {
|
|
@@ -128,6 +127,10 @@ var queryHook = function (dbc, agent) {
|
|
|
128
127
|
ctx.error_message = errorStack.join("\n");
|
|
129
128
|
sql_step.error = ctx.error = StatError.addError('mysql-' + args[0].code, args[0].sqlMessage, ctx.service_hash, TextTypes.SQL, null);
|
|
130
129
|
}
|
|
130
|
+
ctx.error_class = args[0].name || args[0].constructor?.name || 'MySQLError';
|
|
131
|
+
if (!ctx.error_message) {
|
|
132
|
+
ctx.error_message = args[0].message || args[0].sqlMessage || 'MySQL error';
|
|
133
|
+
}
|
|
131
134
|
if (conf._is_trace_ignore_err_cls_contains === true && args[0].code.indexOf(conf.trace_ignore_err_cls_contains) < 0) {
|
|
132
135
|
sql_step.error = StatError.addError('mysql-' + args[0].code, args[0].message || 'mysql error', ctx.service_hash, TextTypes.SQL, sql_step.hash); /*long*/
|
|
133
136
|
if (ctx.error.isZero()) {
|