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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de6063d128d57f930e83b17253e34e4e20624ef796e7eb86df2e7d54bee7825c
4
- data.tar.gz: a6a5f8b3bfcdcfc557ede19e7d89a25de8dca277806da0f662c4165d0a05b03c
3
+ metadata.gz: 8b50055253026b61f26a424e6016118db18c4b1998e1a26f8fa6f4c8c37f9d6d
4
+ data.tar.gz: 9ce58b615705b752f13260b4497b297aa1ad193f018a5699e0d4dca53fb1a743
5
5
  SHA512:
6
- metadata.gz: c9338b1dbd16a81af0c28feb9e8f4efd576ffb3f879aae7dd5d31b00468b32cc18ee49e7a73f87e952e2781845cd1d54124512aef6112194379d3840322fbff8
7
- data.tar.gz: 01bed067acfc6442e62ba17dbda3491e6147778a274c65ccacc7f838e57beda53809e8a8b827fad09266b4b506c2e29d7e8d3b0670c506eb0063eddd40d1aa26
6
+ metadata.gz: 3d96e06e01a4f5d861603528f64f57cfdbca4fe32a9790f8bc82982ea8581d6d07243aa5bfccd1fac018f1da1f1ad7a514fc31a9ff1f660aa2abf99ebfd5a2ab
7
+ data.tar.gz: 17b0f9e00461cea9c9fab69572d16b12a69494b06e52500c4f0ba01ced604116c57419726982a87cdd08f462465c4e4e9fe4a891211ff185be2ca52c67c5841d
data/lib/VERSION.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Version information
4
- GRAFANA_REPORTER_VERSION = [0, 5, 2].freeze
4
+ GRAFANA_REPORTER_VERSION = [0, 5, 3].freeze
5
5
  # Release date
6
- GRAFANA_REPORTER_RELEASE_DATE = '2022-03-22'
6
+ GRAFANA_REPORTER_RELEASE_DATE = '2022-03-24'
@@ -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 = default_variable_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
- json = JSON.parse(response_body)
49
-
50
- raise UnsupportedQueryResponseReceivedError, response_body if json.first['target'].nil?
51
- raise UnsupportedQueryResponseReceivedError, response_body if json.first['datapoints'].nil?
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 @model['datasource'].is_a?(Hash)
32
- dashboard.grafana.datasource_by_uid(@model['datasource']['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(@model['datasource'])
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
- json = {}
59
+ # TODO: show raw response body to debug case https://github.com/divinity666/ruby-grafana-reporter/issues/24
61
60
  begin
62
- json = JSON.parse(response_body)
61
+ return preformat_dataframe_response(response_body)
63
62
  rescue
64
- raise UnsupportedQueryResponseReceivedError, response_body
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
- @datasource = @panel.datasource if @panel
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.2
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-22 00:00:00.000000000 Z
11
+ date: 2022-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor