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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/controllers/builder_apm/diagnose_request_controller.rb +79 -0
- data/app/controllers/builder_apm/request_details_controller.rb +3 -2
- data/app/views/builder_apm/css/_dark.html.erb +161 -118
- data/app/views/builder_apm/css/_main.html.erb +342 -272
- data/app/views/builder_apm/js/_data_fetcher.html.erb +229 -236
- data/app/views/builder_apm/js/_request_details.html.erb +368 -164
- data/builder_apm.gemspec +1 -1
- data/config/routes.rb +3 -0
- data/lib/builder_apm/configuration.rb +6 -0
- data/lib/builder_apm/doctor/ai_doctor.rb +170 -0
- data/lib/builder_apm/doctor/backtrace_reducer.rb +104 -0
- data/lib/builder_apm/doctor/bravo_chat_ai.rb +85 -0
- data/lib/builder_apm/doctor/openai_chat_gpt.rb +84 -0
- data/lib/builder_apm/methods/instrumenter.rb +33 -6
- data/lib/builder_apm/middleware/timing.rb +6 -0
- data/lib/builder_apm/models/instrumenter.rb +15 -3
- data/lib/builder_apm/version.rb +1 -1
- data/lib/generators/builder_apm/templates/builder_apm_config.rb +7 -4
- metadata +8 -4
- data/README.md +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 204f52b000293324cc47566e57c0cfc3a1061262bb4daa85ade76ec733a78e84
|
4
|
+
data.tar.gz: 95ee965f9d8b64a19951ce3335f6f8255668ad91d95947976d594d63edeb3eb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f34eb19856e557ce3c627245cbad8ff1a39cbdcaa23b313220cf9764af2ea97ad42e8beca9fdaa9d06625f3ec5e324140b00b28a3d76b7c1a4701c258a1d88aa
|
7
|
+
data.tar.gz: e8be981fb87a3616d28e950e0421f69e622118bd27e5c0444fefe0e63660ec93ef434e180751e15d2499235eec3150ff640403302ee4718a8f54dd89722a8cfb
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'builder_apm/doctor/backtrace_reducer'
|
2
|
+
require 'builder_apm/doctor/ai_doctor'
|
3
|
+
|
4
|
+
module BuilderApm
|
5
|
+
class DiagnoseRequestController < ApplicationController
|
6
|
+
before_action :fetch_deeper_diagnosis, only: [:deeper_analysis]
|
7
|
+
before_action :fetch_existing_diagnosis, only: [:deeper_analysis, :index]
|
8
|
+
before_action :fetch_request_data, only: [:deeper_analysis, :index]
|
9
|
+
|
10
|
+
def index
|
11
|
+
return render json: { request_id: request_id, full_diagnosis: @existing_diagnosis } if @existing_diagnosis
|
12
|
+
return render json: { error: "No data found for #{request_id}" }, status: :not_found unless @parsed_request_data
|
13
|
+
|
14
|
+
diagnosis = doctor.diagnose(@parsed_request_data)
|
15
|
+
|
16
|
+
redis_client.set(redis_diagnosis_key, diagnosis)
|
17
|
+
render json: { request_id: request_id, full_diagnosis: diagnosis }
|
18
|
+
end
|
19
|
+
|
20
|
+
def deeper_analysis
|
21
|
+
return render json: { request_id: request_id, deeper_diagnosis: @existing_deeper_diagnosis } if @existing_deeper_diagnosis
|
22
|
+
return render json: { error: "No diagnosis found for #{request_id}" }, status: :not_found unless @existing_diagnosis
|
23
|
+
return render json: { error: "No data found for #{request_id}" }, status: :not_found unless @parsed_request_data
|
24
|
+
return render json: { error: "No file or line number passed" }, status: :not_found unless files
|
25
|
+
|
26
|
+
diagnosis = doctor.deeper_analysis(@parsed_request_data, @existing_diagnosis, files)
|
27
|
+
redis_client.set(redis_deeper_diagnosis_key, diagnosis)
|
28
|
+
|
29
|
+
render json: { request_id: request_id, deeper_diagnosis: diagnosis }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def doctor
|
35
|
+
@doctor ||= BuilderApm::Doctor::AiDoctor.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch_deeper_diagnosis
|
39
|
+
@existing_deeper_diagnosis = redis_client.get(redis_deeper_diagnosis_key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def fetch_existing_diagnosis
|
43
|
+
@existing_diagnosis = redis_client.get(redis_diagnosis_key)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_request_data
|
47
|
+
@request_data = redis_client.get(redis_request_key)
|
48
|
+
@parsed_request_data = @request_data ? JSON.parse(@request_data) : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def redis_keys
|
52
|
+
{
|
53
|
+
request: "builder_apm:Request:#{request_id}",
|
54
|
+
diagnosis: "builder_apm:RequestDiagnosis:#{request_id}",
|
55
|
+
deeper_diagnosis: "builder_apm:RequestDiagnosis:Deeper:#{request_id}"
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def redis_request_key
|
60
|
+
redis_keys[:request]
|
61
|
+
end
|
62
|
+
|
63
|
+
def redis_diagnosis_key
|
64
|
+
redis_keys[:diagnosis]
|
65
|
+
end
|
66
|
+
|
67
|
+
def redis_deeper_diagnosis_key
|
68
|
+
redis_keys[:deeper_diagnosis]
|
69
|
+
end
|
70
|
+
|
71
|
+
def request_id
|
72
|
+
@request_id ||= params[:request_id]
|
73
|
+
end
|
74
|
+
|
75
|
+
def files
|
76
|
+
@files ||= params[:files]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -3,9 +3,10 @@ module BuilderApm
|
|
3
3
|
def index
|
4
4
|
@request_id = params[:request_id]
|
5
5
|
@data = redis_client.get("builder_apm:Request:#{@request_id}") || {}
|
6
|
-
|
6
|
+
@diagnosis = redis_client.get("builder_apm:RequestDiagnosis:#{@request_id}") || ''
|
7
|
+
@deeper_diagnosis = redis_client.get("builder_apm:RequestDiagnosis:Deeper:#{@request_id}") || ''
|
8
|
+
@has_api_key = !BuilderApm.configuration.api_key.blank?
|
7
9
|
end
|
8
|
-
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -1,119 +1,162 @@
|
|
1
1
|
<style>
|
2
|
-
body.dark {
|
3
|
-
|
4
|
-
|
5
|
-
}
|
6
|
-
|
7
|
-
body.dark #header {
|
8
|
-
|
9
|
-
}
|
10
|
-
|
11
|
-
body.dark #navbar,
|
12
|
-
body.dark #navbar ul {
|
13
|
-
|
14
|
-
}
|
15
|
-
|
16
|
-
body.dark #navbar li a {
|
17
|
-
|
18
|
-
}
|
19
|
-
|
20
|
-
body.dark #navbar li a:hover {
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
|
25
|
-
body.dark #navbar li a.active {
|
26
|
-
|
27
|
-
|
28
|
-
}
|
29
|
-
|
30
|
-
body.dark table {
|
31
|
-
|
32
|
-
|
33
|
-
}
|
34
|
-
|
35
|
-
body.dark tr:nth-child(even) {
|
36
|
-
|
37
|
-
}
|
38
|
-
|
39
|
-
body.dark th {
|
40
|
-
|
41
|
-
|
42
|
-
}
|
43
|
-
|
44
|
-
body.dark #details_div .bounding-box {
|
45
|
-
|
46
|
-
|
47
|
-
}
|
48
|
-
|
49
|
-
body.dark
|
50
|
-
|
51
|
-
}
|
52
|
-
|
53
|
-
body.dark #details_div div {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
}
|
70
|
-
|
71
|
-
body.dark #details_div .
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
body.dark #details_div .
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
body.dark #details_div .
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
body.dark .
|
93
|
-
|
94
|
-
}
|
95
|
-
|
96
|
-
body.dark .
|
97
|
-
|
98
|
-
}
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
body.dark
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
body.dark #navbar
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
2
|
+
body.dark {
|
3
|
+
background-color: #242424;
|
4
|
+
color: #b3b3b3;
|
5
|
+
}
|
6
|
+
|
7
|
+
body.dark #header {
|
8
|
+
background-color: #666666;
|
9
|
+
}
|
10
|
+
|
11
|
+
body.dark #navbar,
|
12
|
+
body.dark #navbar ul {
|
13
|
+
background-color: #1f1f1f;
|
14
|
+
}
|
15
|
+
|
16
|
+
body.dark #navbar li a {
|
17
|
+
color: #b3b3b3;
|
18
|
+
}
|
19
|
+
|
20
|
+
body.dark #navbar li a:hover {
|
21
|
+
background-color: #b3b3b3;
|
22
|
+
color: #242424;
|
23
|
+
}
|
24
|
+
|
25
|
+
body.dark #navbar li a.active {
|
26
|
+
background-color: #666666;
|
27
|
+
color: #ffffff;
|
28
|
+
}
|
29
|
+
|
30
|
+
body.dark table {
|
31
|
+
color: #b3b3b3;
|
32
|
+
border: 1px solid #666666;
|
33
|
+
}
|
34
|
+
|
35
|
+
body.dark tr:nth-child(even) {
|
36
|
+
background-color: #3c3c3c;
|
37
|
+
}
|
38
|
+
|
39
|
+
body.dark th {
|
40
|
+
background-color: #666666;
|
41
|
+
color: #ffffff;
|
42
|
+
}
|
43
|
+
|
44
|
+
body.dark #details_div .bounding-box {
|
45
|
+
border: 1px solid #666666;
|
46
|
+
box-shadow: 0 0 5px rgba(255, 255, 255, 0.2);
|
47
|
+
}
|
48
|
+
|
49
|
+
body.dark pre {
|
50
|
+
background: rgba(255, 255, 255, 0.1);
|
51
|
+
}
|
52
|
+
|
53
|
+
body.dark #details_div div.has-children {
|
54
|
+
color: #bbbbbb;
|
55
|
+
}
|
56
|
+
|
57
|
+
body.dark #details_div .highlight-results {
|
58
|
+
background-color: #4c4c4c; /* A bit brighter than your usual dark elements, but not too much. */
|
59
|
+
border: 1px solid #777777; /* A slightly visible border */
|
60
|
+
border-radius: 4px; /* To keep it consistent with other styles like your button */
|
61
|
+
padding: 2px 4px; /* A little padding for the text inside */
|
62
|
+
cursor: help; /* Show a hint that there's a tooltip */
|
63
|
+
color: #e6e6e6; /* A bit brighter text for better visibility against the bright background */
|
64
|
+
}
|
65
|
+
|
66
|
+
body.dark #details_div div {
|
67
|
+
color: #bbbbbb;
|
68
|
+
background-color: #3c3c3c;
|
69
|
+
}
|
70
|
+
|
71
|
+
body.dark #details_div .sql-event {
|
72
|
+
background-color: #00001a;
|
73
|
+
color: #6699cc;
|
74
|
+
}
|
75
|
+
|
76
|
+
body.dark #details_div .children {
|
77
|
+
border-left: 1px solid #666666;
|
78
|
+
}
|
79
|
+
|
80
|
+
body.dark #details_div .has_children {
|
81
|
+
border: 1px solid #666666;
|
82
|
+
}
|
83
|
+
|
84
|
+
body.dark #details_div .date,
|
85
|
+
body.dark #details_div .duration,
|
86
|
+
body.dark #details_div .description,
|
87
|
+
body.dark #details_div .sql,
|
88
|
+
body.dark #details_div .method_line,
|
89
|
+
body.dark #details_div .trigger_line,
|
90
|
+
body.dark #details_div .cached,
|
91
|
+
body.dark #details_div .record_count,
|
92
|
+
body.dark #details_div .params {
|
93
|
+
color: #bbbbbb;
|
94
|
+
}
|
95
|
+
|
96
|
+
body.dark #details_div .minor_call {
|
97
|
+
background: #1a331a;
|
98
|
+
}
|
99
|
+
|
100
|
+
body.dark #details_div .error_status {
|
101
|
+
border: 1px solid #ff0000;
|
102
|
+
background-color: rgb(51, 0, 0);
|
103
|
+
}
|
104
|
+
|
105
|
+
body.dark .duration-circle {
|
106
|
+
border: 1px solid #666666;
|
107
|
+
}
|
108
|
+
|
109
|
+
body.dark .image-container::before {
|
110
|
+
background: radial-gradient(ellipse at center, rgba(0,0,0,0) 57%, rgba(0,0,0,1) 71%);
|
111
|
+
}
|
112
|
+
|
113
|
+
/* Dark mode styles */
|
114
|
+
|
115
|
+
body.dark #navbar li a,
|
116
|
+
body.dark #navbar .nav-button {
|
117
|
+
color: #ddd;
|
118
|
+
background-color: #666;
|
119
|
+
}
|
120
|
+
|
121
|
+
body.dark #navbar li a:hover,
|
122
|
+
body.dark #navbar .nav-button:hover {
|
123
|
+
background-color: #555;
|
124
|
+
color: #fff;
|
125
|
+
}
|
126
|
+
|
127
|
+
body.dark #navbar li a.active,
|
128
|
+
body.dark #navbar .nav-button.active {
|
129
|
+
background-color: #777;
|
130
|
+
color: #fff;
|
131
|
+
}
|
132
|
+
body.dark #details_div .request-summary {
|
133
|
+
background-color: #3a3a3a;
|
134
|
+
border: 1px solid #555;
|
135
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
136
|
+
}
|
137
|
+
|
138
|
+
body.dark #details_div .request-summary span {
|
139
|
+
color: #ddd;
|
140
|
+
}
|
141
|
+
|
142
|
+
/* AiDoctor Button Styles */
|
143
|
+
body.dark #details_div .ai-doctor-button,
|
144
|
+
body.dark #details_div .deeper-analysis-button {
|
145
|
+
background-color: #3498db;
|
146
|
+
color: #fff;
|
147
|
+
border: none;
|
148
|
+
transition: background-color 0.3s ease;
|
149
|
+
}
|
150
|
+
|
151
|
+
body.dark #details_div .ai-doctor-button:hover,
|
152
|
+
body.dark #details_div .deeper-analysis-button:hover {
|
153
|
+
background-color: #2980b9;
|
154
|
+
}
|
155
|
+
|
156
|
+
body.dark #details_div .ai-doctor-button.disabled,
|
157
|
+
body.dark #details_div .ai-doctor-button.disabled:hover,
|
158
|
+
body.dark #details_div .deeper-analysis-button.disabled,
|
159
|
+
body.dark #details_div .deeper-analysis-button.disabled:hover {
|
160
|
+
background-color: #aaa;
|
161
|
+
}
|
162
|
+
</style>
|