builder_apm 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,192 +1,396 @@
1
1
  <script>
2
- var request_id = '<%= @request_id %>';
3
- var request_data = <%= @data.to_json.html_safe %>;
4
- var current_index = 0;
5
-
6
- $(document).ready(function() {
7
- prepPage();
8
- var request = JSON.parse(request_data);
9
- tagQueriesWithNPlusOne(request);
10
- const preparedData = flattenData(request.stack);
11
-
12
- $("#details_div").empty()
13
- if(request.exception_message) {
14
- $("#details_div").append(errorDetails(request));
15
- }
16
- $("#details_div").append(renderDetails(preparedData));
17
- });
18
-
19
- function prepPage(){
20
- $("#details_div").text("Loading Request Now...");
21
- $("#options").empty();
22
-
23
- // Create a new checkbox
24
- var checkbox = $('<input />', {
25
- type: 'checkbox',
26
- id: 'chkShowMinorCalls',
27
- value: 'showMinorCalls'
28
- }).on('change', function() {
29
- // Show/hide '.minor_call' elements based on checkbox status
30
- if(this.checked) {
31
- $('.minor_call').show();
32
- } else {
33
- $('.minor_call').hide();
2
+ var request_id = '<%= @request_id %>';
3
+ var request = JSON.parse(<%= @data.to_json.html_safe %>);
4
+ var diagnosis = <%= @diagnosis.to_json.html_safe %>;
5
+ var deeper_diagnosis = <%= @deeper_diagnosis.to_json.html_safe %>;
6
+ var has_api_key = <%= @has_api_key.to_s %>;
7
+
8
+ var current_index = 0;
9
+
10
+ $(document).ready(function () {
11
+ prepPage();
12
+ tagQueriesWithNPlusOne(request);
13
+ const preparedData = flattenData(request.stack);
14
+
15
+ mainDiv = $("#details_div")
16
+
17
+ mainDiv.empty();
18
+ mainDiv.append(renderRequestSummary(request));
19
+ if (diagnosis.length > 0) {
20
+ mainDiv.append(renderRequestDiagnosis(diagnosis));
21
+ }
22
+ if (deeper_diagnosis.length > 0) {
23
+ mainDiv.append(renderDeeperDiagnosis(deeper_diagnosis));
24
+ }
25
+
26
+ if (request.exception_message) {
27
+ mainDiv.append(errorDetails(request));
34
28
  }
35
- });
36
29
 
37
- // Create a label for the checkbox
38
- var label = $('<label />', {
39
- 'for': 'chkShowMinorCalls',
40
- text: 'Show Calls with less than 0.1ms duration',
30
+ mainDiv.append(renderDetails(preparedData));
41
31
  });
42
32
 
43
- // Append the checkbox and label to the div
44
- $("#options").append(checkbox).append(label);
45
- }
46
-
47
- function flattenData(stackData, level = 0) {
48
- var result = [];
49
-
50
- stackData.forEach(function(stackItem, level) {
51
- var start = new Date(stackItem.start_time);
52
- var end = new Date(stackItem.end_time);
53
-
54
- if(stackItem.sql) {
55
- result.push({
56
- start: start,
57
- duration: stackItem.duration,
58
- sql: stackItem.sql,
59
- cached: stackItem.cached,
60
- record_count: stackItem.record_count,
61
- triggering_line: stackItem.triggering_line,
62
- params: stackItem.params,
63
- level: level,
64
- possibleNPlusOne: stackItem.possibleNPlusOne
65
- });
66
- } else {
67
- var children = [];
68
- if (stackItem.sql_events && stackItem.sql_events.length > 0) {
69
- children = children.concat(flattenData(stackItem.sql_events, level+1));
33
+ function prepPage() {
34
+ $("#details_div").text("Loading Request Now...");
35
+ $("#options").empty();
36
+
37
+ // Create a new checkbox
38
+ var checkbox = $('<input />', {
39
+ type: 'checkbox',
40
+ id: 'chkShowMinorCalls',
41
+ value: 'showMinorCalls'
42
+ }).on('change', function () { // Show/hide '.minor_call' elements based on checkbox status
43
+ if (this.checked) {
44
+ $('.minor_call').show();
45
+ } else {
46
+ $('.minor_call').hide();
70
47
  }
48
+ });
49
+
50
+ // Create a label for the checkbox
51
+ var label = $('<label />', {
52
+ 'for': 'chkShowMinorCalls',
53
+ text: 'Show Calls with less than 0.1ms duration'
54
+ });
55
+
56
+ // Append the checkbox and label to the div
57
+ $("#options").append(checkbox).append(label);
58
+ }
59
+
60
+ function callTheDoctor() {
61
+ $('.ai-doctor-button').hide();
62
+
63
+ // Show loading message with a simple animated "..." indicator
64
+ var loaded = false;
65
+ var dots = 0;
66
+ var doc_msg = getRandomMessage(wait_4_doc);
67
+ var loadingInterval = setInterval(function () {
68
+ $('.status-message').text(doc_msg + '.'.repeat(dots));
69
+ dots = (dots + 1) % 4;
70
+ }, 500);
71
+
72
+ function fetchDiagnosis() {
73
+ return $.get('/builder_apm/diagnose_request?request_id=' + request_id);
74
+ }
71
75
 
72
- if (stackItem.children && stackItem.children.length > 0) {
73
- children = children.concat(flattenData(stackItem.children, level+1));
76
+
77
+ Promise.race([fetchDiagnosis()]).then(response => {
78
+ if (response && response.full_diagnosis) {
79
+ clearInterval(loadingInterval);
80
+ renderRequestDiagnosis(response.full_diagnosis).insertAfter('.request-summary');
81
+ $('.status-message').hide();
82
+ return;
83
+ } else {
84
+ throw new Error("Failed to get valid response.");
74
85
  }
75
- result.push({
76
- start: start,
77
- duration: stackItem.duration,
78
- method: stackItem.method,
79
- method_line: stackItem.method_line,
80
- triggering_line: stackItem.triggering_line,
81
- children: children,
82
- level
83
- });
86
+ }).catch(err => {
87
+ console.error("Error:", err);
88
+ clearInterval(loadingInterval);
89
+ $('.ai-doctor-button').show();
90
+ $('.status-message').text(getRandomMessage(doc_not_in));
91
+ });
92
+ }
93
+
94
+
95
+ function getRandomMessage(messages) {
96
+ let randomIndex = Math.floor(Math.random() * messages.length);
97
+ return messages[randomIndex];
98
+ }
99
+
100
+ var wait_4_doc = [
101
+ "The Ai Doctor is on it! Analyzing your data now; please wait a moment.",
102
+ "Hold tight! The Ai Doctor is checking your stack trace and data.",
103
+ "Your request is being analyzed by the Ai Doctor. Give it a few minutes.",
104
+ "Summoning the Ai Doctor to review your input. Sit tight!",
105
+ "Please be patient. The Ai Doctor is examining your data for any anomalies.",
106
+ "Analysis in progress! The Ai Doctor is diving deep into your data.",
107
+ "The Ai Doctor is now on duty! Reviewing the provided details.",
108
+ "Your data is on the examination table! The Ai Doctor will be with you shortly.",
109
+ "Sending your information to the Ai Doctor for a thorough check-up. Hang on!",
110
+ "Ai Doctor is rolling up its sleeves! Your data is being analyzed, please wait.",
111
+ "The doctor is being called and will review your notes. This may take a couple of mins."
112
+ ];
113
+
114
+ var doc_not_in = [
115
+ "Oops! The Ai Doctor seems to be offline. Please retry in a bit.",
116
+ "Sorry, the Ai Doctor is currently out of reach. Give it another shot later.",
117
+ "Our apologies! The Ai Doctor is taking a short break. Try again shortly.",
118
+ "It looks like the Ai Doctor is tied up. Please attempt again later.",
119
+ "Regrettably, the Ai Doctor can't be reached right now. Please come back later.",
120
+ "Technical hiccup! The Ai Doctor isn't responsive. Kindly retry after some time.",
121
+ "Brief interruption — the Ai Doctor is momentarily out. Please revisit in a while.",
122
+ "We're experiencing a glitch. The Ai Doctor isn't on call right now. Please retry later.",
123
+ "Ai Doctor seems to be in a meeting. Please push the button again later.",
124
+ "Hold up! The Ai Doctor isn't taking appointments right now. Try after a moment.",
125
+ "The doctor is unavailable, please try again later"
126
+ ];
127
+
128
+ var no_key_4_doc = [
129
+ "Ai Doctor is currently inaccessible - API Key hasn't been configured.",
130
+ "Unable to access Ai Doctor - Missing API Key.",
131
+ "Ai Doctor can't be reached - Please set up your API Key.",
132
+ "Error: Ai Doctor is unavailable due to an unset API Key.",
133
+ "Ai Doctor service is offline - No API Key detected.",
134
+ "Ai Doctor cannot proceed - API Key configuration required.",
135
+ "Operation halted: Ai Doctor requires an API Key setup.",
136
+ "Api Key for Ai Doctor is missing - Service not accessible.",
137
+ "Ai Doctor is not operational - Ensure your API Key is established.",
138
+ "Connectivity issue with Ai Doctor - API Key setup needed."
139
+ ];
140
+
141
+ function renderRequestDiagnosis(diagnosis) { // Create the main diagnosis div
142
+ var diagnosisDiv = $('<div>').addClass('diagnosis-section').html('<h2 class="doc_title">Ai Doctor Analysis</h2><p>' + diagnosis + '</p>');
143
+
144
+ // Extract the file and line number from the diagnosis string
145
+ var parser = new DOMParser();
146
+ var doc = parser.parseFromString(diagnosis, 'text/html');
147
+
148
+ if (deeper_diagnosis.length === 0) {
149
+ // Add the AiDoctor button
150
+ // Create the deeper analysis button
151
+ var deeperAnalysisButton = $("<button>").addClass('deeper-analysis-button').html('<i class="cool-icon"></i> Deeper Analysis');
152
+ var message_div = $("<div>").addClass('deeper-analaysis-status-message');
153
+ if (has_api_key) {
154
+ deeperAnalysisButton.on('click', function () {
155
+ deeperAnalysisHandler();
156
+ });
157
+ } else {
158
+ message_div.text(getRandomMessage(no_key_4_doc));
159
+ deeperAnalysisButton.addClass('disabled');
160
+ } diagnosisDiv.append(deeperAnalysisButton);
161
+ diagnosisDiv.append(message_div)
162
+ } else {
163
+ diagnosisDiv.find('input[type="checkbox"]').remove();
84
164
  }
85
- });
86
165
 
87
- // sort by start_time
88
- result.sort((a, b) => a.start - b.start);
89
-
90
- return result;
91
- }
92
- function getDurationClass(duration) {
93
- if (duration < 500) {
94
- return "green-circle";
95
- } else if (duration >= 500 && duration < 1000) {
96
- return "amber-circle";
97
- } else {
98
- return "red-circle";
166
+ return diagnosisDiv;
167
+ }
168
+
169
+ function renderDeeperDiagnosis(diagnosis) { // Create the main diagnosis div
170
+ var diagnosisDiv = $('<div>').addClass('diagnosis-section').html('<h2 class="doc_title">Ai Doctor Deeper Analysis</h2><p>' + diagnosis + '</p>');
171
+
172
+ return diagnosisDiv;
99
173
  }
100
- }
174
+ // An example handler function for the deeper analysis button click
175
+ function deeperAnalysisHandler() {
101
176
 
102
- function getFormattedDate(date) {
103
- return `${date.toLocaleDateString('en-GB')} ${date.toLocaleTimeString('en-GB', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' })}`;
104
- }
177
+ var selectedCheckboxes = document.querySelectorAll('input[name="deeper_dive_filename"]:checked');
105
178
 
106
- function renderDetails(stackData, level = 0) {
107
- return stackData.map((item, index) => {
108
- var itemDiv = $("<div>").addClass('bounding-box');
179
+ var selectedFiles = Array.from(selectedCheckboxes).map(checkbox => checkbox.value);
109
180
 
110
- var formattedDate = getFormattedDate(item.start);
111
- var formattedDuration = parseFloat(parseFloat(item.duration).toFixed(3)) + 'ms';
112
- var durationClass = getDurationClass(item.duration);
181
+ console.log("Deeper analysis for:", selectedFiles);
113
182
 
114
- var durationSpan = $("<span>").addClass("duration").append(
115
- $("<span>").addClass("duration-circle " + durationClass),
116
- `${formattedDuration}`
117
- );
183
+ $('.deeper-analysis-button').hide();
118
184
 
119
- if (item.method) { // If it's a method.
120
- if(item.duration < 0.1 && level > 0){
121
- itemDiv.addClass('minor_call');
122
- }
123
- itemDiv.addClass("method")
124
- .append($('<span>').addClass('date').text(formattedDate), durationSpan,
125
- $('<span>').addClass('description').text(item.method),
126
- $('<span>').addClass('method_line').text(item.method_line),
127
- $('<span>').addClass('trigger_line').text(item.triggering_line));
128
-
129
- if(item.children && item.children.length > 0) {
130
- itemDiv.prepend($("<span>").addClass('has_children').text("+"))
131
- .append(
132
- $("<div>").addClass("children")
133
- .append(renderDetails(item.children, level +1))
134
- .hide() // Hide the children initially
135
- );
136
- }
137
- } else { // If it's an SQL event.
138
- itemDiv.addClass("sql-event")
139
- .append($('<span>').addClass('date').text(formattedDate), durationSpan,
140
- $('<span>').addClass('record_count').text(item.record_count + ' Results'),
141
- $('<span>').addClass('cached').text(item.cached ? 'Cached' : ''),
142
- $('<span>').addClass('n_plus_one').text(item.possibleNPlusOne ? 'Possible N+1' : ''),
143
- $('<span>').addClass('trigger_line').text(item.triggering_line),
144
- $('<span>').addClass('sql').text(item.sql));
145
-
146
- if(item.possibleNPlusOne) {
147
- itemDiv.addClass('possible_n_plus_one');
148
- }
149
- if(item.params && item.params.length > 0) {
150
- itemDiv.append($('<span>').addClass('params').text('Params: ' + item.params));
185
+ // Show loading message with a simple animated "..." indicator
186
+ var loaded = false;
187
+ var dots = 0;
188
+ var doc_msg = getRandomMessage(wait_4_doc);
189
+ var loadingInterval = setInterval(function () {
190
+ $('.deeper-analaysis-status-message').text(doc_msg + '.'.repeat(dots));
191
+ dots = (dots + 1) % 4;
192
+ }, 500);
193
+
194
+ function fetchDeeperDiagnosis() {
195
+ return $.post('/builder_apm/deeper_analysis', {
196
+ request_id: request_id,
197
+ files: selectedFiles
198
+ });
199
+ }
200
+
201
+
202
+ Promise.race([fetchDeeperDiagnosis()]).then(response => {
203
+ if (response && response.deeper_diagnosis) {
204
+ clearInterval(loadingInterval);
205
+ renderDeeperDiagnosis(response.deeper_diagnosis).insertAfter('.diagnosis-section');
206
+ $('.deeper-analaysis-status-message').hide();
207
+ return;
208
+ } else {
209
+ throw new Error("Failed to get valid response.");
151
210
  }
211
+ }).catch(err => {
212
+ console.error("Error:", err);
213
+ clearInterval(loadingInterval);
214
+ $('.ai-doctor-button').show();
215
+ $('.deeper-analaysis-status-message').text(getRandomMessage(doc_not_in));
216
+ });
217
+ }
218
+
219
+
220
+ function renderRequestSummary(request) {
221
+ var summaryDiv = $("<div>").addClass('request-summary');
222
+
223
+ // Add the details to the summary
224
+ summaryDiv.append($('<span>').addClass('url').text('URL: ' + request.path));
225
+ summaryDiv.append($('<span>').addClass('controller').text('Controller: ' + request.controller));
226
+ summaryDiv.append($('<span>').addClass('duration').text('Duration: ' + formatDuration(request.duration) + 'ms'));
227
+ summaryDiv.append($('<span>').addClass('db_duration').text('DB Duration: ' + formatDuration(request.db_runtime) + 'ms'));
228
+ summaryDiv.append($('<span>').addClass('view_duration').text('View Duration: ' + formatDuration(request.view_runtime) + 'ms'));
229
+ summaryDiv.append($('<span>').addClass('method').text('Method: ' + request.method));
230
+ summaryDiv.append($('<span>').addClass('params').text('Params: ' + JSON.stringify(request.params)));
231
+
232
+ if (diagnosis.length === 0) { // Add the AiDoctor button
233
+ var aiDoctorButton = $("<button>").addClass('ai-doctor-button').html('<i class="cool-icon"></i> Call AiDoctor');
234
+ var message_div = $("<div>").addClass('status-message');
235
+ if (has_api_key) {
236
+ aiDoctorButton.on('click', callTheDoctor);
237
+ } else {
238
+ message_div.text(getRandomMessage(no_key_4_doc));
239
+ aiDoctorButton.addClass('disabled');
240
+ } summaryDiv.append(aiDoctorButton);
241
+ summaryDiv.append(message_div)
152
242
  }
153
- return itemDiv;
154
- });
155
- }
156
-
157
- $(document).on('click', '.bounding-box', function(e) {
158
- e.stopPropagation();
159
- var toggleElement = $(this).find(".has_children:first");
160
- if (toggleElement.length > 0) {
161
- if (toggleElement.text() === "+") {
162
- toggleElement.text("-");
243
+ return summaryDiv;
244
+ }
245
+
246
+ function formatDuration(value) {
247
+ if (isNaN(value)) {
248
+ return 'N/A'; // or whatever default/failover value you prefer
163
249
  } else {
164
- toggleElement.text("+");
250
+ return parseFloat(value).toFixed(3);
165
251
  }
166
- $(this).find(".children:first").slideToggle();
167
252
  }
168
- });
169
253
 
254
+ function flattenData(stackData, level = 0) {
255
+ var result = [];
256
+
257
+ stackData.forEach(function (stackItem, level) {
258
+ var start = new Date(stackItem.start_time);
259
+ var end = new Date(stackItem.end_time);
260
+
261
+ if (stackItem.sql) {
262
+ result.push({
263
+ start: start,
264
+ duration: stackItem.duration,
265
+ sql: stackItem.sql,
266
+ cached: stackItem.cached,
267
+ record_count: stackItem.record_count,
268
+ triggering_line: stackItem.triggering_line,
269
+ params: stackItem.params,
270
+ level: level,
271
+ possibleNPlusOne: stackItem.possibleNPlusOne
272
+ });
273
+ } else {
274
+ var children = [];
275
+ if (stackItem.sql_events && stackItem.sql_events.length > 0) {
276
+ children = children.concat(flattenData(stackItem.sql_events, level + 1));
277
+ }
170
278
 
171
- function errorDetails(request) {
172
- // Create a container for the error details
173
- var errorContainer = $('<div>').addClass('error_status');
279
+ if (stackItem.children && stackItem.children.length > 0) {
280
+ children = children.concat(flattenData(stackItem.children, level + 1));
281
+ }
282
+ result.push({
283
+ start: start,
284
+ duration: stackItem.duration,
285
+ method: stackItem.method,
286
+ method_line: stackItem.method_line,
287
+ triggering_line: stackItem.triggering_line,
288
+ children: children,
289
+ level
290
+ });
291
+ }
292
+ });
174
293
 
175
- // Create and append elements for the exception class and message
176
- var exceptionClassElement = $('<h2>').text(request.exception_class).css('margin', '0');
177
- var exceptionMessageElement = $('<p>').text(request.exception_message);
178
- errorContainer.append(exceptionClassElement, exceptionMessageElement);
294
+ // sort by start_time
295
+ result.sort((a, b) => a.start - b.start);
179
296
 
180
- // Create and append an element for the backtrace
181
- var backtraceElement = $('<ol>');
182
- request.exception_backtrace.forEach(function(line) {
183
- var lineElement = $('<li>').text(line);
184
- backtraceElement.append(lineElement);
297
+ return result;
298
+ }
299
+ function getDurationClass(duration) {
300
+ if (duration < 500) {
301
+ return "green-circle";
302
+ } else if (duration >= 500 && duration < 1000) {
303
+ return "amber-circle";
304
+ } else {
305
+ return "red-circle";
306
+ }
307
+ }
308
+
309
+ function getFormattedDate(date) {
310
+ return `${
311
+ date.toLocaleDateString('en-GB')
312
+ } ${
313
+ date.toLocaleTimeString('en-GB', {
314
+ hour12: false,
315
+ hour: '2-digit',
316
+ minute: '2-digit',
317
+ second: '2-digit'
318
+ })
319
+ }`;
320
+ }
321
+
322
+ function renderDetails(stackData, level = 0) {
323
+ return stackData.map((item, index) => {
324
+ var itemDiv = $("<div>").addClass('bounding-box');
325
+
326
+ var formattedDate = getFormattedDate(item.start);
327
+ var formattedDuration = parseFloat(parseFloat(item.duration).toFixed(3)) + 'ms';
328
+ var durationClass = getDurationClass(item.duration);
329
+
330
+ var durationSpan = $("<span>").addClass("duration").append($("<span>").addClass("duration-circle " + durationClass), `${formattedDuration}`);
331
+
332
+ if (item.method) { // If it's a method.
333
+ if (item.duration < 0.1 && level > 0) {
334
+ itemDiv.addClass('minor_call');
335
+ }
336
+ itemDiv.addClass("method").append($('<span>').addClass('date').text(formattedDate), durationSpan, $('<span>').addClass('description').text(item.method), $('<span>').addClass('method_line').text(item.method_line), $('<span>').addClass('trigger_line').text(item.triggering_line));
337
+
338
+ if (item.children && item.children.length > 0) {
339
+ itemDiv.prepend($("<span>").addClass('has_children').text("+")).append($("<div>").addClass("children").append(renderDetails(item.children, level + 1)).hide() // Hide the children initially
340
+ );
341
+ }
342
+ } else { // If it's an SQL event.
343
+ let resultsSpan = $('<span>').addClass('record_count').text(item.record_count + ' Results');
344
+
345
+ // Check if results are more than 50
346
+ if (item.record_count > 50) {
347
+ resultsSpan.addClass('highlight-results').attr('title', "This is a large number of results. Review if this can be paginated or limited.");
348
+ }
349
+
350
+ itemDiv.addClass("sql-event").append($('<span>').addClass('date').text(formattedDate), durationSpan, resultsSpan, $('<span>').addClass('cached').text(item.cached ? 'Cached' : ''), $('<span>').addClass('n_plus_one').text(item.possibleNPlusOne ? 'Possible N+1' : ''), $('<span>').addClass('trigger_line').text(item.triggering_line), $('<span>').addClass('sql').text(item.sql));
351
+
352
+ if (item.possibleNPlusOne) {
353
+ itemDiv.addClass('possible_n_plus_one');
354
+ }
355
+ if (item.params && item.params.length > 0) {
356
+ itemDiv.append($('<span>').addClass('params').text('Params: ' + item.params));
357
+ }
358
+ }
359
+ return itemDiv;
360
+ });
361
+ }
362
+
363
+ $(document).on('click', '.bounding-box', function (e) {
364
+ e.stopPropagation();
365
+ var toggleElement = $(this).find(".has_children:first");
366
+ if (toggleElement.length > 0) {
367
+ if (toggleElement.text() === "+") {
368
+ toggleElement.text("-");
369
+ } else {
370
+ toggleElement.text("+");
371
+ }
372
+ $(this).find(".children:first").slideToggle();
373
+ }
185
374
  });
186
- errorContainer.append(backtraceElement);
187
375
 
188
- // Append the error details container to the body of the page
189
- return errorContainer;
190
- }
191
376
 
192
- </script>
377
+ function errorDetails(request) { // Create a container for the error details
378
+ var errorContainer = $('<div>').addClass('error_status');
379
+
380
+ // Create and append elements for the exception class and message
381
+ var exceptionClassElement = $('<h2>').text(request.exception_class).css('margin', '0');
382
+ var exceptionMessageElement = $('<p>').text(request.exception_message);
383
+ errorContainer.append(exceptionClassElement, exceptionMessageElement);
384
+
385
+ // Create and append an element for the backtrace
386
+ var backtraceElement = $('<ol>');
387
+ request.exception_backtrace.forEach(function (line) {
388
+ var lineElement = $('<li>').text(line);
389
+ backtraceElement.append(lineElement);
390
+ });
391
+ errorContainer.append(backtraceElement);
392
+
393
+ // Append the error details container to the body of the page
394
+ return errorContainer;
395
+ }
396
+ </script>
data/builder_apm.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.add_dependency "redis", "~> 4.5"
16
16
 
17
17
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f == 'README.md' }
19
19
  end
20
20
  spec.bindir = "exe"
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
data/config/routes.rb CHANGED
@@ -9,4 +9,7 @@ BuilderApm::Engine.routes.draw do
9
9
  get 'request_analysis', to: 'request_analysis#index'
10
10
  get 'n_plus_one', to: 'n_plus_one#index'
11
11
 
12
+ post 'deeper_analysis', to: 'diagnose_request#deeper_analysis', defaults: { format: 'json' }
13
+ get 'diagnose_request', to: 'diagnose_request#index', defaults: { format: 'json' }
14
+
12
15
  end
@@ -5,6 +5,9 @@ module BuilderApm
5
5
  attr_accessor :enable_active_record_profiler
6
6
  attr_accessor :enable_methods_profiler
7
7
  attr_accessor :enable_n_plus_one_profiler
8
+ attr_accessor :api_key
9
+ attr_accessor :api
10
+ attr_accessor :gems_to_track
8
11
 
9
12
  def initialize
10
13
  @redis_url = 'redis://localhost:6379/0'
@@ -12,6 +15,9 @@ module BuilderApm
12
15
  @enable_active_record_profiler = true
13
16
  @enable_methods_profiler = true
14
17
  @enable_n_plus_one_profiler = true
18
+ @api_key = nil
19
+ @api = 'Bravo'
20
+ @gems_to_track = ["bx_block_"]
15
21
  end
16
22
  end
17
23
  end