pghero 2.5.0 → 2.7.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pghero might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +1 -7
- data/app/assets/javascripts/pghero/Chart.bundle.js +4432 -2965
- data/app/assets/javascripts/pghero/application.js +7 -0
- data/app/assets/javascripts/pghero/jquery.js +756 -482
- data/app/assets/javascripts/pghero/nouislider.js +287 -94
- data/app/assets/stylesheets/pghero/application.css +4 -0
- data/app/assets/stylesheets/pghero/nouislider.css +22 -11
- data/app/controllers/pg_hero/home_controller.rb +1 -1
- data/lib/generators/pghero/templates/config.yml.tt +3 -3
- data/lib/pghero.rb +10 -5
- data/lib/pghero/database.rb +3 -2
- data/lib/pghero/methods/basic.rb +9 -1
- data/lib/pghero/methods/explain.rb +1 -1
- data/lib/pghero/methods/query_stats.rb +81 -22
- data/lib/pghero/methods/space.rb +4 -0
- data/lib/pghero/methods/system.rb +55 -22
- data/lib/pghero/methods/users.rb +4 -0
- data/lib/pghero/version.rb +1 -1
- data/licenses/LICENSE-chart.js.txt +9 -0
- data/licenses/LICENSE-chartkick.js.txt +22 -0
- data/licenses/LICENSE-highlight.js.txt +29 -0
- data/licenses/LICENSE-jquery.txt +20 -0
- data/licenses/LICENSE-moment.txt +22 -0
- data/licenses/LICENSE-nouislider.txt +21 -0
- metadata +8 -2
@@ -1,4 +1,4 @@
|
|
1
|
-
/*! nouislider - 14.
|
1
|
+
/*! nouislider - 14.6.1 - 8/17/2020 */
|
2
2
|
/* Functional styling;
|
3
3
|
* These styles are required for noUiSlider to function.
|
4
4
|
* You don't need to change these rules to apply your design.
|
@@ -18,7 +18,6 @@
|
|
18
18
|
}
|
19
19
|
.noUi-target {
|
20
20
|
position: relative;
|
21
|
-
direction: ltr;
|
22
21
|
}
|
23
22
|
.noUi-base,
|
24
23
|
.noUi-connects {
|
@@ -39,7 +38,7 @@
|
|
39
38
|
position: absolute;
|
40
39
|
z-index: 1;
|
41
40
|
top: 0;
|
42
|
-
|
41
|
+
right: 0;
|
43
42
|
-ms-transform-origin: 0 0;
|
44
43
|
-webkit-transform-origin: 0 0;
|
45
44
|
-webkit-transform-style: preserve-3d;
|
@@ -56,9 +55,9 @@
|
|
56
55
|
}
|
57
56
|
/* Offset direction
|
58
57
|
*/
|
59
|
-
|
60
|
-
left:
|
61
|
-
right:
|
58
|
+
.noUi-txt-dir-rtl.noUi-horizontal .noUi-origin {
|
59
|
+
left: 0;
|
60
|
+
right: auto;
|
62
61
|
}
|
63
62
|
/* Give origins 0 height/width so they don't interfere with clicking the
|
64
63
|
* connect elements.
|
@@ -94,7 +93,7 @@ html:not([dir="rtl"]) .noUi-horizontal .noUi-origin {
|
|
94
93
|
.noUi-horizontal .noUi-handle {
|
95
94
|
width: 34px;
|
96
95
|
height: 28px;
|
97
|
-
|
96
|
+
right: -17px;
|
98
97
|
top: -6px;
|
99
98
|
}
|
100
99
|
.noUi-vertical {
|
@@ -103,12 +102,12 @@ html:not([dir="rtl"]) .noUi-horizontal .noUi-origin {
|
|
103
102
|
.noUi-vertical .noUi-handle {
|
104
103
|
width: 28px;
|
105
104
|
height: 34px;
|
106
|
-
|
105
|
+
right: -6px;
|
107
106
|
top: -17px;
|
108
107
|
}
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
.noUi-txt-dir-rtl.noUi-horizontal .noUi-handle {
|
109
|
+
left: -17px;
|
110
|
+
right: auto;
|
112
111
|
}
|
113
112
|
/* Styling;
|
114
113
|
* Giving the connect element a border radius causes issues with using transform: scale
|
@@ -297,3 +296,15 @@ html:not([dir="rtl"]) .noUi-horizontal .noUi-handle {
|
|
297
296
|
top: 50%;
|
298
297
|
right: 120%;
|
299
298
|
}
|
299
|
+
.noUi-horizontal .noUi-origin > .noUi-tooltip {
|
300
|
+
-webkit-transform: translate(50%, 0);
|
301
|
+
transform: translate(50%, 0);
|
302
|
+
left: auto;
|
303
|
+
bottom: 10px;
|
304
|
+
}
|
305
|
+
.noUi-vertical .noUi-origin > .noUi-tooltip {
|
306
|
+
-webkit-transform: translate(0, -18px);
|
307
|
+
transform: translate(0, -18px);
|
308
|
+
top: auto;
|
309
|
+
right: 28px;
|
310
|
+
}
|
@@ -32,14 +32,14 @@ databases:
|
|
32
32
|
|
33
33
|
# Basic authentication
|
34
34
|
# username: admin
|
35
|
-
# password:
|
35
|
+
# password: <%%= ENV["PGHERO_PASSWORD"] %>
|
36
36
|
|
37
37
|
# Stats database URL (defaults to app database)
|
38
38
|
# stats_database_url: <%%= ENV["PGHERO_STATS_DATABASE_URL"] %>
|
39
39
|
|
40
40
|
# AWS configuration (defaults to app AWS config)
|
41
|
-
# aws_access_key_id:
|
42
|
-
# aws_secret_access_key:
|
41
|
+
# aws_access_key_id: <%%= ENV["AWS_ACCESS_KEY_ID"] %>
|
42
|
+
# aws_secret_access_key: <%%= ENV["AWS_SECRET_ACCESS_KEY"] %>
|
43
43
|
# aws_region: us-east-1
|
44
44
|
|
45
45
|
# Filter data from queries (experimental)
|
data/lib/pghero.rb
CHANGED
@@ -43,7 +43,7 @@ module PgHero
|
|
43
43
|
self.long_running_query_sec = (ENV["PGHERO_LONG_RUNNING_QUERY_SEC"] || 60).to_i
|
44
44
|
self.slow_query_ms = (ENV["PGHERO_SLOW_QUERY_MS"] || 20).to_i
|
45
45
|
self.slow_query_calls = (ENV["PGHERO_SLOW_QUERY_CALLS"] || 100).to_i
|
46
|
-
self.explain_timeout_sec = (ENV["PGHERO_EXPLAIN_TIMEOUT_SEC"] || 10).
|
46
|
+
self.explain_timeout_sec = (ENV["PGHERO_EXPLAIN_TIMEOUT_SEC"] || 10).to_f
|
47
47
|
self.total_connections_threshold = (ENV["PGHERO_TOTAL_CONNECTIONS_THRESHOLD"] || 500).to_i
|
48
48
|
self.cache_hit_rate_threshold = 99
|
49
49
|
self.env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
@@ -119,11 +119,16 @@ module PgHero
|
|
119
119
|
|
120
120
|
if databases.empty?
|
121
121
|
databases["primary"] = {
|
122
|
-
"url" => ENV["PGHERO_DATABASE_URL"] || ActiveRecord::Base.connection_config
|
122
|
+
"url" => ENV["PGHERO_DATABASE_URL"] || ActiveRecord::Base.connection_config
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
if databases.size == 1
|
127
|
+
databases.values.first.merge!(
|
123
128
|
"db_instance_identifier" => ENV["PGHERO_DB_INSTANCE_IDENTIFIER"],
|
124
129
|
"gcp_database_id" => ENV["PGHERO_GCP_DATABASE_ID"],
|
125
130
|
"azure_resource_id" => ENV["PGHERO_AZURE_RESOURCE_ID"]
|
126
|
-
|
131
|
+
)
|
127
132
|
end
|
128
133
|
|
129
134
|
{
|
@@ -191,13 +196,13 @@ module PgHero
|
|
191
196
|
# stats for old databases are not cleaned up since we can't use an index
|
192
197
|
def clean_query_stats
|
193
198
|
each_database do |database|
|
194
|
-
|
199
|
+
database.clean_query_stats
|
195
200
|
end
|
196
201
|
end
|
197
202
|
|
198
203
|
def clean_space_stats
|
199
204
|
each_database do |database|
|
200
|
-
|
205
|
+
database.clean_space_stats
|
201
206
|
end
|
202
207
|
end
|
203
208
|
|
data/lib/pghero/database.rb
CHANGED
@@ -55,15 +55,16 @@ module PgHero
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def explain_timeout_sec
|
58
|
-
(config["explain_timeout_sec"] || PgHero.config["explain_timeout_sec"] || PgHero.explain_timeout_sec).
|
58
|
+
(config["explain_timeout_sec"] || PgHero.config["explain_timeout_sec"] || PgHero.explain_timeout_sec).to_f
|
59
59
|
end
|
60
60
|
|
61
61
|
def long_running_query_sec
|
62
62
|
(config["long_running_query_sec"] || PgHero.config["long_running_query_sec"] || PgHero.long_running_query_sec).to_i
|
63
63
|
end
|
64
64
|
|
65
|
+
# defaults to 100 megabytes
|
65
66
|
def index_bloat_bytes
|
66
|
-
(config["index_bloat_bytes"] || PgHero.config["index_bloat_bytes"] ||
|
67
|
+
(config["index_bloat_bytes"] || PgHero.config["index_bloat_bytes"] || 104857600).to_i
|
67
68
|
end
|
68
69
|
|
69
70
|
def aws_access_key_id
|
data/lib/pghero/methods/basic.rb
CHANGED
@@ -18,6 +18,10 @@ module PgHero
|
|
18
18
|
select_one("SELECT current_database()")
|
19
19
|
end
|
20
20
|
|
21
|
+
def current_user
|
22
|
+
select_one("SELECT current_user")
|
23
|
+
end
|
24
|
+
|
21
25
|
def server_version
|
22
26
|
@server_version ||= select_one("SHOW server_version")
|
23
27
|
end
|
@@ -38,7 +42,11 @@ module PgHero
|
|
38
42
|
retries = 0
|
39
43
|
begin
|
40
44
|
result = conn.select_all(add_source(squish(sql)))
|
41
|
-
|
45
|
+
if ActiveRecord::VERSION::STRING.to_f >= 6.1
|
46
|
+
result = result.map(&:symbolize_keys)
|
47
|
+
else
|
48
|
+
result = result.map { |row| Hash[row.map { |col, val| [col.to_sym, result.column_types[col].send(:cast_value, val)] }] }
|
49
|
+
end
|
42
50
|
if filter_data
|
43
51
|
query_columns.each do |column|
|
44
52
|
result.each do |row|
|
@@ -6,7 +6,7 @@ module PgHero
|
|
6
6
|
explanation = nil
|
7
7
|
|
8
8
|
# use transaction for safety
|
9
|
-
with_transaction(statement_timeout: (explain_timeout_sec * 1000), rollback: true) do
|
9
|
+
with_transaction(statement_timeout: (explain_timeout_sec * 1000).round, rollback: true) do
|
10
10
|
if (sql.sub(/;\z/, "").include?(";") || sql.upcase.include?("COMMIT")) && !explain_safe?
|
11
11
|
raise ActiveRecord::StatementInvalid, "Unsafe statement"
|
12
12
|
end
|
@@ -56,8 +56,46 @@ module PgHero
|
|
56
56
|
true
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
# TODO scope by database in PgHero 3.0
|
60
|
+
# (add database: database_name to options)
|
61
|
+
def reset_query_stats(**options)
|
62
|
+
reset_instance_query_stats(**options)
|
63
|
+
end
|
64
|
+
|
65
|
+
# resets query stats for the entire instance
|
66
|
+
# it's possible to reset stats for a specific
|
67
|
+
# database, user or query hash in Postgres 12+
|
68
|
+
def reset_instance_query_stats(database: nil, user: nil, query_hash: nil, raise_errors: false)
|
69
|
+
if database || user || query_hash
|
70
|
+
raise PgHero::Error, "Requires PostgreSQL 12+" if server_version_num < 120000
|
71
|
+
|
72
|
+
if database
|
73
|
+
database_id = execute("SELECT oid FROM pg_database WHERE datname = #{quote(database)}").first.try(:[], "oid")
|
74
|
+
raise PgHero::Error, "Database not found: #{database}" unless database_id
|
75
|
+
else
|
76
|
+
database_id = 0
|
77
|
+
end
|
78
|
+
|
79
|
+
if user
|
80
|
+
user_id = execute("SELECT usesysid FROM pg_user WHERE usename = #{quote(user)}").first.try(:[], "usesysid")
|
81
|
+
raise PgHero::Error, "User not found: #{user}" unless user_id
|
82
|
+
else
|
83
|
+
user_id = 0
|
84
|
+
end
|
85
|
+
|
86
|
+
if query_hash
|
87
|
+
query_id = query_hash.to_i
|
88
|
+
# may not be needed
|
89
|
+
# but not intuitive that all query hashes are reset with 0
|
90
|
+
raise PgHero::Error, "Invalid query hash: #{query_hash}" if query_id == 0
|
91
|
+
else
|
92
|
+
query_id = 0
|
93
|
+
end
|
94
|
+
|
95
|
+
execute("SELECT pg_stat_statements_reset(#{quote(user_id.to_i)}, #{quote(database_id.to_i)}, #{quote(query_id.to_i)})")
|
96
|
+
else
|
97
|
+
execute("SELECT pg_stat_statements_reset()")
|
98
|
+
end
|
61
99
|
true
|
62
100
|
rescue ActiveRecord::StatementInvalid => e
|
63
101
|
raise e if raise_errors
|
@@ -104,31 +142,32 @@ module PgHero
|
|
104
142
|
query_stats[database_id] = query_stats(limit: 1000000, database: database_name)
|
105
143
|
end
|
106
144
|
|
107
|
-
|
145
|
+
query_stats = query_stats.select { |_, v| v.any? }
|
108
146
|
|
109
|
-
|
147
|
+
# nothing to do
|
148
|
+
return if query_stats.empty?
|
149
|
+
|
150
|
+
# use mapping, not query stats here
|
151
|
+
# TODO add option for this, and make default in PgHero 3.0
|
152
|
+
if false # mapping.size == 1 && server_version_num >= 120000
|
110
153
|
query_stats.each do |db_id, db_query_stats|
|
111
|
-
if
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
now,
|
120
|
-
supports_query_hash ? qs[:query_hash] : nil,
|
121
|
-
qs[:user]
|
122
|
-
]
|
123
|
-
end
|
124
|
-
|
125
|
-
columns = %w[database query total_time calls captured_at query_hash user]
|
126
|
-
insert_stats("pghero_query_stats", columns, values)
|
154
|
+
if reset_query_stats(database: mapping[db_id], raise_errors: raise_errors)
|
155
|
+
insert_query_stats(db_id, db_query_stats, now)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
else
|
159
|
+
if reset_query_stats(raise_errors: raise_errors)
|
160
|
+
query_stats.each do |db_id, db_query_stats|
|
161
|
+
insert_query_stats(db_id, db_query_stats, now)
|
127
162
|
end
|
128
163
|
end
|
129
164
|
end
|
130
165
|
end
|
131
166
|
|
167
|
+
def clean_query_stats
|
168
|
+
PgHero::QueryStats.where(database: id).where("captured_at < ?", 14.days.ago).delete_all
|
169
|
+
end
|
170
|
+
|
132
171
|
def slow_queries(query_stats: nil, **options)
|
133
172
|
query_stats ||= self.query_stats(options)
|
134
173
|
query_stats.select { |q| q[:calls].to_i >= slow_query_calls.to_i && q[:average_time].to_f >= slow_query_ms.to_f }
|
@@ -166,14 +205,15 @@ module PgHero
|
|
166
205
|
if query_stats_enabled?
|
167
206
|
limit ||= 100
|
168
207
|
sort ||= "total_minutes"
|
208
|
+
total_time = server_version_num >= 130000 ? "(total_plan_time + total_exec_time)" : "total_time"
|
169
209
|
query = <<-SQL
|
170
210
|
WITH query_stats AS (
|
171
211
|
SELECT
|
172
212
|
LEFT(query, 10000) AS query,
|
173
213
|
#{supports_query_hash? ? "queryid" : "md5(query)"} AS query_hash,
|
174
214
|
rolname AS user,
|
175
|
-
(total_time / 1000 / 60) AS total_minutes,
|
176
|
-
(total_time / calls) AS average_time,
|
215
|
+
(#{total_time} / 1000 / 60) AS total_minutes,
|
216
|
+
(#{total_time} / calls) AS average_time,
|
177
217
|
calls
|
178
218
|
FROM
|
179
219
|
pg_stat_statements
|
@@ -182,6 +222,7 @@ module PgHero
|
|
182
222
|
INNER JOIN
|
183
223
|
pg_roles ON pg_roles.oid = pg_stat_statements.userid
|
184
224
|
WHERE
|
225
|
+
calls > 0 AND
|
185
226
|
pg_database.datname = #{database ? quote(database) : "current_database()"}
|
186
227
|
#{query_hash ? "AND queryid = #{quote(query_hash)}" : nil}
|
187
228
|
)
|
@@ -285,6 +326,24 @@ module PgHero
|
|
285
326
|
def normalize_query(query)
|
286
327
|
squish(query.to_s.gsub(/\?(, ?\?)+/, "?").gsub(/\/\*.+?\*\//, ""))
|
287
328
|
end
|
329
|
+
|
330
|
+
def insert_query_stats(db_id, db_query_stats, now)
|
331
|
+
values =
|
332
|
+
db_query_stats.map do |qs|
|
333
|
+
[
|
334
|
+
db_id,
|
335
|
+
qs[:query],
|
336
|
+
qs[:total_minutes] * 60 * 1000,
|
337
|
+
qs[:calls],
|
338
|
+
now,
|
339
|
+
supports_query_hash? ? qs[:query_hash] : nil,
|
340
|
+
qs[:user]
|
341
|
+
]
|
342
|
+
end
|
343
|
+
|
344
|
+
columns = %w[database query total_time calls captured_at query_hash user]
|
345
|
+
insert_stats("pghero_query_stats", columns, values)
|
346
|
+
end
|
288
347
|
end
|
289
348
|
end
|
290
349
|
end
|
data/lib/pghero/methods/space.rb
CHANGED
@@ -129,6 +129,10 @@ module PgHero
|
|
129
129
|
insert_stats("pghero_space_stats", columns, values) if values.any?
|
130
130
|
end
|
131
131
|
|
132
|
+
def clean_space_stats
|
133
|
+
PgHero::SpaceStats.where(database: id).where("captured_at < ?", 90.days.ago).delete_all
|
134
|
+
end
|
135
|
+
|
132
136
|
def space_stats_enabled?
|
133
137
|
table_exists?("pghero_space_stats")
|
134
138
|
end
|
@@ -5,7 +5,7 @@ module PgHero
|
|
5
5
|
!system_stats_provider.nil?
|
6
6
|
end
|
7
7
|
|
8
|
-
# TODO
|
8
|
+
# TODO remove defined checks in 3.0
|
9
9
|
def system_stats_provider
|
10
10
|
if aws_db_instance_identifier && (defined?(Aws) || defined?(AWS))
|
11
11
|
:aws
|
@@ -133,7 +133,7 @@ module PgHero
|
|
133
133
|
private
|
134
134
|
|
135
135
|
def gcp_stats(metric_name, duration: nil, period: nil, offset: nil, series: false)
|
136
|
-
require "google/cloud/monitoring"
|
136
|
+
require "google/cloud/monitoring/v3"
|
137
137
|
|
138
138
|
# TODO DRY with RDS stats
|
139
139
|
duration = (duration || 1.hour).to_i
|
@@ -142,30 +142,63 @@ module PgHero
|
|
142
142
|
end_time = Time.at(((Time.now - offset).to_f / period).ceil * period)
|
143
143
|
start_time = end_time - duration
|
144
144
|
|
145
|
-
client = Google::Cloud::Monitoring::Metric.new
|
146
|
-
|
147
|
-
interval = Google::Monitoring::V3::TimeInterval.new
|
148
|
-
interval.end_time = Google::Protobuf::Timestamp.new(seconds: end_time.to_i)
|
149
|
-
# subtract period to make sure we get first data point
|
150
|
-
interval.start_time = Google::Protobuf::Timestamp.new(seconds: (start_time - period).to_i)
|
151
|
-
|
152
|
-
aggregation = Google::Monitoring::V3::Aggregation.new
|
153
|
-
# may be better to use ALIGN_NEXT_OLDER for space stats to show most recent data point
|
154
|
-
# stick with average for now to match AWS
|
155
|
-
aggregation.per_series_aligner = Google::Monitoring::V3::Aggregation::Aligner::ALIGN_MEAN
|
156
|
-
aggregation.alignment_period = period
|
157
|
-
|
158
145
|
# validate input since we need to interpolate below
|
159
146
|
raise Error, "Invalid metric name" unless metric_name =~ /\A[a-z\/_]+\z/i
|
160
147
|
raise Error, "Invalid database id" unless gcp_database_id =~ /\A[a-z\-:]+\z/i
|
161
148
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
149
|
+
# we handle three situations:
|
150
|
+
# 1. google-cloud-monitoring-v3
|
151
|
+
# 2. google-cloud-monitoring >= 1
|
152
|
+
# 3. google-cloud-monitoring < 1
|
153
|
+
|
154
|
+
# for situations 1 and 2
|
155
|
+
# Google::Cloud::Monitoring.metric_service is documented
|
156
|
+
# but doesn't work for situation 1
|
157
|
+
if defined?(Google::Cloud::Monitoring::V3::MetricService::Client)
|
158
|
+
client = Google::Cloud::Monitoring::V3::MetricService::Client.new
|
159
|
+
|
160
|
+
interval = Google::Cloud::Monitoring::V3::TimeInterval.new
|
161
|
+
interval.end_time = Google::Protobuf::Timestamp.new(seconds: end_time.to_i)
|
162
|
+
# subtract period to make sure we get first data point
|
163
|
+
interval.start_time = Google::Protobuf::Timestamp.new(seconds: (start_time - period).to_i)
|
164
|
+
|
165
|
+
aggregation = Google::Cloud::Monitoring::V3::Aggregation.new
|
166
|
+
# may be better to use ALIGN_NEXT_OLDER for space stats to show most recent data point
|
167
|
+
# stick with average for now to match AWS
|
168
|
+
aggregation.per_series_aligner = Google::Cloud::Monitoring::V3::Aggregation::Aligner::ALIGN_MEAN
|
169
|
+
aggregation.alignment_period = period
|
170
|
+
|
171
|
+
results = client.list_time_series({
|
172
|
+
name: "projects/#{gcp_database_id.split(":").first}",
|
173
|
+
filter: "metric.type = \"cloudsql.googleapis.com/database/#{metric_name}\" AND resource.label.database_id = \"#{gcp_database_id}\"",
|
174
|
+
interval: interval,
|
175
|
+
view: Google::Cloud::Monitoring::V3::ListTimeSeriesRequest::TimeSeriesView::FULL,
|
176
|
+
aggregation: aggregation
|
177
|
+
})
|
178
|
+
else
|
179
|
+
require "google/cloud/monitoring"
|
180
|
+
|
181
|
+
client = Google::Cloud::Monitoring::Metric.new
|
182
|
+
|
183
|
+
interval = Google::Monitoring::V3::TimeInterval.new
|
184
|
+
interval.end_time = Google::Protobuf::Timestamp.new(seconds: end_time.to_i)
|
185
|
+
# subtract period to make sure we get first data point
|
186
|
+
interval.start_time = Google::Protobuf::Timestamp.new(seconds: (start_time - period).to_i)
|
187
|
+
|
188
|
+
aggregation = Google::Monitoring::V3::Aggregation.new
|
189
|
+
# may be better to use ALIGN_NEXT_OLDER for space stats to show most recent data point
|
190
|
+
# stick with average for now to match AWS
|
191
|
+
aggregation.per_series_aligner = Google::Monitoring::V3::Aggregation::Aligner::ALIGN_MEAN
|
192
|
+
aggregation.alignment_period = period
|
193
|
+
|
194
|
+
results = client.list_time_series(
|
195
|
+
"projects/#{gcp_database_id.split(":").first}",
|
196
|
+
"metric.type = \"cloudsql.googleapis.com/database/#{metric_name}\" AND resource.label.database_id = \"#{gcp_database_id}\"",
|
197
|
+
interval,
|
198
|
+
Google::Monitoring::V3::ListTimeSeriesRequest::TimeSeriesView::FULL,
|
199
|
+
aggregation: aggregation
|
200
|
+
)
|
201
|
+
end
|
169
202
|
|
170
203
|
data = {}
|
171
204
|
result = results.first
|