ruby-grafana-reporter 0.4.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 +185 -180
- data/lib/VERSION.rb +2 -2
- data/lib/grafana/abstract_datasource.rb +32 -12
- data/lib/grafana/errors.rb +1 -9
- data/lib/grafana/grafana.rb +3 -7
- data/lib/grafana/graphite_datasource.rb +6 -0
- data/lib/grafana/prometheus_datasource.rb +6 -0
- data/lib/grafana/sql_datasource.rb +6 -0
- data/lib/grafana/unsupported_datasource.rb +7 -0
- data/lib/grafana/webrequest.rb +1 -1
- data/lib/grafana_reporter/abstract_query.rb +20 -62
- data/lib/grafana_reporter/abstract_report.rb +66 -15
- data/lib/grafana_reporter/alerts_table_query.rb +5 -5
- data/lib/grafana_reporter/annotations_table_query.rb +4 -4
- data/lib/grafana_reporter/application/application.rb +10 -16
- data/lib/grafana_reporter/application/webservice.rb +34 -10
- data/lib/grafana_reporter/asciidoctor/alerts_table_include_processor.rb +5 -5
- data/lib/grafana_reporter/asciidoctor/annotations_table_include_processor.rb +5 -5
- data/lib/grafana_reporter/asciidoctor/panel_image_block_macro.rb +2 -1
- data/lib/grafana_reporter/asciidoctor/panel_image_inline_macro.rb +7 -5
- data/lib/grafana_reporter/asciidoctor/panel_property_inline_macro.rb +2 -1
- data/lib/grafana_reporter/asciidoctor/panel_query_table_include_processor.rb +6 -5
- data/lib/grafana_reporter/asciidoctor/panel_query_value_inline_macro.rb +5 -5
- data/lib/grafana_reporter/asciidoctor/processor_mixin.rb +43 -2
- data/lib/grafana_reporter/asciidoctor/report.rb +17 -41
- data/lib/grafana_reporter/asciidoctor/sql_table_include_processor.rb +4 -4
- data/lib/grafana_reporter/asciidoctor/sql_value_inline_macro.rb +4 -4
- data/lib/grafana_reporter/configuration.rb +14 -2
- data/lib/grafana_reporter/console_configuration_wizard.rb +2 -10
- data/lib/grafana_reporter/demo_report_wizard.rb +16 -2
- data/lib/grafana_reporter/erb/report.rb +43 -0
- data/lib/grafana_reporter/errors.rb +9 -1
- data/lib/grafana_reporter/help.rb +1 -5
- data/lib/grafana_reporter/logger/{two_way_logger.rb → two_way_delegate_logger.rb} +0 -0
- data/lib/grafana_reporter/panel_image_query.rb +2 -2
- data/lib/grafana_reporter/query_value_query.rb +4 -4
- data/lib/ruby_grafana_extension.rb +8 -0
- data/lib/ruby_grafana_reporter.rb +13 -0
- metadata +9 -6
@@ -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'
|
@@ -30,7 +34,15 @@ module GrafanaReporter
|
|
30
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}.
|
@@ -31,7 +31,7 @@ module GrafanaReporter
|
|
31
31
|
demo_report = create_demo_report(config)
|
32
32
|
|
33
33
|
demo_report ||= '<<your_report_name>>'
|
34
|
-
config_param = config_file ==
|
34
|
+
config_param = config_file == Configuration::DEFAULT_CONFIG_FILE_NAME ? '' : " -c #{config_file}"
|
35
35
|
program_call = "#{Gem.ruby} #{$PROGRAM_NAME}"
|
36
36
|
program_call = ENV['OCRA_EXECUTABLE'].gsub("#{Dir.pwd}/".gsub('/', '\\'), '') if ENV['OCRA_EXECUTABLE']
|
37
37
|
|
@@ -137,16 +137,8 @@ default-document-attributes:
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
-
# TODO: move this to Asciidoctor::Report class
|
141
|
-
classes = [Asciidoctor::AlertsTableIncludeProcessor, Asciidoctor::AnnotationsTableIncludeProcessor,
|
142
|
-
Asciidoctor::PanelImageBlockMacro, Asciidoctor::PanelImageInlineMacro,
|
143
|
-
Asciidoctor::PanelPropertyInlineMacro, Asciidoctor::PanelQueryTableIncludeProcessor,
|
144
|
-
Asciidoctor::PanelQueryValueInlineMacro, Asciidoctor::SqlTableIncludeProcessor,
|
145
|
-
Asciidoctor::SqlValueInlineMacro, Asciidoctor::ShowHelpIncludeProcessor,
|
146
|
-
Asciidoctor::ShowEnvironmentIncludeProcessor]
|
147
|
-
|
148
140
|
grafana = ::Grafana::Grafana.new(config.grafana_host, config.grafana_api_key)
|
149
|
-
demo_report_content = DemoReportWizard.new(
|
141
|
+
demo_report_content = DemoReportWizard.new(config.report_class.demo_report_classes).build(grafana)
|
150
142
|
|
151
143
|
begin
|
152
144
|
File.write(demo_report_file, demo_report_content, mode: 'w')
|
@@ -26,8 +26,15 @@ module GrafanaReporter
|
|
26
26
|
puts "done - #{(@query_classes - results.keys).length} examples to go"
|
27
27
|
break if (@query_classes - results.keys).empty?
|
28
28
|
end
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
if grafana.dashboard_ids.length > 15 && !(@query_classes - results.keys).empty?
|
31
|
+
puts 'Aborting evaluating further dashboards after 15 samples.'
|
32
|
+
end
|
33
|
+
|
34
|
+
unless (@query_classes - results.keys).empty?
|
35
|
+
puts "For #{(@query_classes - results.keys).length} reporter functionalities no appropriate "\
|
36
|
+
'examples could be found in the configured grafana instance.'
|
37
|
+
end
|
31
38
|
|
32
39
|
format_results(default_result(@query_classes - results.keys).merge(results))
|
33
40
|
end
|
@@ -48,6 +55,8 @@ module GrafanaReporter
|
|
48
55
|
results = {}
|
49
56
|
|
50
57
|
dashboard.panels.shuffle.each do |panel|
|
58
|
+
next if panel.datasource.is_a?(Grafana::UnsupportedDatasource)
|
59
|
+
|
51
60
|
query_classes.each do |query_class|
|
52
61
|
unless query_class.public_instance_methods.include?(:build_demo_entry)
|
53
62
|
results[query_class] = "Method 'build_demo_entry' not implemented for #{query_class.name}"
|
@@ -57,6 +66,11 @@ module GrafanaReporter
|
|
57
66
|
begin
|
58
67
|
result = query_class.new.build_demo_entry(panel)
|
59
68
|
results[query_class] = result if result
|
69
|
+
rescue Grafana::DatasourceDoesNotExistError
|
70
|
+
# properly catch DatasourceDoesNotExist errors here, as they don't lead to a real issue
|
71
|
+
# during demo report creation
|
72
|
+
# This may e.g. happen if a panel asks e.g. for datasource '-- Dashboard --' which is
|
73
|
+
# currently not allowed
|
60
74
|
rescue StandardError => e
|
61
75
|
puts "#{e.message}\n#{e.backtrace.join("\n")}"
|
62
76
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module GrafanaReporter
|
6
|
+
module ERB
|
7
|
+
# Implementation of a specific {AbstractReport}. It is used to
|
8
|
+
# build reports specifically for erb templates.
|
9
|
+
class Report < ::GrafanaReporter::AbstractReport
|
10
|
+
# Starts to create an asciidoctor report. It utilizes all extensions in the {GrafanaReporter::Asciidoctor}
|
11
|
+
# namespace to realize the conversion.
|
12
|
+
# @see AbstractReport#create_report
|
13
|
+
def create_report(template, destination_file_or_path = nil, custom_attributes = {})
|
14
|
+
super
|
15
|
+
attrs = @config.default_document_attributes.merge(@custom_attributes)
|
16
|
+
logger.debug("Document attributes: #{attrs}")
|
17
|
+
|
18
|
+
# TODO: if path is true, a default filename has to be generated. check if this should be a general function instead
|
19
|
+
@report = self
|
20
|
+
File.write(path, ::ERB.new(File.read(template)).result(binding))
|
21
|
+
|
22
|
+
# TODO: check if closing output file is correct here, or maybe can be moved to AbstractReport.done!
|
23
|
+
@destination_file_or_path.close if @destination_file_or_path.is_a?(File)
|
24
|
+
rescue MissingTemplateError => e
|
25
|
+
@logger.error(e.message)
|
26
|
+
@error = [e.message]
|
27
|
+
done!
|
28
|
+
raise e
|
29
|
+
rescue StandardError => e
|
30
|
+
# catch all errors during execution
|
31
|
+
died_with_error(e)
|
32
|
+
raise e
|
33
|
+
ensure
|
34
|
+
done!
|
35
|
+
end
|
36
|
+
|
37
|
+
# @see AbstractReport#demo_report_classes
|
38
|
+
def self.demo_report_classes
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -8,6 +8,14 @@ module GrafanaReporter
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
# Raised if a datasource shall be queried, which is not (yet) supported by the reporter
|
12
|
+
class DatasourceNotSupportedError < GrafanaReporterError
|
13
|
+
def initialize(ds, query)
|
14
|
+
super("The datasource '#{ds.name}' is of type '#{ds.type}' which is currently not supported for "\
|
15
|
+
"the query type '#{query}'.")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
11
19
|
# Thrown, if the requested grafana instance does not have the mandatory 'host'
|
12
20
|
# setting configured.
|
13
21
|
class GrafanaInstanceWithoutHostError < GrafanaReporterError
|
@@ -46,7 +54,7 @@ module GrafanaReporter
|
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
# Thrown, if the value configuration in {
|
57
|
+
# Thrown, if the value configuration in {AbstractQuery#replace_values} is
|
50
58
|
# invalid.
|
51
59
|
class MalformedReplaceValuesStatementError < GrafanaReporterError
|
52
60
|
def initialize(statement)
|
@@ -18,11 +18,6 @@ module GrafanaReporter
|
|
18
18
|
"#{toc}\n\n#{help_text(github_options.merge(level: headline_level))}"
|
19
19
|
end
|
20
20
|
|
21
|
-
# @see AbstractQuery#self.build_demo_entry
|
22
|
-
def self.build_demo_entry(_panel)
|
23
|
-
'include::grafana_help[]'
|
24
|
-
end
|
25
|
-
|
26
21
|
private
|
27
22
|
|
28
23
|
def github_options
|
@@ -134,6 +129,7 @@ end}
|
|
134
129
|
result
|
135
130
|
end
|
136
131
|
|
132
|
+
# TODO: use same wording/grouping as in README file
|
137
133
|
def raw_help_yaml
|
138
134
|
<<~YAML_HELP
|
139
135
|
global_options:
|
File without changes
|
@@ -5,9 +5,9 @@ module GrafanaReporter
|
|
5
5
|
class PanelImageQuery < AbstractQuery
|
6
6
|
# Sets the proper render variables.
|
7
7
|
def pre_process
|
8
|
-
@from = translate_date(@from, @variables['
|
8
|
+
@from = translate_date(@from, @variables['grafana_report_timestamp'], false, @variables['from_timezone'] ||
|
9
9
|
@variables['grafana_default_from_timezone'])
|
10
|
-
@to = translate_date(@to, @variables['
|
10
|
+
@to = translate_date(@to, @variables['grafana_report_timestamp'], true, @variables['to_timezone'] ||
|
11
11
|
@variables['grafana_default_to_timezone'])
|
12
12
|
# TODO: ensure that in case of timezones are specified, that they are also forwarded to the image renderer
|
13
13
|
# rename "render-" variables
|
@@ -8,15 +8,15 @@ module GrafanaReporter
|
|
8
8
|
def pre_process
|
9
9
|
@datasource = @panel.datasource if @panel
|
10
10
|
|
11
|
-
@from = translate_date(@from, @variables['
|
11
|
+
@from = translate_date(@from, @variables['grafana_report_timestamp'], false, @variables['from_timezone'] ||
|
12
12
|
@variables['grafana_default_from_timezone'])
|
13
|
-
@to = translate_date(@to, @variables['
|
13
|
+
@to = translate_date(@to, @variables['grafana_report_timestamp'], true, @variables['to_timezone'] ||
|
14
14
|
@variables['grafana_default_to_timezone'])
|
15
15
|
@variables['result_type'] ||= Variable.new('')
|
16
16
|
end
|
17
17
|
|
18
|
-
# Executes {
|
19
|
-
# {
|
18
|
+
# Executes {AbstractQuery#format_columns}, {AbstractQuery#replace_values} and
|
19
|
+
# {AbstractQuery#filter_columns} on the query results.
|
20
20
|
#
|
21
21
|
# Finally the results are formatted as a asciidoctor table.
|
22
22
|
# @see Grafana::AbstractQuery#post_process
|
@@ -18,12 +18,25 @@ require 'asciidoctor-pdf'
|
|
18
18
|
require 'zip'
|
19
19
|
require_relative 'VERSION'
|
20
20
|
|
21
|
+
# TODO: show error in document, if grafana could not be accessed
|
22
|
+
# TODO: show backtrace in extension error rescues
|
23
|
+
# TODO: improve ERB calls
|
24
|
+
# TODO: add test case for proper image generation
|
25
|
+
# TODO: allow to choose report-class during execution, not mandatory by config file
|
26
|
+
# TODO: add docu for ERB reports
|
27
|
+
# TODO: add docu for custom plugins
|
28
|
+
# TODO: add docu for webhook
|
29
|
+
|
30
|
+
# TODO: enable as asciidoctor extension
|
31
|
+
# TODO: build ADOC template as a result with resolved grafana content for further editing
|
32
|
+
|
21
33
|
folders = [
|
22
34
|
%w[grafana],
|
23
35
|
%w[grafana_reporter logger],
|
24
36
|
%w[grafana_reporter],
|
25
37
|
%w[grafana_reporter asciidoctor extensions],
|
26
38
|
%w[grafana_reporter asciidoctor],
|
39
|
+
%w[grafana_reporter erb],
|
27
40
|
%w[grafana_reporter application]
|
28
41
|
]
|
29
42
|
folders.each { |folder| Dir[File.join(__dir__, *folder, '*.rb')].sort.each { |file| require_relative file } }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-grafana-reporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Kohlmeyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.6'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubyzip
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- "./lib/grafana/panel.rb"
|
125
125
|
- "./lib/grafana/prometheus_datasource.rb"
|
126
126
|
- "./lib/grafana/sql_datasource.rb"
|
127
|
+
- "./lib/grafana/unsupported_datasource.rb"
|
127
128
|
- "./lib/grafana/variable.rb"
|
128
129
|
- "./lib/grafana/webrequest.rb"
|
129
130
|
- "./lib/grafana_reporter/abstract_query.rb"
|
@@ -150,13 +151,15 @@ files:
|
|
150
151
|
- "./lib/grafana_reporter/configuration.rb"
|
151
152
|
- "./lib/grafana_reporter/console_configuration_wizard.rb"
|
152
153
|
- "./lib/grafana_reporter/demo_report_wizard.rb"
|
154
|
+
- "./lib/grafana_reporter/erb/report.rb"
|
153
155
|
- "./lib/grafana_reporter/errors.rb"
|
154
156
|
- "./lib/grafana_reporter/help.rb"
|
155
|
-
- "./lib/grafana_reporter/logger/
|
157
|
+
- "./lib/grafana_reporter/logger/two_way_delegate_logger.rb"
|
156
158
|
- "./lib/grafana_reporter/panel_image_query.rb"
|
157
159
|
- "./lib/grafana_reporter/panel_property_query.rb"
|
158
160
|
- "./lib/grafana_reporter/query_value_query.rb"
|
159
161
|
- "./lib/grafana_reporter/report_webhook.rb"
|
162
|
+
- "./lib/ruby_grafana_extension.rb"
|
160
163
|
- "./lib/ruby_grafana_reporter.rb"
|
161
164
|
- LICENSE
|
162
165
|
- README.md
|
@@ -175,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
175
178
|
requirements:
|
176
179
|
- - ">="
|
177
180
|
- !ruby/object:Gem::Version
|
178
|
-
version: 2.
|
181
|
+
version: '2.5'
|
179
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
183
|
requirements:
|
181
184
|
- - ">="
|