ruby-grafana-reporter 0.5.2 → 0.5.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/lib/VERSION.rb +2 -2
- data/lib/grafana/abstract_datasource.rb +30 -4
- data/lib/grafana/grafana_property_datasource.rb +0 -0
- data/lib/grafana/graphite_datasource.rb +10 -6
- data/lib/grafana/influxdb_datasource.rb +10 -6
- data/lib/grafana/panel.rb +26 -3
- data/lib/grafana/prometheus_datasource.rb +9 -28
- data/lib/grafana/sql_datasource.rb +10 -4
- data/lib/grafana_reporter/abstract_query.rb +2 -1
- data/lib/grafana_reporter/query_value_query.rb +4 -1
- data/lib/ruby_grafana_reporter.rb +0 -11
- 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: 8b50055253026b61f26a424e6016118db18c4b1998e1a26f8fa6f4c8c37f9d6d
|
4
|
+
data.tar.gz: 9ce58b615705b752f13260b4497b297aa1ad193f018a5699e0d4dca53fb1a743
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d96e06e01a4f5d861603528f64f57cfdbca4fe32a9790f8bc82982ea8581d6d07243aa5bfccd1fac018f1da1f1ad7a514fc31a9ff1f660aa2abf99ebfd5a2ab
|
7
|
+
data.tar.gz: 17b0f9e00461cea9c9fab69572d16b12a69494b06e52500c4f0ba01ced604116c57419726982a87cdd08f462465c4e4e9fe4a891211ff185be2ca52c67c5841d
|
data/lib/VERSION.rb
CHANGED
@@ -113,15 +113,14 @@ module Grafana
|
|
113
113
|
raise NotImplementedError
|
114
114
|
end
|
115
115
|
|
116
|
-
private
|
117
|
-
|
118
116
|
# Replaces the grafana variables in the given string with their replacement value.
|
119
117
|
#
|
120
118
|
# @param string [String] string in which the variables shall be replaced
|
121
119
|
# @param variables [Hash<String,Variable>] Hash containing the variables, which shall be replaced in the
|
122
120
|
# given string
|
121
|
+
# @param overwrite_default_format [String] {Variable#value_formatted} value, if a custom default format should be used, otherwise {#default_variable_format} is used as default, which may be overwritten
|
123
122
|
# @return [String] string in which all variables are properly replaced
|
124
|
-
def replace_variables(string, variables =
|
123
|
+
def replace_variables(string, variables, overwrite_default_format = nil)
|
125
124
|
res = string
|
126
125
|
repeat = true
|
127
126
|
repeat_count = 0
|
@@ -141,7 +140,8 @@ module Grafana
|
|
141
140
|
next unless var_name =~ /^\w+$/
|
142
141
|
|
143
142
|
res = res.gsub(/(?:\$\{#{var_name}(?::(?<format>\w+))?\}|\$#{var_name}(?!\w))/) do
|
144
|
-
format =
|
143
|
+
format = overwrite_default_format
|
144
|
+
format = default_variable_format if overwrite_default_format.nil?
|
145
145
|
if $LAST_MATCH_INFO
|
146
146
|
format = $LAST_MATCH_INFO[:format] if $LAST_MATCH_INFO[:format]
|
147
147
|
end
|
@@ -153,5 +153,31 @@ module Grafana
|
|
153
153
|
|
154
154
|
res
|
155
155
|
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
# Provides a general method to handle the given query response as general Grafana Dataframe format.
|
160
|
+
#
|
161
|
+
# This method throws {UnsupportedQueryResponseReceivedError} if the given query response is not a
|
162
|
+
# properly formattes dataframe
|
163
|
+
#
|
164
|
+
# @param response_body [String] raw response body
|
165
|
+
def preformat_dataframe_response(response_body)
|
166
|
+
json = JSON.parse(response_body)
|
167
|
+
data = json['results'].values.first
|
168
|
+
|
169
|
+
# TODO: check how multiple frames have to be handled
|
170
|
+
data = data['frames']
|
171
|
+
headers = []
|
172
|
+
data.first['schema']['fields'].each do |headline|
|
173
|
+
header = headline['config']['displayNameFromDS'].nil? ? headline['name'] : headline['config']['displayNameFromDS']
|
174
|
+
headers << header
|
175
|
+
end
|
176
|
+
content = data.first['data']['values'][0].zip(data.first['data']['values'][1])
|
177
|
+
return { header: headers, content: content }
|
178
|
+
|
179
|
+
rescue
|
180
|
+
raise UnsupportedQueryResponseReceivedError, response_body
|
181
|
+
end
|
156
182
|
end
|
157
183
|
end
|
File without changes
|
@@ -43,13 +43,14 @@ module Grafana
|
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
# @see AbstractDatasource#preformat_response
|
47
46
|
def preformat_response(response_body)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
begin
|
48
|
+
return preformat_dataframe_response(response_body)
|
49
|
+
rescue
|
50
|
+
# TODO: show an info, that the response if not a dataframe
|
51
|
+
end
|
52
52
|
|
53
|
+
json = JSON.parse(response_body)
|
53
54
|
header = ['time']
|
54
55
|
content = {}
|
55
56
|
|
@@ -69,7 +70,10 @@ module Grafana
|
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
72
|
-
{ header: header, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
73
|
+
return { header: header, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
74
|
+
|
75
|
+
rescue
|
76
|
+
raise UnsupportedQueryResponseReceivedError, response_body
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
@@ -127,14 +127,15 @@ module Grafana
|
|
127
127
|
"#{res} #{parts.join(', ')}"
|
128
128
|
end
|
129
129
|
|
130
|
-
# @see AbstractDatasource#preformat_response
|
131
130
|
def preformat_response(response_body)
|
131
|
+
begin
|
132
|
+
return preformat_dataframe_response(response_body)
|
133
|
+
rescue
|
134
|
+
# TODO: show an info, that the response if not a dataframe
|
135
|
+
end
|
136
|
+
|
132
137
|
# TODO: how to handle multiple query results?
|
133
138
|
json = JSON.parse(response_body)
|
134
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['results'].nil?
|
135
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['results'].first.nil?
|
136
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['results'].first['series'].nil?
|
137
|
-
|
138
139
|
json = json['results'].first['series']
|
139
140
|
return {} if json.nil?
|
140
141
|
|
@@ -157,7 +158,10 @@ module Grafana
|
|
157
158
|
end
|
158
159
|
end
|
159
160
|
|
160
|
-
{ header: header, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
161
|
+
return { header: header, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
162
|
+
|
163
|
+
rescue
|
164
|
+
raise UnsupportedQueryResponseReceivedError, response_body
|
161
165
|
end
|
162
166
|
end
|
163
167
|
end
|
data/lib/grafana/panel.rb
CHANGED
@@ -12,6 +12,11 @@ module Grafana
|
|
12
12
|
def initialize(model, dashboard)
|
13
13
|
@model = model
|
14
14
|
@dashboard = dashboard
|
15
|
+
|
16
|
+
@datasource_uid_or_name = @model['datasource']
|
17
|
+
if @model['datasource'].is_a?(Hash)
|
18
|
+
@datasource_uid_or_name = @model['datasource']['uid']
|
19
|
+
end
|
15
20
|
end
|
16
21
|
|
17
22
|
# @return [String] content of the requested field or +''+ if not found
|
@@ -26,12 +31,21 @@ module Grafana
|
|
26
31
|
@model['id']
|
27
32
|
end
|
28
33
|
|
34
|
+
# This method should always be called before the +datasource+ method of a
|
35
|
+
# panel is invoked, to ensure that the variable names in the datasource
|
36
|
+
# field are resolved.
|
37
|
+
#
|
38
|
+
# @param variables [Hash] variables hash, which should be use to resolve variable datasource
|
39
|
+
def resolve_variable_datasource(variables)
|
40
|
+
@datasource_uid_or_name = AbstractDatasource.new(nil).replace_variables(@datasource_uid_or_name, variables, 'raw')
|
41
|
+
end
|
42
|
+
|
29
43
|
# @return [Datasource] datasource object specified for the current panel
|
30
44
|
def datasource
|
31
|
-
if
|
32
|
-
dashboard.grafana.datasource_by_uid(@
|
45
|
+
if datasource_kind_is_uid?
|
46
|
+
dashboard.grafana.datasource_by_uid(@datasource_uid_or_name)
|
33
47
|
else
|
34
|
-
dashboard.grafana.datasource_by_name(@
|
48
|
+
dashboard.grafana.datasource_by_name(@datasource_uid_or_name)
|
35
49
|
end
|
36
50
|
end
|
37
51
|
|
@@ -47,5 +61,14 @@ module Grafana
|
|
47
61
|
def render_url
|
48
62
|
"/render/d-solo/#{@dashboard.id}?panelId=#{@model['id']}"
|
49
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def datasource_kind_is_uid?
|
68
|
+
if @model['datasource'].is_a?(Hash)
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
false
|
72
|
+
end
|
50
73
|
end
|
51
74
|
end
|
@@ -55,47 +55,25 @@ module Grafana
|
|
55
55
|
|
56
56
|
private
|
57
57
|
|
58
|
-
# @see AbstractDatasource#preformat_response
|
59
58
|
def preformat_response(response_body)
|
60
|
-
|
59
|
+
# TODO: show raw response body to debug case https://github.com/divinity666/ruby-grafana-reporter/issues/24
|
61
60
|
begin
|
62
|
-
|
61
|
+
return preformat_dataframe_response(response_body)
|
63
62
|
rescue
|
64
|
-
|
63
|
+
# TODO: show an info, that the response if not a dataframe
|
65
64
|
end
|
66
65
|
|
66
|
+
json = JSON.parse(response_body)
|
67
|
+
|
67
68
|
# handle response with error result
|
68
69
|
unless json['error'].nil?
|
69
70
|
return { header: ['error'], content: [[ json['error'] ]] }
|
70
71
|
end
|
71
72
|
|
72
|
-
# handle dataframes
|
73
|
-
if json['results']
|
74
|
-
data = json['results'].values.first
|
75
|
-
raise UnsupportedQueryResponseReceivedError, response_body if data.nil?
|
76
|
-
raise UnsupportedQueryResponseReceivedError, response_body if data['frames'].nil?
|
77
|
-
# TODO: check how multiple frames have to be handled
|
78
|
-
|
79
|
-
data = data['frames']
|
80
|
-
headers = []
|
81
|
-
data.first['schema']['fields'].each do |headline|
|
82
|
-
header = headline['config']['displayNameFromDS'].nil? ? headline['name'] : headline['config']['displayNameFromDS']
|
83
|
-
headers << header
|
84
|
-
end
|
85
|
-
content = data.first['data']['values'][0].zip(data.first['data']['values'][1])
|
86
|
-
return { header: headers, content: content }
|
87
|
-
end
|
88
|
-
|
89
73
|
# handle former result formats
|
90
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['data'].nil?
|
91
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['data']['resultType'].nil?
|
92
|
-
raise UnsupportedQueryResponseReceivedError, response_body if json['data']['result'].nil?
|
93
|
-
|
94
74
|
result_type = json['data']['resultType']
|
95
75
|
json = json['data']['result']
|
96
76
|
|
97
|
-
raise UnsupportedQueryResponseReceivedError, response_body if not result_type =~ /^(?:scalar|string|vector|matrix)$/
|
98
|
-
|
99
77
|
headers = ['time']
|
100
78
|
content = {}
|
101
79
|
|
@@ -130,7 +108,10 @@ module Grafana
|
|
130
108
|
end
|
131
109
|
end
|
132
110
|
|
133
|
-
{ header: headers, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
111
|
+
return { header: headers, content: content.to_a.map(&:flatten).sort { |a, b| a[0] <=> b[0] } }
|
112
|
+
|
113
|
+
rescue
|
114
|
+
raise UnsupportedQueryResponseReceivedError, response_body
|
134
115
|
end
|
135
116
|
end
|
136
117
|
end
|
@@ -47,6 +47,12 @@ module Grafana
|
|
47
47
|
private
|
48
48
|
|
49
49
|
def preformat_response(response_body)
|
50
|
+
begin
|
51
|
+
return preformat_dataframe_response(response_body)
|
52
|
+
rescue
|
53
|
+
# TODO: show an info, that the response if not a dataframe
|
54
|
+
end
|
55
|
+
|
50
56
|
results = {}
|
51
57
|
results.default = []
|
52
58
|
results[:header] = []
|
@@ -64,13 +70,13 @@ module Grafana
|
|
64
70
|
results[:content] = table['rows']
|
65
71
|
end
|
66
72
|
end
|
67
|
-
|
68
|
-
else
|
69
|
-
raise UnsupportedQueryResponseReceivedError, response_body
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
73
|
-
results
|
76
|
+
return results
|
77
|
+
|
78
|
+
rescue
|
79
|
+
raise UnsupportedQueryResponseReceivedError, response_body
|
74
80
|
end
|
75
81
|
end
|
76
82
|
end
|
@@ -13,6 +13,7 @@ module GrafanaReporter
|
|
13
13
|
attr_reader :variables, :result, :panel, :dashboard
|
14
14
|
|
15
15
|
def timeout
|
16
|
+
# TODO: PRIO check where value priorities should be evaluated
|
16
17
|
return @variables['timeout'].raw_value if @variables['timeout']
|
17
18
|
return @variables['grafana_default_timeout'].raw_value if @variables['grafana_default_timeout']
|
18
19
|
|
@@ -88,7 +89,7 @@ module GrafanaReporter
|
|
88
89
|
# grafana errors will be directly passed through
|
89
90
|
raise
|
90
91
|
rescue StandardError => e
|
91
|
-
raise DatasourceRequestInternalError.new(@datasource, e.message)
|
92
|
+
raise DatasourceRequestInternalError.new(@datasource, "#{e.message}\n#{e.backtrace.join("\n")}")
|
92
93
|
end
|
93
94
|
|
94
95
|
raise DatasourceRequestInvalidReturnValueError.new(@datasource, @result) unless datasource_response_valid?
|
@@ -5,7 +5,10 @@ module GrafanaReporter
|
|
5
5
|
class QueryValueQuery < AbstractQuery
|
6
6
|
# @see Grafana::AbstractQuery#pre_process
|
7
7
|
def pre_process
|
8
|
-
|
8
|
+
if @panel
|
9
|
+
@panel.resolve_variable_datasource(@variables)
|
10
|
+
@datasource = @panel.datasource
|
11
|
+
end
|
9
12
|
|
10
13
|
@variables['result_type'] ||= Variable.new('')
|
11
14
|
end
|
@@ -18,17 +18,6 @@ require 'asciidoctor-pdf'
|
|
18
18
|
require 'zip'
|
19
19
|
require_relative 'VERSION'
|
20
20
|
|
21
|
-
# TODO: add test for variable replacement for sql
|
22
|
-
# TODO: check why value is All instead of $__all
|
23
|
-
# TODO: check why single sql values are replaced including ticks, whereas grafana does not do so
|
24
|
-
|
25
|
-
# TODO: add FAQ for fixing most common issues with the reporter
|
26
|
-
# TODO: implement an easy function to document a whole dashboard at once with different presentations
|
27
|
-
# TODO: add automated test against grafana playground before building a new release
|
28
|
-
# TODO: allow registration of files to be defined in config file
|
29
|
-
# TODO: append necessary variables on demo report creation for plain SQL queries, as they are lacking the grafana reference
|
30
|
-
# TODO: make demo report more readable
|
31
|
-
|
32
21
|
folders = [
|
33
22
|
%w[grafana],
|
34
23
|
%w[grafana_reporter logger],
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-grafana-reporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Kohlmeyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|