ruby-grafana-reporter 0.1.7 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +86 -245
- data/bin/ruby-grafana-reporter +3 -2
- data/lib/VERSION.rb +6 -3
- data/lib/grafana/abstract_datasource.rb +116 -0
- data/lib/grafana/dashboard.rb +75 -66
- data/lib/grafana/errors.rb +81 -61
- data/lib/grafana/grafana.rb +130 -131
- data/lib/grafana/grafana_alerts_datasource.rb +57 -0
- data/lib/grafana/grafana_annotations_datasource.rb +56 -0
- data/lib/grafana/grafana_property_datasource.rb +25 -0
- data/lib/grafana/graphite_datasource.rb +44 -0
- data/lib/grafana/image_rendering_datasource.rb +44 -0
- data/lib/grafana/panel.rb +47 -39
- data/lib/grafana/prometheus_datasource.rb +39 -0
- data/lib/grafana/sql_datasource.rb +65 -0
- data/lib/grafana/variable.rb +218 -259
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +401 -0
- data/lib/grafana_reporter/abstract_report.rb +163 -109
- data/lib/grafana_reporter/alerts_table_query.rb +44 -0
- data/lib/grafana_reporter/annotations_table_query.rb +43 -0
- data/lib/grafana_reporter/application/application.rb +162 -229
- data/lib/grafana_reporter/application/errors.rb +33 -30
- data/lib/grafana_reporter/application/webservice.rb +242 -0
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +90 -0
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +89 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +76 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +77 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +72 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +98 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +93 -0
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +23 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +172 -159
- data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +46 -0
- data/lib/grafana_reporter/asciidoctor/show_help_include_processor.rb +35 -0
- data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +92 -0
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +88 -0
- data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
- data/lib/grafana_reporter/configuration.rb +310 -326
- data/lib/grafana_reporter/console_configuration_wizard.rb +319 -0
- data/lib/grafana_reporter/demo_report_wizard.rb +87 -0
- data/lib/grafana_reporter/errors.rb +81 -38
- data/lib/grafana_reporter/help.rb +447 -0
- data/lib/grafana_reporter/logger/two_way_logger.rb +58 -52
- data/lib/grafana_reporter/panel_image_query.rb +29 -0
- data/lib/grafana_reporter/panel_property_query.rb +22 -0
- data/lib/grafana_reporter/query_value_query.rb +79 -0
- data/lib/grafana_reporter/report_webhook.rb +35 -0
- data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +29 -27
- metadata +48 -60
- data/lib/grafana/abstract_panel_query.rb +0 -20
- data/lib/grafana/abstract_query.rb +0 -127
- data/lib/grafana/abstract_sql_query.rb +0 -42
- data/lib/grafana/panel_image_query.rb +0 -49
- data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +0 -99
- data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -96
- data/lib/grafana_reporter/asciidoctor/errors.rb +0 -37
- data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +0 -86
- data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +0 -86
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +0 -67
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +0 -65
- data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +0 -58
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +0 -75
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +0 -70
- data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +0 -18
- data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +0 -41
- data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +0 -202
- data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +0 -67
- data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +0 -65
- data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +0 -57
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -32
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -23
- data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -43
- data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -36
- data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -309
- data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -34
- data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +0 -32
@@ -0,0 +1,319 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
# This class provides a console configuration wizard, to reduce the manual efforts that have
|
5
|
+
# to be spent for that action and to reduce mistakes as good as possible.
|
6
|
+
class ConsoleConfigurationWizard
|
7
|
+
# Provides a command line configuration wizard for setting up the necessary configuration
|
8
|
+
# file.
|
9
|
+
# TODO: refactor class
|
10
|
+
def start_wizard(config_file, console_config)
|
11
|
+
action = overwrite_or_use_config_file(config_file)
|
12
|
+
return if action == 'abort'
|
13
|
+
|
14
|
+
config = create_config_wizard(config_file, console_config) if action == 'overwrite'
|
15
|
+
config ||= Configuration.new
|
16
|
+
|
17
|
+
begin
|
18
|
+
config.config = YAML.load_file(config_file)
|
19
|
+
rescue StandardError => e
|
20
|
+
raise ConfigurationError, "Could not read config file '#{config_file}' (Error: #{e.message})\n"\
|
21
|
+
"Source:\n#{File.read(config_file)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
config.validate(true)
|
26
|
+
puts 'Configuration file validated successfully.'
|
27
|
+
rescue ConfigurationError => e
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
|
31
|
+
demo_report = create_demo_report(config)
|
32
|
+
|
33
|
+
demo_report ||= '<<your_report_name>>'
|
34
|
+
config_param = config_file == Application::Application::CONFIG_FILE ? '' : " -c #{config_file}"
|
35
|
+
program_call = "#{Gem.ruby} #{$PROGRAM_NAME}"
|
36
|
+
program_call = ENV['OCRA_EXECUTABLE'].gsub("#{Dir.pwd}/".gsub('/', '\\'), '') if ENV['OCRA_EXECUTABLE']
|
37
|
+
|
38
|
+
puts
|
39
|
+
puts 'Now everything is setup properly. Create your reports as required in the templates '\
|
40
|
+
'folder and run the reporter either standalone with e.g. the following command:'
|
41
|
+
puts
|
42
|
+
puts " #{program_call}#{config_param} -t #{demo_report} -o demo_report_with_help.pdf"
|
43
|
+
puts
|
44
|
+
puts 'or run it as a service using the following command:'
|
45
|
+
puts
|
46
|
+
puts " #{program_call}#{config_param}"
|
47
|
+
puts
|
48
|
+
puts "Open 'http://localhost:#{config.webserver_port}/render?var-template=#{demo_report}' in a webbrowser to"\
|
49
|
+
' test your configuration.'
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def create_config_wizard(config_file, console_config)
|
55
|
+
config = Configuration.new
|
56
|
+
|
57
|
+
puts 'This wizard will guide you through an initial configuration for'\
|
58
|
+
' the ruby-grafana-reporter. The configuration file will be created'\
|
59
|
+
' in the current folder. Please make sure to specify necessary paths'\
|
60
|
+
' either with a relative or an absolute path properly.'
|
61
|
+
puts
|
62
|
+
puts "Wizard is creating configuration file '#{config_file}'."
|
63
|
+
puts
|
64
|
+
port = ui_config_port
|
65
|
+
grafana = ui_config_grafana(console_config)
|
66
|
+
templates = ui_config_templates_folder
|
67
|
+
reports = ui_config_reports_folder
|
68
|
+
images = ui_config_images_folder(templates)
|
69
|
+
retention = ui_config_retention
|
70
|
+
|
71
|
+
config_yaml = %(# This configuration has been built with the configuration wizard.
|
72
|
+
|
73
|
+
#{grafana}
|
74
|
+
|
75
|
+
grafana-reporter:
|
76
|
+
report-class: GrafanaReporter::Asciidoctor::Report
|
77
|
+
templates-folder: #{templates}
|
78
|
+
reports-folder: #{reports}
|
79
|
+
report-retention: #{retention}
|
80
|
+
webservice-port: #{port}
|
81
|
+
# you may want to configure the following webhook callbacks to get informed on certain events
|
82
|
+
# callbacks:
|
83
|
+
# all:
|
84
|
+
# - <<your_callback_url>>
|
85
|
+
# - ...
|
86
|
+
# on_before_create:
|
87
|
+
# - <<your_callback_url>>
|
88
|
+
# - ...
|
89
|
+
# on_after_cancel:
|
90
|
+
# - <<your_callback_url>>
|
91
|
+
# - ...
|
92
|
+
# on_after_finish:
|
93
|
+
# - <<your_callback_url>>
|
94
|
+
# - ...
|
95
|
+
|
96
|
+
default-document-attributes:
|
97
|
+
imagesdir: #{images}
|
98
|
+
# feel free to add here additional asciidoctor document attributes which are applied to all your templates
|
99
|
+
)
|
100
|
+
|
101
|
+
begin
|
102
|
+
File.write(config_file, config_yaml, mode: 'w')
|
103
|
+
puts 'Configuration file successfully created.'
|
104
|
+
rescue StandardError => e
|
105
|
+
raise e
|
106
|
+
end
|
107
|
+
|
108
|
+
config
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_demo_report(config)
|
112
|
+
unless Dir.exist?(config.templates_folder)
|
113
|
+
puts "Skip creation of DEMO template, as folder '#{config.templates_folder}' does not exist."
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
|
117
|
+
create = user_input('Shall I create a demo report for your new configuration file? Please note '\
|
118
|
+
'that this report might contain confidential information, depending on the '\
|
119
|
+
'confidentiality of the information stored in your dashboard.', 'yN')
|
120
|
+
return nil unless create =~ /^(?:y|Y)$/
|
121
|
+
|
122
|
+
demo_report = 'demo_report'
|
123
|
+
demo_report_file = "#{config.templates_folder}#{demo_report}.adoc"
|
124
|
+
|
125
|
+
# ask to overwrite file
|
126
|
+
if File.exist?(demo_report_file)
|
127
|
+
input = user_input("Demo template '#{demo_report_file}' does already exist. Do you want to "\
|
128
|
+
'overwrite it?', 'yN')
|
129
|
+
|
130
|
+
case input
|
131
|
+
when /^(?:y|Y)$/
|
132
|
+
puts 'Overwriting existing DEMO template.'
|
133
|
+
|
134
|
+
else
|
135
|
+
puts 'Skip creation of DEMO template.'
|
136
|
+
return demo_report
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# TODO: move this to Asciidoctor::Report class
|
141
|
+
classes = [Asciidoctor::AlertsTableIncludeProcessor, Asciidoctor::AnnotationsTableIncludeProcessor,
|
142
|
+
Asciidoctor::PanelImageBlockMacro, Asciidoctor::PanelImageInlineMacro,
|
143
|
+
Asciidoctor::PanelPropertyInlineMacro, Asciidoctor::PanelQueryTableIncludeProcessor,
|
144
|
+
Asciidoctor::PanelQueryValueInlineMacro, Asciidoctor::SqlTableIncludeProcessor,
|
145
|
+
Asciidoctor::SqlValueInlineMacro, Asciidoctor::ShowHelpIncludeProcessor,
|
146
|
+
Asciidoctor::ShowEnvironmentIncludeProcessor]
|
147
|
+
|
148
|
+
grafana = ::Grafana::Grafana.new(config.grafana_host, config.grafana_api_key)
|
149
|
+
demo_report_content = DemoReportWizard.new(classes).build(grafana)
|
150
|
+
|
151
|
+
begin
|
152
|
+
File.write(demo_report_file, demo_report_content, mode: 'w')
|
153
|
+
puts "DEMO template '#{demo_report_file}' successfully created."
|
154
|
+
rescue StandardError => e
|
155
|
+
puts e.message
|
156
|
+
return nil
|
157
|
+
end
|
158
|
+
|
159
|
+
demo_report
|
160
|
+
end
|
161
|
+
|
162
|
+
def ui_config_grafana(config)
|
163
|
+
valid = false
|
164
|
+
url = nil
|
165
|
+
api_key = nil
|
166
|
+
until valid
|
167
|
+
url ||= user_input('Specify grafana host', 'http://localhost:3000')
|
168
|
+
print "Testing connection to '#{url}' #{api_key ? '_with_' : '_without_'} API key..."
|
169
|
+
begin
|
170
|
+
res = Grafana::Grafana.new(url,
|
171
|
+
api_key,
|
172
|
+
logger: config.logger).test_connection
|
173
|
+
rescue StandardError => e
|
174
|
+
puts
|
175
|
+
puts e.message
|
176
|
+
end
|
177
|
+
puts 'done.'
|
178
|
+
|
179
|
+
case res
|
180
|
+
when 'Admin'
|
181
|
+
tmp = user_input('Access to grafana is permitted as Admin, which is a potential security risk.'\
|
182
|
+
' Do you want to use another [a]pi key, [r]e-enter url key or [i]gnore?', 'aRi')
|
183
|
+
|
184
|
+
case tmp
|
185
|
+
when /(?:i|I)$/
|
186
|
+
valid = true
|
187
|
+
|
188
|
+
when /(?:a|A)$/
|
189
|
+
print 'Enter API key: '
|
190
|
+
api_key = gets.strip
|
191
|
+
|
192
|
+
else
|
193
|
+
url = nil
|
194
|
+
api_key = nil
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
when 'NON-Admin'
|
199
|
+
print 'Access to grafana is permitted as NON-Admin.'
|
200
|
+
valid = true
|
201
|
+
|
202
|
+
else
|
203
|
+
tmp = user_input("Grafana could not be accessed at '#{url}'. Do you want to use an [a]pi key,"\
|
204
|
+
' [r]e-enter url, or [i]gnore and proceed?', 'aRi')
|
205
|
+
|
206
|
+
case tmp
|
207
|
+
when /(?:i|I)$/
|
208
|
+
valid = true
|
209
|
+
|
210
|
+
when /(?:a|A)$/
|
211
|
+
print 'Enter API key: '
|
212
|
+
api_key = gets.strip
|
213
|
+
|
214
|
+
else
|
215
|
+
url = nil
|
216
|
+
api_key = nil
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|
222
|
+
%(grafana:
|
223
|
+
default:
|
224
|
+
host: #{url}#{api_key ? "\n api_key: #{api_key}" : ''}
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
def ui_config_port
|
229
|
+
input = nil
|
230
|
+
until input
|
231
|
+
input = user_input('Specify port on which reporter shall run', '8815')
|
232
|
+
input = nil unless input =~ /[0-9]+/
|
233
|
+
end
|
234
|
+
input
|
235
|
+
end
|
236
|
+
|
237
|
+
def ui_config_templates_folder
|
238
|
+
input = nil
|
239
|
+
until input
|
240
|
+
input = user_input('Specify path where templates shall be stored', './templates')
|
241
|
+
input = nil unless validate_config_folder(input)
|
242
|
+
end
|
243
|
+
input
|
244
|
+
end
|
245
|
+
|
246
|
+
def ui_config_reports_folder
|
247
|
+
input = nil
|
248
|
+
until input
|
249
|
+
input = user_input('Specify path where created reports shall be stored', './reports')
|
250
|
+
input = nil unless validate_config_folder(input)
|
251
|
+
end
|
252
|
+
input
|
253
|
+
end
|
254
|
+
|
255
|
+
def ui_config_images_folder(parent)
|
256
|
+
input = nil
|
257
|
+
until input
|
258
|
+
input = user_input('Specify path where rendered images shall be stored (relative to templates folder)',
|
259
|
+
'./images')
|
260
|
+
input = nil unless validate_config_folder(File.join(parent, input))
|
261
|
+
end
|
262
|
+
input
|
263
|
+
end
|
264
|
+
|
265
|
+
def ui_config_retention
|
266
|
+
input = nil
|
267
|
+
until input
|
268
|
+
input = user_input('Specify report retention duration in hours', '24')
|
269
|
+
input = nil unless input =~ /[0-9]+/
|
270
|
+
end
|
271
|
+
input
|
272
|
+
end
|
273
|
+
|
274
|
+
def user_input(text, default)
|
275
|
+
print "#{text} [#{default}]: "
|
276
|
+
input = gets.gsub(/\n$/, '')
|
277
|
+
input = default if input.empty?
|
278
|
+
input
|
279
|
+
end
|
280
|
+
|
281
|
+
def validate_config_folder(folder)
|
282
|
+
return true if Dir.exist?(folder)
|
283
|
+
|
284
|
+
print "Directory '#{folder} does not exist: [c]reate, [r]e-enter path or [i]gnore? [cRi]: "
|
285
|
+
case gets
|
286
|
+
when /^(?:c|C)$/
|
287
|
+
begin
|
288
|
+
Dir.mkdir(folder)
|
289
|
+
puts "Directory '#{folder}' successfully created."
|
290
|
+
return true
|
291
|
+
rescue StandardError => e
|
292
|
+
puts "WARN: Directory '#{folder}' could not be created. Please create it manually."
|
293
|
+
puts e.message
|
294
|
+
end
|
295
|
+
|
296
|
+
when /^(?:i|I)$/
|
297
|
+
puts "WARN: Directory '#{folder}' does not exist. Please create manually."
|
298
|
+
return true
|
299
|
+
end
|
300
|
+
|
301
|
+
false
|
302
|
+
end
|
303
|
+
|
304
|
+
def overwrite_or_use_config_file(config_file)
|
305
|
+
return 'overwrite' unless File.exist?(config_file)
|
306
|
+
|
307
|
+
input = nil
|
308
|
+
until input
|
309
|
+
input = user_input("Configuration file '#{config_file}' already exists. Do you want to [o]verwrite it, "\
|
310
|
+
'use it to for [d]emo report creation only, or [a]bort?', 'odA')
|
311
|
+
end
|
312
|
+
|
313
|
+
return 'demo_report' if input =~ /^(?:d|D)$/
|
314
|
+
return 'abort' if input =~ /^(?:A|a|odA)$/
|
315
|
+
|
316
|
+
'overwrite'
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
# This class is used to build a demo report based on a real grafana instance. Therefore
|
5
|
+
# it checks available grafana dashboards and panels and returns a final template file as
|
6
|
+
# string, which can then be used as a template.
|
7
|
+
class DemoReportWizard
|
8
|
+
# @param query_classes [Array] class objects, for which a demo report shall be created
|
9
|
+
def initialize(query_classes)
|
10
|
+
@query_classes = query_classes
|
11
|
+
end
|
12
|
+
|
13
|
+
# Invokes the build process for the given +grafana+ object. Progress is printed to
|
14
|
+
# STDOUT.
|
15
|
+
# @param grafana [Grafana] grafana instance, for which the demo report shall be built
|
16
|
+
# @return [String] demo template as string
|
17
|
+
def build(grafana)
|
18
|
+
results = {}
|
19
|
+
|
20
|
+
grafana.dashboard_ids.sample(15).each do |dashboard_id|
|
21
|
+
print "Evaluating dashboard '#{dashboard_id}' for building a demo report..."
|
22
|
+
dashboard = grafana.dashboard(dashboard_id)
|
23
|
+
|
24
|
+
results = evaluate_dashboard(dashboard, @query_classes - results.keys).merge(results)
|
25
|
+
|
26
|
+
puts "done - #{(@query_classes - results.keys).length} examples to go"
|
27
|
+
break if (@query_classes - results.keys).empty?
|
28
|
+
end
|
29
|
+
puts 'Aborting evaluating further dashboards after 15 samples.' if grafana.dashboard_ids.length > 15 and !(@query_classes - results.keys).empty?
|
30
|
+
puts "For #{(@query_classes - results.keys).length} reporter functionalities no appropriate examples could be found in the configured grafana instance." unless (@query_classes - results.keys).empty?
|
31
|
+
|
32
|
+
format_results(default_result(@query_classes - results.keys).merge(results))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def default_result(query_classes)
|
38
|
+
results = {}
|
39
|
+
|
40
|
+
query_classes.each do |query_class|
|
41
|
+
results[query_class] = "No example found for #{query_class.name} in the dashboards."
|
42
|
+
end
|
43
|
+
|
44
|
+
results
|
45
|
+
end
|
46
|
+
|
47
|
+
def evaluate_dashboard(dashboard, query_classes)
|
48
|
+
results = {}
|
49
|
+
|
50
|
+
dashboard.panels.shuffle.each do |panel|
|
51
|
+
query_classes.each do |query_class|
|
52
|
+
unless query_class.public_instance_methods.include?(:build_demo_entry)
|
53
|
+
results[query_class] = "Method 'build_demo_entry' not implemented for #{query_class.name}"
|
54
|
+
next
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
result = query_class.new.build_demo_entry(panel)
|
59
|
+
results[query_class] = result if result
|
60
|
+
rescue StandardError => e
|
61
|
+
puts "#{e.message}\n#{e.backtrace.join("\n")}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
results
|
67
|
+
end
|
68
|
+
|
69
|
+
# TODO: move this method to Asciidoctor::Report
|
70
|
+
def format_results(raw_results)
|
71
|
+
results = ['= Demo report',
|
72
|
+
"Created by `+ruby-grafana-reporter+` version #{GRAFANA_REPORTER_VERSION.join('.')}",
|
73
|
+
'== Examples']
|
74
|
+
|
75
|
+
raw_results.each do |k, v|
|
76
|
+
results += if v =~ /^[A-Z]/
|
77
|
+
["=== #{k.to_s.gsub(/.*::/, '')}", v.to_s]
|
78
|
+
else
|
79
|
+
["=== #{k.to_s.gsub(/.*::/, '')}", 'Sample call:', " #{v.gsub(/\n/, "\n ")}",
|
80
|
+
'Result:', v.to_s]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
results.join("\n\n")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,38 +1,81 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
# General error of the reporter. All other errors will inherit from this class.
|
5
|
+
class GrafanaReporterError < StandardError
|
6
|
+
def initialize(message)
|
7
|
+
super("GrafanaReporterError: #{message}")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Thrown, if the requested grafana instance does not have the mandatory 'host'
|
12
|
+
# setting configured.
|
13
|
+
class GrafanaInstanceWithoutHostError < GrafanaReporterError
|
14
|
+
def initialize(instance)
|
15
|
+
super("Grafana instance '#{instance}' has been configured without mandatory 'host' setting.")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# General configuration error. All configuration errors inherit from this class.
|
20
|
+
class ConfigurationError < GrafanaReporterError
|
21
|
+
def initialize(message)
|
22
|
+
super("Configuration error: #{message}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Thrown if a non existing template has been specified.
|
27
|
+
class MissingTemplateError < ConfigurationError
|
28
|
+
def initialize(template)
|
29
|
+
super("Given report template '#{template}' is not a valid template.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Thrown, if a configured path does not exist.
|
34
|
+
class FolderDoesNotExistError < ConfigurationError
|
35
|
+
def initialize(folder, config_item)
|
36
|
+
super("#{config_item} '#{folder}' does not exist.")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Thrown if the configuration does not match the expected schema.
|
41
|
+
# Details about how to fix that are provided in the message.
|
42
|
+
class ConfigurationDoesNotMatchSchemaError < ConfigurationError
|
43
|
+
def initialize(item, verb, expected, currently)
|
44
|
+
super("Configuration file does not match schema definition. Expected '#{item}' to #{verb} '#{expected}',"\
|
45
|
+
"but was '#{currently}'.")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Thrown, if the value configuration in {QueryMixin#replace_values} is
|
50
|
+
# invalid.
|
51
|
+
class MalformedReplaceValuesStatementError < GrafanaReporterError
|
52
|
+
def initialize(statement)
|
53
|
+
super("The specified replace_values statement '#{statement}' is invalid. Make sure it contains"\
|
54
|
+
" exactly one not escaped ':' symbol.")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Thrown, if a configured parameter is malformed.
|
59
|
+
class MalformedAttributeContentError < GrafanaReporterError
|
60
|
+
def initialize(message, attribute, content)
|
61
|
+
super("The content '#{content}' in attribute '#{attribute}' is malformed: #{message}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Thrown, if a configured time range is not supported by the reporter.
|
66
|
+
#
|
67
|
+
# If this happens, most likely the reporter has to implement the new
|
68
|
+
# time range definition.
|
69
|
+
class TimeRangeUnknownError < GrafanaReporterError
|
70
|
+
def initialize(time_range)
|
71
|
+
super("The specified time range '#{time_range}' is unknown.")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Thrown, if a mandatory attribute is not set.
|
76
|
+
class MissingMandatoryAttributeError < GrafanaReporterError
|
77
|
+
def initialize(attribute)
|
78
|
+
super("Missing mandatory attribute '#{attribute}'.")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|