builder_apm 0.4.2 → 0.5.1

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.
@@ -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