ruby-grafana-reporter 0.3.0 → 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 +81 -71
- data/bin/ruby-grafana-reporter +5 -5
- data/lib/VERSION.rb +3 -2
- data/lib/grafana/abstract_datasource.rb +116 -0
- data/lib/grafana/dashboard.rb +1 -3
- data/lib/grafana/errors.rb +15 -0
- data/lib/grafana/grafana.rb +53 -56
- 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 +9 -3
- data/lib/grafana/prometheus_datasource.rb +39 -0
- data/lib/grafana/sql_datasource.rb +65 -0
- data/lib/grafana/variable.rb +1 -0
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +401 -0
- data/lib/grafana_reporter/abstract_report.rb +54 -3
- 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 +12 -8
- data/lib/grafana_reporter/application/webservice.rb +18 -6
- 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 +24 -31
- 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 +12 -6
- data/lib/grafana_reporter/console_configuration_wizard.rb +115 -65
- data/lib/grafana_reporter/demo_report_wizard.rb +87 -0
- data/lib/grafana_reporter/errors.rb +33 -0
- data/lib/grafana_reporter/help.rb +447 -0
- data/lib/grafana_reporter/logger/two_way_logger.rb +1 -1
- 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} +0 -3
- metadata +37 -35
- data/lib/grafana/abstract_panel_query.rb +0 -22
- data/lib/grafana/abstract_query.rb +0 -132
- data/lib/grafana/abstract_sql_query.rb +0 -51
- data/lib/grafana/panel_image_query.rb +0 -52
- data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +0 -101
- data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -96
- data/lib/grafana_reporter/asciidoctor/errors.rb +0 -40
- data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +0 -92
- data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +0 -91
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +0 -69
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +0 -68
- data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +0 -61
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +0 -78
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +0 -73
- data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +0 -20
- data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +0 -43
- data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +0 -30
- data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +0 -70
- data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +0 -66
- data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +0 -88
- data/lib/grafana_reporter/asciidoctor/help.rb +0 -435
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -36
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -28
- data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -44
- data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -40
- data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -312
- data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -42
- data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +0 -44
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
# This class is used to query alerts from grafana.
|
5
|
+
class AlertsTableQuery < AbstractQuery
|
6
|
+
# Check if mandatory {Grafana::Variable} +columns+ is specified in variables.
|
7
|
+
#
|
8
|
+
# The value of the +columns+ variable has to be a comma separated list of column titles, which
|
9
|
+
# need to be included in the following list:
|
10
|
+
# - limit
|
11
|
+
# - dashboardId
|
12
|
+
# - panelId
|
13
|
+
# - query
|
14
|
+
# - state
|
15
|
+
# - folderId
|
16
|
+
# - dashboardQuery
|
17
|
+
# - dashboardTag
|
18
|
+
# @return [void]
|
19
|
+
def pre_process
|
20
|
+
raise MissingMandatoryAttributeError, 'columns' unless @raw_query['columns']
|
21
|
+
|
22
|
+
@from = translate_date(@from, @variables['grafana-report-timestamp'], false, @variables['from_timezone'] ||
|
23
|
+
@variables['grafana_default_from_timezone'])
|
24
|
+
@to = translate_date(@to, @variables['grafana-report-timestamp'], true, @variables['to_timezone'] ||
|
25
|
+
@variables['grafana_default_to_timezone'])
|
26
|
+
@datasource = Grafana::GrafanaAlertsDatasource.new(nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Filter the query result for the given columns and sets the result in the preformatted SQL
|
30
|
+
# result stlye.
|
31
|
+
|
32
|
+
# Additionally it applies {QueryMixin#format_columns}, {QueryMixin#replace_values} and
|
33
|
+
# {QueryMixin#filter_columns}.
|
34
|
+
# @return [void]
|
35
|
+
def post_process
|
36
|
+
@result = format_columns(@result, @variables['format'])
|
37
|
+
@result = replace_values(@result, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
|
38
|
+
@result = filter_columns(@result, @variables['filter_columns'])
|
39
|
+
|
40
|
+
# TODO: move formatting to Asciidoctor namespace
|
41
|
+
@result = @result[:content].map { |row| "| #{row.map { |item| item.to_s.gsub('|', '\\|') }.join(' | ')}" }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
# This class is used to query annotations from grafana.
|
5
|
+
class AnnotationsTableQuery < AbstractQuery
|
6
|
+
# Check if mandatory {Grafana::Variable} +columns+ is specified in variables.
|
7
|
+
#
|
8
|
+
# The value of the +columns+ variable has to be a comma separated list of column titles, which
|
9
|
+
# need to be included in the following list:
|
10
|
+
# - limit
|
11
|
+
# - alertId
|
12
|
+
# - userId
|
13
|
+
# - type
|
14
|
+
# - tags
|
15
|
+
# - dashboardId
|
16
|
+
# - panelId
|
17
|
+
# @return [void]
|
18
|
+
def pre_process
|
19
|
+
raise MissingMandatoryAttributeError, 'columns' unless @raw_query['columns']
|
20
|
+
|
21
|
+
@from = translate_date(@from, @variables['grafana-report-timestamp'], false, @variables['from_timezone'] ||
|
22
|
+
@variables['grafana_default_from_timezone'])
|
23
|
+
@to = translate_date(@to, @variables['grafana-report-timestamp'], true, @variables['to_timezone'] ||
|
24
|
+
@variables['grafana_default_to_timezone'])
|
25
|
+
@datasource = Grafana::GrafanaAnnotationsDatasource.new(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Filters the query result for the given columns and sets the result
|
29
|
+
# in the preformatted SQL result style.
|
30
|
+
#
|
31
|
+
# Additionally it applies {QueryMixin#format_columns}, {QueryMixin#replace_values} and
|
32
|
+
# {QueryMixin#filter_columns}.
|
33
|
+
# @return [void]
|
34
|
+
def post_process
|
35
|
+
@result = format_columns(@result, @variables['format'])
|
36
|
+
@result = replace_values(@result, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
|
37
|
+
@result = filter_columns(@result, @variables['filter_columns'])
|
38
|
+
|
39
|
+
# TODO: move formatting to Asciidoctor namespace
|
40
|
+
@result = result[:content].map { |row| "| #{row.map { |item| item.to_s.gsub('|', '\\|') }.join(' | ')}" }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -19,8 +19,12 @@ module GrafanaReporter
|
|
19
19
|
# Contains the {Configuration} object of the application.
|
20
20
|
attr_accessor :config
|
21
21
|
|
22
|
+
# Stores the {Webservice} object of the application
|
23
|
+
attr_reader :webservice
|
24
|
+
|
22
25
|
def initialize
|
23
26
|
@config = Configuration.new
|
27
|
+
@webservice = Webservice.new
|
24
28
|
end
|
25
29
|
|
26
30
|
# This is the main method, which is called, if the application is
|
@@ -33,11 +37,11 @@ module GrafanaReporter
|
|
33
37
|
action_wizard = false
|
34
38
|
|
35
39
|
parser = OptionParser.new do |opts|
|
36
|
-
if ENV['OCRA_EXECUTABLE']
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
opts.banner = if ENV['OCRA_EXECUTABLE']
|
41
|
+
"Usage: #{ENV['OCRA_EXECUTABLE'].gsub("#{Dir.pwd}/".gsub('/', '\\'), '')} [options]"
|
42
|
+
else
|
43
|
+
"Usage: #{Gem.ruby} #{$PROGRAM_NAME} [options]"
|
44
|
+
end
|
41
45
|
|
42
46
|
opts.on('-c', '--config CONFIG_FILE_NAME', 'Specify custom configuration file,'\
|
43
47
|
" instead of #{CONFIG_FILE}.") do |file_name|
|
@@ -137,18 +141,18 @@ module GrafanaReporter
|
|
137
141
|
when Configuration::MODE_CONNECTION_TEST
|
138
142
|
res = Grafana::Grafana.new(config.grafana_host(config.test_instance),
|
139
143
|
config.grafana_api_key(config.test_instance),
|
140
|
-
logger: config.logger
|
144
|
+
logger: config.logger).test_connection
|
141
145
|
puts res
|
142
146
|
|
143
147
|
when Configuration::MODE_SINGLE_RENDER
|
144
148
|
begin
|
145
149
|
config.report_class.new(config, config.template, config.to_file).create_report
|
146
150
|
rescue StandardError => e
|
147
|
-
puts e.message
|
151
|
+
puts "#{e.message}\n#{e.backtrace.join("\n")}"
|
148
152
|
end
|
149
153
|
|
150
154
|
when Configuration::MODE_SERVICE
|
151
|
-
|
155
|
+
@webservice.run(config)
|
152
156
|
end
|
153
157
|
|
154
158
|
0
|
@@ -6,21 +6,30 @@ module GrafanaReporter
|
|
6
6
|
# make use of `webrick` or similar, so that it can be used without futher dependencies
|
7
7
|
# in conjunction with the standard asciidoctor docker container.
|
8
8
|
class Webservice
|
9
|
-
def initialize
|
9
|
+
def initialize
|
10
10
|
@reports = []
|
11
|
+
@running = false
|
12
|
+
end
|
13
|
+
|
14
|
+
# Runs the webservice with the given {Configuration} object.
|
15
|
+
def run(config)
|
11
16
|
@config = config
|
12
17
|
@logger = config.logger
|
13
|
-
end
|
14
18
|
|
15
|
-
# Runs the webservice with the current set {Configuration} object.
|
16
|
-
def run
|
17
19
|
# start webserver
|
18
20
|
@server = TCPServer.new(@config.webserver_port)
|
19
21
|
@logger.info("Server listening on port #{@config.webserver_port}...")
|
22
|
+
@running = true
|
20
23
|
|
21
24
|
@progress_reporter = Thread.new {}
|
22
25
|
|
23
26
|
accept_requests_loop
|
27
|
+
@running = false
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return True, if webservice is up and running, false otherwise
|
31
|
+
def running?
|
32
|
+
@running
|
24
33
|
end
|
25
34
|
|
26
35
|
private
|
@@ -164,7 +173,8 @@ module GrafanaReporter
|
|
164
173
|
return http_response(200, 'OK', content, "Content-Type": 'application/pdf') if content.start_with?('%PDF')
|
165
174
|
|
166
175
|
http_response(200, 'OK', content, "Content-Type": 'application/octet-stream',
|
167
|
-
"Content-Disposition":
|
176
|
+
"Content-Disposition": 'attachment; '\
|
177
|
+
"filename=report_#{attrs['report_id']}.zip")
|
168
178
|
end
|
169
179
|
|
170
180
|
def render_report(attrs)
|
@@ -210,7 +220,9 @@ module GrafanaReporter
|
|
210
220
|
"<td>#{report.start_time}</td>"\
|
211
221
|
"<td>#{report.end_time}</td>"\
|
212
222
|
"<td>#{report.template}</td>"\
|
213
|
-
"<td>#{report.execution_time.to_i} secs</td
|
223
|
+
"<td>#{report.execution_time.to_i} secs</td>"\
|
224
|
+
"<td>#{report.status} (#{(report.progress * 100).to_i}%)</td>"\
|
225
|
+
"<td>#{report.error.join('<br>')}</td>"\
|
214
226
|
"<td>#{!report.done && !report.cancel ? "<a href=\"/cancel_report?report_id=#{report.object_id}\">Cancel</a> " : ''}"\
|
215
227
|
"#{(report.status == 'finished') || (report.status == 'cancelled') ? "<a href=\"/view_report?report_id=#{report.object_id}\">View</a> " : ' '}"\
|
216
228
|
"<a href=\"/view_log?report_id=#{report.object_id}\">Log</a></td>"\
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'processor_mixin'
|
4
|
+
|
5
|
+
module GrafanaReporter
|
6
|
+
module Asciidoctor
|
7
|
+
# Implements the hook
|
8
|
+
# include::grafana_alerts[<options>]
|
9
|
+
#
|
10
|
+
# Returns the results of alerts query as a asciidoctor table.
|
11
|
+
#
|
12
|
+
# == Used document parameters
|
13
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
14
|
+
#
|
15
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
16
|
+
#
|
17
|
+
# +from+ - 'from' time for the sql query
|
18
|
+
#
|
19
|
+
# +to+ - 'to' time for the sql query
|
20
|
+
#
|
21
|
+
# == Supported options
|
22
|
+
# +columns+ - see {AlertsTableQuery#pre_process} (*mandatory*)
|
23
|
+
#
|
24
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
25
|
+
#
|
26
|
+
# +dashboard+ - uid of grafana dashboard to query for, empty string if no filter is wanted
|
27
|
+
#
|
28
|
+
# +panel+ - id of the panel to query for
|
29
|
+
#
|
30
|
+
# +from+ - 'from' time for the sql query
|
31
|
+
#
|
32
|
+
# +to+ - 'to' time for the sql query
|
33
|
+
#
|
34
|
+
# +format+ - see {QueryMixin#format_columns}
|
35
|
+
#
|
36
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
37
|
+
#
|
38
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
39
|
+
class AlertsTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
40
|
+
include ProcessorMixin
|
41
|
+
|
42
|
+
# :nodoc:
|
43
|
+
def handles?(target)
|
44
|
+
target.start_with? 'grafana_alerts'
|
45
|
+
end
|
46
|
+
|
47
|
+
# :nodoc:
|
48
|
+
def process(doc, reader, _target, attrs)
|
49
|
+
return if @report.cancel
|
50
|
+
|
51
|
+
@report.next_step
|
52
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
53
|
+
dashboard_id = attrs['dashboard'] || doc.attr('grafana_default_dashboard')
|
54
|
+
panel_id = attrs['panel']
|
55
|
+
@report.logger.debug("Processing AlertsTableIncludeProcessor (instance: #{instance},"\
|
56
|
+
" dashboard: #{dashboard_id}, panel: #{panel_id})")
|
57
|
+
|
58
|
+
query = AlertsTableQuery.new(@report.grafana(instance))
|
59
|
+
query.set_defaults_from_dashboard(@report.grafana(instance).dashboard(dashboard_id)) if dashboard_id
|
60
|
+
defaults = {}
|
61
|
+
defaults['dashboardId'] = dashboard_id if dashboard_id
|
62
|
+
defaults['panelId'] = panel_id if panel_id
|
63
|
+
|
64
|
+
query.merge_hash_variables(doc.attributes, attrs)
|
65
|
+
selected_attrs = attrs.select do |k, _v|
|
66
|
+
k =~ /(?:columns|limit|folderId|dashboardId|panelId|dahboardTag|dashboardQuery|state|query)/x
|
67
|
+
end
|
68
|
+
query.raw_query = defaults.merge(selected_attrs.each_with_object({}) { |(k, v), h| h[k] = v })
|
69
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
70
|
+
|
71
|
+
begin
|
72
|
+
reader.unshift_lines query.execute
|
73
|
+
rescue GrafanaReporterError => e
|
74
|
+
@report.logger.error(e.message)
|
75
|
+
reader.unshift_line "|#{e.message}"
|
76
|
+
rescue StandardError => e
|
77
|
+
@report.logger.fatal(e.message)
|
78
|
+
reader.unshift_line "|#{e.message}"
|
79
|
+
end
|
80
|
+
|
81
|
+
reader
|
82
|
+
end
|
83
|
+
|
84
|
+
# @see ProcessorMixin#build_demo_entry
|
85
|
+
def build_demo_entry(_panel)
|
86
|
+
"|===\ninclude::grafana_alerts[columns=\"panelId,name,state\"]\n|==="
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'processor_mixin'
|
4
|
+
|
5
|
+
module GrafanaReporter
|
6
|
+
module Asciidoctor
|
7
|
+
# Implements the hook
|
8
|
+
# include::grafana_annotations[<options>]
|
9
|
+
#
|
10
|
+
# Returns the results of alerts query as a asciidoctor table.
|
11
|
+
#
|
12
|
+
# == Used document parameters
|
13
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
14
|
+
#
|
15
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
16
|
+
#
|
17
|
+
# +from+ - 'from' time for the sql query
|
18
|
+
#
|
19
|
+
# +to+ - 'to' time for the sql query
|
20
|
+
#
|
21
|
+
# == Supported options
|
22
|
+
# +columns+ - see {AnnotationsTableQuery#pre_process} (*mandatory*)
|
23
|
+
#
|
24
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
25
|
+
#
|
26
|
+
# +dashboard+ - uid of grafana dashboard to query for, empty string if no filter is wanted
|
27
|
+
#
|
28
|
+
# +panel+ - id of the panel to query for
|
29
|
+
#
|
30
|
+
# +from+ - 'from' time for the sql query
|
31
|
+
#
|
32
|
+
# +to+ - 'to' time for the sql query
|
33
|
+
#
|
34
|
+
# +format+ - see {QueryMixin#format_columns}
|
35
|
+
#
|
36
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
37
|
+
#
|
38
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
39
|
+
class AnnotationsTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
40
|
+
include ProcessorMixin
|
41
|
+
|
42
|
+
# :nodoc:
|
43
|
+
def handles?(target)
|
44
|
+
target.start_with? 'grafana_annotations'
|
45
|
+
end
|
46
|
+
|
47
|
+
# :nodoc:
|
48
|
+
def process(doc, reader, _target, attrs)
|
49
|
+
return if @report.cancel
|
50
|
+
|
51
|
+
@report.next_step
|
52
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
53
|
+
dashboard_id = attrs['dashboard'] || doc.attr('grafana_default_dashboard')
|
54
|
+
panel_id = attrs['panel']
|
55
|
+
@report.logger.debug("Processing AnnotationsTableIncludeProcessor (instance: #{instance})")
|
56
|
+
|
57
|
+
query = AnnotationsTableQuery.new(@report.grafana(instance))
|
58
|
+
query.set_defaults_from_dashboard(@report.grafana(instance).dashboard(dashboard_id)) if dashboard_id
|
59
|
+
defaults = {}
|
60
|
+
defaults['dashboardId'] = dashboard_id if dashboard_id
|
61
|
+
defaults['panelId'] = panel_id if panel_id
|
62
|
+
|
63
|
+
query.merge_hash_variables(doc.attributes, attrs)
|
64
|
+
selected_attrs = attrs.select do |k, _v|
|
65
|
+
k =~ /(?:columns|limit|alertId|dashboardId|panelId|userId|type|tags)/
|
66
|
+
end
|
67
|
+
query.raw_query = defaults.merge(selected_attrs.each_with_object({}) { |(k, v), h| h[k] = v })
|
68
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
69
|
+
|
70
|
+
begin
|
71
|
+
reader.unshift_lines query.execute
|
72
|
+
rescue GrafanaReporterError => e
|
73
|
+
@report.logger.error(e.message)
|
74
|
+
reader.unshift_line "|#{e.message}"
|
75
|
+
rescue StandardError => e
|
76
|
+
@report.logger.fatal(e.message)
|
77
|
+
reader.unshift_line "|#{e.message}"
|
78
|
+
end
|
79
|
+
|
80
|
+
reader
|
81
|
+
end
|
82
|
+
|
83
|
+
# @see ProcessorMixin#build_demo_entry
|
84
|
+
def build_demo_entry(_panel)
|
85
|
+
"|===\ninclude::grafana_annotations[columns=\"time,panelId,newState,prevState,text\"]\n|==="
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'processor_mixin'
|
4
|
+
|
5
|
+
module GrafanaReporter
|
6
|
+
module Asciidoctor
|
7
|
+
# Implements the hook
|
8
|
+
# grafana_panel_image::<panel_id>[<options>]
|
9
|
+
#
|
10
|
+
# Stores the queried panel as a temporary image file and returns an asciidoctor link
|
11
|
+
# to be included in the report.
|
12
|
+
#
|
13
|
+
# == Used document parameters
|
14
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
15
|
+
#
|
16
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
17
|
+
#
|
18
|
+
# +from+ - 'from' time for the sql query
|
19
|
+
#
|
20
|
+
# +to+ - 'to' time for the sql query
|
21
|
+
#
|
22
|
+
# == Supported options
|
23
|
+
# +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
|
24
|
+
#
|
25
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
26
|
+
#
|
27
|
+
# +dashboard+ - uid of grafana dashboard to use
|
28
|
+
#
|
29
|
+
# +from+ - 'from' time for the sql query
|
30
|
+
#
|
31
|
+
# +to+ - 'to' time for the sql query
|
32
|
+
class PanelImageBlockMacro < ::Asciidoctor::Extensions::BlockMacroProcessor
|
33
|
+
include ProcessorMixin
|
34
|
+
use_dsl
|
35
|
+
|
36
|
+
named :grafana_panel_image
|
37
|
+
|
38
|
+
# :nodoc:
|
39
|
+
def process(parent, target, attrs)
|
40
|
+
return if @report.cancel
|
41
|
+
|
42
|
+
@report.next_step
|
43
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
44
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
45
|
+
@report.logger.debug("Processing PanelImageBlockMacro (instance: #{instance}, dashboard: #{dashboard},"\
|
46
|
+
" panel: #{target})")
|
47
|
+
|
48
|
+
begin
|
49
|
+
query = PanelImageQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target))
|
50
|
+
query.merge_hash_variables(parent.document.attributes, attrs)
|
51
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
52
|
+
|
53
|
+
image = query.execute
|
54
|
+
image_path = @report.save_image_file(image)
|
55
|
+
rescue GrafanaReporterError => e
|
56
|
+
@report.logger.error(e.message)
|
57
|
+
return create_paragraph(parent, e.message, attrs)
|
58
|
+
rescue StandardError => e
|
59
|
+
@report.logger.fatal(e.message)
|
60
|
+
return create_paragraph(parent, e.message, attrs)
|
61
|
+
end
|
62
|
+
|
63
|
+
attrs['target'] = image_path
|
64
|
+
create_image_block(parent, attrs)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @see ProcessorMixin#build_demo_entry
|
68
|
+
def build_demo_entry(panel)
|
69
|
+
return nil unless panel
|
70
|
+
return nil unless panel.model['type'] == 'graph'
|
71
|
+
|
72
|
+
"grafana_panel_image::#{panel.id}[dashboard=\"#{panel.dashboard.id}\",width=\"50%\"]"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|