ruby-grafana-reporter 0.2.0 → 0.4.1
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 +105 -86
- data/bin/ruby-grafana-reporter +5 -5
- data/lib/VERSION.rb +3 -2
- data/lib/grafana/abstract_datasource.rb +136 -0
- data/lib/grafana/dashboard.rb +21 -23
- data/lib/grafana/errors.rb +8 -1
- data/lib/grafana/grafana.rb +61 -65
- 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 +50 -0
- data/lib/grafana/image_rendering_datasource.rb +44 -0
- data/lib/grafana/panel.rb +9 -3
- data/lib/grafana/prometheus_datasource.rb +45 -0
- data/lib/grafana/sql_datasource.rb +71 -0
- data/lib/grafana/unsupported_datasource.rb +7 -0
- data/lib/grafana/variable.rb +3 -2
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +359 -0
- data/lib/grafana_reporter/abstract_report.rb +119 -17
- 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 +49 -297
- data/lib/grafana_reporter/application/webservice.rb +49 -14
- 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 +77 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +79 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +73 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +99 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +93 -0
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +64 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +47 -76
- 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 +108 -43
- data/lib/grafana_reporter/console_configuration_wizard.rb +311 -0
- data/lib/grafana_reporter/demo_report_wizard.rb +101 -0
- data/lib/grafana_reporter/erb/report.rb +43 -0
- data/lib/grafana_reporter/errors.rb +41 -0
- data/lib/grafana_reporter/help.rb +443 -0
- data/lib/grafana_reporter/logger/{two_way_logger.rb → two_way_delegate_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_extension.rb +8 -0
- data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +13 -0
- metadata +47 -43
- 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 -104
- data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +0 -99
- 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 -202
- 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 -61
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -34
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -25
- data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +0 -44
- data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +0 -38
- data/lib/grafana_reporter/asciidoctor/query_mixin.rb +0 -310
- data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +0 -37
- data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +0 -39
@@ -0,0 +1,73 @@
|
|
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_property:<panel_id>[<options>]
|
9
|
+
#
|
10
|
+
# Returns the requested panel property.
|
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
|
+
# == Supported options
|
18
|
+
# +field+ - property to query for, e.g. +description+ or +title+ (*mandatory*)
|
19
|
+
#
|
20
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
21
|
+
#
|
22
|
+
# +dashboard+ - uid of grafana dashboard to use
|
23
|
+
class PanelPropertyInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
24
|
+
include ProcessorMixin
|
25
|
+
use_dsl
|
26
|
+
|
27
|
+
named :grafana_panel_property
|
28
|
+
name_positional_attributes :field
|
29
|
+
|
30
|
+
# :nodoc:
|
31
|
+
def process(parent, target, attrs)
|
32
|
+
return if @report.cancel
|
33
|
+
|
34
|
+
@report.next_step
|
35
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
36
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
37
|
+
@report.logger.debug("Processing PanelPropertyInlineMacro (instance: #{instance}, dashboard: #{dashboard},"\
|
38
|
+
" panel: #{target}, property: #{attrs[:field]})")
|
39
|
+
|
40
|
+
begin
|
41
|
+
query = PanelPropertyQuery.new(@report.grafana(instance).dashboard(dashboard).panel(target))
|
42
|
+
query.raw_query = { property_name: attrs[:field] }
|
43
|
+
assign_dashboard_defaults(query, @report.grafana(instance).dashboard(dashboard))
|
44
|
+
assign_doc_and_item_variables(query, parent.document.attributes, attrs)
|
45
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
46
|
+
|
47
|
+
description = query.execute
|
48
|
+
rescue GrafanaReporterError => e
|
49
|
+
@report.logger.error(e.message)
|
50
|
+
return create_inline(parent, :quoted, e.message)
|
51
|
+
rescue StandardError => e
|
52
|
+
@report.logger.fatal(e.message)
|
53
|
+
return create_inline(parent, :quoted, e.message)
|
54
|
+
end
|
55
|
+
|
56
|
+
# translate linebreaks to asciidoctor syntax
|
57
|
+
# and HTML encode to make sure, that HTML formattings are respected
|
58
|
+
create_inline(parent, :quoted, CGI.escapeHTML(description.gsub(%r{//[^\n]*(?:\n)?}, '').gsub(/\n/, " +\n")))
|
59
|
+
end
|
60
|
+
|
61
|
+
# @see ProcessorMixin#build_demo_entry
|
62
|
+
def build_demo_entry(panel)
|
63
|
+
return nil unless panel
|
64
|
+
return nil unless panel.model['title']
|
65
|
+
return nil if panel.model['title'].strip == ''
|
66
|
+
return nil if panel.model['title'].strip == 'Panel Title'
|
67
|
+
|
68
|
+
"this text includes the panel with title grafana_panel_property:#{panel.id}[\"title\","\
|
69
|
+
"dashboard=\"#{panel.dashboard.id}\"]"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,99 @@
|
|
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_panel_query_table:<panel_id>[<options>]
|
9
|
+
#
|
10
|
+
# Returns the results of the SQL 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
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
22
|
+
# in the given SQL query.
|
23
|
+
#
|
24
|
+
# == Supported options
|
25
|
+
# +query+ - query letter, which shall be used, e.g. +C+ (*mandatory*)
|
26
|
+
#
|
27
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
28
|
+
#
|
29
|
+
# +dashboard+ - uid of grafana dashboard to use
|
30
|
+
#
|
31
|
+
# +from+ - 'from' time for the sql query
|
32
|
+
#
|
33
|
+
# +to+ - 'to' time for the sql query
|
34
|
+
#
|
35
|
+
# +format+ - see {AbstractQuery#format_columns}
|
36
|
+
#
|
37
|
+
# +replace_values+ - see {AbstractQuery#replace_values}
|
38
|
+
#
|
39
|
+
# +filter_columns+ - see {AbstractQuery#filter_columns}
|
40
|
+
class PanelQueryTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
41
|
+
include ProcessorMixin
|
42
|
+
|
43
|
+
# :nodoc:
|
44
|
+
def handles?(target)
|
45
|
+
target.start_with? 'grafana_panel_query_table:'
|
46
|
+
end
|
47
|
+
|
48
|
+
# :nodoc:
|
49
|
+
def process(doc, reader, target, attrs)
|
50
|
+
return if @report.cancel
|
51
|
+
|
52
|
+
@report.next_step
|
53
|
+
panel_id = target.split(':')[1]
|
54
|
+
# TODO: check if instance and dashboard shouldn't be set in assign_doc_and_item_variables method
|
55
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
56
|
+
dashboard = attrs['dashboard'] || doc.attr('grafana_default_dashboard')
|
57
|
+
attrs['result_type'] = 'panel_table'
|
58
|
+
@report.logger.debug("Processing PanelQueryTableIncludeProcessor (instance: #{instance}, "\
|
59
|
+
"dashboard: #{dashboard}, panel: #{panel_id}, query: #{attrs['query']})")
|
60
|
+
|
61
|
+
begin
|
62
|
+
panel = @report.grafana(instance).dashboard(dashboard).panel(panel_id)
|
63
|
+
query = QueryValueQuery.new(panel)
|
64
|
+
assign_dashboard_defaults(query, panel.dashboard)
|
65
|
+
assign_doc_and_item_variables(query, doc.attributes, attrs)
|
66
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
67
|
+
|
68
|
+
reader.unshift_lines query.execute
|
69
|
+
rescue GrafanaReporterError => e
|
70
|
+
@report.logger.error(e.message)
|
71
|
+
reader.unshift_line "|#{e.message}"
|
72
|
+
rescue StandardError => e
|
73
|
+
@report.logger.fatal(e.message)
|
74
|
+
reader.unshift_line "|#{e.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
reader
|
78
|
+
end
|
79
|
+
|
80
|
+
# @see ProcessorMixin#build_demo_entry
|
81
|
+
def build_demo_entry(panel)
|
82
|
+
return nil unless panel
|
83
|
+
return nil unless panel.model['type'].include?('table')
|
84
|
+
|
85
|
+
ref_id = nil
|
86
|
+
panel.model['targets'].each do |item|
|
87
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
88
|
+
ref_id = item['refId']
|
89
|
+
break
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return nil unless ref_id
|
93
|
+
|
94
|
+
"|===\ninclude::grafana_panel_query_table:#{panel.id}[query=\"#{ref_id}\",filter_columns=\"time\","\
|
95
|
+
"dashboard=\"#{panel.dashboard.id}\"]\n|==="
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,93 @@
|
|
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_query_value:<panel_id>[<options>]
|
9
|
+
#
|
10
|
+
# Returns the first value of the resulting SQL query.
|
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
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
22
|
+
# in the given SQL query.
|
23
|
+
#
|
24
|
+
# == Supported options
|
25
|
+
# +query+ - query letter, which shall be used, e.g. +C+ (*mandatory*)
|
26
|
+
#
|
27
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
28
|
+
#
|
29
|
+
# +dashboard+ - uid of grafana dashboard to use
|
30
|
+
#
|
31
|
+
# +from+ - 'from' time for the sql query
|
32
|
+
#
|
33
|
+
# +to+ - 'to' time for the sql query
|
34
|
+
#
|
35
|
+
# +format+ - see {AbstractQuery#format_columns}
|
36
|
+
#
|
37
|
+
# +replace_values+ - see {AbstractQuery#replace_values}
|
38
|
+
#
|
39
|
+
# +filter_columns+ - see {AbstractQuery#filter_columns}
|
40
|
+
class PanelQueryValueInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
41
|
+
include ProcessorMixin
|
42
|
+
use_dsl
|
43
|
+
|
44
|
+
named :grafana_panel_query_value
|
45
|
+
|
46
|
+
# :nodoc:
|
47
|
+
def process(parent, target, attrs)
|
48
|
+
return if @report.cancel
|
49
|
+
|
50
|
+
@report.next_step
|
51
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
52
|
+
dashboard = attrs['dashboard'] || parent.document.attr('grafana_default_dashboard')
|
53
|
+
attrs['result_type'] = 'panel_value'
|
54
|
+
@report.logger.debug("Processing PanelQueryValueInlineMacro (instance: #{instance}, dashboard: #{dashboard},"\
|
55
|
+
" panel: #{target}, query: #{attrs['query']})")
|
56
|
+
|
57
|
+
begin
|
58
|
+
panel = @report.grafana(instance).dashboard(dashboard).panel(target)
|
59
|
+
query = QueryValueQuery.new(panel)
|
60
|
+
assign_dashboard_defaults(query, panel.dashboard)
|
61
|
+
assign_doc_and_item_variables(query, parent.document.attributes, attrs)
|
62
|
+
@report.logger.debug("from: #{query.from}, to: #{query.to}")
|
63
|
+
|
64
|
+
create_inline(parent, :quoted, query.execute)
|
65
|
+
rescue GrafanaReporterError => e
|
66
|
+
@report.logger.error(e.message)
|
67
|
+
create_inline(parent, :quoted, e.message)
|
68
|
+
rescue StandardError => e
|
69
|
+
@report.logger.fatal(e.message)
|
70
|
+
create_inline(parent, :quoted, e.message)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @see ProcessorMixin#build_demo_entry
|
75
|
+
def build_demo_entry(panel)
|
76
|
+
return nil unless panel
|
77
|
+
return nil unless panel.model['type'] == 'singlestat'
|
78
|
+
|
79
|
+
ref_id = nil
|
80
|
+
panel.model['targets'].each do |item|
|
81
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
82
|
+
ref_id = item['refId']
|
83
|
+
break
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return nil unless ref_id
|
87
|
+
|
88
|
+
"it's easily possible to include the query value: grafana_panel_query_value:#{panel.id}[query=\"#{ref_id}\""\
|
89
|
+
",dashboard=\"#{panel.dashboard.id}\"] - just within this text."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# This module contains common methods for all asciidoctor extensions.
|
6
|
+
module ProcessorMixin
|
7
|
+
# Used when initializing a object instance, to set the report object, which is currently in progress.
|
8
|
+
# @param report [GrafanaReporter::Asciidoctor::Report] current report
|
9
|
+
# @return [::Asciidoctor::Extensions::Processor] self
|
10
|
+
def current_report(report)
|
11
|
+
@report = report
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
# This method is called if a demo report shall be built for the given {Grafana::Panel}.
|
16
|
+
# @param panel [Grafana::Panel] panel object, for which a demo entry shall be created.
|
17
|
+
# @return [String] String containing the entry, or nil if not possible for given panel
|
18
|
+
def build_demo_entry(panel)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sets default configurations from the given {Grafana::Dashboard} and store them as settings in the
|
23
|
+
# {AbstractQuery}.
|
24
|
+
#
|
25
|
+
# Following data is extracted:
|
26
|
+
# - +from+, by {Grafana::Dashboard#from_time}
|
27
|
+
# - +to+, by {Grafana::Dashboard#to_time}
|
28
|
+
# - and all variables as {Grafana::Variable}, prefixed with +var-+, as grafana also does it
|
29
|
+
# @param query [AbstractQuery] query object, for which the defaults are set
|
30
|
+
# @param dashboard [Grafana::Dashboard] dashboard from which the defaults are captured
|
31
|
+
# TODO: assign_dashboard_defaults is a common method for all report classes - move it to a public place
|
32
|
+
def assign_dashboard_defaults(query, dashboard)
|
33
|
+
query.from = dashboard.from_time
|
34
|
+
query.to = dashboard.to_time
|
35
|
+
dashboard.variables.each { |item| query.assign_variable("var-#{item.name}", item) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Merges the given hashes to the given query object. It respects the priorities of the hashes and the
|
39
|
+
# object and allows only valid variables to be passed.
|
40
|
+
# @param query [AbstractQuery] query object, for which the defaults are set
|
41
|
+
# @param document_hash [Hash] variables from report template level
|
42
|
+
# @param item_hash [Hash] variables from item configuration level, i.e. specific call, which may override document
|
43
|
+
# @return [void]
|
44
|
+
def assign_doc_and_item_variables(query, document_hash, item_hash)
|
45
|
+
sel_doc_items = document_hash.select do |k, _v|
|
46
|
+
k =~ /^var-/ || k =~ /grafana_default_(?:from|to)_timezone/
|
47
|
+
end
|
48
|
+
sel_doc_items.each { |k, v| query.assign_variable(k, ::Grafana::Variable.new(v)) }
|
49
|
+
query.assign_variable('grafana_report_timestamp', ::Grafana::Variable.new(document_hash['localdatetime']))
|
50
|
+
|
51
|
+
sel_items = item_hash.select do |k, _v|
|
52
|
+
# TODO: specify accepted options in each class or check if simply all can be allowed with prefix +var-+
|
53
|
+
k =~ /^var-/ || k =~ /^render-/ || k =~ /filter_columns|format|replace_values_.*|transpose|column_divider|
|
54
|
+
row_divider|from_timezone|to_timezone|result_type|query/x
|
55
|
+
end
|
56
|
+
sel_items.each { |k, v| query.assign_variable(k, ::Grafana::Variable.new(v)) }
|
57
|
+
|
58
|
+
query.timeout = item_hash['timeout'] || document_hash['grafana-default-timeout'] || query.timeout
|
59
|
+
query.from = item_hash['from'] || document_hash['from'] || query.from
|
60
|
+
query.to = item_hash['to'] || document_hash['to'] || query.to
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,27 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GrafanaReporter
|
4
|
+
# This module contains all classes, which are necessary to use the reporter in conjunction with asciidoctor.
|
4
5
|
module Asciidoctor
|
5
6
|
# Implementation of a specific {AbstractReport}. It is used to
|
6
7
|
# build reports specifically for asciidoctor results.
|
7
|
-
class Report < GrafanaReporter::AbstractReport
|
8
|
-
#
|
9
|
-
def initialize(config
|
8
|
+
class Report < ::GrafanaReporter::AbstractReport
|
9
|
+
# @see AbstractReport#initialize
|
10
|
+
def initialize(config)
|
10
11
|
super
|
11
|
-
@current_pos = 0
|
12
12
|
@image_files = []
|
13
|
-
@grafana_instances = {}
|
14
13
|
end
|
15
14
|
|
16
|
-
# Starts to create an asciidoctor report. It utilizes all {
|
17
|
-
# realize the conversion.
|
15
|
+
# Starts to create an asciidoctor report. It utilizes all extensions in the {GrafanaReporter::Asciidoctor}
|
16
|
+
# namespace to realize the conversion.
|
18
17
|
# @see AbstractReport#create_report
|
19
|
-
|
20
|
-
|
21
|
-
@start_time = Time.now
|
18
|
+
def create_report(template, destination_file_or_path = nil, custom_attributes = {})
|
19
|
+
super
|
22
20
|
attrs = { 'convert-backend' => 'pdf' }.merge(@config.default_document_attributes.merge(@custom_attributes))
|
23
|
-
attrs['grafana-report-timestamp'] = @start_time.to_s
|
24
|
-
logger.info("Report started at #{@start_time}")
|
25
21
|
logger.debug("Document attributes: #{attrs}")
|
26
22
|
|
27
23
|
initialize_step_counter
|
@@ -30,19 +26,18 @@ module GrafanaReporter
|
|
30
26
|
::Asciidoctor::LoggerManager.logger = logger
|
31
27
|
|
32
28
|
registry = ::Asciidoctor::Extensions::Registry.new
|
33
|
-
|
34
|
-
registry.inline_macro
|
35
|
-
registry.inline_macro
|
36
|
-
registry.inline_macro
|
37
|
-
registry.
|
38
|
-
registry.
|
39
|
-
registry.include_processor
|
40
|
-
registry.include_processor
|
41
|
-
registry.include_processor
|
42
|
-
registry.include_processor
|
43
|
-
registry.include_processor
|
44
|
-
registry.include_processor
|
45
|
-
registry.include_processor Extensions::AlertsTableIncludeProcessor.new.current_report(self)
|
29
|
+
registry.inline_macro PanelImageInlineMacro.new.current_report(self)
|
30
|
+
registry.inline_macro PanelQueryValueInlineMacro.new.current_report(self)
|
31
|
+
registry.inline_macro PanelPropertyInlineMacro.new.current_report(self)
|
32
|
+
registry.inline_macro SqlValueInlineMacro.new.current_report(self)
|
33
|
+
registry.block_macro PanelImageBlockMacro.new.current_report(self)
|
34
|
+
registry.include_processor ValueAsVariableIncludeProcessor.new.current_report(self)
|
35
|
+
registry.include_processor PanelQueryTableIncludeProcessor.new.current_report(self)
|
36
|
+
registry.include_processor SqlTableIncludeProcessor.new.current_report(self)
|
37
|
+
registry.include_processor ShowEnvironmentIncludeProcessor.new.current_report(self)
|
38
|
+
registry.include_processor ShowHelpIncludeProcessor.new.current_report(self)
|
39
|
+
registry.include_processor AnnotationsTableIncludeProcessor.new.current_report(self)
|
40
|
+
registry.include_processor AlertsTableIncludeProcessor.new.current_report(self)
|
46
41
|
|
47
42
|
::Asciidoctor.convert_file(@template, extension_registry: registry, backend: attrs['convert-backend'],
|
48
43
|
to_file: path, attributes: attrs, header_footer: true)
|
@@ -51,29 +46,28 @@ module GrafanaReporter
|
|
51
46
|
|
52
47
|
# store report including als images as ZIP file, if the result is not a PDF
|
53
48
|
if attrs['convert-backend'] != 'pdf'
|
54
|
-
dest_path =
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
dest_path = @destination_file_or_path.path
|
60
|
-
else
|
61
|
-
dest_path = @destination_file_or_path
|
62
|
-
end
|
49
|
+
dest_path = if @destination_file_or_path.is_a?(File) || @destination_file_or_path.is_a?(Tempfile)
|
50
|
+
@destination_file_or_path.path
|
51
|
+
else
|
52
|
+
@destination_file_or_path
|
53
|
+
end
|
63
54
|
|
64
55
|
# build zip file
|
65
56
|
zip_file = Tempfile.new('gf_zip')
|
66
|
-
Zip::
|
57
|
+
buffer = Zip::OutputStream.write_buffer do |zipfile|
|
67
58
|
# add report file
|
68
|
-
zipfile.
|
69
|
-
|
70
|
-
end
|
59
|
+
zipfile.put_next_entry("#{dest_path.gsub(@config.reports_folder, '')}.#{attrs['convert-backend']}")
|
60
|
+
zipfile.write File.read(dest_path)
|
71
61
|
|
72
62
|
# add image files
|
73
63
|
@image_files.each do |file|
|
74
|
-
zipfile.
|
64
|
+
zipfile.put_next_entry(file.path.gsub(@config.images_folder, ''))
|
65
|
+
zipfile.write File.read(file.path)
|
75
66
|
end
|
76
67
|
end
|
68
|
+
File.open(zip_file, 'wb') do |f|
|
69
|
+
f.write buffer.string
|
70
|
+
end
|
77
71
|
|
78
72
|
# replace original file with zip file
|
79
73
|
zip_file.rewind
|
@@ -89,40 +83,17 @@ module GrafanaReporter
|
|
89
83
|
end
|
90
84
|
|
91
85
|
clean_image_files
|
92
|
-
|
93
|
-
logger.
|
94
|
-
@
|
86
|
+
rescue MissingTemplateError => e
|
87
|
+
@logger.error(e.message)
|
88
|
+
@error = [e.message]
|
89
|
+
done!
|
90
|
+
raise e
|
95
91
|
rescue StandardError => e
|
96
92
|
# catch all errors during execution
|
97
93
|
died_with_error(e)
|
98
94
|
raise e
|
99
|
-
|
100
|
-
|
101
|
-
# @see AbstractReport#progress
|
102
|
-
# @return [Float] number between 0 and 1 reflecting the current progress.
|
103
|
-
def progress
|
104
|
-
return 0 if @total_steps.to_i.zero?
|
105
|
-
|
106
|
-
@current_pos.to_f / @total_steps
|
107
|
-
end
|
108
|
-
|
109
|
-
# @param instance [String] requested grafana instance
|
110
|
-
# @return [Grafana::Grafana] the requested grafana instance.
|
111
|
-
def grafana(instance)
|
112
|
-
unless @grafana_instances[instance]
|
113
|
-
@grafana_instances[instance] = ::Grafana::Grafana.new(@config.grafana_host(instance),
|
114
|
-
@config.grafana_api_key(instance),
|
115
|
-
logger: @logger,
|
116
|
-
datasources: @config.grafana_datasources(instance))
|
117
|
-
end
|
118
|
-
@grafana_instances[instance]
|
119
|
-
end
|
120
|
-
|
121
|
-
# Increments the progress.
|
122
|
-
# @return [Integer] number of the current progress position.
|
123
|
-
def next_step
|
124
|
-
@current_pos += 1
|
125
|
-
@current_pos
|
95
|
+
ensure
|
96
|
+
done!
|
126
97
|
end
|
127
98
|
|
128
99
|
# Called to save a temporary image file. After the final generation of the
|
@@ -131,6 +102,7 @@ module GrafanaReporter
|
|
131
102
|
# @return [String] path to the temporary file.
|
132
103
|
def save_image_file(img_data)
|
133
104
|
file = Tempfile.new(['gf_image_', '.png'], @config.images_folder.to_s)
|
105
|
+
file.binmode
|
134
106
|
file.write(img_data)
|
135
107
|
path = file.path.gsub(/#{@config.images_folder}/, '')
|
136
108
|
|
@@ -140,13 +112,11 @@ module GrafanaReporter
|
|
140
112
|
path
|
141
113
|
end
|
142
114
|
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
@end_time = Time.now
|
149
|
-
@done = true
|
115
|
+
# @see AbstractReport#demo_report_classes
|
116
|
+
def self.demo_report_classes
|
117
|
+
[AlertsTableIncludeProcessor, AnnotationsTableIncludeProcessor, PanelImageBlockMacro, PanelImageInlineMacro,
|
118
|
+
PanelPropertyInlineMacro, PanelQueryTableIncludeProcessor, PanelQueryValueInlineMacro,
|
119
|
+
SqlTableIncludeProcessor, SqlValueInlineMacro, ShowHelpIncludeProcessor, ShowEnvironmentIncludeProcessor]
|
150
120
|
end
|
151
121
|
|
152
122
|
private
|
@@ -160,6 +130,7 @@ module GrafanaReporter
|
|
160
130
|
@total_steps = 0
|
161
131
|
File.readlines(@template).each do |line|
|
162
132
|
begin
|
133
|
+
# TODO: move these calls to the specific processors to ensure all are counted properly
|
163
134
|
@total_steps += line.gsub(%r{//.*}, '').scan(/(?:grafana_panel_image|grafana_panel_query_value|
|
164
135
|
grafana_panel_query_table|grafana_sql_value|
|
165
136
|
grafana_sql_table|grafana_environment|grafana_help|
|