whatap 0.5.19 → 0.5.20

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.
@@ -278,6 +278,13 @@ var ConfigDefault = {
278
278
 
279
279
  "metering_tagcount_enabled": bool("metering_tagcount_enabled", false),
280
280
  "profile_redis_param_enabled": bool("profile_redis_param_enabled", false),
281
+ "profile_mongodb_param_enabled": bool("profile_mongodb_param_enabled", false),
282
+
283
+ "trace_mtrace_traceparent_key": str("trace_mtrace_traceparent_key", "traceparent"),
284
+
285
+ "txtext_txname_enabled": bool("txtext_txname_enabled", true),
286
+
287
+ "ignore_env_variable_set": str("ignore_env_variable_set", "")
281
288
 
282
289
  };
283
290
 
@@ -17,7 +17,8 @@ var PackageCtrHelper = require('./packagectr-helper'),
17
17
  TraceContextManager = require('../trace/trace-context-manager'),
18
18
  Logger = require('../logger'),
19
19
  StatusDetector = require('../topology/status-detector'),
20
- BlobValue = require('../value/blob-value');
20
+ BlobValue = require('../value/blob-value'),
21
+ conf = require('../conf/configure');
21
22
 
22
23
  var ControlHandler = function () {
23
24
  this.queue = new RequestQueue(100);
@@ -136,10 +137,14 @@ ControlHandler.prototype.handle = async function (p) {
136
137
  self._dataPackSender.sendResponseHide(p.getResponse());
137
138
  break;
138
139
  case ParamDef.GET_ENV:
139
-
140
140
  try {
141
141
  var mv = new MapValue();
142
+ let ignore_env_variable = conf.get('ignore_env_variable_set', '');
143
+ let ignore_env_variable_set = ignore_env_variable ? new Set(ignore_env_variable.split(',').map(item => item.trim())) : new Set();
142
144
  for (var k in process.env) {
145
+ if(ignore_env_variable_set.has(k)) {
146
+ continue;
147
+ }
143
148
  var v = process.env[k];
144
149
  mv.putString(k, v);
145
150
  }
@@ -152,23 +157,27 @@ ControlHandler.prototype.handle = async function (p) {
152
157
 
153
158
  case ParamDef.SYSTEM_GC:
154
159
  try {
155
- var total1 = os.totalmem();
156
- var used1 = total1 - os.freemem();
157
- if (global.gc) {
160
+ var mem1 = process.memoryUsage();
161
+ var total1 = mem1.heapTotal;
162
+ var used1 = mem1.heapUsed;
163
+
164
+ if (global && global.gc && typeof global.gc === 'function') {
158
165
  global.gc();
159
166
  } else {
160
167
  Logger.printError('WHATAP-177', 'Garbage collection unavailable. Pass --expose-gc '
161
168
  + 'when launching node to enable forced garbage collection.', new Error());
162
169
  }
163
- var total2 = os.totalmem();
164
- var used2 = total2 - os.freemem();
170
+
171
+ var mem2 = process.memoryUsage();
172
+ var total2 = mem2.heapTotal;
173
+ var used2 = mem2.heapUsed;
165
174
 
166
175
  var mv = new MapValue();
167
- mv.put("before-t", total1);
168
- mv.put("before-u", used1);
169
- mv.put("after-t", total2);
170
- mv.put("after-u", used2);
171
- p.putValue("gc", m);
176
+ mv.putLong("before-t", total1);
177
+ mv.putLong("before-u", used1);
178
+ mv.putLong("after-t", total2);
179
+ mv.putLong("after-u", used2);
180
+ p.putValue("gc", mv);
172
181
  } catch (e) {
173
182
  p.putValue("error", e.toString());
174
183
  }
package/lib/core/agent.js CHANGED
@@ -17,6 +17,7 @@ var Interceptor = require('./interceptor').Interceptor,
17
17
  ExpressObserver = require('../observers/express-observer').ExpressObserver,
18
18
  GlobalObserver = require('../observers/global-observer').GlobalObserver,
19
19
  MysqlObserver = require('../observers/mysql-observer').MysqlObserver,
20
+ Mysql2Observer = require('../observers/mysql2-observer').Mysql2Observer,
20
21
  MariaObserver = require('../observers/maria-observer').MariaObserver,
21
22
  SocketioObserver = require('../observers/socket.io-observer').SocketIOObserver,
22
23
  WebsocketObserver = require('../observers/websocket-observer').WebsocketObserver,
@@ -265,6 +266,7 @@ NodeAgent.prototype.loadObserves = function() {
265
266
  observes.push(NetObserver);
266
267
  observes.push(ClusterObserver);
267
268
  observes.push(MysqlObserver);
269
+ observes.push(Mysql2Observer);
268
270
  observes.push(MariaObserver);
269
271
  observes.push(SocketioObserver);
270
272
  observes.push(WebsocketObserver);
@@ -0,0 +1,437 @@
1
+ /**
2
+ * 메시지/알림 오류 처리
3
+ * @param {Object} ctx - Trace Context
4
+ * @param {Object} step - Message Step
5
+ * @param {Error} error - 오류 객체
6
+ */
7
+ function handleMessageError(ctx, step, error) {
8
+ setCommonErrorInfo(ctx, step, error, {
9
+ prefix: 'msg-',
10
+ textType: TextTypes.MESSAGE,
11
+ defaultMessage: 'Message processing error',
12
+ includeStack: false,
13
+ logPrefix: 'MESSAGE-ERROR'
14
+ });
15
+ }
16
+
17
+ /**
18
+ * 오류 정보를 Context에만 설정 (StatError 생성 없이)
19
+ * @param {Object} ctx - Trace Context
20
+ * @param {Error} error - 오류 객체
21
+ * @param {string} prefix - 오류 접두사
22
+ */
23
+ function setContextErrorOnly(ctx, error, prefix = '') {
24
+ if (!ctx || !error) return;
25
+
26
+ try {
27
+ // 오류 클래스 정보 설정
28
+ ctx.error_class = error.name || (error.constructor && error.constructor.name) || 'UnknownError';
29
+
30
+ // 오류 메시지 설정
31
+ ctx.error_message = error.message || error.stack || 'Unknown error';
32
+
33
+ // 상태 코드 설정 (있는 경우)
34
+ if (error.status || error.statusCode || error.code) {
35
+ ctx.statusCode = error.status || error.statusCode || error.code;
36
+ }
37
+
38
+ } catch (e) {
39
+ Logger.printError(
40
+ 'WHATAP-CONTEXT-ERROR',
41
+ 'Error setting context error info',
42
+ e,
43
+ false
44
+ );
45
+ }
46
+ }/**
47
+ * Step 타입에 따라 TextType 자동 추론
48
+ * @param {Object} step - Step 객체
49
+ * @returns {number} - TextTypes 상수
50
+ */
51
+ function inferTextTypeFromStep(step) {
52
+ if (!step) return TextTypes.MESSAGE;
53
+
54
+ // Step 클래스명 또는 타입으로 판단
55
+ const stepName = step.constructor?.name || '';
56
+
57
+ if (stepName.includes('Http') || step.url !== undefined) {
58
+ return TextTypes.HTTPC_URL;
59
+ }
60
+ if (stepName.includes('Socket') || stepName.includes('Websocket')) {
61
+ return TextTypes.MESSAGE;
62
+ }
63
+ if (stepName.includes('Message') || step.desc !== undefined) {
64
+ return TextTypes.MESSAGE;
65
+ }
66
+ if (stepName.includes('Sql') || step.hash !== undefined) {
67
+ return TextTypes.SQL;
68
+ }
69
+
70
+ // 기본값
71
+ return TextTypes.MESSAGE;
72
+ }/**
73
+ * 공통 오류 처리 유틸리티
74
+ * 모든 Observer에서 사용할 수 있는 통합 오류 처리 함수들
75
+ */
76
+
77
+ const StatError = require('../stat/stat-error');
78
+ const TextTypes = require('../lang/text-types');
79
+ const Logger = require('../logger');
80
+ const conf = require('../conf/configure');
81
+
82
+ /**
83
+ * 공통 오류 정보 설정 함수 (범용)
84
+ * @param {Object} ctx - Trace Context
85
+ * @param {Object} step - Step 객체 (SQL, HTTP, Message 등)
86
+ * @param {Error} error - 오류 객체
87
+ * @param {Object} options - 추가 옵션
88
+ * @param {string} options.prefix - 오류 코드 접두사 (예: 'mysql-', 'httpc-', 'redis-')
89
+ * @param {number} options.textType - TextTypes 상수 (기본값: null, step 타입에 따라 자동 결정)
90
+ * @param {boolean} options.includeStack - 스택 트레이스 포함 여부 (기본값: true)
91
+ * @param {string} options.defaultMessage - 기본 오류 메시지
92
+ * @param {boolean} options.setStatError - StatError 생성 여부 (기본값: true)
93
+ * @param {string} options.logPrefix - 로그 접두사 (기본값: 'COMMON-ERROR')
94
+ */
95
+ function setCommonErrorInfo(ctx, step, error, options = {}) {
96
+ if (!ctx || !error) {
97
+ return;
98
+ }
99
+
100
+ const {
101
+ prefix = '',
102
+ textType = null,
103
+ includeStack = true,
104
+ defaultMessage = 'Error',
105
+ setStatError = true,
106
+ logPrefix = 'COMMON-ERROR'
107
+ } = options;
108
+
109
+ try {
110
+ // 오류 클래스 정보 설정
111
+ const errorClass = error.name || (error.constructor && error.constructor.name) || 'UnknownError';
112
+ ctx.error_class = errorClass;
113
+
114
+ // 오류 코드 생성
115
+ const errorCode = error.code || error.errno || error.errorNum || 'UNKNOWN';
116
+ const fullErrorCode = prefix ? `${prefix}${errorCode}` : errorCode;
117
+
118
+ // 오류 메시지 설정
119
+ const errorMessage = error.message || error.sqlMessage || defaultMessage;
120
+
121
+ // 스택 트레이스 처리
122
+ if (includeStack && conf.trace_sql_error_stack && conf.trace_sql_error_depth && error.stack) {
123
+ const traceDepth = conf.trace_sql_error_depth;
124
+ const errorStack = error.stack.split("\n");
125
+
126
+ if (errorStack.length > traceDepth) {
127
+ ctx.error_message = errorStack.slice(0, traceDepth + 1).join("\n");
128
+ } else {
129
+ ctx.error_message = error.stack;
130
+ }
131
+ } else {
132
+ ctx.error_message = errorMessage;
133
+ }
134
+
135
+ // StatError 생성 (step이 있고 설정이 활성화된 경우)
136
+ if (step && setStatError) {
137
+ const shouldAddError = shouldIgnoreError(errorCode, errorMessage);
138
+
139
+ if (shouldAddError) {
140
+ // textType이 null이면 step 타입에 따라 자동 결정
141
+ const finalTextType = textType || inferTextTypeFromStep(step);
142
+
143
+ step.error = StatError.addError(
144
+ fullErrorCode,
145
+ errorMessage,
146
+ ctx.service_hash,
147
+ finalTextType,
148
+ step.hash || step.url || null
149
+ );
150
+
151
+ // Context 오류가 아직 설정되지 않았다면 설정
152
+ if (ctx.error && ctx.error.isZero && ctx.error.isZero()) {
153
+ ctx.error = step.error;
154
+ }
155
+ }
156
+ }
157
+
158
+ Logger.printError(
159
+ `WHATAP-${logPrefix.toUpperCase()}`,
160
+ `${prefix || 'SYSTEM'} Error: ${fullErrorCode} - ${errorMessage}`,
161
+ error,
162
+ false
163
+ );
164
+
165
+ } catch (e) {
166
+ Logger.printError(
167
+ 'WHATAP-ERROR-HANDLER',
168
+ 'Error in common error handler',
169
+ e,
170
+ false
171
+ );
172
+ }
173
+ }
174
+
175
+ /**
176
+ * 오류 무시 여부 확인
177
+ * @param {string} errorCode - 오류 코드
178
+ * @param {string} errorMessage - 오류 메시지
179
+ * @returns {boolean} - 오류를 처리할지 여부
180
+ */
181
+ function shouldIgnoreError(errorCode, errorMessage) {
182
+ try {
183
+ // 오류 클래스 무시 설정 확인
184
+ if (conf._is_trace_ignore_err_cls_contains === true &&
185
+ conf.trace_ignore_err_cls_contains &&
186
+ errorCode &&
187
+ errorCode.indexOf(conf.trace_ignore_err_cls_contains) >= 0) {
188
+ return false;
189
+ }
190
+
191
+ // 오류 메시지 무시 설정 확인
192
+ if (conf._is_trace_ignore_err_msg_contains === true &&
193
+ conf.trace_ignore_err_msg_contains &&
194
+ errorMessage &&
195
+ errorMessage.indexOf(conf.trace_ignore_err_msg_contains) >= 0) {
196
+ return false;
197
+ }
198
+
199
+ // 기본적으로 오류 처리
200
+ return true;
201
+ } catch (e) {
202
+ Logger.printError(
203
+ 'WHATAP-ERROR-IGNORE-CHECK',
204
+ 'Error checking ignore conditions',
205
+ e,
206
+ false
207
+ );
208
+ return true;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * MySQL 전용 오류 처리
214
+ * @param {Object} ctx - Trace Context
215
+ * @param {Object} step - SQL Step
216
+ * @param {Error} error - MySQL 오류 객체
217
+ */
218
+ function handleMysqlError(ctx, step, error) {
219
+ setCommonErrorInfo(ctx, step, error, {
220
+ prefix: 'mysql-',
221
+ textType: TextTypes.SQL,
222
+ defaultMessage: 'mysql error'
223
+ });
224
+ }
225
+
226
+ /**
227
+ * PostgreSQL 전용 오류 처리
228
+ * @param {Object} ctx - Trace Context
229
+ * @param {Object} step - SQL Step
230
+ * @param {Error} error - PostgreSQL 오류 객체
231
+ */
232
+ function handlePgsqlError(ctx, step, error) {
233
+ setCommonErrorInfo(ctx, step, error, {
234
+ prefix: 'pgsql-',
235
+ textType: TextTypes.SQL,
236
+ defaultMessage: 'postgresql error'
237
+ });
238
+ }
239
+
240
+ /**
241
+ * Oracle 전용 오류 처리
242
+ * @param {Object} ctx - Trace Context
243
+ * @param {Object} step - SQL Step
244
+ * @param {Error} error - Oracle 오류 객체
245
+ */
246
+ function handleOracleError(ctx, step, error) {
247
+ setCommonErrorInfo(ctx, step, error, {
248
+ prefix: 'oracle-',
249
+ textType: TextTypes.SQL,
250
+ defaultMessage: 'Oracle error'
251
+ });
252
+ }
253
+
254
+ /**
255
+ * MongoDB 전용 오류 처리
256
+ * @param {Object} ctx - Trace Context
257
+ * @param {Object} step - SQL Step
258
+ * @param {Error} error - MongoDB 오류 객체
259
+ */
260
+ function handleMongoError(ctx, step, error) {
261
+ setCommonErrorInfo(ctx, step, error, {
262
+ prefix: 'mongodb-',
263
+ textType: TextTypes.SQL,
264
+ defaultMessage: 'MongoDB error'
265
+ });
266
+ }
267
+
268
+ /**
269
+ * Redis 전용 오류 처리
270
+ * @param {Object} ctx - Trace Context
271
+ * @param {Object} step - SQL Step
272
+ * @param {Error} error - Redis 오류 객체
273
+ */
274
+ function handleRedisError(ctx, step, error) {
275
+ setCommonErrorInfo(ctx, step, error, {
276
+ prefix: 'redis-',
277
+ textType: TextTypes.SQL,
278
+ defaultMessage: 'Redis error'
279
+ });
280
+ }
281
+
282
+ /**
283
+ * HTTP 클라이언트 오류 처리
284
+ * @param {Object} ctx - Trace Context
285
+ * @param {Object} step - HTTP Step
286
+ * @param {Error} error - HTTP 오류 객체
287
+ */
288
+ function handleHttpcError(ctx, step, error) {
289
+ setCommonErrorInfo(ctx, step, error, {
290
+ prefix: 'httpc-',
291
+ textType: TextTypes.HTTPC_URL,
292
+ defaultMessage: 'HTTP client error',
293
+ includeStack: false,
294
+ logPrefix: 'HTTPC-ERROR'
295
+ });
296
+ }
297
+
298
+ /**
299
+ * 일반적인 시스템 오류 처리
300
+ * @param {Object} ctx - Trace Context
301
+ * @param {Object} step - Step 객체 (선택사항)
302
+ * @param {Error} error - 오류 객체
303
+ * @param {string} prefix - 오류 접두사
304
+ */
305
+ function handleSystemError(ctx, step, error, prefix = 'system') {
306
+ setCommonErrorInfo(ctx, step, error, {
307
+ prefix: `${prefix}-`,
308
+ textType: null, // 자동 추론
309
+ defaultMessage: 'System error',
310
+ includeStack: true,
311
+ logPrefix: 'SYSTEM-ERROR'
312
+ });
313
+ }
314
+
315
+ /**
316
+ * gRPC 전용 오류 처리
317
+ * @param {Object} ctx - Trace Context
318
+ * @param {Object} step - gRPC Step (MessageStep)
319
+ * @param {Error} error - gRPC 오류 객체
320
+ */
321
+ function handleGrpcError(ctx, step, error) {
322
+ setCommonErrorInfo(ctx, step, error, {
323
+ prefix: 'grpc-',
324
+ textType: TextTypes.MESSAGE,
325
+ defaultMessage: 'gRPC error',
326
+ includeStack: true,
327
+ logPrefix: 'GRPC-ERROR'
328
+ });
329
+ }
330
+
331
+ /**
332
+ * WebSocket 전용 오류 처리
333
+ * @param {Object} ctx - Trace Context
334
+ * @param {Object} step - WebSocket Step (SocketStep)
335
+ * @param {Error} error - WebSocket 오류 객체
336
+ */
337
+ function handleWebsocketError(ctx, step, error) {
338
+ setCommonErrorInfo(ctx, step, error, {
339
+ prefix: 'websocket-',
340
+ textType: TextTypes.MESSAGE,
341
+ defaultMessage: 'WebSocket error',
342
+ includeStack: false,
343
+ logPrefix: 'WEBSOCKET-ERROR'
344
+ });
345
+ }
346
+
347
+ /**
348
+ * Socket.IO 전용 오류 처리
349
+ * @param {Object} ctx - Trace Context
350
+ * @param {Object} step - Socket.IO Step (SocketStep)
351
+ * @param {Error} error - Socket.IO 오류 객체
352
+ */
353
+ function handleSocketIOError(ctx, step, error) {
354
+ setCommonErrorInfo(ctx, step, error, {
355
+ prefix: 'socketio-',
356
+ textType: TextTypes.MESSAGE,
357
+ defaultMessage: 'Socket.IO error',
358
+ includeStack: false,
359
+ logPrefix: 'SOCKETIO-ERROR'
360
+ });
361
+ }
362
+
363
+ /**
364
+ * Global Fetch API 오류 처리
365
+ * @param {Object} ctx - Trace Context
366
+ * @param {Object} step - HTTP Step (HttpStepX)
367
+ * @param {Error|Response} error - Fetch 오류 객체 또는 Response 객체
368
+ */
369
+ function handleFetchError(ctx, step, error) {
370
+ // Response 객체인 경우와 Error 객체인 경우 구분
371
+ const isResponse = error && typeof error.status === 'number';
372
+
373
+ setCommonErrorInfo(ctx, step, error, {
374
+ prefix: 'fetch-',
375
+ textType: TextTypes.HTTPC_URL,
376
+ defaultMessage: isResponse ? 'Fetch HTTP error' : 'Fetch network error',
377
+ includeStack: !isResponse, // Response 객체는 스택 없음
378
+ logPrefix: 'FETCH-ERROR'
379
+ });
380
+ }
381
+
382
+ /**
383
+ * Process 관련 오류 처리 (stdout/stderr)
384
+ * @param {Object} ctx - Trace Context
385
+ * @param {Object} step - Process Step
386
+ * @param {Error} error - Process 오류 객체
387
+ */
388
+ function handleProcessError(ctx, step, error) {
389
+ setCommonErrorInfo(ctx, step, error, {
390
+ prefix: 'process-',
391
+ textType: TextTypes.MESSAGE,
392
+ defaultMessage: 'Process error',
393
+ includeStack: true,
394
+ logPrefix: 'PROCESS-ERROR'
395
+ });
396
+ }
397
+
398
+ /**
399
+ * Prisma 전용 오류 처리
400
+ * @param {Object} ctx - Trace Context
401
+ * @param {Object} step - SQL Step
402
+ * @param {Error} error - Prisma 오류 객체
403
+ */
404
+ function handlePrismaError(ctx, step, error) {
405
+ setCommonErrorInfo(ctx, step, error, {
406
+ prefix: 'prisma-',
407
+ textType: TextTypes.SQL,
408
+ defaultMessage: 'Prisma error'
409
+ });
410
+ }
411
+
412
+ module.exports = {
413
+ setCommonErrorInfo,
414
+ shouldIgnoreError,
415
+ inferTextTypeFromStep,
416
+ setContextErrorOnly,
417
+
418
+ // 데이터베이스 관련
419
+ handleMysqlError,
420
+ handlePgsqlError,
421
+ handleOracleError,
422
+ handleMongoError,
423
+ handleRedisError,
424
+ handlePrismaError,
425
+
426
+ // 네트워크/통신 관련
427
+ handleHttpcError,
428
+ handleFetchError,
429
+ handleGrpcError,
430
+ handleWebsocketError,
431
+ handleSocketIOError,
432
+
433
+ // 시스템 관련
434
+ handleSystemError,
435
+ handleProcessError,
436
+ handleMessageError
437
+ };
@@ -11,6 +11,8 @@ const HashUtil = require('../util/hashutil');
11
11
  const DataTextAgent = require('../data/datatext-agent');
12
12
  const MessageStep = require('../step/message-step');
13
13
  const shimmer = require('../core/shimmer');
14
+ const StatError = require("whatap/lib/stat/stat-error");
15
+ const TextTypes = require("whatap/lib/lang/text-types");
14
16
 
15
17
  var profile_graphql_enabled = conf.getProperty('profile_graphql_enabled', true);
16
18
  var profile_graphql_variable_enabled = conf.getProperty('profile_graphql_variable_enabled', false);
@@ -114,8 +116,13 @@ function wrapExecuteHTTPGraphQLRequest(original) {
114
116
  const result = JSON.parse(response.body.string);
115
117
  if (result.errors && result.errors.length > 0) {
116
118
  const errorMessages = result.errors.map(error => error.message).join('\n');
117
- ctx.statusCode = 500;
119
+ ctx.statusCode = response.status;
118
120
  ctx.error_message = errorMessages;
121
+ ctx.error_class = 'GraphQLError';
122
+
123
+ if(ctx.error.isZero()){
124
+ ctx.error = StatError.addError(response.status, errorMessages, ctx.service_hash, TextTypes.SQL, HashUtil.hashFromString(ctx.service_name));
125
+ }
119
126
  }
120
127
  } catch (e) {
121
128
  Logger.printError('WHATAP-802', 'GraphQL error parsing failed', e, false);
@@ -128,7 +135,8 @@ function wrapExecuteHTTPGraphQLRequest(original) {
128
135
  Logger.printError('WHATAP-801', 'GraphQL executeHTTPGraphQLRequest error: ' + err, false);
129
136
  if (ctx) {
130
137
  ctx.statusCode = 500;
131
- ctx.error_message = err.stack;
138
+ ctx.error_message = err.message;
139
+ ctx.error_class = err.name || err.constructor?.name || 'UnknownError'
132
140
  }
133
141
  return original.apply(this, arguments);
134
142
  }
@@ -101,8 +101,10 @@ function handleResponse(ctx, args, response) {
101
101
  ctx.profile.push(step);
102
102
  }
103
103
 
104
- function handleError(ctx, args, error) {
104
+ function handleError(ctx, args, err) {
105
105
  if (!ctx || !args[0]) return;
106
+ ctx.error_class = err.name || err.constructor?.name || 'HttpError';
107
+ ctx.error_message = err.message;
106
108
 
107
109
  const url = new URL(args[0]);
108
110
  setupContext(ctx, url);
@@ -110,7 +112,7 @@ function handleError(ctx, args, error) {
110
112
  var step = createStep(ctx, url);
111
113
 
112
114
  if (transaction_status_error_enable) {
113
- recordError(ctx, step, error);
115
+ recordError(ctx, step, err);
114
116
  }
115
117
 
116
118
  ctx.profile.push(step);
@@ -135,13 +137,21 @@ function createStep(ctx, url) {
135
137
 
136
138
  function recordError(ctx, step, response) {
137
139
  if (step.error.isZero()) {
138
- var cleanUrl = ctx.httpc_url.split('?')[0];
139
- ctx.service_name = URLPatternDetector.normalize(cleanUrl);
140
- ctx.service_hash = HashUtil.hashFromString(ctx.service_name);
141
-
142
- const errorMessage = response.statusText || (response.cause ? response.cause.message : '') || response.message || 'Unknown error';
140
+ const errorMessage = ctx.error_message = response.statusText || (response.cause ? response.cause.message : '') || response.message || 'Unknown error';
143
141
  step.error = StatError.addError(response.status || null, errorMessage, ctx.service_hash, TextTypes.HTTPC_URL, step.url);
144
142
 
143
+ if (response.status) {
144
+ if (response.status >= 400 && response.status < 500) {
145
+ ctx.error_class = `HttpClientError`;
146
+ } else if (response.status >= 500) {
147
+ ctx.error_class = `HttpServerError`;
148
+ } else {
149
+ ctx.error_class = `HttpError`;
150
+ }
151
+ } else {
152
+ ctx.error_class = 'HttpError';
153
+ }
154
+
145
155
  if (ctx.error.isZero()) {
146
156
  ctx.error = step.error;
147
157
  ctx.statusCode = response.status || null;
@@ -20,6 +20,7 @@ const MessageStep = require("../step/message-step");
20
20
  const MeterService = require('../counter/meter/meter-service').MeterService;
21
21
 
22
22
  const shimmer = require('../core/shimmer');
23
+ const StatError = require("../stat/stat-error");
23
24
 
24
25
  var grpc_profile_enabled = conf.getProperty('grpc_profile_enabled', true);
25
26
  var grpc_profile_stream_client_enabled = conf.getProperty('grpc_profile_stream_client_enabled', true);
@@ -88,8 +89,8 @@ function wrapHandler(handler, methodName, type) {
88
89
  }
89
90
 
90
91
  TraceContextManager._asyncLocalStorage.run(initCtx(), () => {
92
+ var ctx = TraceContextManager._asyncLocalStorage.getStore();
91
93
  try {
92
- var ctx = TraceContextManager._asyncLocalStorage.getStore();
93
94
  if (!ctx) {
94
95
  return handler.call(this, call, callback);
95
96
  }
@@ -120,8 +121,6 @@ function wrapHandler(handler, methodName, type) {
120
121
  ctx.profile.push(step_param);
121
122
  }
122
123
 
123
- console.log(call.pendingStatus)
124
-
125
124
  ctx.grpc_method = method_name;
126
125
 
127
126
  function wrappedCallback(err, response, ctx) {
@@ -129,6 +128,8 @@ function wrapHandler(handler, methodName, type) {
129
128
  if (err) {
130
129
  ctx.error = err.stack;
131
130
  ctx.statusCode = 500;
131
+ ctx.error_message = err.message;
132
+ ctx.error_class = err.name || err.constructor?.name || 'GrpcError';
132
133
 
133
134
  var step_error = new MessageStep();
134
135
  step_error.hash = HashUtil.hashFromString("EXCEPTION");
@@ -146,15 +147,14 @@ function wrapHandler(handler, methodName, type) {
146
147
  }
147
148
 
148
149
  return handler.call(this, call, (err, response) => wrappedCallback(err, response, ctx));
149
- // return handler.call(this, call, (err, response) => {
150
- // if (!err) {
151
- // err = new Error('Exception error occured');
152
- // }
153
- // wrappedCallback(err, response, ctx);
154
150
  } catch (err) {
155
151
  Logger.printError('WHATAP-701', 'gRPC wrapHandler error: ' + err, false);
156
152
 
157
- ctx.error = err.stack;
153
+ if(ctx.error.isZero()) {
154
+ ctx.error = StatError.addError(err.code, err.message, ctx.service_hash);
155
+ }
156
+ ctx.error_message = err.message;
157
+ ctx.error_class = err.name || err.constructor?.name || 'GrpcError';
158
158
 
159
159
  var step_error = new MessageStep();
160
160
  step_error.hash = HashUtil.hashFromString("EXCEPTION");