ruby-grafana-reporter 0.1.6
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +248 -0
- data/lib/VERSION.rb +3 -0
- data/lib/grafana/abstract_panel_query.rb +20 -0
- data/lib/grafana/abstract_query.rb +127 -0
- data/lib/grafana/abstract_sql_query.rb +42 -0
- data/lib/grafana/dashboard.rb +66 -0
- data/lib/grafana/errors.rb +61 -0
- data/lib/grafana/grafana.rb +131 -0
- data/lib/grafana/panel.rb +39 -0
- data/lib/grafana/panel_image_query.rb +49 -0
- data/lib/grafana/variable.rb +259 -0
- data/lib/grafana_reporter/abstract_report.rb +109 -0
- data/lib/grafana_reporter/application/application.rb +229 -0
- data/lib/grafana_reporter/application/errors.rb +30 -0
- data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +99 -0
- data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +96 -0
- data/lib/grafana_reporter/asciidoctor/errors.rb +37 -0
- data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +86 -0
- data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +86 -0
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +67 -0
- data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +65 -0
- data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +58 -0
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +75 -0
- data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +70 -0
- data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +18 -0
- data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +41 -0
- data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +202 -0
- data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +67 -0
- data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +65 -0
- data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +57 -0
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +32 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +23 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +43 -0
- data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +36 -0
- data/lib/grafana_reporter/asciidoctor/query_mixin.rb +309 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +159 -0
- data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +34 -0
- data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +32 -0
- data/lib/grafana_reporter/configuration.rb +326 -0
- data/lib/grafana_reporter/errors.rb +38 -0
- data/lib/grafana_reporter/logger/two_way_logger.rb +52 -0
- data/lib/ruby-grafana-reporter.rb +27 -0
- metadata +88 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
module GrafanaReporter
|
2
|
+
module Asciidoctor
|
3
|
+
# This class is used to query annotations from grafana.
|
4
|
+
class AnnotationsTableQuery < Grafana::AbstractQuery
|
5
|
+
include QueryMixin
|
6
|
+
|
7
|
+
# @option opts [Grafana::Dashboard] :dashboard dashboard, if annotations shall be filtered for a dashboard
|
8
|
+
# @option opts [Grafana::Panel] :panel panel, if annotations shall be filtered for a panel
|
9
|
+
def initialize(opts = {})
|
10
|
+
super()
|
11
|
+
|
12
|
+
@dashboard = opts[:dashboard]
|
13
|
+
@panel = opts[:panel]
|
14
|
+
@dashboard = @panel.dashboard if @panel
|
15
|
+
|
16
|
+
extract_dashboard_variables(@dashboard) if @dashboard
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [String] URL for querying annotations
|
20
|
+
def url
|
21
|
+
'/api/annotations' + url_parameters
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash] empty hash object
|
25
|
+
def request
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check if mandatory {Grafana::Variable} +columns+ is specified in variables.
|
30
|
+
#
|
31
|
+
# The value of the +columns+ variable has to be a comma separated list of column titles, which
|
32
|
+
# need to be included in the following list:
|
33
|
+
# - limit
|
34
|
+
# - alertId
|
35
|
+
# - userId
|
36
|
+
# - type
|
37
|
+
# - tags
|
38
|
+
# - dashboardId
|
39
|
+
# - panelId
|
40
|
+
# @return [void]
|
41
|
+
def pre_process(_grafana)
|
42
|
+
raise MissingMandatoryAttributeError, 'columns' unless @variables['columns']
|
43
|
+
|
44
|
+
@from = translate_date(@from, @variables['grafana-report-timestamp'], false)
|
45
|
+
@to = translate_date(@to, @variables['grafana-report-timestamp'], true)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Filters the query result for the given columns and sets the result
|
49
|
+
# in the preformatted SQL result style.
|
50
|
+
#
|
51
|
+
# Additionally it applies {QueryMixin#format_columns}, {QueryMixin#replace_values} and
|
52
|
+
# {QueryMixin#filter_columns}.
|
53
|
+
# @return [void]
|
54
|
+
def post_process
|
55
|
+
# extract data from returned json
|
56
|
+
result = JSON.parse(@result.body)
|
57
|
+
content = []
|
58
|
+
begin
|
59
|
+
result.each { |item| content << item.fetch_values(*@variables['columns'].raw_value.split(',')) }
|
60
|
+
rescue KeyError => e
|
61
|
+
raise MalformedAttributeContentError.new(e.message, 'columns', @variables['columns'])
|
62
|
+
end
|
63
|
+
|
64
|
+
result = {}
|
65
|
+
result[:header] = [@variables['columns'].raw_value.split(',')]
|
66
|
+
result[:content] = content
|
67
|
+
|
68
|
+
result = format_columns(result, @variables['format'])
|
69
|
+
result = replace_values(result, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
|
70
|
+
result = filter_columns(result, @variables['filter_columns'])
|
71
|
+
if @variables['filter_column']
|
72
|
+
@report.logger.warn("DEPRECATED: Call of no longer supported function 'filter_column' has been found. Rename to 'filter_columns'")
|
73
|
+
result = filter_columns(result, @variables['filter_column'])
|
74
|
+
end
|
75
|
+
|
76
|
+
@result = result[:content].map { |row| '| ' + row.map { |item| item.to_s.gsub('|', '\\|') }.join(' | ') }
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def url_parameters
|
82
|
+
url_vars = {}
|
83
|
+
url_vars['dashboardId'] = ::Grafana::Variable.new(@dashboard.id) if @dashboard
|
84
|
+
url_vars['panelId'] = ::Grafana::Variable.new(@panel.id) if @panel
|
85
|
+
|
86
|
+
url_vars.merge!(variables.select { |k, _v| k =~ /^(?:limit|alertId|dashboardId|panelId|userId|type|tags)/ })
|
87
|
+
url_vars['from'] = ::Grafana::Variable.new(@from) if @from
|
88
|
+
url_vars['to'] = ::Grafana::Variable.new(@to) if @to
|
89
|
+
url_params = URI.encode_www_form(url_vars.map { |k, v| [k, v.raw_value.to_s] })
|
90
|
+
return '' if url_params.empty?
|
91
|
+
|
92
|
+
'?' + url_params
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module GrafanaReporter
|
2
|
+
# This module contains all classes, which are necessary to use the grafana
|
3
|
+
# reporter to be used in conjunction with asciidoctor.
|
4
|
+
module Asciidoctor
|
5
|
+
# Thrown, if the value configuration in {QueryMixin#replace_values} is
|
6
|
+
# invalid.
|
7
|
+
class MalformedReplaceValuesStatementError < GrafanaReporterError
|
8
|
+
def initialize(statement)
|
9
|
+
super("The specified replace_values statement '#{statement}' is invalid. Make sure it contains exactly one not escaped ':' symbol.")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Thrown, if a configured parameter is malformed.
|
14
|
+
class MalformedAttributeContentError < GrafanaReporterError
|
15
|
+
def initialize(message, attribute, content)
|
16
|
+
super("The content '#{content}' in attribute '#{attribute}' is malformed: #{message}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Thrown, if a configured time range is not supported by the reporter.
|
21
|
+
#
|
22
|
+
# If this happens, most likely the reporter has to implement the new
|
23
|
+
# time range definition.
|
24
|
+
class TimeRangeUnknownError < GrafanaReporterError
|
25
|
+
def initialize(time_range)
|
26
|
+
super("The specified time range '#{time_range}' is unknown.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Thrown, if a mandatory attribute is not set.
|
31
|
+
class MissingMandatoryAttributeError < GrafanaReporterError
|
32
|
+
def initialize(attribute)
|
33
|
+
super("Missing mandatory attribute '#{attribute}'.")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative 'processor_mixin'
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
module Extensions
|
6
|
+
# Implements the hook
|
7
|
+
# include::grafana_alerts[<options>]
|
8
|
+
#
|
9
|
+
# Returns the results of alerts query as a asciidoctor table.
|
10
|
+
#
|
11
|
+
# == Used document parameters
|
12
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
13
|
+
#
|
14
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
15
|
+
#
|
16
|
+
# +from+ - 'from' time for the sql query
|
17
|
+
#
|
18
|
+
# +to+ - 'to' time for the sql query
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +columns+ - see {AlertsTableQuery#pre_process} (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +dashboard+ - uid of grafana dashboard to query for, empty string if no filter is wanted
|
26
|
+
#
|
27
|
+
# +panel+ - id of the panel to query for
|
28
|
+
#
|
29
|
+
# +from+ - 'from' time for the sql query
|
30
|
+
#
|
31
|
+
# +to+ - 'to' time for the sql query
|
32
|
+
#
|
33
|
+
# +format+ - see {QueryMixin#format_columns}
|
34
|
+
#
|
35
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
36
|
+
#
|
37
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
38
|
+
class AlertsTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
39
|
+
include ProcessorMixin
|
40
|
+
|
41
|
+
# :nodoc:
|
42
|
+
def handles?(target)
|
43
|
+
target.start_with? 'grafana_alerts'
|
44
|
+
end
|
45
|
+
|
46
|
+
# :nodoc:
|
47
|
+
def process(doc, reader, _target, attrs)
|
48
|
+
return if @report.cancel
|
49
|
+
|
50
|
+
@report.next_step
|
51
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
52
|
+
dashboard_id = attrs['dashboard'] || doc.attr('grafana_default_dashboard')
|
53
|
+
panel_id = attrs['panel']
|
54
|
+
@report.logger.debug("Processing AlertsTableIncludeProcessor (instance: #{instance}, dashboard: #{dashboard_id}, panel: #{panel_id})")
|
55
|
+
|
56
|
+
query = if dashboard_id.to_s.empty?
|
57
|
+
# no dashboard shall be used, so also the panel will be omitted
|
58
|
+
AlertsTableQuery.new
|
59
|
+
elsif panel_id.to_s.empty?
|
60
|
+
# a dashboard is given, but no panel, so set filter for dashboard only
|
61
|
+
AlertsTableQuery.new(dashboard: @report.grafana(instance).dashboard(dashboard_id))
|
62
|
+
else
|
63
|
+
# dashboard and panel is given, so set filter for panel
|
64
|
+
AlertsTableQuery.new(panel: @report.grafana(instance).dashboard(dashboard_id).panel(panel_id))
|
65
|
+
end
|
66
|
+
|
67
|
+
query.merge_hash_variables(doc.attributes, attrs)
|
68
|
+
query.merge_variables(attrs.select { |k, _v| k =~ /(?:columns|limit|folderId|dashboardId|panelId|dahboardTag|dashboardQuery|state|query)/ }.transform_values { |item| ::Grafana::Variable.new(item) })
|
69
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
70
|
+
|
71
|
+
begin
|
72
|
+
reader.unshift_lines query.execute(@report.grafana(instance))
|
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
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative 'processor_mixin'
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
module Extensions
|
6
|
+
# Implements the hook
|
7
|
+
# include::grafana_annotations[<options>]
|
8
|
+
#
|
9
|
+
# Returns the results of alerts query as a asciidoctor table.
|
10
|
+
#
|
11
|
+
# == Used document parameters
|
12
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
13
|
+
#
|
14
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
15
|
+
#
|
16
|
+
# +from+ - 'from' time for the sql query
|
17
|
+
#
|
18
|
+
# +to+ - 'to' time for the sql query
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +columns+ - see {AnnotationsTableQuery#pre_process} (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +dashboard+ - uid of grafana dashboard to query for, empty string if no filter is wanted
|
26
|
+
#
|
27
|
+
# +panel+ - id of the panel to query for
|
28
|
+
#
|
29
|
+
# +from+ - 'from' time for the sql query
|
30
|
+
#
|
31
|
+
# +to+ - 'to' time for the sql query
|
32
|
+
#
|
33
|
+
# +format+ - see {QueryMixin#format_columns}
|
34
|
+
#
|
35
|
+
# +replace_values+ - see {QueryMixin#replace_values}
|
36
|
+
#
|
37
|
+
# +filter_columns+ - see {QueryMixin#filter_columns}
|
38
|
+
class AnnotationsTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
39
|
+
include ProcessorMixin
|
40
|
+
|
41
|
+
# :nodoc:
|
42
|
+
def handles?(target)
|
43
|
+
target.start_with? 'grafana_annotations'
|
44
|
+
end
|
45
|
+
|
46
|
+
# :nodoc:
|
47
|
+
def process(doc, reader, _target, attrs)
|
48
|
+
return if @report.cancel
|
49
|
+
|
50
|
+
@report.next_step
|
51
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
52
|
+
dashboard_id = attrs['dashboard'] || doc.attr('grafana_default_dashboard')
|
53
|
+
panel_id = attrs['panel']
|
54
|
+
@report.logger.debug("Processing AnnotationsTableIncludeProcessor (instance: #{instance})")
|
55
|
+
|
56
|
+
query = if dashboard_id.to_s.empty?
|
57
|
+
# no dashboard shall be used, so also the panel will be omitted
|
58
|
+
AnnotationsTableQuery.new
|
59
|
+
elsif panel_id.to_s.empty?
|
60
|
+
# a dashboard is given, but no panel, so set filter for dashboard only
|
61
|
+
AnnotationsTableQuery.new(dashboard: @report.grafana(instance).dashboard(dashboard_id))
|
62
|
+
else
|
63
|
+
# dashboard and panel is given, so set filter for panel
|
64
|
+
AnnotationsTableQuery.new(panel: @report.grafana(instance).dashboard(dashboard_id).panel(panel_id))
|
65
|
+
end
|
66
|
+
|
67
|
+
query.merge_hash_variables(doc.attributes, attrs)
|
68
|
+
query.merge_variables(attrs.select { |k, _v| k =~ /(?:columns|limit|alertId|dashboardId|panelId|userId|type|tags)/ }.transform_values { |item| ::Grafana::Variable.new(item) })
|
69
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
70
|
+
|
71
|
+
begin
|
72
|
+
reader.unshift_lines query.execute(@report.grafana(instance))
|
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
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative 'processor_mixin'
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
module Extensions
|
6
|
+
# Implements the hook
|
7
|
+
# grafana_panel_image::<panel_id>[<options>]
|
8
|
+
#
|
9
|
+
# Stores the queried panel as a temporary image file and returns an asciidoctor link
|
10
|
+
# to be included in the report.
|
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
|
+
# +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
|
23
|
+
#
|
24
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
25
|
+
#
|
26
|
+
# +dashboard+ - uid of grafana dashboard to use
|
27
|
+
#
|
28
|
+
# +from+ - 'from' time for the sql query
|
29
|
+
#
|
30
|
+
# +to+ - 'to' time for the sql query
|
31
|
+
class PanelImageBlockMacro < ::Asciidoctor::Extensions::BlockMacroProcessor
|
32
|
+
include ProcessorMixin
|
33
|
+
use_dsl
|
34
|
+
|
35
|
+
named :grafana_panel_image
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def process(parent, target, attrs)
|
39
|
+
return if @report.cancel
|
40
|
+
|
41
|
+
@report.next_step
|
42
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
43
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
44
|
+
@report.logger.debug("Processing PanelImageBlockMacro (instance: #{instance}, dashboard: #{dashboard}, panel: #{target})")
|
45
|
+
query = PanelImageQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target))
|
46
|
+
query.merge_hash_variables(parent.document.attributes, attrs)
|
47
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
48
|
+
|
49
|
+
begin
|
50
|
+
image = query.execute(@report.grafana(instance))
|
51
|
+
image_path = @report.save_image_file(image)
|
52
|
+
rescue GrafanaReporterError => e
|
53
|
+
@report.logger.error(e.message)
|
54
|
+
return create_paragraph(parent, e.message, attrs)
|
55
|
+
rescue StandardError => e
|
56
|
+
@report.logger.fatal(e.message)
|
57
|
+
return create_paragraph(parent, e.message, attrs)
|
58
|
+
end
|
59
|
+
|
60
|
+
attrs['target'] = image_path
|
61
|
+
block = create_image_block(parent, attrs)
|
62
|
+
block
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative 'processor_mixin'
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
module Extensions
|
6
|
+
# Implements the hook
|
7
|
+
# grafana_panel_image:<panel_id>[<options>]
|
8
|
+
#
|
9
|
+
# Stores the queried panel as a temporary image file and returns an asciidoctor link
|
10
|
+
# to be included in the report.
|
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
|
+
# +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
|
23
|
+
#
|
24
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
25
|
+
#
|
26
|
+
# +dashboard+ - uid of grafana dashboard to use
|
27
|
+
#
|
28
|
+
# +from+ - 'from' time for the sql query
|
29
|
+
#
|
30
|
+
# +to+ - 'to' time for the sql query
|
31
|
+
class PanelImageInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
32
|
+
include ProcessorMixin
|
33
|
+
use_dsl
|
34
|
+
|
35
|
+
named :grafana_panel_image
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def process(parent, target, attrs)
|
39
|
+
return if @report.cancel
|
40
|
+
|
41
|
+
@report.next_step
|
42
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
43
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
44
|
+
@report.logger.debug("Processing PanelImageInlineMacro (instance: #{instance}, dashboard: #{dashboard}, panel: #{target})")
|
45
|
+
query = PanelImageQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target))
|
46
|
+
query.merge_hash_variables(parent.document.attributes, attrs)
|
47
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
48
|
+
|
49
|
+
begin
|
50
|
+
image = query.execute(@report.grafana(instance))
|
51
|
+
image_path = @report.save_image_file(image)
|
52
|
+
rescue GrafanaReporterError => e
|
53
|
+
@report.logger.error(e.message)
|
54
|
+
return create_inline(parent, :quoted, e.message)
|
55
|
+
rescue StandardError => e
|
56
|
+
@report.logger.fatal(e.message)
|
57
|
+
return create_inline(parent, :quoted, e.message)
|
58
|
+
end
|
59
|
+
|
60
|
+
create_inline(parent, :image, nil, { target: image_path, attributes: attrs })
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'processor_mixin'
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
module Extensions
|
6
|
+
# Implements the hook
|
7
|
+
# grafana_panel_property:<panel_id>[<options>]
|
8
|
+
#
|
9
|
+
# Returns the requested panel property.
|
10
|
+
#
|
11
|
+
# == Used document parameters
|
12
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
13
|
+
#
|
14
|
+
# +grafana_default_dashboard+ - uid of grafana default dashboard to use
|
15
|
+
#
|
16
|
+
# == Supported options
|
17
|
+
# +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
|
18
|
+
#
|
19
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
20
|
+
#
|
21
|
+
# +dashboard+ - uid of grafana dashboard to use
|
22
|
+
class PanelPropertyInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
23
|
+
include ProcessorMixin
|
24
|
+
use_dsl
|
25
|
+
|
26
|
+
named :grafana_panel_property
|
27
|
+
name_positional_attributes :field
|
28
|
+
|
29
|
+
# :nodoc:
|
30
|
+
def process(parent, target, attrs)
|
31
|
+
return if @report.cancel
|
32
|
+
|
33
|
+
@report.next_step
|
34
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
35
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
36
|
+
@report.logger.debug("Processing PanelPropertyInlineMacro (instance: #{instance}, dashboard: #{dashboard}, panel: #{target}, property: #{attrs[:field]})")
|
37
|
+
query = PanelPropertyQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target), attrs[:field])
|
38
|
+
query.merge_hash_variables(parent.document.attributes, attrs)
|
39
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
40
|
+
|
41
|
+
begin
|
42
|
+
description = query.execute(@report.grafana(instance))
|
43
|
+
rescue GrafanaReporterError => e
|
44
|
+
@report.logger.error(e.message)
|
45
|
+
return create_inline(parent, :quoted, e.message)
|
46
|
+
rescue StandardError => e
|
47
|
+
@report.logger.fatal(e.message)
|
48
|
+
return create_inline(parent, :quoted, e.message)
|
49
|
+
end
|
50
|
+
|
51
|
+
# translate linebreaks to asciidoctor syntax
|
52
|
+
# and HTML encode to make sure, that HTML formattings are respected
|
53
|
+
create_inline(parent, :quoted, CGI.escapeHTML(description.gsub(%r{//[^\n]*(?:\n)?}, '').gsub(/\n/, " +\n")))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|