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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -245
  3. data/bin/ruby-grafana-reporter +3 -2
  4. data/lib/VERSION.rb +6 -3
  5. data/lib/grafana/abstract_datasource.rb +116 -0
  6. data/lib/grafana/dashboard.rb +75 -66
  7. data/lib/grafana/errors.rb +81 -61
  8. data/lib/grafana/grafana.rb +130 -131
  9. data/lib/grafana/grafana_alerts_datasource.rb +57 -0
  10. data/lib/grafana/grafana_annotations_datasource.rb +56 -0
  11. data/lib/grafana/grafana_property_datasource.rb +25 -0
  12. data/lib/grafana/graphite_datasource.rb +44 -0
  13. data/lib/grafana/image_rendering_datasource.rb +44 -0
  14. data/lib/grafana/panel.rb +47 -39
  15. data/lib/grafana/prometheus_datasource.rb +39 -0
  16. data/lib/grafana/sql_datasource.rb +65 -0
  17. data/lib/grafana/variable.rb +218 -259
  18. data/lib/grafana/webrequest.rb +71 -0
  19. data/lib/grafana_reporter/abstract_query.rb +401 -0
  20. data/lib/grafana_reporter/abstract_report.rb +163 -109
  21. data/lib/grafana_reporter/alerts_table_query.rb +44 -0
  22. data/lib/grafana_reporter/annotations_table_query.rb +43 -0
  23. data/lib/grafana_reporter/application/application.rb +162 -229
  24. data/lib/grafana_reporter/application/errors.rb +33 -30
  25. data/lib/grafana_reporter/application/webservice.rb +242 -0
  26. data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +90 -0
  27. data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +89 -0
  28. data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +76 -0
  29. data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +77 -0
  30. data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +72 -0
  31. data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +98 -0
  32. data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +93 -0
  33. data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +23 -0
  34. data/lib/grafana_reporter/asciidoctor/report.rb +172 -159
  35. data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +46 -0
  36. data/lib/grafana_reporter/asciidoctor/show_help_include_processor.rb +35 -0
  37. data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +92 -0
  38. data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +88 -0
  39. data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
  40. data/lib/grafana_reporter/configuration.rb +310 -326
  41. data/lib/grafana_reporter/console_configuration_wizard.rb +319 -0
  42. data/lib/grafana_reporter/demo_report_wizard.rb +87 -0
  43. data/lib/grafana_reporter/errors.rb +81 -38
  44. data/lib/grafana_reporter/help.rb +447 -0
  45. data/lib/grafana_reporter/logger/two_way_logger.rb +58 -52
  46. data/lib/grafana_reporter/panel_image_query.rb +29 -0
  47. data/lib/grafana_reporter/panel_property_query.rb +22 -0
  48. data/lib/grafana_reporter/query_value_query.rb +79 -0
  49. data/lib/grafana_reporter/report_webhook.rb +35 -0
  50. data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +29 -27
  51. metadata +48 -60
  52. data/lib/grafana/abstract_panel_query.rb +0 -20
  53. data/lib/grafana/abstract_query.rb +0 -127
  54. data/lib/grafana/abstract_sql_query.rb +0 -42
  55. data/lib/grafana/panel_image_query.rb +0 -49
  56. data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +0 -99
  57. data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -96
  58. data/lib/grafana_reporter/asciidoctor/errors.rb +0 -37
  59. data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +0 -86
  60. data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +0 -86
  61. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +0 -67
  62. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +0 -65
  63. data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +0 -58
  64. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +0 -75
  65. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +0 -70
  66. data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +0 -18
  67. data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +0 -41
  68. data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +0 -202
  69. data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +0 -67
  70. data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +0 -65
  71. data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +0 -57
  72. data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -32
  73. data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -23
  74. data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -43
  75. data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -36
  76. data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -309
  77. data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -34
  78. 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
- module GrafanaReporter
2
- # General error of the reporter. All other errors will inherit from this class.
3
- class GrafanaReporterError < StandardError
4
- def initialize(message)
5
- super('GrafanaReporterError: ' + message.to_s)
6
- end
7
- end
8
-
9
- # Thrown, if the requested grafana instance does not have the mandatory 'host'
10
- # setting configured.
11
- class GrafanaInstanceWithoutHostError < GrafanaReporterError
12
- def initialize(instance)
13
- super("Grafana instance '#{instance}' has been configured without mandatory 'host' setting.")
14
- end
15
- end
16
-
17
- # General configuration error. All configuration errors inherit from this class.
18
- class ConfigurationError < GrafanaReporterError
19
- def initialize(message)
20
- super("Configuration error: #{message}")
21
- end
22
- end
23
-
24
- # Thrown, if a configured path does not exist.
25
- class FolderDoesNotExistError < ConfigurationError
26
- def initialize(folder, config_item)
27
- super("#{config_item} '#{folder}' does not exist.")
28
- end
29
- end
30
-
31
- # Thrown if the configuration does not match the expected schema.
32
- # Details about how to fix that are provided in the message.
33
- class ConfigurationDoesNotMatchSchemaError < ConfigurationError
34
- def initialize(item, verb, expected, currently)
35
- super("Configuration file does not match schema definition. Expected '#{item}' to #{verb} '#{expected}', but was '#{currently}'.")
36
- end
37
- end
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