whatap 0.5.6 → 0.5.8

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.
@@ -267,7 +267,11 @@ var ConfigDefault = {
267
267
  "grpc_profile_ignore_method": bool("grpc_profile_ignore_method", true),
268
268
 
269
269
  "oname_port_postfix_enabled": bool("oname_port_postfix_enabled", false),
270
- "ignore_http_lost_connection": bool("ignore_http_lost_connection", false)
270
+ "ignore_http_lost_connection": bool("ignore_http_lost_connection", false),
271
+
272
+ "profile_graphql_enabled": bool("profile_graphql_enabled", true),
273
+ "profile_graphql_variable_enabled": bool("profile_graphql_variable_enabled", false),
274
+ "ignore_graphql_operation": str("ignore_graphql_operation", '')
271
275
  };
272
276
 
273
277
  ConfigDefault._hook_method_ignore_prefix = ConfigDefault.hook_method_ignore_prefixes.split(',');
package/lib/core/agent.js CHANGED
@@ -30,7 +30,9 @@ var Interceptor = require('./interceptor').Interceptor,
30
30
  PromiseObserver = require('../observers/promise-observer').PromiseObserver,
31
31
  PgSqlObserver = require('../observers/pgsql-observer').PgSqlObserver,
32
32
  ScheduleObserver = require('../observers/schedule-observer').ScheduleObserver,
33
- GRpcObserver = require('../observers/grpc-observer').GRpcObserver;
33
+ GRpcObserver = require('../observers/grpc-observer').GRpcObserver,
34
+ ApolloObserver = require('../observers/apollo-server-observer').ApolloServerObserver;
35
+
34
36
 
35
37
  var Configuration = require('./../conf/configure'),
36
38
  SecurityMaster = require('./../net/security-master'),
@@ -268,6 +270,7 @@ NodeAgent.prototype.loadObserves = function() {
268
270
  observes.push(PgSqlObserver);
269
271
  observes.push(ScheduleObserver);
270
272
  // observes.push(GRpcObserver);
273
+ observes.push(ApolloObserver);
271
274
 
272
275
  var packageToObserve = {};
273
276
  observes.forEach(function(observeObj) {
@@ -0,0 +1,155 @@
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
+ var TraceContextManager = require('../trace/trace-context-manager'),
8
+ conf = require('../conf/configure'),
9
+ Logger = require('../logger');
10
+ const HashUtil = require('../util/hashutil');
11
+ const DataTextAgent = require('../data/datatext-agent');
12
+ const MessageStep = require('../step/message-step');
13
+ const shimmer = require('../core/shimmer');
14
+ const StatError = require("../stat/stat-error");
15
+ const TextTypes = require("../lang/text-types");
16
+
17
+ var profile_graphql_enabled = conf.getProperty('profile_graphql_enabled', true);
18
+ var profile_graphql_variable_enabled = conf.getProperty('profile_graphql_variable_enabled', false);
19
+ var ignore_graphql_operation = conf.getProperty('ignore_graphql_operation', '');
20
+
21
+ conf.on('profile_graphql_enabled', function(newProperty) {
22
+ profile_graphql_enabled = newProperty;
23
+ });
24
+ conf.on('profile_graphql_variable_enabled', function(newProperty) {
25
+ profile_graphql_variable_enabled = newProperty;
26
+ });
27
+ conf.on('ignore_graphql_operation', function(newProperty) {
28
+ ignore_graphql_operation = newProperty;
29
+ });
30
+
31
+ var ApolloServerObserver = function(agent) {
32
+ this.agent = agent;
33
+ this.packages = ['@apollo/server'];
34
+ };
35
+
36
+ function checkIgnoreOperation(ignore_operation, operation_name) {
37
+ try {
38
+ let ignore_operation_set = null;
39
+ if (ignore_operation) {
40
+ ignore_operation_set = new Set(ignore_operation.split(','));
41
+ } else {
42
+ ignore_operation_set = null;
43
+ }
44
+ if (ignore_operation_set && ignore_operation_set.has(operation_name)) {
45
+ return true;
46
+ }
47
+ } catch (e) {
48
+ Logger.printError('WHATAP-803', 'GraphQL checkIgnoreOperation error: ' + e, false);
49
+ }
50
+ return false;
51
+ }
52
+
53
+ function wrapExecuteHTTPGraphQLRequest(original) {
54
+ return async function executeHTTPGraphQLRequest() {
55
+ if (!profile_graphql_enabled) {
56
+ return original.apply(this, arguments);
57
+ }
58
+
59
+ try {
60
+ var ctx = TraceContextManager.getCurrentContext();
61
+ if (!ctx) {
62
+ return original.apply(this, arguments);
63
+ }
64
+
65
+ const [requestContext] = arguments;
66
+ const { httpGraphQLRequest } = requestContext;
67
+ const { body } = httpGraphQLRequest;
68
+
69
+ const operationName = body.operationName;
70
+ if (checkIgnoreOperation(ignore_graphql_operation, operationName)) {
71
+ TraceContextManager.end(ctx._id)
72
+ return original.apply(this, arguments);
73
+ }
74
+
75
+ const originalServiceName = ctx.service_name || '';
76
+ if(operationName){
77
+ ctx.service_name = `${originalServiceName}?operationName=${operationName}`;
78
+ ctx.service_hash = HashUtil.hashFromString(ctx.service_name);
79
+ }
80
+
81
+ // Operation Type Step (query)
82
+ if(body.query && body.query.trim()){
83
+ var step_type = new MessageStep();
84
+ step_type.hash = HashUtil.hashFromString('Type');
85
+ step_type.start_time = ctx.getElapsedTime();
86
+ step_type.desc = body.query.trim().startsWith('mutation') ? 'mutation' : 'query';
87
+ DataTextAgent.MESSAGE.add(step_type.hash, "Type");
88
+ ctx.profile.push(step_type);
89
+ }
90
+
91
+ // Operation Name Step
92
+ if(operationName){
93
+ var step_operation = new MessageStep();
94
+ step_operation.hash = HashUtil.hashFromString('Operation');
95
+ step_operation.start_time = ctx.getElapsedTime();
96
+ step_operation.desc = operationName || 'anonymous';
97
+ DataTextAgent.MESSAGE.add(step_operation.hash, "Operation");
98
+ ctx.profile.push(step_operation);
99
+ }
100
+
101
+ // Variables Step
102
+ if (profile_graphql_variable_enabled && body.variables && Object.keys(body.variables).length > 0) {
103
+ var step_variables = new MessageStep();
104
+ step_variables.hash = HashUtil.hashFromString('Variables');
105
+ step_variables.start_time = ctx.getElapsedTime();
106
+ step_variables.desc = JSON.stringify(Object.keys(body.variables));
107
+ DataTextAgent.MESSAGE.add(step_variables.hash, "Variables");
108
+ ctx.profile.push(step_variables);
109
+ }
110
+
111
+ const response = await original.apply(this, arguments);
112
+
113
+ // 에러 처리
114
+ if (response.body.kind === 'complete' && response.body.string.includes('"errors"')) {
115
+ try {
116
+ const result = JSON.parse(response.body.string);
117
+ if (result.errors && result.errors.length > 0) {
118
+ const errorMessages = result.errors.map(error => error.message).join('\n');
119
+ ctx.statusCode = 500;
120
+ ctx.error_message = errorMessages;
121
+ }
122
+ } catch (e) {
123
+ Logger.printError('WHATAP-802', 'GraphQL error parsing failed', e, false);
124
+ }
125
+ }
126
+
127
+ return response;
128
+
129
+ } catch (err) {
130
+ Logger.printError('WHATAP-801', 'GraphQL executeHTTPGraphQLRequest error: ' + err, false);
131
+ if (ctx) {
132
+ ctx.statusCode = 500;
133
+ ctx.error_message = err.stack;
134
+ }
135
+ return original.apply(this, arguments);
136
+ }
137
+ };
138
+ }
139
+
140
+ ApolloServerObserver.prototype.inject = function(mod, moduleName) {
141
+ if (mod.__whatap_observe__) {
142
+ return;
143
+ }
144
+ mod.__whatap_observe__ = true;
145
+ Logger.initPrint("ApolloServerObserver");
146
+
147
+ if (profile_graphql_enabled) {
148
+ // Hook ApolloServer
149
+ if (mod.ApolloServer && mod.ApolloServer.prototype) {
150
+ shimmer.wrap(mod.ApolloServer.prototype, 'executeHTTPGraphQLRequest', wrapExecuteHTTPGraphQLRequest);
151
+ }
152
+ }
153
+ };
154
+
155
+ exports.ApolloServerObserver = ApolloServerObserver;
@@ -6,19 +6,23 @@
6
6
 
7
7
  var fs = require('fs'),
8
8
  path = require('path');
9
+ const { execSync } = require('child_process');
9
10
 
10
- function getPackageJson(){
11
- var appDir = require('./../conf/configure')['app.root'];
11
+ function getPackageJson() {
12
12
  try {
13
- var whatap_path = path.join(
14
- appDir,
15
- 'node_modules',
16
- 'whatap',
17
- 'package.json');
18
- NodeUtil.packageJson = require(whatap_path, 'utf8');
13
+ const whatapPath = require.resolve('whatap/package.json');
14
+ NodeUtil.packageJson = require(whatapPath);
19
15
  return;
20
16
  } catch(e) {
21
17
  }
18
+
19
+ try{
20
+ const globalPath = execSync('npm root -g').toString().trim();
21
+ const globalWhatapPath = path.join(globalPath, 'whatap', 'package.json');
22
+ NodeUtil.packageJson = require(globalWhatapPath);
23
+ return;
24
+ }catch (e) {
25
+ }
22
26
  NodeUtil.packageJson = {};
23
27
  }
24
28
  function recursiveCall(fullPath, file, cb){
@@ -65,4 +69,4 @@ var NodeUtil = {
65
69
  packageJson : {}
66
70
  };
67
71
 
68
- module.exports = NodeUtil;
72
+ module.exports = NodeUtil;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "whatap",
3
3
  "homepage": "http://www.whatap.io",
4
- "version": "0.5.6",
5
- "releaseDate": "20250123",
4
+ "version": "0.5.8",
5
+ "releaseDate": "20250218",
6
6
  "description": "Monitoring and Profiling Service",
7
7
  "main": "index.js",
8
8
  "scripts": {},