dbviewer 0.3.5 → 0.3.6
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 +10 -0
- data/app/controllers/dbviewer/logs_controller.rb +8 -0
- data/app/controllers/dbviewer/tables_controller.rb +6 -0
- data/app/views/dbviewer/home/index.html.erb +40 -31
- data/app/views/dbviewer/tables/show.html.erb +40 -36
- data/app/views/layouts/dbviewer/application.html.erb +16 -3
- data/lib/dbviewer/configuration.rb +4 -0
- data/lib/dbviewer/logger.rb +2 -0
- data/lib/dbviewer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 151a189372c94a737108969cd768ab9dbc4e16a2abc608f07026d1a6b7ee65a5
|
4
|
+
data.tar.gz: a5fa3a4f4aa8e1acd606f60c2264412a261beec6b6889675ef941d05d1e593cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8345197920cf8c6a006d3faecd9a0b9f2a6ef4c972226707203ba43b121e05c3a02195eec4d38a699231ae488741802a9dff5c7317ddc576f4e27381ad897e7
|
7
|
+
data.tar.gz: b9a8ff1804963de25e85f9a288c198ee4aaa23cf25253ff99f0ce84f3e470e2e35a47c304ff24b2cbd962d9c913fb69b08f11d6bbd2d213af52113ce4d048e18
|
data/README.md
CHANGED
@@ -24,6 +24,7 @@ It's designed for development, debugging, and database analysis, offering a clea
|
|
24
24
|
- Navigate through large datasets with an intuitive pagination interface
|
25
25
|
- Scrollable table with fixed headers for improved navigation
|
26
26
|
- Single-line cell display with ellipsis for wide content (tooltips on hover)
|
27
|
+
- Export table data to CSV format (configurable via `enable_data_export` option)
|
27
28
|
- **SQL Queries**:
|
28
29
|
- Run custom SELECT queries against your database in a secure, read-only environment
|
29
30
|
- View table structure reference while writing queries
|
@@ -179,6 +180,7 @@ Dbviewer.configure do |config|
|
|
179
180
|
config.query_timeout = 30 # SQL query timeout in seconds
|
180
181
|
|
181
182
|
# Query logging options
|
183
|
+
config.enable_query_logging = true # Enable or disable query logging completely (default: true)
|
182
184
|
config.query_logging_mode = :memory # Storage mode for SQL queries (:memory or :file)
|
183
185
|
config.query_log_path = "log/dbviewer.log" # Path for query log file when in :file mode
|
184
186
|
config.max_memory_queries = 1000 # Maximum number of queries to store in memory
|
@@ -194,6 +196,14 @@ The configuration is accessed through `Dbviewer.configuration` throughout the co
|
|
194
196
|
|
195
197
|
DBViewer includes a powerful SQL query logging system that captures and analyzes database queries. You can access this log through the `/dbviewer/logs` endpoint. The logging system offers two storage backends:
|
196
198
|
|
199
|
+
### Disabling Query Logging
|
200
|
+
|
201
|
+
You can completely disable query logging if you don't need this feature:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
config.enable_query_logging = false # Disable query logging completely
|
205
|
+
```
|
206
|
+
|
197
207
|
### In-Memory Storage (Default)
|
198
208
|
|
199
209
|
By default, queries are stored in memory. This provides fast access but queries are lost when the application restarts:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Dbviewer
|
2
2
|
class LogsController < ApplicationController
|
3
3
|
before_action :set_filters, only: [ :index ]
|
4
|
+
before_action :check_logging_enabled
|
4
5
|
|
5
6
|
def index
|
6
7
|
@queries = dbviewer_logger.recent_queries(
|
@@ -28,6 +29,13 @@ module Dbviewer
|
|
28
29
|
|
29
30
|
private
|
30
31
|
|
32
|
+
def check_logging_enabled
|
33
|
+
unless Dbviewer.configuration.enable_query_logging
|
34
|
+
flash[:warning] = "Query logging is disabled. Enable it in the configuration to use this feature."
|
35
|
+
redirect_to root_path
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
31
39
|
def set_filters
|
32
40
|
@table_filter = params[:table_filter]
|
33
41
|
@request_id = params[:request_id]
|
@@ -62,6 +62,12 @@ module Dbviewer
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def export_csv
|
65
|
+
unless Dbviewer.configuration.enable_data_export
|
66
|
+
flash[:alert] = "Data export is disabled in the configuration"
|
67
|
+
redirect_to table_path(params[:id])
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
65
71
|
table_name = params[:id]
|
66
72
|
limit = (params[:limit] || 10000).to_i
|
67
73
|
include_headers = params[:include_headers] != "0"
|
@@ -94,46 +94,55 @@
|
|
94
94
|
<div class="card shadow-sm">
|
95
95
|
<div class="card-header d-flex justify-content-between align-items-center">
|
96
96
|
<h5 class="card-title mb-0">Recent SQL Queries</h5>
|
97
|
-
|
97
|
+
<% if Dbviewer.configuration.enable_query_logging %>
|
98
|
+
<a href="<%= dbviewer.logs_path %>" class="btn btn-sm btn-primary">View All Logs</a>
|
99
|
+
<% end %>
|
98
100
|
</div>
|
99
101
|
<div class="card-body p-0">
|
100
102
|
<% begin %>
|
101
103
|
<% require_dependency "dbviewer/logger" %>
|
102
|
-
<%
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
<
|
104
|
+
<% if Dbviewer.configuration.enable_query_logging %>
|
105
|
+
<% queries = Dbviewer::Logger.instance.recent_queries(limit: 10) %>
|
106
|
+
|
107
|
+
<% if queries.any? %>
|
108
|
+
<div class="table-responsive">
|
109
|
+
<table class="table table-sm table-hover mb-0">
|
107
110
|
|
108
|
-
|
109
|
-
<tr>
|
110
|
-
<th>Query</th>
|
111
|
-
<th class="text-end" style="width: 120px">Duration</th>
|
112
|
-
<th class="text-end" style="width: 180px">Time</th>
|
113
|
-
</tr>
|
114
|
-
</thead>
|
115
|
-
<tbody>
|
116
|
-
<% queries.each do |query| %>
|
111
|
+
<thead>
|
117
112
|
<tr>
|
118
|
-
<
|
119
|
-
|
120
|
-
</
|
121
|
-
<td class="text-end">
|
122
|
-
<span class="<%= query[:duration_ms] > 100 ? 'query-duration-slow' : 'query-duration' %>">
|
123
|
-
<%= query[:duration_ms] %> ms
|
124
|
-
</span>
|
125
|
-
</td>
|
126
|
-
<td class="text-end query-timestamp">
|
127
|
-
<small><%= query[:timestamp].strftime("%H:%M:%S") %></small>
|
128
|
-
</td>
|
113
|
+
<th>Query</th>
|
114
|
+
<th class="text-end" style="width: 120px">Duration</th>
|
115
|
+
<th class="text-end" style="width: 180px">Time</th>
|
129
116
|
</tr>
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
117
|
+
</thead>
|
118
|
+
<tbody>
|
119
|
+
<% queries.each do |query| %>
|
120
|
+
<tr>
|
121
|
+
<td class="text-truncate" style="max-width: 500px;">
|
122
|
+
<code class="sql-query-code"><%= query[:sql] %></code>
|
123
|
+
</td>
|
124
|
+
<td class="text-end">
|
125
|
+
<span class="<%= query[:duration_ms] > 100 ? 'query-duration-slow' : 'query-duration' %>">
|
126
|
+
<%= query[:duration_ms] %> ms
|
127
|
+
</span>
|
128
|
+
</td>
|
129
|
+
<td class="text-end query-timestamp">
|
130
|
+
<small><%= query[:timestamp].strftime("%H:%M:%S") %></small>
|
131
|
+
</td>
|
132
|
+
</tr>
|
133
|
+
<% end %>
|
134
|
+
</tbody>
|
135
|
+
</table>
|
136
|
+
</div>
|
137
|
+
<% else %>
|
138
|
+
<div class="text-center my-4 empty-data-message">
|
139
|
+
<p>No queries recorded yet</p>
|
140
|
+
</div>
|
141
|
+
<% end %>
|
134
142
|
<% else %>
|
135
143
|
<div class="text-center my-4 empty-data-message">
|
136
|
-
<p>
|
144
|
+
<p>Query logging is disabled</p>
|
145
|
+
<small class="text-muted">Enable it in the configuration to see SQL queries here</small>
|
137
146
|
</div>
|
138
147
|
<% end %>
|
139
148
|
<% rescue => e %>
|
@@ -11,53 +11,57 @@
|
|
11
11
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
12
12
|
<h1>Table: <%= @table_name %></h1>
|
13
13
|
<div class="d-flex gap-2">
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
<% if Dbviewer.configuration.enable_data_export %>
|
15
|
+
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#csvExportModal">
|
16
|
+
<i class="bi bi-file-earmark-spreadsheet me-1"></i> Export CSV
|
17
|
+
</button>
|
18
|
+
<% end %>
|
17
19
|
<%= link_to query_table_path(@table_name), class: "btn btn-primary" do %>
|
18
20
|
<i class="bi bi-code-square me-1"></i> Run SQL Query
|
19
21
|
<% end %>
|
20
22
|
</div>
|
21
23
|
</div>
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
<div class="modal-
|
26
|
-
<div class="modal-
|
27
|
-
<div class="modal-
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
<
|
42
|
-
|
25
|
+
<% if Dbviewer.configuration.enable_data_export %>
|
26
|
+
<!-- CSV Export Modal -->
|
27
|
+
<div class="modal fade" id="csvExportModal" tabindex="-1" aria-labelledby="csvExportModalLabel" aria-hidden="true">
|
28
|
+
<div class="modal-dialog">
|
29
|
+
<div class="modal-content">
|
30
|
+
<div class="modal-header">
|
31
|
+
<h5 class="modal-title" id="csvExportModalLabel">Export <strong><%= @table_name %></strong> to CSV</h5>
|
32
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
33
|
+
</div>
|
34
|
+
<div class="modal-body">
|
35
|
+
<%= form_with url: export_csv_table_path(@table_name), method: :get, id: "csvExportForm" do |form| %>
|
36
|
+
<div class="mb-3">
|
37
|
+
<label for="limit" class="form-label">Maximum number of records</label>
|
38
|
+
<input type="number" class="form-control" id="limit" name="limit" value="10000" min="1" max="100000">
|
39
|
+
<div class="form-text">Limit the number of records to export. Large exports may take some time.</div>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<% if @total_count > 10000 %>
|
43
|
+
<div class="alert alert-warning">
|
44
|
+
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
45
|
+
This table has <%= number_with_delimiter(@total_count) %> records. Exporting all records may be slow.
|
46
|
+
</div>
|
47
|
+
<% end %>
|
48
|
+
|
49
|
+
<div class="mb-3 form-check">
|
50
|
+
<input type="checkbox" class="form-check-input" id="includeHeaders" name="include_headers" checked>
|
51
|
+
<label class="form-check-label" for="includeHeaders">Include column headers</label>
|
43
52
|
</div>
|
44
53
|
<% end %>
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
<div class="modal-footer">
|
53
|
-
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
54
|
-
<button type="submit" form="csvExportForm" class="btn btn-success">
|
55
|
-
<i class="bi bi-download me-1"></i> Export CSV
|
56
|
-
</button>
|
54
|
+
</div>
|
55
|
+
<div class="modal-footer">
|
56
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
57
|
+
<button type="submit" form="csvExportForm" class="btn btn-success">
|
58
|
+
<i class="bi bi-download me-1"></i> Export CSV
|
59
|
+
</button>
|
60
|
+
</div>
|
57
61
|
</div>
|
58
62
|
</div>
|
59
63
|
</div>
|
60
|
-
|
64
|
+
<% end %>
|
61
65
|
|
62
66
|
<!-- Records Section -->
|
63
67
|
<div class="dbviewer-card card mb-4">
|
@@ -571,9 +571,11 @@
|
|
571
571
|
<li class="nav-item">
|
572
572
|
<%= link_to raw('<i class="bi bi-diagram-3"></i> ERD'), dbviewer.entity_relationship_diagrams_path, class: "nav-link #{erd_nav_class}" %>
|
573
573
|
</li>
|
574
|
-
|
575
|
-
|
576
|
-
|
574
|
+
<% if Dbviewer.configuration.enable_query_logging %>
|
575
|
+
<li class="nav-item">
|
576
|
+
<%= link_to raw('<i class="bi bi-journal-code"></i> SQL Logs'), dbviewer.logs_path, class: "nav-link #{logs_nav_class}" %>
|
577
|
+
</li>
|
578
|
+
<% end %>
|
577
579
|
</ul>
|
578
580
|
<ul class="navbar-nav ms-auto">
|
579
581
|
<li class="nav-item">
|
@@ -603,6 +605,17 @@
|
|
603
605
|
<!-- Main Content Area -->
|
604
606
|
<div class="dbviewer-main">
|
605
607
|
<div class="dbviewer-main-content">
|
608
|
+
<!-- Flash Messages -->
|
609
|
+
<% if flash.any? %>
|
610
|
+
<% flash.each do |type, message| %>
|
611
|
+
<% alert_class = type.to_s == 'notice' ? 'alert-info' : 'alert-danger' %>
|
612
|
+
<div class="alert <%= alert_class %> alert-dismissible fade show mb-3" role="alert">
|
613
|
+
<%= message %>
|
614
|
+
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
615
|
+
</div>
|
616
|
+
<% end %>
|
617
|
+
<% end %>
|
618
|
+
|
606
619
|
<div class="d-flex d-lg-none align-items-center mb-3">
|
607
620
|
<button class="btn btn-sm btn-outline-primary dbviewer-sidebar-toggle" type="button">
|
608
621
|
<i class="bi bi-list me-1"></i> Tables
|
@@ -31,6 +31,9 @@ module Dbviewer
|
|
31
31
|
# Maximum number of queries to keep in memory
|
32
32
|
attr_accessor :max_memory_queries
|
33
33
|
|
34
|
+
# Enable or disable query logging completely
|
35
|
+
attr_accessor :enable_query_logging
|
36
|
+
|
34
37
|
# Admin access credentials hash with :username and :password keys
|
35
38
|
# @example { username: 'admin', password: 'secret' }
|
36
39
|
attr_accessor :admin_credentials
|
@@ -46,6 +49,7 @@ module Dbviewer
|
|
46
49
|
@query_logging_mode = :memory
|
47
50
|
@query_log_path = "log/dbviewer.log"
|
48
51
|
@max_memory_queries = 1000
|
52
|
+
@enable_query_logging = true
|
49
53
|
@admin_credentials = nil
|
50
54
|
end
|
51
55
|
end
|
data/lib/dbviewer/logger.rb
CHANGED
@@ -10,6 +10,8 @@ module Dbviewer
|
|
10
10
|
|
11
11
|
# Add a new SQL event query to the logger
|
12
12
|
def add(event)
|
13
|
+
# Return early if query logging is disabled
|
14
|
+
return unless Dbviewer.configuration.enable_query_logging
|
13
15
|
return if QueryParser.should_skip_query?(event)
|
14
16
|
|
15
17
|
current_time = Time.now
|
data/lib/dbviewer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbviewer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wailan Tirajoh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|