ruby-grafana-reporter 0.3.0 → 0.4.4
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 +337 -170
- data/bin/ruby-grafana-reporter +5 -5
- data/lib/VERSION.rb +3 -2
- data/lib/grafana/abstract_datasource.rb +149 -0
- data/lib/grafana/dashboard.rb +1 -3
- data/lib/grafana/errors.rb +20 -5
- data/lib/grafana/grafana.rb +52 -57
- 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 +37 -0
- data/lib/grafana/graphite_datasource.rb +72 -0
- data/lib/grafana/image_rendering_datasource.rb +44 -0
- data/lib/grafana/influxdb_datasource.rb +70 -0
- data/lib/grafana/panel.rb +10 -4
- data/lib/grafana/prometheus_datasource.rb +67 -0
- data/lib/grafana/sql_datasource.rb +70 -0
- data/lib/grafana/unsupported_datasource.rb +7 -0
- data/lib/grafana/variable.rb +27 -21
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +478 -0
- data/lib/grafana_reporter/abstract_report.rb +152 -18
- data/lib/grafana_reporter/abstract_table_format_strategy.rb +34 -0
- data/lib/grafana_reporter/alerts_table_query.rb +43 -0
- data/lib/grafana_reporter/annotations_table_query.rb +42 -0
- data/lib/grafana_reporter/application/application.rb +28 -25
- data/lib/grafana_reporter/application/webservice.rb +80 -39
- data/lib/grafana_reporter/asciidoctor/adoc_plain_table_format_strategy.rb +25 -0
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +92 -0
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +91 -0
- data/lib/grafana_reporter/asciidoctor/help.rb +336 -313
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +78 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +80 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +74 -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 +50 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +41 -82
- 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 +94 -0
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +90 -0
- data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
- data/lib/grafana_reporter/configuration.rb +26 -8
- data/lib/grafana_reporter/console_configuration_wizard.rb +109 -67
- data/lib/grafana_reporter/csv_table_format_strategy.rb +23 -0
- data/lib/grafana_reporter/demo_report_wizard.rb +104 -0
- data/lib/grafana_reporter/erb/demo_report_builder.rb +46 -0
- data/lib/grafana_reporter/erb/report.rb +36 -0
- data/lib/grafana_reporter/erb/report_jail.rb +21 -0
- data/lib/grafana_reporter/errors.rb +57 -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 +25 -0
- data/lib/grafana_reporter/panel_property_query.rb +22 -0
- data/lib/grafana_reporter/query_value_query.rb +61 -0
- data/lib/grafana_reporter/report_webhook.rb +39 -0
- data/lib/ruby_grafana_extension.rb +8 -0
- data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +1 -3
- metadata +49 -38
- 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/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
@@ -1,27 +1,22 @@
|
|
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.
|
18
|
-
# @see AbstractReport#
|
19
|
-
|
20
|
-
def create_report
|
21
|
-
@start_time = Time.now
|
15
|
+
# Starts to create an asciidoctor report. It utilizes all extensions in the {GrafanaReporter::Asciidoctor}
|
16
|
+
# namespace to realize the conversion.
|
17
|
+
# @see AbstractReport#build
|
18
|
+
def build
|
22
19
|
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
20
|
logger.debug("Document attributes: #{attrs}")
|
26
21
|
|
27
22
|
initialize_step_counter
|
@@ -30,43 +25,30 @@ module GrafanaReporter
|
|
30
25
|
::Asciidoctor::LoggerManager.logger = logger
|
31
26
|
|
32
27
|
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)
|
28
|
+
registry.inline_macro PanelImageInlineMacro.new.current_report(self)
|
29
|
+
registry.inline_macro PanelQueryValueInlineMacro.new.current_report(self)
|
30
|
+
registry.inline_macro PanelPropertyInlineMacro.new.current_report(self)
|
31
|
+
registry.inline_macro SqlValueInlineMacro.new.current_report(self)
|
32
|
+
registry.block_macro PanelImageBlockMacro.new.current_report(self)
|
33
|
+
registry.include_processor ValueAsVariableIncludeProcessor.new.current_report(self)
|
34
|
+
registry.include_processor PanelQueryTableIncludeProcessor.new.current_report(self)
|
35
|
+
registry.include_processor SqlTableIncludeProcessor.new.current_report(self)
|
36
|
+
registry.include_processor ShowEnvironmentIncludeProcessor.new.current_report(self)
|
37
|
+
registry.include_processor ShowHelpIncludeProcessor.new.current_report(self)
|
38
|
+
registry.include_processor AnnotationsTableIncludeProcessor.new.current_report(self)
|
39
|
+
registry.include_processor AlertsTableIncludeProcessor.new.current_report(self)
|
46
40
|
|
47
41
|
::Asciidoctor.convert_file(@template, extension_registry: registry, backend: attrs['convert-backend'],
|
48
42
|
to_file: path, attributes: attrs, header_footer: true)
|
49
43
|
|
50
|
-
@destination_file_or_path.close if @destination_file_or_path.is_a?(File)
|
51
|
-
|
52
44
|
# store report including als images as ZIP file, if the result is not a PDF
|
53
45
|
if attrs['convert-backend'] != 'pdf'
|
54
|
-
dest_path = nil
|
55
|
-
case
|
56
|
-
when @destination_file_or_path.is_a?(File)
|
57
|
-
dest_path = @destination_file_or_path.path
|
58
|
-
when @destination_file_or_path.is_a?(Tempfile)
|
59
|
-
dest_path = @destination_file_or_path.path
|
60
|
-
else
|
61
|
-
dest_path = @destination_file_or_path
|
62
|
-
end
|
63
|
-
|
64
46
|
# build zip file
|
65
47
|
zip_file = Tempfile.new('gf_zip')
|
66
48
|
buffer = Zip::OutputStream.write_buffer do |zipfile|
|
67
49
|
# add report file
|
68
|
-
zipfile.put_next_entry("#{
|
69
|
-
zipfile.write File.read(
|
50
|
+
zipfile.put_next_entry("#{path.gsub(@config.reports_folder, '')}.#{attrs['convert-backend']}")
|
51
|
+
zipfile.write File.read(path)
|
70
52
|
|
71
53
|
# add image files
|
72
54
|
@image_files.each do |file|
|
@@ -81,9 +63,9 @@ module GrafanaReporter
|
|
81
63
|
# replace original file with zip file
|
82
64
|
zip_file.rewind
|
83
65
|
begin
|
84
|
-
File.write(
|
66
|
+
File.write(path, zip_file.read)
|
85
67
|
rescue StandardError => e
|
86
|
-
logger.fatal("Could not overwrite report file '#{
|
68
|
+
logger.fatal("Could not overwrite report file '#{path}' with ZIP file. (#{e.message}).")
|
87
69
|
end
|
88
70
|
|
89
71
|
# cleanup temporary zip file
|
@@ -92,39 +74,6 @@ module GrafanaReporter
|
|
92
74
|
end
|
93
75
|
|
94
76
|
clean_image_files
|
95
|
-
@end_time = Time.now
|
96
|
-
logger.info("Report finished after #{@end_time - @start_time} seconds.")
|
97
|
-
@done = true
|
98
|
-
rescue StandardError => e
|
99
|
-
# catch all errors during execution
|
100
|
-
died_with_error(e)
|
101
|
-
raise e
|
102
|
-
end
|
103
|
-
|
104
|
-
# @see AbstractReport#progress
|
105
|
-
# @return [Float] number between 0 and 1 reflecting the current progress.
|
106
|
-
def progress
|
107
|
-
return 0 if @total_steps.to_i.zero?
|
108
|
-
|
109
|
-
@current_pos.to_f / @total_steps
|
110
|
-
end
|
111
|
-
|
112
|
-
# @param instance [String] requested grafana instance
|
113
|
-
# @return [Grafana::Grafana] the requested grafana instance.
|
114
|
-
def grafana(instance)
|
115
|
-
unless @grafana_instances[instance]
|
116
|
-
@grafana_instances[instance] = ::Grafana::Grafana.new(@config.grafana_host(instance),
|
117
|
-
@config.grafana_api_key(instance),
|
118
|
-
logger: @logger, ssl_cert: @config.ssl_cert)
|
119
|
-
end
|
120
|
-
@grafana_instances[instance]
|
121
|
-
end
|
122
|
-
|
123
|
-
# Increments the progress.
|
124
|
-
# @return [Integer] number of the current progress position.
|
125
|
-
def next_step
|
126
|
-
@current_pos += 1
|
127
|
-
@current_pos
|
128
77
|
end
|
129
78
|
|
130
79
|
# Called to save a temporary image file. After the final generation of the
|
@@ -133,6 +82,7 @@ module GrafanaReporter
|
|
133
82
|
# @return [String] path to the temporary file.
|
134
83
|
def save_image_file(img_data)
|
135
84
|
file = Tempfile.new(['gf_image_', '.png'], @config.images_folder.to_s)
|
85
|
+
file.binmode
|
136
86
|
file.write(img_data)
|
137
87
|
path = file.path.gsub(/#{@config.images_folder}/, '')
|
138
88
|
|
@@ -142,13 +92,21 @@ module GrafanaReporter
|
|
142
92
|
path
|
143
93
|
end
|
144
94
|
|
145
|
-
#
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
95
|
+
# @see AbstractReport#default_template_extension
|
96
|
+
def self.default_template_extension
|
97
|
+
'adoc'
|
98
|
+
end
|
99
|
+
|
100
|
+
# @see AbstractReport#default_result_extension
|
101
|
+
def self.default_result_extension
|
102
|
+
'pdf'
|
103
|
+
end
|
104
|
+
|
105
|
+
# @see AbstractReport#demo_report_classes
|
106
|
+
def self.demo_report_classes
|
107
|
+
[AlertsTableIncludeProcessor, AnnotationsTableIncludeProcessor, PanelImageBlockMacro, PanelImageInlineMacro,
|
108
|
+
PanelPropertyInlineMacro, PanelQueryTableIncludeProcessor, PanelQueryValueInlineMacro,
|
109
|
+
SqlTableIncludeProcessor, SqlValueInlineMacro, ShowHelpIncludeProcessor, ShowEnvironmentIncludeProcessor]
|
152
110
|
end
|
153
111
|
|
154
112
|
private
|
@@ -162,6 +120,7 @@ module GrafanaReporter
|
|
162
120
|
@total_steps = 0
|
163
121
|
File.readlines(@template).each do |line|
|
164
122
|
begin
|
123
|
+
# TODO: move these calls to the specific processors to ensure all are counted properly
|
165
124
|
@total_steps += line.gsub(%r{//.*}, '').scan(/(?:grafana_panel_image|grafana_panel_query_value|
|
166
125
|
grafana_panel_query_table|grafana_sql_value|
|
167
126
|
grafana_sql_table|grafana_environment|grafana_help|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_environment[]
|
7
|
+
#
|
8
|
+
# Shows all available variables, which are accessible during this run of the asciidoctor
|
9
|
+
# grafana reporter in a asciidoctor readable form.
|
10
|
+
#
|
11
|
+
# This processor is very helpful during report template design, to find out the available
|
12
|
+
# variables, that can be accessed.
|
13
|
+
#
|
14
|
+
# == Used document parameters
|
15
|
+
# All, to be listed as the available environment.
|
16
|
+
class ShowEnvironmentIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
17
|
+
include ProcessorMixin
|
18
|
+
|
19
|
+
# :nodoc:
|
20
|
+
def handles?(target)
|
21
|
+
target.start_with? 'grafana_environment'
|
22
|
+
end
|
23
|
+
|
24
|
+
# :nodoc:
|
25
|
+
def process(doc, reader, _target, _attrs)
|
26
|
+
# return if @report.cancel
|
27
|
+
@report.next_step
|
28
|
+
@report.logger.debug('Processing ShowEnvironmentIncludeProcessor')
|
29
|
+
|
30
|
+
vars = ['== Accessible Variables',
|
31
|
+
'|===']
|
32
|
+
doc.attributes.sort.each do |k, v|
|
33
|
+
vars << "| `+{#{k}}+` | #{v}"
|
34
|
+
end
|
35
|
+
vars << '|==='
|
36
|
+
|
37
|
+
reader.unshift_lines vars
|
38
|
+
end
|
39
|
+
|
40
|
+
# @see ProcessorMixin#build_demo_entry
|
41
|
+
def build_demo_entry(_panel)
|
42
|
+
'include::grafana_environment[]'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_help[]
|
7
|
+
#
|
8
|
+
# Shows all available options for the asciidoctor grafana reporter in a asciidoctor readable form.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# None
|
12
|
+
class ShowHelpIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
13
|
+
include ProcessorMixin
|
14
|
+
|
15
|
+
# :nodoc:
|
16
|
+
def handles?(target)
|
17
|
+
target.start_with? 'grafana_help'
|
18
|
+
end
|
19
|
+
|
20
|
+
# :nodoc:
|
21
|
+
def process(_doc, reader, _target, _attrs)
|
22
|
+
# return if @report.cancel
|
23
|
+
@report.next_step
|
24
|
+
@report.logger.debug('Processing ShowHelpIncludeProcessor')
|
25
|
+
|
26
|
+
reader.unshift_lines Help.new.asciidoctor.split("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see ProcessorMixin#build_demo_entry
|
30
|
+
def build_demo_entry(_panel)
|
31
|
+
'include::grafana_help[]'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# include::grafana_sql_table:<datasource_id>[<options>]
|
7
|
+
#
|
8
|
+
# Returns the results of the SQL query as a asciidoctor table.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
12
|
+
#
|
13
|
+
# +from+ - 'from' time for the sql query
|
14
|
+
#
|
15
|
+
# +to+ - 'to' time for the sql query
|
16
|
+
#
|
17
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
18
|
+
# in the given SQL query.
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +sql+ - sql statement (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +from+ - 'from' time for the sql query
|
26
|
+
#
|
27
|
+
# +to+ - 'to' time for the sql query
|
28
|
+
#
|
29
|
+
# +format+ - see {AbstractQuery#format_columns}
|
30
|
+
#
|
31
|
+
# +replace_values+ - see {AbstractQuery#replace_values}
|
32
|
+
#
|
33
|
+
# +filter_columns+ - see {AbstractQuery#filter_columns}
|
34
|
+
class SqlTableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
35
|
+
include ProcessorMixin
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def handles?(target)
|
39
|
+
target.start_with? 'grafana_sql_table:'
|
40
|
+
end
|
41
|
+
|
42
|
+
# :nodoc:
|
43
|
+
def process(doc, reader, target, attrs)
|
44
|
+
return if @report.cancel
|
45
|
+
|
46
|
+
@report.next_step
|
47
|
+
instance = attrs['instance'] || doc.attr('grafana_default_instance') || 'default'
|
48
|
+
attrs['result_type'] = 'sql_table'
|
49
|
+
@report.logger.debug("Processing SqlTableIncludeProcessor (instance: #{instance},"\
|
50
|
+
" datasource: #{target.split(':')[1]}, sql: #{attrs['sql']})")
|
51
|
+
|
52
|
+
begin
|
53
|
+
# catch properly if datasource could not be identified
|
54
|
+
vars = { 'table_formatter' => 'adoc_plain' }.merge(build_attribute_hash(doc.attributes, attrs))
|
55
|
+
query = QueryValueQuery.new(@report.grafana(instance), variables: vars)
|
56
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target.split(':')[1].to_i)
|
57
|
+
query.raw_query = attrs['sql']
|
58
|
+
|
59
|
+
reader.unshift_lines query.execute
|
60
|
+
rescue GrafanaError => e
|
61
|
+
@report.logger.error(e.message)
|
62
|
+
reader.unshift_line "|#{e.message}"
|
63
|
+
rescue GrafanaReporterError => e
|
64
|
+
@report.logger.error(e.message)
|
65
|
+
reader.unshift_line "|#{e.message}"
|
66
|
+
rescue StandardError => e
|
67
|
+
@report.logger.fatal(e.message)
|
68
|
+
reader.unshift_line "|#{e.message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
reader
|
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'].include?('table')
|
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
|
+
"|===\ninclude::grafana_sql_table:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
89
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",filter_columns=\"time\","\
|
90
|
+
"dashboard=\"#{panel.dashboard.id}\",from=\"now-1h\",to=\"now\"]\n|==="
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrafanaReporter
|
4
|
+
module Asciidoctor
|
5
|
+
# Implements the hook
|
6
|
+
# grafana_sql_value:<datasource_id>[<options>]
|
7
|
+
#
|
8
|
+
# Returns the first value of the resulting SQL query.
|
9
|
+
#
|
10
|
+
# == Used document parameters
|
11
|
+
# +grafana_default_instance+ - name of grafana instance, 'default' if not specified
|
12
|
+
#
|
13
|
+
# +from+ - 'from' time for the sql query
|
14
|
+
#
|
15
|
+
# +to+ - 'to' time for the sql query
|
16
|
+
#
|
17
|
+
# All other variables starting with +var-+ will be used to replace grafana templating strings
|
18
|
+
# in the given SQL query.
|
19
|
+
#
|
20
|
+
# == Supported options
|
21
|
+
# +sql+ - sql statement (*mandatory*)
|
22
|
+
#
|
23
|
+
# +instance+ - name of grafana instance, 'default' if not specified
|
24
|
+
#
|
25
|
+
# +from+ - 'from' time for the sql query
|
26
|
+
#
|
27
|
+
# +to+ - 'to' time for the sql query
|
28
|
+
#
|
29
|
+
# +format+ - see {AbstractQuery#format_columns}
|
30
|
+
#
|
31
|
+
# +replace_values+ - see {AbstractQuery#replace_values}
|
32
|
+
#
|
33
|
+
# +filter_columns+ - see {AbstractQuery#filter_columns}
|
34
|
+
class SqlValueInlineMacro < ::Asciidoctor::Extensions::InlineMacroProcessor
|
35
|
+
include ProcessorMixin
|
36
|
+
use_dsl
|
37
|
+
|
38
|
+
named :grafana_sql_value
|
39
|
+
|
40
|
+
# @see GrafanaReporter::Asciidoctor::SqlFirstValueQuery
|
41
|
+
def process(parent, target, attrs)
|
42
|
+
return if @report.cancel
|
43
|
+
|
44
|
+
@report.next_step
|
45
|
+
instance = attrs['instance'] || parent.document.attr('grafana_default_instance') || 'default'
|
46
|
+
attrs['result_type'] = 'sql_value'
|
47
|
+
@report.logger.debug("Processing SqlValueInlineMacro (instance: #{instance}, datasource: #{target},"\
|
48
|
+
" sql: #{attrs['sql']})")
|
49
|
+
|
50
|
+
begin
|
51
|
+
# catch properly if datasource could not be identified
|
52
|
+
query = QueryValueQuery.new(@report.grafana(instance),
|
53
|
+
variables: build_attribute_hash(parent.document.attributes, attrs))
|
54
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target)
|
55
|
+
query.raw_query = attrs['sql']
|
56
|
+
|
57
|
+
create_inline(parent, :quoted, query.execute)
|
58
|
+
rescue GrafanaError => e
|
59
|
+
@report.logger.error(e.message)
|
60
|
+
create_inline(parent, :quoted, e.message)
|
61
|
+
rescue GrafanaReporterError => e
|
62
|
+
@report.logger.error(e.message)
|
63
|
+
create_inline(parent, :quoted, e.message)
|
64
|
+
rescue StandardError => e
|
65
|
+
@report.logger.fatal(e.message)
|
66
|
+
create_inline(parent, :quoted, e.message)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @see ProcessorMixin#build_demo_entry
|
71
|
+
def build_demo_entry(panel)
|
72
|
+
return nil unless panel
|
73
|
+
return nil unless panel.model['type'] == 'singlestat'
|
74
|
+
|
75
|
+
ref_id = nil
|
76
|
+
panel.model['targets'].each do |item|
|
77
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
78
|
+
ref_id = item['refId']
|
79
|
+
break
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return nil unless ref_id
|
83
|
+
|
84
|
+
"grafana_sql_value:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
85
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",from=\"now-1h\","\
|
86
|
+
'to="now"]'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|