ruby-grafana-reporter 0.4.2 → 0.5.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +144 -11
  3. data/lib/VERSION.rb +2 -2
  4. data/lib/grafana/abstract_datasource.rb +9 -3
  5. data/lib/grafana/dashboard.rb +6 -1
  6. data/lib/grafana/errors.rb +4 -11
  7. data/lib/grafana/grafana.rb +25 -1
  8. data/lib/grafana/grafana_environment_datasource.rb +56 -0
  9. data/lib/grafana/grafana_property_datasource.rb +8 -1
  10. data/lib/grafana/image_rendering_datasource.rb +5 -1
  11. data/lib/grafana/influxdb_datasource.rb +87 -3
  12. data/lib/grafana/panel.rb +1 -1
  13. data/lib/grafana/prometheus_datasource.rb +11 -2
  14. data/lib/grafana/sql_datasource.rb +3 -9
  15. data/lib/grafana/variable.rb +67 -36
  16. data/lib/grafana/webrequest.rb +1 -0
  17. data/lib/grafana_reporter/abstract_query.rb +65 -39
  18. data/lib/grafana_reporter/abstract_report.rb +19 -4
  19. data/lib/grafana_reporter/abstract_table_format_strategy.rb +74 -0
  20. data/lib/grafana_reporter/alerts_table_query.rb +6 -1
  21. data/lib/grafana_reporter/annotations_table_query.rb +6 -1
  22. data/lib/grafana_reporter/application/application.rb +7 -2
  23. data/lib/grafana_reporter/application/webservice.rb +41 -32
  24. data/lib/grafana_reporter/asciidoctor/adoc_plain_table_format_strategy.rb +27 -0
  25. data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +3 -2
  26. data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +3 -2
  27. data/lib/grafana_reporter/asciidoctor/help.rb +470 -0
  28. data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +7 -5
  29. data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +7 -5
  30. data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +5 -1
  31. data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +6 -2
  32. data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +3 -0
  33. data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +3 -2
  34. data/lib/grafana_reporter/asciidoctor/report.rb +15 -13
  35. data/lib/grafana_reporter/asciidoctor/show_environment_include_processor.rb +37 -6
  36. data/lib/grafana_reporter/asciidoctor/show_help_include_processor.rb +1 -1
  37. data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +6 -2
  38. data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +5 -1
  39. data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +0 -5
  40. data/lib/grafana_reporter/configuration.rb +27 -0
  41. data/lib/grafana_reporter/console_configuration_wizard.rb +5 -3
  42. data/lib/grafana_reporter/csv_table_format_strategy.rb +25 -0
  43. data/lib/grafana_reporter/demo_report_wizard.rb +3 -7
  44. data/lib/grafana_reporter/erb/demo_report_builder.rb +46 -0
  45. data/lib/grafana_reporter/erb/report.rb +13 -7
  46. data/lib/grafana_reporter/errors.rb +9 -7
  47. data/lib/grafana_reporter/panel_image_query.rb +1 -1
  48. data/lib/grafana_reporter/query_value_query.rb +7 -1
  49. data/lib/grafana_reporter/report_webhook.rb +12 -8
  50. data/lib/grafana_reporter/reporter_environment_datasource.rb +24 -0
  51. metadata +9 -3
  52. data/lib/grafana_reporter/help.rb +0 -443
@@ -26,7 +26,13 @@ module GrafanaReporter
26
26
  @progress_reporter = Thread.new {}
27
27
 
28
28
  @status = :running
29
- accept_requests_loop
29
+ begin
30
+ accept_requests_loop
31
+ rescue SystemExit, Interrupt
32
+ @logger.info("Server shutting down.")
33
+ stop!
34
+ retry
35
+ end
30
36
  @status = :stopped
31
37
  end
32
38
 
@@ -57,8 +63,6 @@ module GrafanaReporter
57
63
  # step 1) accept incoming connection
58
64
  socket = @server.accept
59
65
 
60
- # TODO: shutdown properly on SIGINT/SIGHUB
61
-
62
66
  # stop webservice properly, if shall be shutdown
63
67
  if @status == :stopping
64
68
  socket.close
@@ -224,35 +228,40 @@ module GrafanaReporter
224
228
  def get_reports_status_as_html(reports)
225
229
  i = reports.length
226
230
 
227
- content = '<html>'\
228
- '<head></head>'\
229
- '<body>'\
230
- '<table>'\
231
- '<thead>'\
232
- '<th>#</th>'\
233
- '<th>Start Time</th>'\
234
- '<th>End Time</th>'\
235
- '<th>Template</th>'\
236
- '<th>Execution time</th>'\
237
- '<th>Status</th>'\
238
- '<th>Error</th>'\
239
- '<th>Action</th>'\
240
- '</thead>' +
241
- reports.reverse.map do |report|
242
- '<tr>'\
243
- "<td>#{i -= 1}</td>"\
244
- "<td>#{report.start_time}</td>"\
245
- "<td>#{report.end_time}</td>"\
246
- "<td>#{report.template}</td>"\
247
- "<td>#{report.execution_time.to_i} secs</td>"\
248
- "<td>#{report.status} (#{(report.progress * 100).to_i}%)</td>"\
249
- "<td>#{report.error.join('<br>')}</td>"\
250
- "<td>#{!report.done && !report.cancel ? "<a href=\"/cancel_report?report_id=#{report.object_id}\">Cancel</a>&nbsp;" : ''}"\
251
- "#{(report.status == 'finished') || (report.status == 'cancelled') ? "<a href=\"/view_report?report_id=#{report.object_id}\">View</a>&nbsp;" : '&nbsp;'}"\
252
- "<a href=\"/view_log?report_id=#{report.object_id}\">Log</a></td>"\
253
- '</tr>'
254
- end.join('') +
255
- '</table></body></html>'
231
+ # TODO: make reporter HTML results customizable
232
+ template = <<~HTML_TEMPLATE
233
+ <html>
234
+ <head></head>
235
+ <body>
236
+ <table>
237
+ <thead>
238
+ <th>#</th><th>Start Time</th><th>End Time</th><th>Template</th><th>Execution time</th>
239
+ <th>Status</th><th>Error</th><th>Action</th>
240
+ </thead>
241
+ <tbody>
242
+ <% reports.reverse.map do |report| %>
243
+ <tr><td><%= i-= 1 %></td><td><%= report.start_time %></td><td><%= report.end_time %></td>
244
+ <td><%= report.template %></td><td><%= report.execution_time.to_i %> secs</td>
245
+ <td><%= report.status %> (<%= (report.progress * 100).to_i %>%)</td>
246
+ <td><%= report.error.join('<br>') %></td>
247
+ <td><% if !report.done && !report.cancel %>
248
+ <a href="/cancel_report?report_id=<%= report.object_id %>">Cancel</a>
249
+ <% end %>
250
+ &nbsp;
251
+ <% if (report.status == 'finished') || (report.status == 'cancelled') %>
252
+ <a href="/view_report?report_id=<%= report.object_id %>">View</a>
253
+ <% end %>
254
+ &nbsp;
255
+ <a href="/view_log?report_id=<%= report.object_id %>">Log</a></td></tr>
256
+ <% end.join('') %>
257
+ <tbody>
258
+ </table>
259
+ <p style="font-size: small; color:grey">You are running ruby-grafana-reporter version <%= GRAFANA_REPORTER_VERSION.join('.') %>.<%= @config.latest_version_check_ok? ? '' : ' Check out the latest version <a href="https://github.com/divinity666/ruby-grafana-reporter/releases/latest">here</a>.' %></p>
260
+ </body>
261
+ </html>
262
+ HTML_TEMPLATE
263
+
264
+ content = ::ERB.new(template).result(binding)
256
265
 
257
266
  http_response(200, 'OK', content, "Content-Type": 'text/html')
258
267
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrafanaReporter
4
+ module Asciidoctor
5
+ # Implements a default table format strategy, which will return tables
6
+ # as asciidoctor formatted table.
7
+ class AdocPlainTableFormatStrategy < AbstractTableFormatStrategy
8
+ # @see AbstractTableFormatStrategy#abbreviation
9
+ def self.abbreviation
10
+ 'adoc_plain'
11
+ end
12
+
13
+ # @see AbstractTableFormatStrategy#format_rules
14
+ def format_rules
15
+ {
16
+ row_start: '| ',
17
+ row_end: "\n",
18
+ cell_start: '',
19
+ between_cells: ' | ',
20
+ cell_end: '',
21
+ replace_string_or_regex: '|',
22
+ replacement: '\\|'
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -59,7 +59,8 @@ module GrafanaReporter
59
59
  grafana_obj = @report.grafana(instance).dashboard(dashboard_id) if dashboard_id
60
60
  grafana_obj = grafana_obj.panel(panel_id) if panel_id
61
61
 
62
- query = AlertsTableQuery.new(grafana_obj, variables: build_attribute_hash(doc.attributes, attrs))
62
+ vars = { 'table_formatter' => 'adoc_plain' }.merge(build_attribute_hash(doc.attributes, attrs))
63
+ query = AlertsTableQuery.new(grafana_obj, variables: vars)
63
64
  defaults = {}
64
65
  defaults['dashboardId'] = dashboard_id if dashboard_id
65
66
  defaults['panelId'] = panel_id if panel_id
@@ -70,7 +71,7 @@ module GrafanaReporter
70
71
  query.raw_query = defaults.merge(selected_attrs.each_with_object({}) { |(k, v), h| h[k] = v })
71
72
 
72
73
  begin
73
- reader.unshift_lines query.execute
74
+ reader.unshift_lines query.execute.split("\n")
74
75
  rescue GrafanaReporterError => e
75
76
  @report.logger.error(e.message)
76
77
  reader.unshift_line "|#{e.message}"
@@ -58,7 +58,8 @@ module GrafanaReporter
58
58
  grafana_obj = @report.grafana(instance).dashboard(dashboard_id) if dashboard_id
59
59
  grafana_obj = grafana_obj.panel(panel_id) if panel_id
60
60
 
61
- query = AnnotationsTableQuery.new(grafana_obj, variables: build_attribute_hash(doc.attributes, attrs))
61
+ vars = { 'table_formatter' => 'adoc_plain' }.merge(build_attribute_hash(doc.attributes, attrs))
62
+ query = AnnotationsTableQuery.new(grafana_obj, variables: vars)
62
63
  defaults = {}
63
64
  defaults['dashboardId'] = dashboard_id if dashboard_id
64
65
  defaults['panelId'] = panel_id if panel_id
@@ -69,7 +70,7 @@ module GrafanaReporter
69
70
  query.raw_query = defaults.merge(selected_attrs.each_with_object({}) { |(k, v), h| h[k] = v })
70
71
 
71
72
  begin
72
- reader.unshift_lines query.execute
73
+ reader.unshift_lines query.execute.split("\n")
73
74
  rescue GrafanaReporterError => e
74
75
  @report.logger.error(e.message)
75
76
  reader.unshift_line "|#{e.message}"
@@ -0,0 +1,470 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module GrafanaReporter
6
+ module Asciidoctor
7
+ # This class generates the functional help documentation for the asciidoctor report.
8
+ # It can create the documentation for github markdown, as well as in asciidoctor syntax.
9
+ class Help
10
+ # @param headline_level [Integer] top level of headline
11
+ # @return [String] asciidoctor compatible documentation
12
+ def asciidoctor(headline_level = 2)
13
+ help_text(asciidoctor_options.merge(level: headline_level))
14
+ end
15
+
16
+ # @param headline_level [Integer] top level of headline
17
+ # @return [String] github markdown compatible documentation
18
+ def github(headline_level = 2)
19
+ "#{toc}\n\n#{help_text(github_options.merge(level: headline_level))}"
20
+ end
21
+
22
+ private
23
+
24
+ def github_options
25
+ { headline_separator: '#', code_begin: '`', code_end: '`', table_begin: "\n", head_postfix_col: '| -- ' }
26
+ end
27
+
28
+ def asciidoctor_options
29
+ { headline_separator: '=', code_begin: '`+', code_end: '+`', table_begin: "\n[%autowidth.stretch, "\
30
+ "options=\"header\"]\n|===\n", table_end: "\n|===" }
31
+ end
32
+
33
+ def help_text(opts)
34
+ %(#{opts[:headline_separator] * opts[:level]} Global options
35
+ #{global_options_as_text(opts.merge(level: opts[:level] + 1))}
36
+ #{opts[:headline_separator] * opts[:level]} Functions
37
+ #{functions_as_text(opts.merge(level: opts[:level] + 1))})
38
+ end
39
+
40
+ def toc
41
+ result = []
42
+
43
+ result << 'Table of contents'
44
+ result << '* [Global options](#global-options)'
45
+ prepared_help[:global_options].sort.map do |k, _v|
46
+ result << " * [#{k}](##{k.downcase})"
47
+ end
48
+
49
+ result << '* [Functions](#functions)'
50
+ prepared_help[:functions].sort.map do |k, _v|
51
+ result << " * [#{k}](##{k.downcase})"
52
+ end
53
+
54
+ result.join("\n")
55
+ end
56
+
57
+ def global_options_as_text(opts = {})
58
+ opts = { level: 3 }.merge(opts)
59
+ result = []
60
+
61
+ prepared_help[:global_options].sort.map do |k, v|
62
+ result << %(
63
+ #{opts[:headline_separator] * opts[:level]} #{opts[:code_begin]}#{k}#{opts[:code_end]}
64
+ Usage: #{opts[:code_begin]}#{v['call']}#{opts[:code_end]}
65
+
66
+ #{v['description']}
67
+ )
68
+ end
69
+
70
+ result.join
71
+ end
72
+
73
+ def functions_as_text(opts = {})
74
+ opts = { level: 3, headline_separator: '=' }.merge(opts)
75
+ result = []
76
+
77
+ prepared_help[:functions].sort.map do |k, v|
78
+ result << %(
79
+ #{opts[:headline_separator] * opts[:level]} #{opts[:code_begin]}#{k}#{opts[:code_end]}
80
+ Usage: #{opts[:code_begin]}#{v[:call]}#{opts[:code_end]}
81
+
82
+ #{v[:description]}#{"\n\nSee also: #{v[:see]}" if v[:see]}#{unless v[:options].empty?
83
+ %(
84
+ #{opts[:table_begin]}| Option | Description#{"\n#{opts[:head_postfix_col] * 2}" if opts[:head_postfix_col]}
85
+ #{v[:options].sort.map { |_opt_k, opt_v| "| #{opts[:code_begin]}#{opt_v[:call]}#{opts[:code_end]} | #{opt_v[:description].gsub('|', '\|')}#{"\nSee also: #{opt_v[:see]}" if opt_v[:see]}" }.join("\n") }#{opts[:table_end]})
86
+ end}
87
+ )
88
+ end
89
+
90
+ result.join
91
+ end
92
+
93
+ def prepared_help
94
+ yaml = YAML.safe_load(raw_help_yaml)
95
+
96
+ result = {}
97
+ result[:functions] = {}
98
+ result[:global_options] = yaml['global_options']
99
+
100
+ functions = result[:functions]
101
+ std_opts = yaml['standard_options']
102
+ yaml.reject { |k, _v| k =~ /.*_options$/ }.each_key do |key|
103
+ functions[key] = {}
104
+ res_item = functions[key]
105
+ res_item[:options] = {}
106
+
107
+ item = yaml[key]
108
+ res_item[:call] = item['call']
109
+ res_item[:description] = item['description']
110
+ res_item[:see] = item['see']
111
+
112
+ opts = ((item['options'] ? item['options'].keys : []) +
113
+ (item['standard_options'] ? item['standard_options'].keys : [])).sort
114
+ opts.each do |opt_key|
115
+ res_item[:options][opt_key] = {}
116
+
117
+ if std_opts.key?(opt_key)
118
+ res_item[:options][opt_key][:call] = std_opts[opt_key]['call']
119
+ res_item[:options][opt_key][:description] = "#{std_opts[opt_key]['description']} "\
120
+ "#{item['standard_options'][opt_key]}".chop
121
+ res_item[:options][opt_key][:see] = std_opts[opt_key]['see'] if std_opts[opt_key]['see']
122
+ else
123
+ res_item[:options][opt_key][:call] = item['options'][opt_key]['call']
124
+ res_item[:options][opt_key][:description] = item['options'][opt_key]['description']
125
+ res_item[:options][opt_key][:see] = item['options'][opt_key]['see'] if item['options'][opt_key]['see']
126
+ end
127
+ end
128
+ end
129
+
130
+ result
131
+ end
132
+
133
+ def raw_help_yaml
134
+ <<~YAML_HELP
135
+ global_options:
136
+ grafana_default_instance:
137
+ call: ":grafana_default_instance: <instance_name>"
138
+ description: >-
139
+ Specifies which grafana instance shall be used. If not set, the grafana instance names `default`
140
+ will be used.
141
+
142
+ grafana_default_dashboard:
143
+ call: ":grafana_default_dashboard: <dashboard_uid>"
144
+ description: >-
145
+ Specifies to which dashboard the queries shall be targeted by default.
146
+
147
+ grafana_default_from_timezone:
148
+ call: ":grafana_default_from_timezone: <timezone>"
149
+ description: Specifies which timezone shall be used for the `from` time, e.g. `CET` or `CEST`.
150
+
151
+ grafana_default_to_timezone:
152
+ call: ":grafana_default_to_timezone: <timezone>"
153
+ description: Specifies which timezone shall be used for the `to` time, e.g. `CET` or `CEST`.
154
+
155
+ from:
156
+ call: ":from: <from_timestamp>"
157
+ description: >-
158
+ Overrides the time setting from grafana. It may contain dates as `now-1M/M`, which will be translated
159
+ properly to timestamps relative to the called time.
160
+
161
+ to:
162
+ call: ":to: <to_timestamp>"
163
+ description: >-
164
+ Overrides the time setting from grafana. It may contain dates as `now-1M/M`, which will be translated
165
+ properly to timestamps relative to the called time.
166
+
167
+ standard_options:
168
+ instance:
169
+ call: instance="<instance_name>"
170
+ description: >-
171
+ can be used to override global grafana instance, set in the report with `grafana_default_instance`.
172
+ If nothing is set, the configured grafana instance with name `default` will be used.
173
+
174
+ dashboard:
175
+ call: dashboard="<dashboard_uid>"
176
+ description: >-
177
+ Specifies the dashboard to be used. If `grafana_default_dashboard` is specified in the report template,
178
+ this value can be overridden with this option.
179
+
180
+ from:
181
+ call: from="<timestamp>"
182
+ description: can be used to override default `from` time
183
+
184
+ from_timezone:
185
+ call: from_timezone="<timezone>"
186
+ description: can be used to override system timezone for `from` time and will also override `grafana_default_from_timezone` option
187
+
188
+ to_timezone:
189
+ call: to_timezone="<timezone>"
190
+ description: can be used to override system timezone for `to` time and will also override `grafana_default_to_timezone` option
191
+
192
+ to:
193
+ call: to="<timestamp>"
194
+ description: can be used to override default `to` time
195
+
196
+ format:
197
+ call: format="<format_col1>,<format_col2>,..."
198
+ description: >-
199
+ Specify format in which the results in a specific column shall be returned, e.g. `%.2f` for only
200
+ two digit decimals of a float. Several column formats are separated by `,`, i.e. `%.2f,%.3f` would
201
+ apply `%.2f` to the first column and `%.3f` to the second column. All other columns would not be
202
+ formatted. You may also format time in milliseconds to a time format by specifying e.g. `date:iso`.
203
+ Commas in format strings are supported, but have to be escaped by useing `_,`.
204
+ Execution of related functions is applied in the following order `format`,
205
+ `replace_values`, `filter_columns`, `transpose`.
206
+ see: 'https://ruby-doc.org/core/Kernel.html#method-i-sprintf'
207
+
208
+ replace_values:
209
+ call: replace_values="<replace_1>:<with_1>,<replace_2>:<with_2>,..."
210
+ description: >-
211
+ Specify result values which shall be replaced, e.g. `2:OK` will replace query values `2` with value `OK`.
212
+ Replacing several values is possible by separating by `,`. Matches with regular expressions are also
213
+ supported, but must be full matches, i.e. have to start with `^` and end with `$`, e.g. `^[012]$:OK`.
214
+ Number replacements can also be performed, e.g. `<8.2` or `<>3`. Execution of related functions is
215
+ applied in the following order `format`,
216
+ `replace_values`, `filter_columns`, `transpose`.
217
+ see: https://ruby-doc.org/core/Regexp.html#class-Regexp-label-Character+Classes
218
+
219
+ filter_columns:
220
+ call: filter_columns="<column_name_1>,<column_name_2>,..."
221
+ description: >-
222
+ Removes specified columns from result. Commas in format strings are supported, but have to be
223
+ escaped by useing `_,`. Execution of related functions is applied in the following order
224
+ `format`, `replace_values`, `filter_columns`, `transpose`.
225
+
226
+ transpose:
227
+ call: transpose="true"
228
+ description: >-
229
+ Transposes the query result, i.e. columns become rows and rows become columnns. Execution of related
230
+ functions is applied in the following order `format`, `replace_values`, `filter_columns`,
231
+ `transpose`.
232
+
233
+ column_divider:
234
+ call: column_divider="<divider>"
235
+ description: >-
236
+ Replace the default column divider with another one, when used in conjunction with `table_formatter` set to
237
+ `adoc_deprecated`. Defaults to ` | ` for being interpreted as a asciidoctor column. DEPRECATED: switch to
238
+ `table_formatter` named `adoc_plain`, or implement a custom table formatter.
239
+
240
+ row_divider:
241
+ call: row_divider="<divider>"
242
+ description: >-
243
+ Replace the default row divider with another one, when used in conjunction with `table_formatter` set to
244
+ `adoc_deprecated`. Defaults to `| ` for being interpreted as a asciidoctor row. DEPRECATED: switch to
245
+ `table_formatter` named `adoc_plain`, or implement a custom table formatter.
246
+
247
+ table_formatter:
248
+ call: table_formatter="<formatter>"
249
+ description: >-
250
+ Specify a table formatter fitting for your expected target format. It defaults to `adoc_plain` for asciidoctor
251
+ templates and to `csv` for all other templates, e.g. ERB.
252
+
253
+ timeout:
254
+ call: timeout="<timeout_in_seconds>"
255
+ description: >-
256
+ Set a timeout for the current query. If not overridden with `grafana_default_timeout` in the report template,
257
+ this defaults to 60 seconds.
258
+
259
+ # ----------------------------------
260
+ # FUNCTION DOCUMENTATION STARTS HERE
261
+ # ----------------------------------
262
+
263
+ grafana_help:
264
+ description: Show all available grafana calls within the asciidoctor templates, including available options.
265
+ call: 'include::grafana_help[]'
266
+
267
+ grafana_environment:
268
+ description: >-
269
+ Shows all available variables in the rendering context which can be used in the asciidoctor template.
270
+ If optional `instance` is specified, additional information about the configured grafana instance will be provided.
271
+ This is especially helpful for debugging.
272
+ call: 'include::grafana_environment[]'
273
+ standard_options:
274
+ instance:
275
+
276
+ grafana_alerts:
277
+ description: >-
278
+ Returns a table of active alert states including the specified columns and the connected information. Supports
279
+ all query parameters from the Grafana Alerting API, such as `query`, `state`, `limit`, `folderId` and others.
280
+ call: 'include::grafana_alerts[columns="<column_name_1>,<column_name_2>,...",options]'
281
+ see: https://grafana.com/docs/grafana/latest/http_api/alerting/#get-alerts
282
+ options:
283
+ columns:
284
+ description: >-
285
+ Specifies columns that shall be returned. Valid columns are `id`, `dashboardId`, `dashboardUId`, `dashboardSlug`,
286
+ `panelId`, `name`, `state`, `newStateDate`, `evalDate`, `evalData` and `executionError`.
287
+ call: columns="<column_name_1>,<columns_name_2>,..."
288
+ panel:
289
+ description: >-
290
+ If specified, the resulting alerts are filtered for this panel. This option will only work, if a `dashboard`
291
+ or `grafana_default_dashboard` is set.
292
+ call: panel="<panel_id>"
293
+ standard_options:
294
+ column_divider:
295
+ dashboard: >-
296
+ If this option, or the global option `grafana_default_dashboard` is set, the resulting alerts will be limited to
297
+ this dashboard. To show all alerts in this case, specify `dashboard=""` as option.
298
+ filter_columns:
299
+ format:
300
+ from:
301
+ instance:
302
+ replace_values:
303
+ row_divider:
304
+ table_formatter:
305
+ timeout:
306
+ to:
307
+ transpose:
308
+ from_timezone:
309
+ to_timezone:
310
+
311
+ grafana_annotations:
312
+ description: >-
313
+ Returns a table of all annotations, matching the specified filter criteria and the specified columns. Supports all
314
+ query parameters from the Grafana Alerting API, such as `limit`, `alertId`, `panelId` and others.
315
+ call: 'include::grafana_annotations[columns="<column_name_1>,<column_name_2>,...",options]'
316
+ see: https://grafana.com/docs/grafana/latest/http_api/annotations/#find-annotations
317
+ options:
318
+ columns:
319
+ description: >-
320
+ Specified the columns that shall be returned. Valid columns are `id`, `alertId`, `dashboardId`, `panelId`, `userId`,
321
+ `userName`, `newState`, `prevState`, `time`, `timeEnd`, `text`, `metric` and `type`.
322
+ call: columns="<column_name_1>,<columns_name_2>,..."
323
+ panel:
324
+ description: >-
325
+ If specified, the resulting alerts are filtered for this panel. This option will only work, if a `dashboard` or
326
+ `grafana_default_dashboard` is set.
327
+ call: panel="<panel_id>"
328
+ standard_options:
329
+ column_divider:
330
+ dashboard: >-
331
+ If this option, or the global option `grafana_default_dashboard` is set, the resulting alerts will be limited to this
332
+ dashboard. To show all alerts in this case, specify `dashboard=""` as option.
333
+ filter_columns:
334
+ format:
335
+ from:
336
+ instance:
337
+ replace_values:
338
+ row_divider:
339
+ table_formatter:
340
+ timeout:
341
+ to:
342
+ transpose:
343
+ from_timezone:
344
+ to_timezone:
345
+
346
+ grafana_panel_property:
347
+ description: >-
348
+ Returns a property field for the specified panel. `<type>` can either be `title` or `description`.
349
+ Grafana variables will be replaced in the returned value.
350
+ call: 'grafana_panel_property:<panel_id>["<type>",options]'
351
+ see: https://grafana.com/docs/grafana/latest/variables/syntax/
352
+ standard_options:
353
+ dashboard:
354
+ instance:
355
+
356
+ grafana_panel_image:
357
+ description: Includes a panel image as an image in the document. Can be called for inline-images as well as for blocks.
358
+ call: 'grafana_panel_image:<panel_id>[options] or grafana_panel_image::<panel_id>[options]'
359
+ options:
360
+ render-height:
361
+ description: can be used to override default `height` in which the panel shall be rendered
362
+ call: render-height="<height>"
363
+ render-width:
364
+ description: can be used to override default `width` in which the panel shall be rendered
365
+ call: render-width="<width>"
366
+ render-theme:
367
+ description: can be used to override default `theme` in which the panel shall be rendered (light by default)
368
+ call: render-theme="<theme>"
369
+ render-timeout:
370
+ description: can be used to override default `timeout` in which the panel shall be rendered (60 seconds by default)
371
+ call: render-timeout="<timeout>"
372
+ standard_options:
373
+ dashboard:
374
+ from:
375
+ instance:
376
+ timeout:
377
+ to:
378
+ from_timezone:
379
+ to_timezone:
380
+
381
+ grafana_panel_query_table:
382
+ description: >-
383
+ Returns the results of a query, which is configured in a grafana panel, as a table in asciidoctor.
384
+ Grafana variables will be replaced in the panel's SQL statement.
385
+ call: 'include::grafana_panel_query_table:<panel_id>[query="<query_letter>",options]'
386
+ see: https://grafana.com/docs/grafana/latest/variables/syntax/
387
+ options:
388
+ query:
389
+ call: query="<query_letter>"
390
+ description: +<query_letter>+ needs to point to the grafana query which shall be evaluated, e.g. +A+ or +B+.
391
+ standard_options:
392
+ column_divider:
393
+ dashboard:
394
+ filter_columns:
395
+ format:
396
+ from:
397
+ instance:
398
+ replace_values:
399
+ row_divider:
400
+ table_formatter:
401
+ timeout:
402
+ to:
403
+ transpose:
404
+ from_timezone:
405
+ to_timezone:
406
+
407
+ grafana_panel_query_value:
408
+ call: 'grafana_panel_query_value:<panel_id>[query="<query_letter>",options]'
409
+ description: >-
410
+ Returns the value in the first column and the first row of a query, which is configured in a grafana panel.
411
+ Grafana variables will be replaced in the panel's SQL statement.
412
+ see: https://grafana.com/docs/grafana/latest/variables/syntax/
413
+ options:
414
+ query:
415
+ call: query="<query_letter>"
416
+ description: +<query_letter>+ needs to point to the grafana query which shall be evaluated, e.g. +A+ or +B+.
417
+ standard_options:
418
+ dashboard:
419
+ filter_columns:
420
+ format:
421
+ from:
422
+ instance:
423
+ replace_values:
424
+ timeout:
425
+ to:
426
+ from_timezone:
427
+ to_timezone:
428
+
429
+ grafana_sql_table:
430
+ call: 'include::grafana_sql_table:<datasource_id>[sql="<sql_query>",options]'
431
+ description: >-
432
+ Returns a table with all results of the given query.
433
+ Grafana variables will be replaced in the SQL statement.
434
+ see: https://grafana.com/docs/grafana/latest/variables/syntax/
435
+ standard_options:
436
+ column_divider:
437
+ filter_columns:
438
+ format:
439
+ from:
440
+ instance:
441
+ replace_values:
442
+ row_divider:
443
+ table_formatter:
444
+ timeout:
445
+ to:
446
+ transpose:
447
+ from_timezone:
448
+ to_timezone:
449
+
450
+ grafana_sql_value:
451
+ call: 'grafana_sql_value:<datasource_id>[sql="<sql_query>",options]'
452
+ description: >-
453
+ Returns the value in the first column and the first row of the given query.
454
+ Grafana variables will be replaced in the SQL statement.
455
+ see: https://grafana.com/docs/grafana/latest/variables/syntax/
456
+ standard_options:
457
+ filter_columns:
458
+ format:
459
+ from:
460
+ instance:
461
+ replace_values:
462
+ timeout:
463
+ to:
464
+ from_timezone:
465
+ to_timezone:
466
+ YAML_HELP
467
+ end
468
+ end
469
+ end
470
+ end
@@ -7,8 +7,8 @@ module GrafanaReporter
7
7
  # Implements the hook
8
8
  # grafana_panel_image::<panel_id>[<options>]
9
9
  #
10
- # Stores the queried panel as a temporary image file and returns an asciidoctor link
11
- # to be included in the report.
10
+ # Stores the queried panel as a temporary image file and returns a relative asciidoctor link
11
+ # to the storage location, which can then be included in the report.
12
12
  #
13
13
  # == Used document parameters
14
14
  # +grafana_default_instance+ - name of grafana instance, 'default' if not specified
@@ -20,8 +20,6 @@ module GrafanaReporter
20
20
  # +to+ - 'to' time for the sql query
21
21
  #
22
22
  # == Supported options
23
- # +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
24
- #
25
23
  # +instance+ - name of grafana instance, 'default' if not specified
26
24
  #
27
25
  # +dashboard+ - uid of grafana dashboard to use
@@ -46,10 +44,14 @@ module GrafanaReporter
46
44
  " panel: #{target})")
47
45
 
48
46
  begin
49
- query = PanelImageQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target), variables: build_attribute_hash(parent.document.attributes, attrs))
47
+ query = PanelImageQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target),
48
+ variables: build_attribute_hash(parent.document.attributes, attrs))
50
49
 
51
50
  image = query.execute
52
51
  image_path = @report.save_image_file(image)
52
+ rescue Grafana::GrafanaError => e
53
+ @report.logger.error(e.message)
54
+ return create_paragraph(parent, e.message, attrs)
53
55
  rescue GrafanaReporterError => e
54
56
  @report.logger.error(e.message)
55
57
  return create_paragraph(parent, e.message, attrs)