ruby-grafana-reporter 0.4.5 → 0.5.2

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/VERSION.rb +2 -2
  4. data/lib/grafana/abstract_datasource.rb +8 -0
  5. data/lib/grafana/dashboard.rb +6 -1
  6. data/lib/grafana/errors.rb +9 -1
  7. data/lib/grafana/grafana.rb +35 -0
  8. data/lib/grafana/grafana_environment_datasource.rb +56 -0
  9. data/lib/grafana/graphite_datasource.rb +3 -0
  10. data/lib/grafana/image_rendering_datasource.rb +5 -1
  11. data/lib/grafana/influxdb_datasource.rb +11 -4
  12. data/lib/grafana/panel.rb +5 -1
  13. data/lib/grafana/prometheus_datasource.rb +71 -11
  14. data/lib/grafana/sql_datasource.rb +10 -4
  15. data/lib/grafana/variable.rb +46 -23
  16. data/lib/grafana/webrequest.rb +1 -0
  17. data/lib/grafana_reporter/abstract_query.rb +31 -24
  18. data/lib/grafana_reporter/abstract_report.rb +2 -0
  19. data/lib/grafana_reporter/abstract_table_format_strategy.rb +44 -4
  20. data/lib/grafana_reporter/alerts_table_query.rb +2 -1
  21. data/lib/grafana_reporter/annotations_table_query.rb +2 -1
  22. data/lib/grafana_reporter/application/webservice.rb +8 -4
  23. data/lib/grafana_reporter/asciidoctor/adoc_plain_table_format_strategy.rb +11 -9
  24. data/lib/grafana_reporter/asciidoctor/help.rb +53 -14
  25. data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +2 -4
  26. data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +2 -4
  27. data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +1 -1
  28. data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +37 -6
  29. data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +11 -2
  30. data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +0 -5
  31. data/lib/grafana_reporter/configuration.rb +53 -22
  32. data/lib/grafana_reporter/console_configuration_wizard.rb +3 -1
  33. data/lib/grafana_reporter/csv_table_format_strategy.rb +11 -9
  34. data/lib/grafana_reporter/demo_report_wizard.rb +3 -6
  35. data/lib/grafana_reporter/errors.rb +2 -2
  36. data/lib/grafana_reporter/panel_image_query.rb +0 -1
  37. data/lib/grafana_reporter/query_value_query.rb +7 -1
  38. data/lib/grafana_reporter/reporter_environment_datasource.rb +24 -0
  39. data/lib/ruby_grafana_reporter.rb +7 -7
  40. metadata +8 -7
@@ -152,6 +152,32 @@ module GrafanaReporter
152
152
  get_config('default-document-attributes') || {}
153
153
  end
154
154
 
155
+ # Checks if this is the latest ruby-grafana-reporter version. If and how often the check if
156
+ # performed, depends on the configuration setting `check-for-updates`. By default this is
157
+ # 0 (=disabled). If a number >0 is specified, the checks are performed once every n-days on
158
+ # report creation or call of overview webpage.
159
+ # @return [Boolean] true, if is ok, false if a newer version exists
160
+ def latest_version_check_ok?
161
+ return false if @newer_version_exists
162
+
163
+ value = get_config('grafana-reporter:check-for-updates') || 0
164
+ return true if value <= 0
165
+
166
+ # repeat check only every n-th day
167
+ if @last_version_check
168
+ return true if (Time.now - @last_version_check) < (value * 24*60*60)
169
+ end
170
+
171
+ # check for newer version
172
+ @last_version_check = Time.now
173
+ url = 'https://github.com/divinity666/ruby-grafana-reporter/releases/latest'
174
+ response = Grafana::WebRequest.new(url).execute
175
+ return true if response['location'] =~ /.*[\/v]#{GRAFANA_REPORTER_VERSION.join('.')}$/
176
+
177
+ @newer_version_exists = true
178
+ return false
179
+ end
180
+
155
181
  # This function shall be called, before the configuration object is used in the
156
182
  # {Application::Application#run}. It ensures, that everything is setup properly
157
183
  # and all necessary folders exist. Appropriate errors are raised in case of errors.
@@ -237,13 +263,13 @@ module GrafanaReporter
237
263
  cur_pos
238
264
  end
239
265
 
240
- def validate_schema(schema, subject)
266
+ def validate_schema(schema, subject, pattern = nil)
241
267
  return nil if subject.nil?
242
268
 
243
269
  schema.each do |key, config|
244
- type, min_occurence, next_level = config
270
+ type, min_occurence, pattern, next_level = config
245
271
 
246
- validate_schema(next_level, subject[key]) if next_level
272
+ validate_schema(next_level, subject[key], pattern) if next_level
247
273
 
248
274
  if key.nil?
249
275
  # apply to all on this level
@@ -263,9 +289,13 @@ module GrafanaReporter
263
289
  elsif subject.is_a?(Hash)
264
290
  if !subject.key?(key) && min_occurence.positive?
265
291
  raise ConfigurationDoesNotMatchSchemaError.new(key, 'occur', min_occurence, 0)
266
- end
267
- if !subject[key].is_a?(type) && subject.key?(key)
292
+ elsif !subject[key].is_a?(type) && subject.key?(key)
268
293
  raise ConfigurationDoesNotMatchSchemaError.new(key, 'be a', type, subject[key].class)
294
+ elsif pattern
295
+ # validate for regex
296
+ unless subject[key].to_s =~ pattern
297
+ raise ConfigurationDoesNotMatchSchemaError.new(key, 'match pattern', pattern.inspect, subject[key].to_s)
298
+ end
269
299
  end
270
300
 
271
301
  else
@@ -286,34 +316,35 @@ module GrafanaReporter
286
316
  {
287
317
  'grafana' =>
288
318
  [
289
- Hash, 1,
319
+ Hash, 1, nil,
290
320
  {
291
321
  nil =>
292
322
  [
293
- Hash, 1,
323
+ Hash, 1, nil,
294
324
  {
295
- 'host' => [String, 1],
296
- 'api_key' => [String, 0]
325
+ 'host' => [String, 1, %r{^http(s)?://.+}],
326
+ 'api_key' => [String, 0, %r{^(?:[\w]+[=]*)?$}]
297
327
  }
298
328
  ]
299
329
  }
300
330
  ],
301
- 'default-document-attributes' => [Hash, explicit ? 1 : 0],
302
- 'to_file' => [String, 0],
331
+ 'default-document-attributes' => [Hash, explicit ? 1 : 0, nil],
332
+ 'to_file' => [String, 0, nil],
303
333
  'grafana-reporter' =>
304
334
  [
305
- Hash, 1,
335
+ Hash, 1, nil,
306
336
  {
307
- 'debug-level' => [String, 0],
308
- 'run-mode' => [String, 0],
309
- 'test-instance' => [String, 0],
310
- 'templates-folder' => [String, explicit ? 1 : 0],
311
- 'report-class' => [String, 1],
312
- 'reports-folder' => [String, explicit ? 1 : 0],
313
- 'report-retention' => [Integer, explicit ? 1 : 0],
314
- 'ssl-cert' => [String, 0],
315
- 'webservice-port' => [Integer, explicit ? 1 : 0],
316
- 'callbacks' => [Hash, 0, { nil => [String, 1] }]
337
+ 'check-for-updates' => [Integer, 0, /^[0-9]*$/],
338
+ 'debug-level' => [String, 0, /^(?:DEBUG|INFO|WARN|ERROR|FATAL|UNKNOWN)?$/],
339
+ 'run-mode' => [String, 0, /^(?:test|single-render|webservice)?$/],
340
+ 'test-instance' => [String, 0, nil],
341
+ 'templates-folder' => [String, explicit ? 1 : 0, nil],
342
+ 'report-class' => [String, 1, nil],
343
+ 'reports-folder' => [String, explicit ? 1 : 0, nil],
344
+ 'report-retention' => [Integer, explicit ? 1 : 0, nil],
345
+ 'ssl-cert' => [String, 0, nil],
346
+ 'webservice-port' => [Integer, explicit ? 1 : 0, nil],
347
+ 'callbacks' => [Hash, 0, nil, { nil => [String, 1, nil] }]
317
348
  }
318
349
  ]
319
350
  }
@@ -6,7 +6,6 @@ module GrafanaReporter
6
6
  class ConsoleConfigurationWizard
7
7
  # Provides a command line configuration wizard for setting up the necessary configuration
8
8
  # file.
9
- # TODO: refactor class
10
9
  def start_wizard(config_file, console_config)
11
10
  action = overwrite_or_use_config_file(config_file)
12
11
  return if action == 'abort'
@@ -73,6 +72,9 @@ module GrafanaReporter
73
72
  #{grafana}
74
73
 
75
74
  grafana-reporter:
75
+ # Specifies how often the reporter shall check for newer versions [number of days].
76
+ # You may set check-for-updates to 0 to disable
77
+ check-for-updates: 1
76
78
  report-class: GrafanaReporter::Asciidoctor::Report
77
79
  templates-folder: #{templates}
78
80
  reports-folder: #{reports}
@@ -9,15 +9,17 @@ module GrafanaReporter
9
9
  'csv'
10
10
  end
11
11
 
12
- # @see AbstractTableFormatStrategy#format
13
- def format(result, include_headline)
14
- headline = result[:header].map { |item| item.to_s.gsub(',', '\\,') }.join(',')
15
-
16
- content = result[:content].map do |row|
17
- row.map { |item| item.to_s.gsub(',', '\,') }.join(',')
18
- end.join("\n")
19
-
20
- "#{"#{headline}\n" if include_headline}#{content}"
12
+ # @see AbstractTableFormatStrategy#format_rules
13
+ def format_rules
14
+ {
15
+ row_start: '',
16
+ row_end: "\n",
17
+ cell_start: '',
18
+ between_cells: ', ',
19
+ cell_end: '',
20
+ replace_string_or_regex: ',',
21
+ replacement: '\\,'
22
+ }
21
23
  end
22
24
  end
23
25
  end
@@ -55,12 +55,6 @@ module GrafanaReporter
55
55
  results = {}
56
56
 
57
57
  dashboard.panels.shuffle.each do |panel|
58
- begin
59
- next if panel.datasource.is_a?(Grafana::UnsupportedDatasource)
60
- rescue Grafana::DatasourceDoesNotExistError
61
- next
62
- end
63
-
64
58
  query_classes.each do |query_class|
65
59
  unless query_class.public_instance_methods.include?(:build_demo_entry)
66
60
  results[query_class] = "Method 'build_demo_entry' not implemented for #{query_class.name}"
@@ -77,6 +71,9 @@ module GrafanaReporter
77
71
  # currently not allowed
78
72
  rescue StandardError => e
79
73
  puts "#{e.message}\n#{e.backtrace.join("\n")}"
74
+ rescue NotImplementedError
75
+ # Ignore these errors, as it only means, that a class does not implement
76
+ # the demo entry
80
77
  end
81
78
  end
82
79
  end
@@ -27,7 +27,7 @@ module GrafanaReporter
27
27
  # Raised if the return value of a datasource request does not match the expected return hash.
28
28
  class DatasourceRequestInvalidReturnValueError < GrafanaReporterError
29
29
  def initialize(datasource, message)
30
- super("The datasource request to '#{datasource.name}' (#{datasource.class})"\
30
+ super("The datasource request to '#{datasource.name}' (#{datasource.class}) "\
31
31
  "returned an invalid value: '#{message}'")
32
32
  end
33
33
  end
@@ -65,7 +65,7 @@ module GrafanaReporter
65
65
  # Details about how to fix that are provided in the message.
66
66
  class ConfigurationDoesNotMatchSchemaError < ConfigurationError
67
67
  def initialize(item, verb, expected, currently)
68
- super("Configuration file does not match schema definition. Expected '#{item}' to #{verb} '#{expected}',"\
68
+ super("Configuration file does not match schema definition. Expected '#{item}' to #{verb} '#{expected}', "\
69
69
  "but was '#{currently}'.")
70
70
  end
71
71
  end
@@ -15,7 +15,6 @@ module GrafanaReporter
15
15
  # Returns the body of the http query, which contains the raw image.
16
16
  def post_process
17
17
  @result = @result[:content].first
18
- raise ::Grafana::ImageCouldNotBeRenderedError, @panel if @result.include?('<html')
19
18
  end
20
19
 
21
20
  # @see AbstractQuery#raw_query
@@ -19,8 +19,14 @@ module GrafanaReporter
19
19
  modify_results
20
20
 
21
21
  case @variables['result_type'].raw_value
22
+ when 'object'
23
+
22
24
  when /(?:panel_table|sql_table)/
23
- @result = format_table_output(@result, row_divider: @variables['row_divider'], column_divider: @variables['column_divider'], table_formatter: @variables['table_formatter'], include_headline: @variables['include_headline'])
25
+ @result = format_table_output(@result, row_divider: @variables['row_divider'],
26
+ column_divider: @variables['column_divider'],
27
+ table_formatter: @variables['table_formatter'],
28
+ include_headline: @variables['include_headline'],
29
+ transpose: @variables['transpose'])
24
30
 
25
31
  when /(?:panel_value|sql_value)/
26
32
  tmp = @result[:content] || []
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrafanaReporter
4
+ # Implements a datasource to return environment related information about the reporter in a tabular format.
5
+ class ReporterEnvironmentDatasource < ::Grafana::AbstractDatasource
6
+ # @see AbstractDatasource#request
7
+ def request(query_description)
8
+ {
9
+ header: ['Version', 'Release Date'],
10
+ content: [[GRAFANA_REPORTER_VERSION.join('.'), GRAFANA_REPORTER_RELEASE_DATE]]
11
+ }
12
+ end
13
+
14
+ # @see AbstractDatasource#default_variable_format
15
+ def default_variable_format
16
+ nil
17
+ end
18
+
19
+ # @see AbstractDatasource#name
20
+ def name
21
+ self.class.to_s
22
+ end
23
+ end
24
+ end
@@ -18,16 +18,16 @@ require 'asciidoctor-pdf'
18
18
  require 'zip'
19
19
  require_relative 'VERSION'
20
20
 
21
- # TODO: add test to see if datasource default formats are applied
22
- # TODO: add test for render-height and render-width, as they are not forwarded
23
- # TODO: show convert-backend, template language and all variables in webservice overview
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
24
27
  # TODO: add automated test against grafana playground before building a new release
25
28
  # TODO: allow registration of files to be defined in config file
26
- # TODO: PRIO: check in cloud - variables fetched from queries are replaced with SQL query instead of the resolved values, which can lead to issues, e.g. when using that in a function as SUBSTRING
27
- # TODO: PRIO: allow multiple report classes in configuration file including possibility to decide for the individual class for each rendering call
28
- # TODO: add configuration example to README
29
- # TODO: find a way, how to automatically update test grafana responses with _real_ grafana responses
30
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
31
 
32
32
  folders = [
33
33
  %w[grafana],
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.4.5
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Kohlmeyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-26 00:00:00.000000000 Z
11
+ date: 2022-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -100,9 +100,9 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '3.9'
103
- description: Build reports based on grafana dashboards in asciidoctor syntax. Runs
104
- as webservice for easy integration with grafana, or as a standalone, command line
105
- utility.
103
+ description: Build reports based on grafana dashboards in asciidoctor or ERB syntax.
104
+ Runs as webservice for easy integration with grafana, or as a standalone, command
105
+ line utility.
106
106
  email: kohly@gmx.de
107
107
  executables:
108
108
  - ruby-grafana-reporter
@@ -118,6 +118,7 @@ files:
118
118
  - "./lib/grafana/grafana.rb"
119
119
  - "./lib/grafana/grafana_alerts_datasource.rb"
120
120
  - "./lib/grafana/grafana_annotations_datasource.rb"
121
+ - "./lib/grafana/grafana_environment_datasource.rb"
121
122
  - "./lib/grafana/grafana_property_datasource.rb"
122
123
  - "./lib/grafana/graphite_datasource.rb"
123
124
  - "./lib/grafana/image_rendering_datasource.rb"
@@ -165,6 +166,7 @@ files:
165
166
  - "./lib/grafana_reporter/panel_property_query.rb"
166
167
  - "./lib/grafana_reporter/query_value_query.rb"
167
168
  - "./lib/grafana_reporter/report_webhook.rb"
169
+ - "./lib/grafana_reporter/reporter_environment_datasource.rb"
168
170
  - "./lib/ruby_grafana_extension.rb"
169
171
  - "./lib/ruby_grafana_reporter.rb"
170
172
  - LICENSE
@@ -191,8 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
193
  - !ruby/object:Gem::Version
192
194
  version: '0'
193
195
  requirements: []
194
- rubyforge_project:
195
- rubygems_version: 2.7.6.2
196
+ rubygems_version: 3.2.5
196
197
  signing_key:
197
198
  specification_version: 4
198
199
  summary: Reporter Service for Grafana