dbwatcher 1.1.4 → 1.1.5
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/README.md +79 -26
- data/app/assets/images/dbwatcher/apple-touch-icon.png +0 -0
- data/app/assets/images/dbwatcher/dbwatcher-social-preview.png +0 -0
- data/app/assets/images/dbwatcher/dbwatcher-tranparent_512x512.png +0 -0
- data/app/assets/images/dbwatcher/dbwatcher_512x512.png +0 -0
- data/app/assets/images/dbwatcher/favicon-96x96.png +0 -0
- data/app/assets/images/dbwatcher/favicon.ico +0 -0
- data/app/assets/images/dbwatcher/favicon.svg +3 -0
- data/app/assets/images/dbwatcher/site.webmanifest +21 -0
- data/app/assets/images/dbwatcher/web-app-manifest-192x192.png +0 -0
- data/app/assets/images/dbwatcher/web-app-manifest-512x512.png +0 -0
- data/app/assets/stylesheets/dbwatcher/application.css +38 -4
- data/app/assets/stylesheets/dbwatcher/components/_tabulator.scss +57 -13
- data/app/controllers/dbwatcher/api/v1/system_info_controller.rb +1 -1
- data/app/controllers/dbwatcher/dashboard_controller.rb +1 -1
- data/app/views/dbwatcher/dashboard/_overview.html.erb +8 -7
- data/app/views/dbwatcher/sessions/index.html.erb +42 -59
- data/app/views/layouts/dbwatcher/application.html.erb +22 -6
- data/lib/dbwatcher/configuration.rb +49 -83
- data/lib/dbwatcher/logging.rb +2 -2
- data/lib/dbwatcher/services/diagram_analyzers/concerns/activerecord_introspection.rb +60 -0
- data/lib/dbwatcher/services/diagram_analyzers/concerns/association_scope_filtering.rb +60 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_analysis/association_extractor.rb +224 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_analysis/dataset_builder.rb +226 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_analysis/model_discovery.rb +161 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_association_analyzer.rb +27 -514
- data/lib/dbwatcher/services/diagram_data/attribute.rb +22 -83
- data/lib/dbwatcher/services/diagram_data/base.rb +129 -0
- data/lib/dbwatcher/services/diagram_data/entity.rb +23 -72
- data/lib/dbwatcher/services/diagram_data/relationship.rb +15 -66
- data/lib/dbwatcher/services/mermaid_syntax/erd_builder.rb +2 -2
- data/lib/dbwatcher/services/mermaid_syntax/sanitizer.rb +4 -14
- data/lib/dbwatcher/services/system_info/runtime_info_collector.rb +7 -7
- data/lib/dbwatcher/services/system_info/system_info_collector.rb +3 -3
- data/lib/dbwatcher/services/timeline_data_service/entry_builder.rb +23 -1
- data/lib/dbwatcher/storage/session_storage.rb +2 -2
- data/lib/dbwatcher/storage.rb +1 -1
- data/lib/dbwatcher/version.rb +1 -1
- metadata +18 -2
@@ -35,24 +35,39 @@
|
|
35
35
|
position: sticky;
|
36
36
|
left: 0;
|
37
37
|
z-index: 20;
|
38
|
-
background: #f3f3f3;
|
38
|
+
background: #f3f3f3 !important;
|
39
|
+
background-color: #f3f3f3 !important;
|
39
40
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
41
|
+
will-change: transform;
|
42
|
+
transform: translateZ(0);
|
43
|
+
opacity: 1 !important;
|
44
|
+
transition: opacity 0.1s ease-out;
|
40
45
|
}
|
41
46
|
|
42
47
|
&.sticky-left-1 {
|
43
48
|
position: sticky;
|
44
49
|
left: 60px;
|
45
50
|
z-index: 19;
|
46
|
-
background: #f3f3f3;
|
51
|
+
background: #f3f3f3 !important;
|
52
|
+
background-color: #f3f3f3 !important;
|
47
53
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
54
|
+
will-change: transform;
|
55
|
+
transform: translateZ(0);
|
56
|
+
opacity: 1 !important;
|
57
|
+
transition: opacity 0.1s ease-out;
|
48
58
|
}
|
49
59
|
|
50
60
|
&.sticky-left-2 {
|
51
61
|
position: sticky;
|
52
62
|
left: 108px;
|
53
63
|
z-index: 18;
|
54
|
-
background: #f3f3f3;
|
64
|
+
background: #f3f3f3 !important;
|
65
|
+
background-color: #f3f3f3 !important;
|
55
66
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
67
|
+
will-change: transform;
|
68
|
+
transform: translateZ(0);
|
69
|
+
opacity: 1 !important;
|
70
|
+
transition: opacity 0.1s ease-out;
|
56
71
|
}
|
57
72
|
}
|
58
73
|
}
|
@@ -115,25 +130,40 @@
|
|
115
130
|
&.sticky-left-0 {
|
116
131
|
position: sticky;
|
117
132
|
left: 0;
|
118
|
-
background: white;
|
133
|
+
background: white !important;
|
134
|
+
background-color: white !important;
|
119
135
|
z-index: 5;
|
120
136
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
|
137
|
+
will-change: transform;
|
138
|
+
transform: translateZ(0);
|
139
|
+
opacity: 1 !important;
|
140
|
+
transition: opacity 0.1s ease-out;
|
121
141
|
}
|
122
142
|
|
123
143
|
&.sticky-left-1 {
|
124
144
|
position: sticky;
|
125
145
|
left: 60px;
|
126
|
-
background: white;
|
146
|
+
background: white !important;
|
147
|
+
background-color: white !important;
|
127
148
|
z-index: 4;
|
128
149
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
|
150
|
+
will-change: transform;
|
151
|
+
transform: translateZ(0);
|
152
|
+
opacity: 1 !important;
|
153
|
+
transition: opacity 0.1s ease-out;
|
129
154
|
}
|
130
155
|
|
131
156
|
&.sticky-left-2 {
|
132
157
|
position: sticky;
|
133
158
|
left: 108px;
|
134
|
-
background: white;
|
159
|
+
background: white !important;
|
160
|
+
background-color: white !important;
|
135
161
|
z-index: 3;
|
136
162
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
|
163
|
+
will-change: transform;
|
164
|
+
transform: translateZ(0);
|
165
|
+
opacity: 1 !important;
|
166
|
+
transition: opacity 0.1s ease-out;
|
137
167
|
}
|
138
168
|
}
|
139
169
|
|
@@ -143,7 +173,9 @@
|
|
143
173
|
&.sticky-left-0,
|
144
174
|
&.sticky-left-1,
|
145
175
|
&.sticky-left-2 {
|
146
|
-
background: #f9fafb;
|
176
|
+
background: #f9fafb !important;
|
177
|
+
background-color: #f9fafb !important;
|
178
|
+
opacity: 1 !important;
|
147
179
|
}
|
148
180
|
}
|
149
181
|
}
|
@@ -151,38 +183,50 @@
|
|
151
183
|
// Operation-specific sticky cell backgrounds
|
152
184
|
&.operation-insert .tabulator-cell {
|
153
185
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
154
|
-
background
|
186
|
+
background: rgba(16, 185, 129, 0.05) !important;
|
187
|
+
background-color: rgba(16, 185, 129, 0.05) !important;
|
188
|
+
opacity: 1 !important;
|
155
189
|
}
|
156
190
|
}
|
157
191
|
|
158
192
|
&.operation-update .tabulator-cell {
|
159
193
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
160
|
-
background
|
194
|
+
background: rgba(108, 173, 223, 0.05) !important;
|
195
|
+
background-color: rgba(108, 173, 223, 0.05) !important;
|
196
|
+
opacity: 1 !important;
|
161
197
|
}
|
162
198
|
}
|
163
199
|
|
164
200
|
&.operation-delete .tabulator-cell {
|
165
201
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
166
|
-
background
|
202
|
+
background: rgba(239, 68, 68, 0.05) !important;
|
203
|
+
background-color: rgba(239, 68, 68, 0.05) !important;
|
204
|
+
opacity: 1 !important;
|
167
205
|
}
|
168
206
|
}
|
169
207
|
|
170
208
|
// Operation-specific sticky cell hover backgrounds
|
171
209
|
&.operation-insert:hover .tabulator-cell {
|
172
210
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
173
|
-
background
|
211
|
+
background: rgba(16, 185, 129, 0.1) !important;
|
212
|
+
background-color: rgba(16, 185, 129, 0.1) !important;
|
213
|
+
opacity: 1 !important;
|
174
214
|
}
|
175
215
|
}
|
176
216
|
|
177
217
|
&.operation-update:hover .tabulator-cell {
|
178
218
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
179
|
-
background
|
219
|
+
background: rgba(108, 173, 223, 0.1) !important;
|
220
|
+
background-color: rgba(108, 173, 223, 0.1) !important;
|
221
|
+
opacity: 1 !important;
|
180
222
|
}
|
181
223
|
}
|
182
224
|
|
183
225
|
&.operation-delete:hover .tabulator-cell {
|
184
226
|
&.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
|
185
|
-
background
|
227
|
+
background: rgba(239, 68, 68, 0.1) !important;
|
228
|
+
background-color: rgba(239, 68, 68, 0.1) !important;
|
229
|
+
opacity: 1 !important;
|
186
230
|
}
|
187
231
|
}
|
188
232
|
}
|
@@ -166,7 +166,7 @@ module Dbwatcher
|
|
166
166
|
#
|
167
167
|
# @return [void]
|
168
168
|
def ensure_system_info_enabled
|
169
|
-
return if Dbwatcher.configuration.
|
169
|
+
return if Dbwatcher.configuration.system_info
|
170
170
|
|
171
171
|
render json: {
|
172
172
|
error: "System information collection is disabled",
|
@@ -10,7 +10,7 @@ module Dbwatcher
|
|
10
10
|
@active_tab = params[:tab] || "overview"
|
11
11
|
|
12
12
|
# Add system information if enabled
|
13
|
-
return unless Dbwatcher.configuration.
|
13
|
+
return unless Dbwatcher.configuration.system_info
|
14
14
|
|
15
15
|
@system_info_summary = system_info_storage.summary
|
16
16
|
@system_info = system_info_storage.cached_info
|
@@ -118,10 +118,11 @@
|
|
118
118
|
</div>
|
119
119
|
<% else %>
|
120
120
|
<div class="p-8 text-center text-gray-500">
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
<%= image_tag "dbwatcher/dbwatcher-tranparent_512x512.png",
|
122
|
+
alt: "DBWatcher Logo",
|
123
|
+
class: "w-12 h-12 mx-auto opacity-30 mb-2" %>
|
124
124
|
<p class="text-sm">No recent sessions</p>
|
125
|
+
<p class="text-xs text-gray-400 mt-1">Start tracking with <code>?dbwatch=true</code></p>
|
125
126
|
</div>
|
126
127
|
<% end %>
|
127
128
|
</div>
|
@@ -175,11 +176,11 @@
|
|
175
176
|
</div>
|
176
177
|
<% else %>
|
177
178
|
<div class="p-8 text-center text-gray-500">
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
</svg>
|
179
|
+
<%= image_tag "dbwatcher/dbwatcher-tranparent_512x512.png",
|
180
|
+
alt: "DBWatcher Logo",
|
181
|
+
class: "w-12 h-12 mx-auto opacity-30 mb-2" %>
|
182
182
|
<p class="text-sm">No active tables</p>
|
183
|
+
<p class="text-xs text-gray-400 mt-1">Tables will appear when data changes</p>
|
183
184
|
</div>
|
184
185
|
<% end %>
|
185
186
|
</div>
|
@@ -41,46 +41,39 @@
|
|
41
41
|
</div>
|
42
42
|
|
43
43
|
<!-- Content Area -->
|
44
|
-
<div class="flex-1 overflow-auto
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
</
|
53
|
-
<p class="text-xs">No tracking sessions yet</p>
|
54
|
-
<p class="text-xs text-gray-400">Start tracking with <code class="bg-gray-200 px-1 rounded">Dbwatcher.track { ... }</code></p>
|
44
|
+
<div class="flex-1 overflow-auto">
|
45
|
+
<% if @sessions.empty? %>
|
46
|
+
<div class="p-8 text-center text-gray-500">
|
47
|
+
<%= image_tag "dbwatcher/dbwatcher-tranparent_512x512.png",
|
48
|
+
alt: "DBWatcher Logo",
|
49
|
+
class: "mx-auto w-12 h-12 opacity-30 mb-3" %>
|
50
|
+
<p class="text-sm font-medium text-gray-600 mb-2">No tracking sessions yet</p>
|
51
|
+
<p class="text-xs text-gray-400">Start tracking with <code class="bg-gray-100 px-1 rounded text-xs">Dbwatcher.track { ... }</code></p>
|
52
|
+
<p class="text-xs text-gray-400 mt-1">or add <code class="bg-gray-100 px-1 rounded text-xs">?dbwatch=true</code> to any URL</p>
|
55
53
|
</div>
|
56
|
-
|
57
|
-
|
58
|
-
<div class="bg-white border border-gray-300 rounded shadow-sm">
|
59
|
-
<table class="compact-table sessions-table w-full">
|
54
|
+
<% else %>
|
55
|
+
<table class="compact-table w-full">
|
60
56
|
<thead>
|
61
57
|
<tr>
|
62
|
-
<th class="text-left" style="
|
63
|
-
<th class="text-left" style="
|
64
|
-
<th class="text-center" style="width:100px">Status</th>
|
65
|
-
<th class="text-center" style="width:100px">Changes</th>
|
66
|
-
<th class="text-right" style="width:120px">Started</th>
|
67
|
-
<th class="text-right" style="width:120px">Duration</th>
|
68
|
-
<th class="text-center" style="width:80px">Actions</th>
|
58
|
+
<th class="text-left" style="width: 18%; min-width: 180px">Session ID</th>
|
59
|
+
<th class="text-left" style="width: 22%; min-width: 160px">Name</th>
|
60
|
+
<th class="text-center" style="width: 100px">Status</th>
|
61
|
+
<th class="text-center" style="width: 100px">Changes</th>
|
62
|
+
<th class="text-right" style="width: 120px">Started</th>
|
63
|
+
<th class="text-right" style="width: 120px">Duration</th>
|
64
|
+
<th class="text-center" style="width: 80px">Actions</th>
|
69
65
|
</tr>
|
70
66
|
</thead>
|
71
67
|
<tbody>
|
72
68
|
<% @sessions.each do |session| %>
|
73
69
|
<tr class="session-row">
|
74
|
-
<td
|
75
|
-
|
76
|
-
<%= safe_value(session, :id) %>
|
77
|
-
</span>
|
70
|
+
<td class="font-mono text-xs">
|
71
|
+
<%= safe_value(session, :id) %>
|
78
72
|
</td>
|
79
|
-
<td
|
73
|
+
<td title="<%= safe_value(session, :name) %>">
|
80
74
|
<%= link_to display_session_name(safe_value(session, :name)),
|
81
75
|
session_path(safe_value(session, :id)),
|
82
|
-
class: "text-navy-dark hover:text-blue-medium
|
83
|
-
style: "max-width:260px; overflow-x:auto; display:inline-block;" %>
|
76
|
+
class: "text-navy-dark hover:text-blue-medium" %>
|
84
77
|
</td>
|
85
78
|
<td class="text-center">
|
86
79
|
<%= render 'dbwatcher/shared/badge',
|
@@ -106,44 +99,34 @@
|
|
106
99
|
) rescue 'N/A' %>
|
107
100
|
<% end %>
|
108
101
|
</td>
|
109
|
-
<td class="text-center
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
title: "View session details" do %>
|
114
|
-
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
115
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
116
|
-
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
117
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
118
|
-
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
119
|
-
</svg>
|
120
|
-
<% end %>
|
121
|
-
</div>
|
102
|
+
<td class="text-center">
|
103
|
+
<%= link_to "View", session_path(safe_value(session, :id)),
|
104
|
+
class: "compact-button bg-navy-dark text-white hover:bg-blue-medium",
|
105
|
+
title: "View session details" %>
|
122
106
|
</td>
|
123
107
|
</tr>
|
124
108
|
<% end %>
|
125
109
|
</tbody>
|
126
110
|
</table>
|
127
|
-
</div>
|
128
111
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
112
|
+
<!-- No Results Message -->
|
113
|
+
<div
|
114
|
+
x-show="filterText && document.querySelectorAll('.session-row:not(.hidden)').length === 0"
|
115
|
+
x-cloak
|
116
|
+
class="p-8 text-center text-gray-500 bg-gray-50">
|
117
|
+
<p class="mb-2">No sessions match your filter criteria</p>
|
118
|
+
<button
|
119
|
+
@click="filterText = ''"
|
120
|
+
class="compact-button bg-gray-500 text-white hover:bg-gray-600">
|
121
|
+
Clear filter
|
122
|
+
</button>
|
123
|
+
</div>
|
124
|
+
<% end %>
|
125
|
+
</div>
|
142
126
|
|
143
127
|
<!-- Status Bar -->
|
144
|
-
<div class="h-6 bg-gray-100 border-t border-gray-300 flex items-center px-4 text-xs text-gray-600
|
145
|
-
<span x-show="!filterText"><%= @sessions.count %> sessions total •
|
146
|
-
<%= @sessions.count { |s| session_active?(s) } %> active</span>
|
128
|
+
<div class="h-6 bg-gray-100 border-t border-gray-300 flex items-center px-4 text-xs text-gray-600">
|
129
|
+
<span x-show="!filterText"><%= @sessions.count %> sessions total • <%= @sessions.count { |s| session_active?(s) } %> active</span>
|
147
130
|
<span x-show="filterText" x-text="`${document.querySelectorAll('.session-row:not(.hidden)').length} of ${<%= @sessions.count %>} sessions shown`"></span>
|
148
131
|
<span class="ml-auto">Last updated: <%= Time.current.strftime("%H:%M:%S") %></span>
|
149
132
|
</div>
|
@@ -5,6 +5,14 @@
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
6
|
<%= csrf_meta_tags %>
|
7
7
|
|
8
|
+
<!-- Favicon -->
|
9
|
+
<%= favicon_link_tag asset_path('dbwatcher/favicon.ico') %>
|
10
|
+
<%= favicon_link_tag asset_path('dbwatcher/favicon-96x96.png'), sizes: '96x96', type: 'image/png' %>
|
11
|
+
<%= favicon_link_tag asset_path('dbwatcher/apple-touch-icon.png'), rel: 'apple-touch-icon', sizes: '180x180' %>
|
12
|
+
<%= favicon_link_tag asset_path('dbwatcher/web-app-manifest-192x192.png'), sizes: '192x192', type: 'image/png' %>
|
13
|
+
<%= favicon_link_tag asset_path('dbwatcher/web-app-manifest-512x512.png'), sizes: '512x512', type: 'image/png' %>
|
14
|
+
<link rel="manifest" href="<%= asset_path('dbwatcher/site.webmanifest') %>"
|
15
|
+
|
8
16
|
<!-- Alpine.js and Plugins - ensure plugins load BEFORE Alpine.js core -->
|
9
17
|
<script defer src="https://unpkg.com/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
|
10
18
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
@@ -119,12 +127,20 @@
|
|
119
127
|
:style="{ width: sidebarCollapsed ? '48px' : sidebarWidth + 'px' }">
|
120
128
|
<div class="flex flex-col h-full">
|
121
129
|
<!-- Logo -->
|
122
|
-
<div class="h-
|
123
|
-
<div class="flex items-center gap-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
<
|
130
|
+
<div class="h-12 flex items-center justify-between px-3 border-b border-gray-700 bg-gray-800">
|
131
|
+
<div class="flex items-center gap-3" x-show="!sidebarCollapsed">
|
132
|
+
<%= image_tag "dbwatcher/dbwatcher-tranparent_512x512.png",
|
133
|
+
alt: "DBWatcher Logo",
|
134
|
+
class: "w-10 h-10" %>
|
135
|
+
<div class="flex flex-col">
|
136
|
+
<span class="text-base font-bold text-white">dbwatcher</span>
|
137
|
+
</div>
|
138
|
+
</div>
|
139
|
+
<!-- Collapsed state logo -->
|
140
|
+
<div class="flex items-center justify-center w-full" x-show="sidebarCollapsed">
|
141
|
+
<%= image_tag "dbwatcher/dbwatcher-tranparent_512x512.png",
|
142
|
+
alt: "dbwatcher Logo",
|
143
|
+
class: "w-8 h-8" %>
|
128
144
|
</div>
|
129
145
|
<button @click="sidebarCollapsed = !sidebarCollapsed"
|
130
146
|
class="p-1 hover:bg-gray-800 rounded text-gray-400">
|
@@ -3,104 +3,84 @@
|
|
3
3
|
module Dbwatcher
|
4
4
|
# Configuration class for DBWatcher
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# storage, tracking, and diagram visualization settings.
|
6
|
+
# Simplified configuration with logical groupings and sensible defaults
|
8
7
|
class Configuration
|
9
|
-
#
|
10
|
-
attr_accessor :
|
8
|
+
# Core settings - what users need most
|
9
|
+
attr_accessor :enabled, :storage_path
|
11
10
|
|
12
|
-
#
|
13
|
-
attr_accessor :
|
11
|
+
# Session management - how data is stored and cleaned
|
12
|
+
attr_accessor :max_sessions, :auto_clean_days
|
14
13
|
|
15
|
-
#
|
16
|
-
attr_accessor :
|
14
|
+
# Query tracking - performance monitoring
|
15
|
+
attr_accessor :track_queries
|
17
16
|
|
18
|
-
#
|
19
|
-
attr_accessor :
|
20
|
-
:diagram_max_attributes, :diagram_attribute_types, :diagram_relationship_labels,
|
21
|
-
:diagram_preserve_table_case, :diagram_direction, :diagram_cardinality_format,
|
22
|
-
:diagram_show_attribute_count, :diagram_show_method_count
|
17
|
+
# System info - debugging and monitoring
|
18
|
+
attr_accessor :system_info, :debug_mode
|
23
19
|
|
24
|
-
#
|
25
|
-
attr_accessor :
|
26
|
-
:
|
27
|
-
:
|
28
|
-
|
29
|
-
# Logging configuration
|
30
|
-
attr_accessor :debug_logging
|
20
|
+
# Advanced diagram options - available but not commonly needed
|
21
|
+
attr_accessor :diagram_show_methods, :diagram_max_attributes,
|
22
|
+
:diagram_attribute_types, :diagram_relationship_labels,
|
23
|
+
:diagram_show_attributes, :diagram_show_cardinality
|
31
24
|
|
32
25
|
# Initialize with default values
|
33
26
|
def initialize
|
34
|
-
#
|
35
|
-
@storage_path = default_storage_path
|
27
|
+
# Core settings
|
36
28
|
@enabled = true
|
29
|
+
@storage_path = default_storage_path
|
30
|
+
|
31
|
+
# Session management
|
37
32
|
@max_sessions = 50
|
38
|
-
@
|
33
|
+
@auto_clean_days = 7
|
39
34
|
|
40
|
-
# Query tracking
|
35
|
+
# Query tracking
|
41
36
|
@track_queries = false
|
42
|
-
@slow_query_threshold = 200 # milliseconds
|
43
|
-
@max_query_logs_per_day = 1000
|
44
|
-
|
45
|
-
# Routing configuration defaults
|
46
|
-
@mount_path = "/dbwatcher"
|
47
37
|
|
48
|
-
#
|
49
|
-
|
38
|
+
# System info
|
39
|
+
@system_info = true
|
40
|
+
@debug_mode = false
|
50
41
|
|
51
|
-
#
|
52
|
-
|
42
|
+
# Advanced diagram options - sensible defaults
|
43
|
+
@diagram_show_methods = false
|
44
|
+
@diagram_max_attributes = 10
|
45
|
+
@diagram_attribute_types = true
|
46
|
+
@diagram_relationship_labels = true
|
47
|
+
@diagram_show_attributes = true
|
48
|
+
@diagram_show_cardinality = true
|
49
|
+
end
|
53
50
|
|
54
|
-
|
55
|
-
|
51
|
+
# Fixed defaults for options that are still used in codebase but not configurable
|
52
|
+
def slow_query_threshold
|
53
|
+
200 # Fixed default value
|
56
54
|
end
|
57
55
|
|
58
|
-
|
59
|
-
|
60
|
-
@diagram_show_attributes = true
|
61
|
-
@diagram_show_methods = false # Hide methods by default
|
62
|
-
@diagram_show_cardinality = true
|
63
|
-
@diagram_max_attributes = 10
|
64
|
-
@diagram_attribute_types = true # Changed from array to boolean
|
65
|
-
@diagram_relationship_labels = true # Changed from symbol to boolean
|
66
|
-
@diagram_preserve_table_case = false # Changed from true to false
|
67
|
-
@diagram_direction = "LR" # Left to right by default
|
68
|
-
@diagram_cardinality_format = :simple # Use simpler 1:N format
|
69
|
-
@diagram_show_attribute_count = true
|
70
|
-
@diagram_show_method_count = true
|
56
|
+
def diagram_direction
|
57
|
+
"LR" # Fixed default value
|
71
58
|
end
|
72
59
|
|
73
|
-
#
|
74
|
-
def
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
60
|
+
# Fixed defaults for complex options that are still used in codebase but not configurable
|
61
|
+
def max_query_logs_per_day = 1000
|
62
|
+
def system_info_refresh_interval = 5 * 60
|
63
|
+
def system_info_cache_duration = 60 * 60
|
64
|
+
|
65
|
+
def collect_sensitive_env_vars?
|
66
|
+
false
|
80
67
|
end
|
81
68
|
|
82
|
-
|
83
|
-
|
84
|
-
@debug_logging = false
|
69
|
+
def system_info_include_performance_metrics?
|
70
|
+
true
|
85
71
|
end
|
86
72
|
|
87
73
|
# Validate configuration
|
88
|
-
#
|
89
|
-
# @return [Boolean] true if configuration is valid
|
90
74
|
def valid?
|
91
75
|
validate_storage_path
|
92
76
|
validate_max_sessions
|
93
|
-
|
94
|
-
validate_slow_query_threshold
|
95
|
-
validate_max_query_logs_per_day
|
77
|
+
validate_auto_clean_days
|
96
78
|
true
|
97
79
|
end
|
98
80
|
|
99
81
|
private
|
100
82
|
|
101
83
|
# Default storage path based on Rails or current directory
|
102
|
-
#
|
103
|
-
# @return [String] default storage path
|
104
84
|
def default_storage_path
|
105
85
|
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
106
86
|
Rails.root.join("tmp", "dbwatcher").to_s
|
@@ -127,25 +107,11 @@ module Dbwatcher
|
|
127
107
|
raise ConfigurationError, "max_sessions must be a positive integer"
|
128
108
|
end
|
129
109
|
|
130
|
-
# Validate auto clean
|
131
|
-
def
|
132
|
-
return if
|
133
|
-
|
134
|
-
raise ConfigurationError, "auto_clean_after_days must be a positive integer"
|
135
|
-
end
|
136
|
-
|
137
|
-
# Validate slow query threshold
|
138
|
-
def validate_slow_query_threshold
|
139
|
-
return if slow_query_threshold.is_a?(Integer) && slow_query_threshold.positive?
|
140
|
-
|
141
|
-
raise ConfigurationError, "slow_query_threshold must be a positive integer"
|
142
|
-
end
|
143
|
-
|
144
|
-
# Validate max query logs per day
|
145
|
-
def validate_max_query_logs_per_day
|
146
|
-
return if max_query_logs_per_day.is_a?(Integer) && max_query_logs_per_day.positive?
|
110
|
+
# Validate auto clean days
|
111
|
+
def validate_auto_clean_days
|
112
|
+
return if auto_clean_days.is_a?(Integer) && auto_clean_days.positive?
|
147
113
|
|
148
|
-
raise ConfigurationError, "
|
114
|
+
raise ConfigurationError, "auto_clean_days must be a positive integer"
|
149
115
|
end
|
150
116
|
end
|
151
117
|
|
data/lib/dbwatcher/logging.rb
CHANGED
@@ -40,8 +40,8 @@ module Dbwatcher
|
|
40
40
|
# Check if debug logging is enabled
|
41
41
|
# @return [Boolean] true if debug logging is enabled
|
42
42
|
def debug_enabled?
|
43
|
-
return Dbwatcher.configuration.
|
44
|
-
|
43
|
+
return Dbwatcher.configuration.debug_mode if defined?(Dbwatcher.configuration) &&
|
44
|
+
Dbwatcher.configuration.respond_to?(:debug_mode)
|
45
45
|
return Rails.env.development? if defined?(Rails)
|
46
46
|
|
47
47
|
false
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dbwatcher
|
4
|
+
module Services
|
5
|
+
module DiagramAnalyzers
|
6
|
+
module Concerns
|
7
|
+
# Concern for ActiveRecord introspection utilities
|
8
|
+
#
|
9
|
+
# This module provides common methods for checking ActiveRecord availability
|
10
|
+
# and performing model introspection operations.
|
11
|
+
module ActiverecordIntrospection
|
12
|
+
extend ActiveSupport::Concern if defined?(ActiveSupport)
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Check if ActiveRecord is available
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
def activerecord_available?
|
20
|
+
defined?(ActiveRecord::Base)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Check if models analysis is available
|
24
|
+
#
|
25
|
+
# @return [Boolean] true if models can be analyzed
|
26
|
+
def models_available?
|
27
|
+
unless activerecord_available?
|
28
|
+
Rails.logger.warn "#{self.class.name}: ActiveRecord not available"
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Eagerly load all models including those from gems
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
def eager_load_models
|
39
|
+
return unless defined?(Rails) && Rails.respond_to?(:application)
|
40
|
+
|
41
|
+
begin
|
42
|
+
# Force eager loading of application models
|
43
|
+
Rails.application.eager_load!
|
44
|
+
|
45
|
+
# Also load models from engines/gems if any are configured
|
46
|
+
Rails::Engine.descendants.each do |engine|
|
47
|
+
engine.eager_load! if engine.respond_to?(:eager_load!)
|
48
|
+
rescue StandardError => e
|
49
|
+
error_message = "#{self.class.name}: Could not eager load engine #{engine.class.name}: #{e.message}"
|
50
|
+
Rails.logger.debug error_message
|
51
|
+
end
|
52
|
+
rescue StandardError => e
|
53
|
+
Rails.logger.debug "#{self.class.name}: Could not eager load models: #{e.message}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|