pg_reports 0.2.2 → 0.3.0

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.
data/config/routes.rb CHANGED
@@ -3,9 +3,12 @@
3
3
  PgReports::Engine.routes.draw do
4
4
  root to: "dashboard#index"
5
5
 
6
+ get "live_metrics", to: "dashboard#live_metrics", as: :live_metrics
7
+
6
8
  post "enable_pg_stat_statements", to: "dashboard#enable_pg_stat_statements", as: :enable_pg_stat_statements
7
9
  post "reset_statistics", to: "dashboard#reset_statistics", as: :reset_statistics
8
10
  post "explain_analyze", to: "dashboard#explain_analyze", as: :explain_analyze
11
+ post "execute_query", to: "dashboard#execute_query", as: :execute_query
9
12
  post "create_migration", to: "dashboard#create_migration", as: :create_migration
10
13
 
11
14
  get ":category/:report", to: "dashboard#show", as: :report
@@ -97,6 +97,36 @@ module PgReports
97
97
  }
98
98
  end
99
99
 
100
+ # Live metrics for dashboard monitoring
101
+ # @param long_query_threshold [Integer] Threshold in seconds for long queries
102
+ # @return [Hash] Metrics data
103
+ def live_metrics(long_query_threshold: 60)
104
+ data = executor.execute_from_file(:system, :live_metrics,
105
+ long_query_threshold: long_query_threshold
106
+ )
107
+
108
+ row = data.first || {}
109
+
110
+ {
111
+ connections: {
112
+ active: row["active_connections"].to_i,
113
+ idle: row["idle_connections"].to_i,
114
+ total: row["total_connections"].to_i,
115
+ max: row["max_connections"].to_i,
116
+ percent: row["connections_pct"].to_f
117
+ },
118
+ transactions: {
119
+ total: row["total_transactions"].to_i,
120
+ commit: row["xact_commit"].to_i,
121
+ rollback: row["xact_rollback"].to_i
122
+ },
123
+ cache_hit_ratio: row["heap_hit_ratio"].to_f,
124
+ long_running_count: row["long_running_count"].to_i,
125
+ blocked_count: row["blocked_count"].to_i,
126
+ timestamp: row["timestamp_epoch"].to_f
127
+ }
128
+ end
129
+
100
130
  # Enable pg_stat_statements extension
101
131
  # Tries to create extension, returns helpful error if it fails
102
132
  # @return [Hash] Result with success status and message
@@ -0,0 +1,62 @@
1
+ -- Live monitoring metrics
2
+ -- Single optimized query for dashboard live metrics
3
+
4
+ WITH connection_stats AS (
5
+ SELECT
6
+ COUNT(*) FILTER (WHERE state = 'active' AND pid != pg_backend_pid()) AS active_connections,
7
+ COUNT(*) FILTER (WHERE state = 'idle') AS idle_connections,
8
+ COUNT(*) FILTER (WHERE pid != pg_backend_pid()) AS total_connections,
9
+ (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections
10
+ FROM pg_stat_activity
11
+ WHERE datname = current_database()
12
+ ),
13
+ tps_stats AS (
14
+ SELECT
15
+ xact_commit + xact_rollback AS total_transactions,
16
+ xact_commit,
17
+ xact_rollback
18
+ FROM pg_stat_database
19
+ WHERE datname = current_database()
20
+ ),
21
+ cache_stats AS (
22
+ SELECT
23
+ CASE
24
+ WHEN blks_hit + blks_read > 0 THEN
25
+ ROUND((blks_hit * 100.0 / (blks_hit + blks_read))::numeric, 2)
26
+ ELSE 100.0
27
+ END AS heap_hit_ratio
28
+ FROM pg_stat_database
29
+ WHERE datname = current_database()
30
+ ),
31
+ long_running AS (
32
+ SELECT COUNT(*) AS count
33
+ FROM pg_stat_activity
34
+ WHERE datname = current_database()
35
+ AND pid != pg_backend_pid()
36
+ AND state = 'active'
37
+ AND query_start IS NOT NULL
38
+ AND EXTRACT(EPOCH FROM (NOW() - query_start)) > :long_query_threshold
39
+ ),
40
+ blocked AS (
41
+ SELECT COUNT(*) AS count
42
+ FROM pg_locks
43
+ WHERE NOT granted
44
+ )
45
+ SELECT
46
+ cs.active_connections,
47
+ cs.idle_connections,
48
+ cs.total_connections,
49
+ cs.max_connections,
50
+ ROUND((cs.total_connections * 100.0 / NULLIF(cs.max_connections, 0))::numeric, 1) AS connections_pct,
51
+ ts.total_transactions,
52
+ ts.xact_commit,
53
+ ts.xact_rollback,
54
+ ca.heap_hit_ratio,
55
+ lr.count AS long_running_count,
56
+ bl.count AS blocked_count,
57
+ EXTRACT(EPOCH FROM NOW()) AS timestamp_epoch
58
+ FROM connection_stats cs
59
+ CROSS JOIN tps_stats ts
60
+ CROSS JOIN cache_stats ca
61
+ CROSS JOIN long_running lr
62
+ CROSS JOIN blocked bl;
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgReports
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_reports
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eldar Avatov
@@ -108,6 +108,9 @@ files:
108
108
  - app/controllers/pg_reports/dashboard_controller.rb
109
109
  - app/views/layouts/pg_reports/application.html.erb
110
110
  - app/views/pg_reports/dashboard/_fake_source_data.html.erb
111
+ - app/views/pg_reports/dashboard/_show_modals.html.erb
112
+ - app/views/pg_reports/dashboard/_show_scripts.html.erb
113
+ - app/views/pg_reports/dashboard/_show_styles.html.erb
111
114
  - app/views/pg_reports/dashboard/index.html.erb
112
115
  - app/views/pg_reports/dashboard/show.html.erb
113
116
  - config/locales/en.yml
@@ -150,6 +153,7 @@ files:
150
153
  - lib/pg_reports/sql/system/cache_stats.sql
151
154
  - lib/pg_reports/sql/system/database_sizes.sql
152
155
  - lib/pg_reports/sql/system/extensions.sql
156
+ - lib/pg_reports/sql/system/live_metrics.sql
153
157
  - lib/pg_reports/sql/system/settings.sql
154
158
  - lib/pg_reports/sql/tables/bloated_tables.sql
155
159
  - lib/pg_reports/sql/tables/cache_hit_ratios.sql