pg_monitor 0.1.1 → 0.1.3
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 +22 -10
- data/Rakefile +7 -0
- data/lib/pg_monitor/index_usage.rb +6 -4
- data/lib/pg_monitor/pg_locks.rb +33 -0
- data/lib/pg_monitor/user_tables.rb +38 -0
- data/lib/pg_monitor/version.rb +1 -1
- data/lib/pg_monitor/views/index.erb +56 -0
- data/lib/pg_monitor/views/index_usage_table.erb +28 -0
- data/lib/pg_monitor/views/locks_table.erb +44 -0
- data/lib/pg_monitor/views/slow_queries_table.erb +35 -0
- data/lib/pg_monitor/views/user_tables_table.erb +52 -0
- data/lib/pg_monitor/web_app.rb +17 -0
- data/lib/pg_monitor.rb +2 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6771bf4e358737710bbdfc1618a2c249a1c62f20dde4b245bd12a55156ef65f
|
4
|
+
data.tar.gz: a80e060c2b717966d0b873c144e56b12bdb97f27f47953bdd237e6263e151495
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acfd32102a43294fe20a7971a608f19227a34790caab53bc2b54b8f36c4cc08f31cee5436ca26f1a27b2e493309e18aca73c7a6031e6967bb403229b11b9ceac
|
7
|
+
data.tar.gz: 3fe3429f7c64b0503863acba9d590cc69935bf3e39ff4bf49947662931d95e6258b3fda56117fe77d28bbbd965470c1754fabf87f08e8f6b224a803d422154e6
|
data/README.md
CHANGED
@@ -7,8 +7,8 @@ It would integrate seamlessly with a Rails application in the future, and would
|
|
7
7
|
|
8
8
|
- View index usage statistics (last used, scan count, etc.)
|
9
9
|
- Identify slow queries using `pg_stat_statements`
|
10
|
-
- Works with
|
11
|
-
-
|
10
|
+
- Works with existing Rails database configuration, if present
|
11
|
+
- Provides a simple HTML interface for monitoring
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
@@ -59,17 +59,19 @@ Execute the above SQL query by connecting to your database using `psql` or any o
|
|
59
59
|
|
60
60
|
## Usage
|
61
61
|
|
62
|
-
|
62
|
+
To run the PgMonitor, follow these steps:
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
1. Ensure you have all the dependencies installed:
|
65
|
+
```sh
|
66
|
+
bundle install
|
67
|
+
```
|
67
68
|
|
68
|
-
|
69
|
+
2. Run the server using the Rake task:
|
70
|
+
```sh
|
71
|
+
rake server
|
72
|
+
```
|
69
73
|
|
70
|
-
|
71
|
-
http://localhost:3000/pg_monitor
|
72
|
-
```
|
74
|
+
3. The application should now be running. You can access it in your web browser at `http://localhost:4567`.
|
73
75
|
|
74
76
|
### Programmatic Access
|
75
77
|
|
@@ -83,6 +85,16 @@ PgMonitor::IndexUsage.fetch
|
|
83
85
|
PgMonitor::SlowQueries.fetch(limit: 10)
|
84
86
|
```
|
85
87
|
|
88
|
+
### **User Table Stats**
|
89
|
+
```ruby
|
90
|
+
PgMonitor::UserTables.fetch
|
91
|
+
```
|
92
|
+
|
93
|
+
### **Pg Locks**
|
94
|
+
```ruby
|
95
|
+
PgMonitor::PgLocks.fetch
|
96
|
+
```
|
97
|
+
|
86
98
|
## Running Tests
|
87
99
|
|
88
100
|
### **1. Start PostgreSQL in Docker**
|
data/Rakefile
CHANGED
@@ -7,13 +7,15 @@ module PgMonitor
|
|
7
7
|
def fetch
|
8
8
|
query = <<~SQL
|
9
9
|
SELECT
|
10
|
-
|
10
|
+
relname AS table_name,
|
11
11
|
indexrelname AS index_name,
|
12
12
|
idx_scan AS index_scan_count,
|
13
13
|
idx_tup_read AS tuples_read,
|
14
|
-
idx_tup_fetch AS tuples_fetched
|
15
|
-
|
16
|
-
|
14
|
+
idx_tup_fetch AS tuples_fetched,
|
15
|
+
last_idx_scan AS last_index_scan,
|
16
|
+
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,
|
17
|
+
pg_size_pretty(pg_total_relation_size(indexrelid)) AS total_index_size
|
18
|
+
FROM pg_stat_user_indexes
|
17
19
|
ORDER BY idx_scan DESC;
|
18
20
|
SQL
|
19
21
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "db_connection"
|
2
|
+
|
3
|
+
module PgMonitor
|
4
|
+
module PGLocks
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def fetch
|
8
|
+
query = <<~SQL
|
9
|
+
SELECT
|
10
|
+
locktype,
|
11
|
+
database,
|
12
|
+
relation,
|
13
|
+
page,
|
14
|
+
tuple,
|
15
|
+
virtualxid,
|
16
|
+
transactionid,
|
17
|
+
classid,
|
18
|
+
objid,
|
19
|
+
objsubid,
|
20
|
+
virtualtransaction,
|
21
|
+
pid,
|
22
|
+
mode,
|
23
|
+
granted,
|
24
|
+
fastpath,
|
25
|
+
waitstart
|
26
|
+
FROM pg_locks;
|
27
|
+
SQL
|
28
|
+
|
29
|
+
result = DBConnection.connection.exec(query)
|
30
|
+
result.map { |row| row }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "db_connection"
|
2
|
+
|
3
|
+
module PgMonitor
|
4
|
+
module UserTables
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def fetch
|
8
|
+
query = <<~SQL
|
9
|
+
SELECT
|
10
|
+
relname AS table_name,
|
11
|
+
seq_scan,
|
12
|
+
last_seq_scan,
|
13
|
+
seq_tup_read,
|
14
|
+
idx_scan,
|
15
|
+
last_idx_scan,
|
16
|
+
idx_tup_fetch,
|
17
|
+
n_tup_ins,
|
18
|
+
n_tup_upd,
|
19
|
+
n_tup_del,
|
20
|
+
n_live_tup,
|
21
|
+
n_dead_tup,
|
22
|
+
last_vacuum,
|
23
|
+
last_autovacuum,
|
24
|
+
last_analyze,
|
25
|
+
last_autoanalyze,
|
26
|
+
vacuum_count,
|
27
|
+
autovacuum_count,
|
28
|
+
analyze_count,
|
29
|
+
autoanalyze_count
|
30
|
+
FROM pg_stat_user_tables
|
31
|
+
ORDER BY relname;
|
32
|
+
SQL
|
33
|
+
|
34
|
+
result = DBConnection.connection.exec(query)
|
35
|
+
result.map { |row| row }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/pg_monitor/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>PgMonitor</title>
|
5
|
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
6
|
+
<script>
|
7
|
+
function showTab(tabId) {
|
8
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
9
|
+
tab.classList.remove('active');
|
10
|
+
});
|
11
|
+
document.getElementById(tabId).classList.add('active');
|
12
|
+
}
|
13
|
+
</script>
|
14
|
+
<style>
|
15
|
+
.tab {
|
16
|
+
display: none;
|
17
|
+
}
|
18
|
+
.tab.active {
|
19
|
+
display: block;
|
20
|
+
}
|
21
|
+
body {
|
22
|
+
padding: 10px;
|
23
|
+
}
|
24
|
+
</style>
|
25
|
+
</head>
|
26
|
+
<body>
|
27
|
+
<div class="container">
|
28
|
+
<div class="btn-group tab-buttons" role="group">
|
29
|
+
<button type="button" class="btn btn-primary" onclick="showTab('index-usage')">Index Usage</button>
|
30
|
+
<button type="button" class="btn btn-secondary" onclick="showTab('slow-queries')">Slow Queries</button>
|
31
|
+
<button type="button" class="btn btn-secondary" onclick="showTab('user-tables')">User Tables</button>
|
32
|
+
<button type="button" class="btn btn-secondary" onclick="showTab('locks')">Locks</button>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="index-usage" class="tab active">
|
36
|
+
<h1>Index Usage Statistics</h1>
|
37
|
+
<%= erb :index_usage_table, layout: false, locals: { index_usage: @index_usage } %>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div id="slow-queries" class="tab">
|
41
|
+
<h1>Slow Queries</h1>
|
42
|
+
<%= erb :slow_queries_table, layout: false, locals: { slow_queries: @slow_queries } %>
|
43
|
+
</div>
|
44
|
+
|
45
|
+
<div id="user-tables" class="tab">
|
46
|
+
<h1>User Tables Statistics</h1>
|
47
|
+
<%= erb :user_tables_table, layout: false, locals: { user_tables: @user_tables } %>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div id="locks" class="tab">
|
51
|
+
<h1>Locks</h1>
|
52
|
+
<%= erb :locks_table, layout: false, locals: { locks: @locks } %>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
</body>
|
56
|
+
</html>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<table class="table table-striped">
|
2
|
+
<thead class="thead-light">
|
3
|
+
<tr>
|
4
|
+
<th>Table Name</th>
|
5
|
+
<th>Index Name</th>
|
6
|
+
<th>Index Scan Count</th>
|
7
|
+
<th>Tuples Read</th>
|
8
|
+
<th>Tuples Fetched</th>
|
9
|
+
<th>Last Index Scan</th>
|
10
|
+
<th>Index Size</th>
|
11
|
+
<th>Total Index Size</th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
<tbody>
|
15
|
+
<% index_usage.each do |row| %>
|
16
|
+
<tr>
|
17
|
+
<td><%= row["table_name"] %></td>
|
18
|
+
<td><%= row["index_name"] %></td>
|
19
|
+
<td><%= row["index_scan_count"] %></td>
|
20
|
+
<td><%= row["tuples_read"] %></td>
|
21
|
+
<td><%= row["tuples_fetched"] %></td>
|
22
|
+
<td><%= row["last_index_scan"] %></td>
|
23
|
+
<td><%= row["index_size"] %></td>
|
24
|
+
<td><%= row["total_index_size"] %></td>
|
25
|
+
</tr>
|
26
|
+
<% end %>
|
27
|
+
</tbody>
|
28
|
+
</table>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<table class="table table-striped">
|
2
|
+
<thead class="thead-light">
|
3
|
+
<tr>
|
4
|
+
<th>Lock Type</th>
|
5
|
+
<th>Database</th>
|
6
|
+
<th>Relation</th>
|
7
|
+
<th>Page</th>
|
8
|
+
<th>Tuple</th>
|
9
|
+
<th>Virtual XID</th>
|
10
|
+
<th>Transaction ID</th>
|
11
|
+
<th>Class ID</th>
|
12
|
+
<th>Object ID</th>
|
13
|
+
<th>Object Sub ID</th>
|
14
|
+
<th>Virtual Transaction</th>
|
15
|
+
<th>PID</th>
|
16
|
+
<th>Mode</th>
|
17
|
+
<th>Granted</th>
|
18
|
+
<th>Fast Path</th>
|
19
|
+
<th>Wait Start</th>
|
20
|
+
</tr>
|
21
|
+
</thead>
|
22
|
+
<tbody>
|
23
|
+
<% @locks.each do |row| %>
|
24
|
+
<tr>
|
25
|
+
<td><%= row["locktype"] %></td>
|
26
|
+
<td><%= row["database"] %></td>
|
27
|
+
<td><%= row["relation"] %></td>
|
28
|
+
<td><%= row["page"] %></td>
|
29
|
+
<td><%= row["tuple"] %></td>
|
30
|
+
<td><%= row["virtualxid"] %></td>
|
31
|
+
<td><%= row["transactionid"] %></td>
|
32
|
+
<td><%= row["classid"] %></td>
|
33
|
+
<td><%= row["objid"] %></td>
|
34
|
+
<td><%= row["objsubid"] %></td>
|
35
|
+
<td><%= row["virtualtransaction"] %></td>
|
36
|
+
<td><%= row["pid"] %></td>
|
37
|
+
<td><%= row["mode"] %></td>
|
38
|
+
<td><%= row["granted"] %></td>
|
39
|
+
<td><%= row["fastpath"] %></td>
|
40
|
+
<td><%= row["waitstart"] %></td>
|
41
|
+
</tr>
|
42
|
+
<% end %>
|
43
|
+
</tbody>
|
44
|
+
</table>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<table class="table table-striped">
|
2
|
+
<thead class="thead-light">
|
3
|
+
<tr>
|
4
|
+
<th>Query</th>
|
5
|
+
<th>Calls</th>
|
6
|
+
<th>Total Time</th>
|
7
|
+
<th>Mean Time</th>
|
8
|
+
<th>Max Time</th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% slow_queries.each do |row| %>
|
13
|
+
<tr>
|
14
|
+
<td>
|
15
|
+
<% full_query = row["query"] %>
|
16
|
+
<% if full_query.length > 100 %>
|
17
|
+
<span class="query-short" data-full-query="<%= ERB::Util.html_escape full_query %>">
|
18
|
+
<%= full_query[0, 100] %>...
|
19
|
+
</span>
|
20
|
+
<a href="#" class="show-more"
|
21
|
+
onclick="var el = this.previousElementSibling; el.textContent = el.getAttribute('data-full-query'); this.style.display='none'; return false;">
|
22
|
+
show more
|
23
|
+
</a>
|
24
|
+
<% else %>
|
25
|
+
<%= full_query %>
|
26
|
+
<% end %>
|
27
|
+
</td>
|
28
|
+
<td><%= row["calls"] %></td>
|
29
|
+
<td><%= row["total_time"] %></td>
|
30
|
+
<td><%= row["mean_time"] %></td>
|
31
|
+
<td><%= row["max_time"] %></td>
|
32
|
+
</tr>
|
33
|
+
<% end %>
|
34
|
+
</tbody>
|
35
|
+
</table>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<table class="table table-striped">
|
2
|
+
<thead class="thead-light">
|
3
|
+
<tr>
|
4
|
+
<th>Table Name</th>
|
5
|
+
<th>Seq Scan</th>
|
6
|
+
<th>Last Seq Scan</th>
|
7
|
+
<th>Seq Tup Read</th>
|
8
|
+
<th>Idx Scan</th>
|
9
|
+
<th>Last Idx Scan</th>
|
10
|
+
<th>Idx Tup Fetch</th>
|
11
|
+
<th>Tuples Inserted</th>
|
12
|
+
<th>Tuples Updated</th>
|
13
|
+
<th>Tuples Deleted</th>
|
14
|
+
<th>Live Tuples</th>
|
15
|
+
<th>Dead Tuples</th>
|
16
|
+
<th>Last Vacuum</th>
|
17
|
+
<th>Last Autovacuum</th>
|
18
|
+
<th>Last Analyze</th>
|
19
|
+
<th>Last Autoanalyze</th>
|
20
|
+
<th>Vacuum Count</th>
|
21
|
+
<th>Autovacuum Count</th>
|
22
|
+
<th>Analyze Count</th>
|
23
|
+
<th>Autoanalyze Count</th>
|
24
|
+
</tr>
|
25
|
+
</thead>
|
26
|
+
<tbody>
|
27
|
+
<% user_tables.each do |row| %>
|
28
|
+
<tr>
|
29
|
+
<td><%= row["table_name"] %></td>
|
30
|
+
<td><%= row["seq_scan"] %></td>
|
31
|
+
<td><%= row["last_seq_scan"] %></td>
|
32
|
+
<td><%= row["seq_tup_read"] %></td>
|
33
|
+
<td><%= row["idx_scan"] %></td>
|
34
|
+
<td><%= row["last_idx_scan"] %></td>
|
35
|
+
<td><%= row["idx_tup_fetch"] %></td>
|
36
|
+
<td><%= row["n_tup_ins"] %></td>
|
37
|
+
<td><%= row["n_tup_upd"] %></td>
|
38
|
+
<td><%= row["n_tup_del"] %></td>
|
39
|
+
<td><%= row["n_live_tup"] %></td>
|
40
|
+
<td><%= row["n_dead_tup"] %></td>
|
41
|
+
<td><%= row["last_vacuum"] %></td>
|
42
|
+
<td><%= row["last_autovacuum"] %></td>
|
43
|
+
<td><%= row["last_analyze"] %></td>
|
44
|
+
<td><%= row["last_autoanalyze"] %></td>
|
45
|
+
<td><%= row["vacuum_count"] %></td>
|
46
|
+
<td><%= row["autovacuum_count"] %></td>
|
47
|
+
<td><%= row["analyze_count"] %></td>
|
48
|
+
<td><%= row["autoanalyze_count"] %></td>
|
49
|
+
</tr>
|
50
|
+
<% end %>
|
51
|
+
</tbody>
|
52
|
+
</table>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "sinatra"
|
2
|
+
require_relative "db_connection"
|
3
|
+
require_relative "index_usage"
|
4
|
+
require_relative "slow_queries"
|
5
|
+
require_relative "user_tables"
|
6
|
+
require_relative "pg_locks"
|
7
|
+
|
8
|
+
class PgMonitorApp < Sinatra::Base
|
9
|
+
get "/" do
|
10
|
+
@index_usage = PgMonitor::IndexUsage.fetch
|
11
|
+
@slow_queries = PgMonitor::SlowQueries.fetch(limit: 10)
|
12
|
+
@user_tables = PgMonitor::UserTables.fetch
|
13
|
+
@locks = PgMonitor::PGLocks.fetch
|
14
|
+
|
15
|
+
erb :index
|
16
|
+
end
|
17
|
+
end
|
data/lib/pg_monitor.rb
CHANGED
@@ -5,6 +5,8 @@ require_relative "pg_monitor/version"
|
|
5
5
|
require_relative "pg_monitor/db_connection"
|
6
6
|
require_relative "pg_monitor/index_usage"
|
7
7
|
require_relative "pg_monitor/slow_queries"
|
8
|
+
require_relative "pg_monitor/user_tables"
|
9
|
+
require_relative "pg_monitor/pg_locks"
|
8
10
|
|
9
11
|
module PgMonitor
|
10
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_monitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hassan Murtaza
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -43,8 +43,16 @@ files:
|
|
43
43
|
- lib/pg_monitor.rb
|
44
44
|
- lib/pg_monitor/db_connection.rb
|
45
45
|
- lib/pg_monitor/index_usage.rb
|
46
|
+
- lib/pg_monitor/pg_locks.rb
|
46
47
|
- lib/pg_monitor/slow_queries.rb
|
48
|
+
- lib/pg_monitor/user_tables.rb
|
47
49
|
- lib/pg_monitor/version.rb
|
50
|
+
- lib/pg_monitor/views/index.erb
|
51
|
+
- lib/pg_monitor/views/index_usage_table.erb
|
52
|
+
- lib/pg_monitor/views/locks_table.erb
|
53
|
+
- lib/pg_monitor/views/slow_queries_table.erb
|
54
|
+
- lib/pg_monitor/views/user_tables_table.erb
|
55
|
+
- lib/pg_monitor/web_app.rb
|
48
56
|
- postgresql.conf
|
49
57
|
- sig/pg_monitor.rbs
|
50
58
|
homepage: https://github.com/hmurtaza7/pg_monitor
|