ruby-grafana-reporter 0.2.2 → 0.4.3
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 +126 -88
- data/bin/ruby-grafana-reporter +2 -2
- data/lib/VERSION.rb +3 -2
- data/lib/grafana/abstract_datasource.rb +146 -0
- data/lib/grafana/dashboard.rb +1 -3
- data/lib/grafana/errors.rb +18 -3
- data/lib/grafana/grafana.rb +64 -66
- 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 +30 -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 +9 -3
- data/lib/grafana/prometheus_datasource.rb +67 -0
- data/lib/grafana/sql_datasource.rb +78 -0
- data/lib/grafana/unsupported_datasource.rb +7 -0
- data/lib/grafana/variable.rb +1 -1
- data/lib/grafana/webrequest.rb +71 -0
- data/lib/grafana_reporter/abstract_query.rb +460 -0
- data/lib/grafana_reporter/abstract_report.rb +139 -18
- data/lib/grafana_reporter/alerts_table_query.rb +39 -0
- data/lib/grafana_reporter/annotations_table_query.rb +38 -0
- data/lib/grafana_reporter/application/application.rb +34 -286
- data/lib/grafana_reporter/application/webservice.rb +50 -15
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +91 -0
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +90 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +74 -0
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +76 -0
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +70 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +95 -0
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +90 -0
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +49 -0
- data/lib/grafana_reporter/asciidoctor/report.rb +32 -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 +90 -0
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +86 -0
- data/lib/grafana_reporter/asciidoctor/value_as_variable_include_processor.rb +90 -0
- data/lib/grafana_reporter/configuration.rb +59 -52
- data/lib/grafana_reporter/console_configuration_wizard.rb +311 -0
- data/lib/grafana_reporter/demo_report_wizard.rb +105 -0
- data/lib/grafana_reporter/erb/report.rb +30 -0
- data/lib/grafana_reporter/erb/report_jail.rb +21 -0
- data/lib/grafana_reporter/errors.rb +55 -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 +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 +35 -0
- data/lib/ruby_grafana_extension.rb +8 -0
- data/lib/{ruby-grafana-reporter.rb → ruby_grafana_reporter.rb} +1 -0
- metadata +47 -39
- 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 -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 -86
- data/lib/grafana_reporter/asciidoctor/help.rb +0 -435
- data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +0 -34
- data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +0 -26
- 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 -301
- 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,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 GrafanaReporter::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,90 @@
|
|
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
|
+
query = QueryValueQuery.new(@report.grafana(instance), variables: build_attribute_hash(doc.attributes, attrs))
|
55
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target.split(':')[1].to_i)
|
56
|
+
query.raw_query = attrs['sql']
|
57
|
+
|
58
|
+
reader.unshift_lines query.execute
|
59
|
+
rescue GrafanaReporterError => e
|
60
|
+
@report.logger.error(e.message)
|
61
|
+
reader.unshift_line "|#{e.message}"
|
62
|
+
rescue StandardError => e
|
63
|
+
@report.logger.fatal(e.message)
|
64
|
+
reader.unshift_line "|#{e.message}"
|
65
|
+
end
|
66
|
+
|
67
|
+
reader
|
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'].include?('table')
|
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
|
+
"|===\ninclude::grafana_sql_table:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
85
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",filter_columns=\"time\","\
|
86
|
+
"dashboard=\"#{panel.dashboard.id}\",from=\"now-1h\",to=\"now\"]\n|==="
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,86 @@
|
|
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), variables: build_attribute_hash(parent.document.attributes, attrs))
|
53
|
+
query.datasource = @report.grafana(instance).datasource_by_id(target)
|
54
|
+
query.raw_query = attrs['sql']
|
55
|
+
|
56
|
+
create_inline(parent, :quoted, query.execute)
|
57
|
+
rescue GrafanaReporterError => e
|
58
|
+
@report.logger.error(e.message)
|
59
|
+
create_inline(parent, :quoted, e.message)
|
60
|
+
rescue StandardError => e
|
61
|
+
@report.logger.fatal(e.message)
|
62
|
+
create_inline(parent, :quoted, e.message)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @see ProcessorMixin#build_demo_entry
|
67
|
+
def build_demo_entry(panel)
|
68
|
+
return nil unless panel
|
69
|
+
return nil unless panel.model['type'] == 'singlestat'
|
70
|
+
|
71
|
+
ref_id = nil
|
72
|
+
panel.model['targets'].each do |item|
|
73
|
+
if !item['hide'] && !panel.query(item['refId']).to_s.empty?
|
74
|
+
ref_id = item['refId']
|
75
|
+
break
|
76
|
+
end
|
77
|
+
end
|
78
|
+
return nil unless ref_id
|
79
|
+
|
80
|
+
"grafana_sql_value:#{panel.dashboard.grafana.datasource_by_name(panel.model['datasource']).id}"\
|
81
|
+
"[sql=\"#{panel.query(ref_id).gsub(/"/, '\"').gsub("\n", ' ').gsub(/\\/, '\\\\')}\",from=\"now-1h\","\
|
82
|
+
'to="now"]'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -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_value_as_variable[<options>]
|
9
|
+
#
|
10
|
+
# Returns an attribute definition in asciidoctor format. This is needed if you want to refer to values of
|
11
|
+
# a grafana query within a variable in asciidoctor. As this works without this function for the
|
12
|
+
# `IncludeProcessor`s values, it will not work for all the other processors.
|
13
|
+
#
|
14
|
+
# This method is just a proxy for all other hooks and will forward parameters accordingly.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# include:grafana_value_as_variable[call="grafana_sql_value:1",variable_name="my_variable",sql="SELECT 'looks good'",<any_other_option>]
|
19
|
+
#
|
20
|
+
# This will call the {SqlValueInlineMacro} with `datasource_id` set to `1` and store the result in the
|
21
|
+
# variable. The resulting asciidoctor variable definition will be created as:
|
22
|
+
#
|
23
|
+
# :my_variable: looks good
|
24
|
+
#
|
25
|
+
# and can be refered to in your document easily as
|
26
|
+
#
|
27
|
+
# {my_variable}
|
28
|
+
#
|
29
|
+
# == Supported options
|
30
|
+
# +call+ - regular call to the reporter hook (*mandatory*)
|
31
|
+
#
|
32
|
+
# +variable_name+ - name of the variable, to which the result shall be assigned (*mandatory*)
|
33
|
+
class ValueAsVariableIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
34
|
+
include ProcessorMixin
|
35
|
+
|
36
|
+
# :nodoc:
|
37
|
+
def handles?(target)
|
38
|
+
target.start_with? 'grafana_value_as_variable'
|
39
|
+
end
|
40
|
+
|
41
|
+
# :nodoc:
|
42
|
+
def process(doc, reader, target, attrs)
|
43
|
+
return if @report.cancel
|
44
|
+
|
45
|
+
# increase step for this processor as well as it is also counted in the step counter
|
46
|
+
@report.next_step
|
47
|
+
|
48
|
+
call_attr = attrs.delete('call')
|
49
|
+
call, target = call_attr.split(':') if call_attr
|
50
|
+
attribute = attrs.delete('variable_name')
|
51
|
+
@report.logger.debug("Processing ValueAsVariableIncludeProcessor (call: #{call}, target: #{target},"\
|
52
|
+
" variable_name: #{attribute}, attrs: #{attrs})")
|
53
|
+
if !call || !attribute
|
54
|
+
@report.logger.error('ValueAsVariableIncludeProcessor: Missing mandatory attribute \'call\' or '\
|
55
|
+
'\'variable_name\'.')
|
56
|
+
# increase counter, as error occured and no sub call is being processed
|
57
|
+
@report.next_step
|
58
|
+
return reader
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: remove dirty hack to allow the document as parameter for other processors
|
62
|
+
def doc.document
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# TODO: properly show error messages also in document
|
67
|
+
ext = doc.extensions.find_inline_macro_extension(call) if doc.extensions.inline_macros?
|
68
|
+
if !ext
|
69
|
+
@report.logger.error('ValueAsVariableIncludeProcessor: Could not find inline macro extension for '\
|
70
|
+
"'#{call}'.")
|
71
|
+
# increase counter, as error occured and no sub call is being processed
|
72
|
+
@report.next_step
|
73
|
+
else
|
74
|
+
@report.logger.debug('ValueAsVariableIncludeProcessor: Calling sub-method.')
|
75
|
+
item = ext.process_method.call(doc, target, attrs)
|
76
|
+
if !item.text.to_s.empty?
|
77
|
+
result = ":#{attribute}: #{item.text}"
|
78
|
+
@report.logger.debug("ValueAsVariableIncludeProcessor: Adding '#{result}' to document.")
|
79
|
+
reader.unshift_line(result)
|
80
|
+
else
|
81
|
+
@report.logger.debug("ValueAsVariableIncludeProcessor: Not adding variable '#{attribute}'"\
|
82
|
+
' as query result was empty.')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
reader
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -13,6 +13,10 @@ module GrafanaReporter
|
|
13
13
|
class Configuration
|
14
14
|
# @return [AbstractReport] specific report class, which should be used.
|
15
15
|
attr_accessor :report_class
|
16
|
+
attr_accessor :logger
|
17
|
+
|
18
|
+
# Default file name for grafana reporter configuration file
|
19
|
+
DEFAULT_CONFIG_FILE_NAME = 'grafana_reporter.config'
|
16
20
|
|
17
21
|
# Returned by {#mode} if only a connection test shall be executed.
|
18
22
|
MODE_CONNECTION_TEST = 'test'
|
@@ -27,10 +31,18 @@ module GrafanaReporter
|
|
27
31
|
|
28
32
|
def initialize
|
29
33
|
@config = {}
|
30
|
-
@logger = ::Logger.new($stderr, level: :
|
34
|
+
@logger = ::Logger.new($stderr, level: :info)
|
31
35
|
end
|
32
36
|
|
33
|
-
|
37
|
+
# Reads a given configuration file.
|
38
|
+
# @param config_file [String] path to configuration file, defaults to DEFAULT_CONFIG_FILE_NAME
|
39
|
+
# @return [Hash] configuration hash to be set as {Configuration#config}
|
40
|
+
def load_config_from_file(config_file = nil)
|
41
|
+
config_file ||= DEFAULT_CONFIG_FILE_NAME
|
42
|
+
self.config = YAML.load_file(config_file)
|
43
|
+
rescue StandardError => e
|
44
|
+
raise ConfigurationError, "Could not read config file '#{config_file}' (Error: #{e.message})"
|
45
|
+
end
|
34
46
|
|
35
47
|
# Used to overwrite the current configuration.
|
36
48
|
def config=(new_config)
|
@@ -53,7 +65,7 @@ module GrafanaReporter
|
|
53
65
|
def template
|
54
66
|
return nil if get_config('default-document-attributes:var-template').nil?
|
55
67
|
|
56
|
-
"#{templates_folder}#{get_config('default-document-attributes:var-template')}
|
68
|
+
"#{templates_folder}#{get_config('default-document-attributes:var-template')}"
|
57
69
|
end
|
58
70
|
|
59
71
|
# @return [String] destination filename for the report in {MODE_SINGLE_RENDER}.
|
@@ -84,16 +96,6 @@ module GrafanaReporter
|
|
84
96
|
get_config("grafana:#{instance}:api_key")
|
85
97
|
end
|
86
98
|
|
87
|
-
# @param instance [String] grafana instance name, for which the value shall be retrieved.
|
88
|
-
# @return [Hash<String,Integer>] configured datasources for the requested grafana instance. Name as key,
|
89
|
-
# ID as value.
|
90
|
-
def grafana_datasources(instance = 'default')
|
91
|
-
hash = get_config("grafana:#{instance}:datasources")
|
92
|
-
return nil if hash.nil?
|
93
|
-
|
94
|
-
hash.map { |k, v| [k, v] }.to_h
|
95
|
-
end
|
96
|
-
|
97
99
|
# @return [String] configured folder, in which the report templates are stored including trailing slash.
|
98
100
|
# By default: current folder.
|
99
101
|
def templates_folder
|
@@ -153,10 +155,11 @@ module GrafanaReporter
|
|
153
155
|
# This function shall be called, before the configuration object is used in the
|
154
156
|
# {Application::Application#run}. It ensures, that everything is setup properly
|
155
157
|
# and all necessary folders exist. Appropriate errors are raised in case of errors.
|
158
|
+
# @param explicit [Boolean] true, if validation shall expect explicit (wizard) configuration file
|
156
159
|
# @return [void]
|
157
|
-
def validate
|
160
|
+
def validate(explicit = false)
|
158
161
|
check_deprecation
|
159
|
-
validate_schema(schema, @config)
|
162
|
+
validate_schema(schema(explicit), @config)
|
160
163
|
|
161
164
|
# check if set folders exist
|
162
165
|
raise FolderDoesNotExistError.new(reports_folder, 'reports-folder') unless File.directory?(reports_folder)
|
@@ -176,12 +179,8 @@ module GrafanaReporter
|
|
176
179
|
|
177
180
|
cur_pos = @config
|
178
181
|
levels.each do |subpath|
|
179
|
-
|
180
|
-
|
181
|
-
else
|
182
|
-
cur_pos[subpath] = {}
|
183
|
-
cur_pos = cur_pos[subpath]
|
184
|
-
end
|
182
|
+
cur_pos[subpath] = {} unless cur_pos[subpath]
|
183
|
+
cur_pos = cur_pos[subpath]
|
185
184
|
end
|
186
185
|
|
187
186
|
cur_pos[last_level] = value
|
@@ -193,7 +192,7 @@ module GrafanaReporter
|
|
193
192
|
#
|
194
193
|
# param other_config [Configuration] other configuration object
|
195
194
|
def merge!(other_config)
|
196
|
-
|
195
|
+
config.merge!(other_config.config) { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2) : v2 }
|
197
196
|
update_configuration
|
198
197
|
end
|
199
198
|
|
@@ -202,19 +201,29 @@ module GrafanaReporter
|
|
202
201
|
def check_deprecation
|
203
202
|
return if report_class
|
204
203
|
|
205
|
-
logger.warn('DEPRECATION WARNING: Your configuration explicitly needs to specify the
|
206
|
-
'
|
207
|
-
'
|
204
|
+
logger.warn('DEPRECATION WARNING: Your configuration explicitly needs to specify the '\
|
205
|
+
'\'grafana-reporter:report-class\' value. Currently this defaults to '\
|
206
|
+
'\'GrafanaReporter::Asciidoctor::Report\'. You can get rid of this warning, if you '\
|
207
|
+
'explicitly set this configuration in your configuration file. Setting this default will be '\
|
208
|
+
'removed in a future version.')
|
208
209
|
set_param('grafana-reporter:report-class', 'GrafanaReporter::Asciidoctor::Report')
|
209
210
|
end
|
210
211
|
|
211
212
|
def update_configuration
|
212
|
-
|
213
|
-
|
214
|
-
|
213
|
+
debug_level = get_config('grafana-reporter:debug-level')
|
214
|
+
rep_class = get_config('grafana-reporter:report-class')
|
215
|
+
|
216
|
+
@logger.level = Object.const_get("::Logger::Severity::#{debug_level}") if debug_level =~ /DEBUG|INFO|WARN|
|
217
|
+
ERROR|FATAL|UNKNOWN/x
|
218
|
+
self.report_class = Object.const_get(rep_class) if rep_class
|
219
|
+
::Grafana::WebRequest.ssl_cert = get_config('grafana-reporter:ssl-cert')
|
215
220
|
|
216
|
-
|
217
|
-
|
221
|
+
# register callbacks
|
222
|
+
callbacks = get_config('grafana-reporter:callbacks')
|
223
|
+
return unless callbacks
|
224
|
+
|
225
|
+
callbacks.each do |url, event|
|
226
|
+
AbstractReport.add_event_listener(event.to_sym, ReportWebhook.new(url))
|
218
227
|
end
|
219
228
|
end
|
220
229
|
|
@@ -238,20 +247,16 @@ module GrafanaReporter
|
|
238
247
|
|
239
248
|
if key.nil?
|
240
249
|
# apply to all on this level
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
else
|
254
|
-
raise ConfigurationError, "Unhandled configuration data type '#{subject.class}'."
|
250
|
+
raise ConfigurationError, "Unhandled configuration data type '#{subject.class}'." unless subject.is_a?(Hash)
|
251
|
+
|
252
|
+
if subject.length < min_occurence
|
253
|
+
raise ConfigurationDoesNotMatchSchemaError.new(key, 'occur', min_occurence, subject.length)
|
254
|
+
end
|
255
|
+
|
256
|
+
subject.each do |k, _v|
|
257
|
+
sub_scheme = {}
|
258
|
+
sub_scheme[k] = schema[nil]
|
259
|
+
validate_schema(sub_scheme, subject)
|
255
260
|
end
|
256
261
|
|
257
262
|
# apply to single item
|
@@ -277,7 +282,7 @@ module GrafanaReporter
|
|
277
282
|
end
|
278
283
|
end
|
279
284
|
|
280
|
-
def schema
|
285
|
+
def schema(explicit)
|
281
286
|
{
|
282
287
|
'grafana' =>
|
283
288
|
[
|
@@ -288,13 +293,13 @@ module GrafanaReporter
|
|
288
293
|
Hash, 1,
|
289
294
|
{
|
290
295
|
'host' => [String, 1],
|
291
|
-
'api_key' => [String, 0]
|
292
|
-
'datasources' => [Hash, 0, { nil => [Integer, 1] }]
|
296
|
+
'api_key' => [String, 0]
|
293
297
|
}
|
294
298
|
]
|
295
299
|
}
|
296
300
|
],
|
297
|
-
'default-document-attributes' => [Hash, 0],
|
301
|
+
'default-document-attributes' => [Hash, explicit ? 1 : 0],
|
302
|
+
'to_file' => [String, 0],
|
298
303
|
'grafana-reporter' =>
|
299
304
|
[
|
300
305
|
Hash, 1,
|
@@ -302,11 +307,13 @@ module GrafanaReporter
|
|
302
307
|
'debug-level' => [String, 0],
|
303
308
|
'run-mode' => [String, 0],
|
304
309
|
'test-instance' => [String, 0],
|
305
|
-
'templates-folder' => [String, 0],
|
310
|
+
'templates-folder' => [String, explicit ? 1 : 0],
|
306
311
|
'report-class' => [String, 1],
|
307
|
-
'reports-folder' => [String, 0],
|
308
|
-
'report-retention' => [Integer, 0],
|
309
|
-
'
|
312
|
+
'reports-folder' => [String, explicit ? 1 : 0],
|
313
|
+
'report-retention' => [Integer, explicit ? 1 : 0],
|
314
|
+
'ssl-cert' => [String, 0],
|
315
|
+
'webservice-port' => [Integer, explicit ? 1 : 0],
|
316
|
+
'callbacks' => [Hash, 0, { nil => [String, 1] }]
|
310
317
|
}
|
311
318
|
]
|
312
319
|
}
|