ruby-grafana-reporter 0.1.7 → 0.2.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +166 -339
  3. data/bin/ruby-grafana-reporter +5 -4
  4. data/lib/VERSION.rb +5 -3
  5. data/lib/grafana/abstract_panel_query.rb +22 -20
  6. data/lib/grafana/abstract_query.rb +132 -127
  7. data/lib/grafana/abstract_sql_query.rb +51 -42
  8. data/lib/grafana/dashboard.rb +77 -66
  9. data/lib/grafana/errors.rb +66 -61
  10. data/lib/grafana/grafana.rb +130 -131
  11. data/lib/grafana/panel.rb +41 -39
  12. data/lib/grafana/panel_image_query.rb +52 -49
  13. data/lib/grafana/variable.rb +217 -259
  14. data/lib/grafana_reporter/abstract_report.rb +112 -109
  15. data/lib/grafana_reporter/application/application.rb +404 -229
  16. data/lib/grafana_reporter/application/errors.rb +33 -30
  17. data/lib/grafana_reporter/application/webservice.rb +231 -0
  18. data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +104 -99
  19. data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +99 -96
  20. data/lib/grafana_reporter/asciidoctor/errors.rb +40 -37
  21. data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +92 -86
  22. data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +91 -86
  23. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +69 -67
  24. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +68 -65
  25. data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +61 -58
  26. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +78 -75
  27. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +73 -70
  28. data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +20 -18
  29. data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +43 -41
  30. data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +70 -67
  31. data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +66 -65
  32. data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +61 -57
  33. data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +34 -32
  34. data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +25 -23
  35. data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +44 -43
  36. data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +38 -36
  37. data/lib/grafana_reporter/asciidoctor/query_mixin.rb +310 -309
  38. data/lib/grafana_reporter/asciidoctor/report.rb +177 -159
  39. data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +37 -34
  40. data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +39 -32
  41. data/lib/grafana_reporter/configuration.rb +257 -326
  42. data/lib/grafana_reporter/errors.rb +48 -38
  43. data/lib/grafana_reporter/logger/two_way_logger.rb +58 -52
  44. data/lib/ruby-grafana-reporter.rb +29 -27
  45. metadata +10 -23
@@ -1,4 +1,5 @@
1
- #!/usr/bin/env ruby
2
- require_relative '../lib/ruby-grafana-reporter'
3
-
4
- GrafanaReporter::Application::Application.new.configure_and_run(ARGV)
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ruby-grafana-reporter'
5
+ GrafanaReporter::Application::Application.new.configure_and_run(ARGV)
@@ -1,3 +1,5 @@
1
- # Version information
2
- GRAFANA_REPORTER_VERSION = [0, 1, 7].freeze
3
- GRAFANA_REPORTER_RELEASE_DATE = '2020-10-24'
1
+ # frozen_string_literal: true
2
+
3
+ # Version information
4
+ GRAFANA_REPORTER_VERSION = [0, 2, 0].freeze
5
+ GRAFANA_REPORTER_RELEASE_DATE = '2020-11-30'
@@ -1,20 +1,22 @@
1
- require_relative 'abstract_query'
2
-
3
- module Grafana
4
- # @abstract
5
- #
6
- # Used as a superclass for all queries, which rely on a {Panel} object.
7
- #
8
- # @see AbstractQuery
9
- class AbstractPanelQuery < AbstractQuery
10
- attr_reader :panel
11
-
12
- # Initializes the variables of the query using {AbstractQuery#extract_dashboard_variables}.
13
- # @param panel [Panel] panel for which the query shall be executed
14
- def initialize(panel)
15
- super()
16
- @panel = panel
17
- extract_dashboard_variables(@panel.dashboard)
18
- end
19
- end
20
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract_query'
4
+
5
+ module Grafana
6
+ # @abstract
7
+ #
8
+ # Used as a superclass for all queries, which rely on a {Panel} object.
9
+ #
10
+ # @see AbstractQuery
11
+ class AbstractPanelQuery < AbstractQuery
12
+ attr_reader :panel
13
+
14
+ # Initializes the variables of the query using {AbstractQuery#extract_dashboard_variables}.
15
+ # @param panel [Panel] panel for which the query shall be executed
16
+ def initialize(panel)
17
+ super()
18
+ @panel = panel
19
+ extract_dashboard_variables(@panel.dashboard)
20
+ end
21
+ end
22
+ end
@@ -1,127 +1,132 @@
1
- module Grafana
2
- # @abstract Override {#url}, #{#request}, {#pre_process} and {#post_process} in subclass.
3
- #
4
- # Superclass containing everything for all queries towards grafana.
5
- class AbstractQuery
6
- attr_accessor :from, :to, :timeout, :result
7
- attr_reader :variables
8
-
9
- def initialize
10
- @variables = {}
11
- end
12
-
13
- # Runs the whole process to receive values properly from this query:
14
- # - calls {#pre_process}
15
- # - executes this query against the given {Grafana} instance
16
- # - calls {#post_process}
17
- # - returns the result
18
- #
19
- # @param grafana [Grafana] {Grafana} object, against which the query is executed
20
- # @return [Object] result of the query
21
- def execute(grafana)
22
- return @result unless @result.nil?
23
-
24
- pre_process(grafana)
25
- @result = grafana.execute_http_request(url, request, timeout)
26
- post_process
27
- @result
28
- end
29
-
30
- # Used to retrieve default configurations from the given {Dashboard} and store them as settings in the query.
31
- #
32
- # Following data is extracted:
33
- # - +from+, by {Dashboard#from_time}
34
- # - +to+, by {Dashboard#to_time}
35
- # - and all variables as {Variable}, prefixed with +var-+, as grafana also does it
36
- def extract_dashboard_variables(dashboard)
37
- @from = dashboard.from_time
38
- @to = dashboard.to_time
39
- dashboard.variables.each { |item| merge_variables({ "var-#{item.name}": item }) }
40
- self
41
- end
42
-
43
- # Merges the given Hash with the stored variables.
44
- #
45
- # Can be used to easily set many values at once in the local variables hash.
46
- #
47
- # Please note, that the values of the Hash need to be of type {Variable}.
48
- #
49
- # @param hash [Hash<String,Variable>] Hash containing variable name as key and {Variable} as value
50
- # @return [AbstractQuery] this object
51
- def merge_variables(hash)
52
- hash.each do |k, v|
53
- if @variables[k.to_s].nil?
54
- @variables[k.to_s] = v
55
- else
56
- @variables[k.to_s].raw_value = v.raw_value
57
- end
58
- end
59
- self
60
- end
61
-
62
- # @return [Hash<String, Variable>] all grafana variables stored in this query, i.e. the variable name is prefixed with +var-+
63
- def grafana_variables
64
- @variables.select { |k, _v| k =~ /^var-.+/ }
65
- end
66
-
67
- # Replaces the grafana variables in the given string with their replacement value.
68
- #
69
- # @param string [String] string in which the variables shall be replaced
70
- # @param variables [Hash<String,Variable>] Hash containing the variables, which shall be replaced in the given string
71
- # @return [String] string in which all variables are properly replaced
72
- def replace_variables(string, variables = {})
73
- res = string
74
- repeat = true
75
- repeat_count = 0
76
-
77
- # TODO find a proper way to replace variables recursively instead of over and over again
78
- # TODO add tests for recursive replacement of variable
79
- while repeat and repeat_count < 3
80
- repeat = false
81
- repeat_count += 1
82
- variables.each do |var_name, obj|
83
- # only set ticks if value is string
84
- variable = var_name.gsub(/^var-/, '')
85
- res = res.gsub(/(?:\$\{#{variable}(?::(?<format>[\w]+))?\}|(?<!\.)\$#{variable}(?!\.))/) do
86
- obj.value_formatted($~[:format])
87
- end
88
- end
89
- repeat = true if res.include?('$')
90
- end
91
-
92
- res
93
- end
94
-
95
- # @abstract
96
- #
97
- # @return [String] String containing the relative URL to execute the query
98
- def uri
99
- raise NotImplementedError
100
- end
101
-
102
- # @abstract
103
- #
104
- # @return [Hash] Hash containing the request parameters, which shall be overwritten or extended in {Grafana#execute_http_request}
105
- def request
106
- raise NotImplementedError
107
- end
108
-
109
- # @abstract
110
- #
111
- # Use this function to perform all necessary actions, before the query is actually executed.
112
- # Here you can e.g. set values of variables or similar.
113
- #
114
- # @param grafana [Grafana] {Grafana} object, against which the query shall be executed
115
- def pre_process(grafana)
116
- raise NotImplementedError
117
- end
118
-
119
- # @abstract
120
- #
121
- # Use this function to format the raw result of the @result variable to conform to the expected return value.
122
- # You might also want to {#replace_variables} in the @result or similar.
123
- def post_process
124
- raise NotImplementedError
125
- end
126
- end
127
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Grafana
4
+ # @abstract Override {#url}, #{#request}, {#pre_process} and {#post_process} in subclass.
5
+ #
6
+ # Superclass containing everything for all queries towards grafana.
7
+ class AbstractQuery
8
+ attr_accessor :from, :to, :timeout, :result
9
+ attr_reader :variables
10
+
11
+ def initialize
12
+ @variables = {}
13
+ end
14
+
15
+ # Runs the whole process to receive values properly from this query:
16
+ # - calls {#pre_process}
17
+ # - executes this query against the given {Grafana} instance
18
+ # - calls {#post_process}
19
+ # - returns the result
20
+ #
21
+ # @param grafana [Grafana] {Grafana} object, against which the query is executed
22
+ # @return [Object] result of the query
23
+ def execute(grafana)
24
+ return @result unless @result.nil?
25
+
26
+ pre_process(grafana)
27
+ @result = grafana.execute_http_request(url, request, timeout)
28
+ post_process
29
+ @result
30
+ end
31
+
32
+ # Used to retrieve default configurations from the given {Dashboard} and store them as settings in the query.
33
+ #
34
+ # Following data is extracted:
35
+ # - +from+, by {Dashboard#from_time}
36
+ # - +to+, by {Dashboard#to_time}
37
+ # - and all variables as {Variable}, prefixed with +var-+, as grafana also does it
38
+ def extract_dashboard_variables(dashboard)
39
+ @from = dashboard.from_time
40
+ @to = dashboard.to_time
41
+ dashboard.variables.each { |item| merge_variables({ "var-#{item.name}": item }) }
42
+ self
43
+ end
44
+
45
+ # Merges the given Hash with the stored variables.
46
+ #
47
+ # Can be used to easily set many values at once in the local variables hash.
48
+ #
49
+ # Please note, that the values of the Hash need to be of type {Variable}.
50
+ #
51
+ # @param hash [Hash<String,Variable>] Hash containing variable name as key and {Variable} as value
52
+ # @return [AbstractQuery] this object
53
+ def merge_variables(hash)
54
+ hash.each do |k, v|
55
+ if @variables[k.to_s].nil?
56
+ @variables[k.to_s] = v
57
+ else
58
+ @variables[k.to_s].raw_value = v.raw_value
59
+ end
60
+ end
61
+ self
62
+ end
63
+
64
+ # @return [Hash<String, Variable>] all grafana variables stored in this query, i.e. the variable name
65
+ # is prefixed with +var-+
66
+ def grafana_variables
67
+ @variables.select { |k, _v| k =~ /^var-.+/ }
68
+ end
69
+
70
+ # Replaces the grafana variables in the given string with their replacement value.
71
+ #
72
+ # @param string [String] string in which the variables shall be replaced
73
+ # @param variables [Hash<String,Variable>] Hash containing the variables, which shall be replaced in the
74
+ # given string
75
+ # @return [String] string in which all variables are properly replaced
76
+ def replace_variables(string, variables = {})
77
+ res = string
78
+ repeat = true
79
+ repeat_count = 0
80
+
81
+ # TODO: find a proper way to replace variables recursively instead of over and over again
82
+ # TODO: add tests for recursive replacement of variable
83
+ while repeat && (repeat_count < 3)
84
+ repeat = false
85
+ repeat_count += 1
86
+ variables.each do |var_name, obj|
87
+ # only set ticks if value is string
88
+ variable = var_name.gsub(/^var-/, '')
89
+ res = res.gsub(/(?:\$\{#{variable}(?::(?<format>\w+))?\}|(?<!\.)\$#{variable}(?!\.))/) do
90
+ obj.value_formatted($LAST_MATCH_INFO[:format])
91
+ end
92
+ end
93
+ repeat = true if res.include?('$')
94
+ end
95
+
96
+ res
97
+ end
98
+
99
+ # @abstract
100
+ #
101
+ # @return [String] String containing the relative URL to execute the query
102
+ def uri
103
+ raise NotImplementedError
104
+ end
105
+
106
+ # @abstract
107
+ #
108
+ # @return [Hash] Hash containing the request parameters, which shall be overwritten or extended in
109
+ # {Grafana#execute_http_request}
110
+ def request
111
+ raise NotImplementedError
112
+ end
113
+
114
+ # @abstract
115
+ #
116
+ # Use this function to perform all necessary actions, before the query is actually executed.
117
+ # Here you can e.g. set values of variables or similar.
118
+ #
119
+ # @param grafana [Grafana] {Grafana} object, against which the query shall be executed
120
+ def pre_process(grafana)
121
+ raise NotImplementedError
122
+ end
123
+
124
+ # @abstract
125
+ #
126
+ # Use this function to format the raw result of the @result variable to conform to the expected return value.
127
+ # You might also want to {#replace_variables} in the @result or similar.
128
+ def post_process
129
+ raise NotImplementedError
130
+ end
131
+ end
132
+ end
@@ -1,42 +1,51 @@
1
- module Grafana
2
- # @abstract
3
- #
4
- # Used as a superclass for all queries, which execute SQL queries against {Grafana}.
5
- #
6
- # @see AbstractQuery
7
- class AbstractSqlQuery < AbstractQuery
8
- attr_reader :sql, :datasource_id
9
-
10
- # @param raw_sql [String] raw sql statement, as it can be sent to a SQL database
11
- # @param datasource_id [Integer] ID of the datasource against which the query is run
12
- def initialize(raw_sql, datasource_id)
13
- super()
14
- @sql = raw_sql
15
- @datasource_id = datasource_id
16
- end
17
-
18
- # @return [String] relative URL, where the request has to be sent to.
19
- def url
20
- '/api/tsdb/query'
21
- end
22
-
23
- # @return [Hash] request, which executes the SQL statement against the specified datasource
24
- def request
25
- { body: { from: @from, to: @to, queries: [rawSql: @sql, datasourceId: @datasource_id.to_i, format: 'table'] }.to_json, request: Net::HTTP::Post }
26
- end
27
-
28
- # Replaces all variables in the SQL statement.
29
- def pre_process(grafana)
30
- raise MissingSqlQueryError if @sql.nil?
31
- unless grafana.datasource_id_exists?(@datasource_id.to_i)
32
- raise DatasourceDoesNotExistError.new('id', @datasource_id)
33
- end
34
-
35
- @sql = replace_variables(@sql, grafana_variables)
36
- # remove comments in query
37
- @sql.gsub!(/--[^\r\n]*(?:[\r\n]+|$)/, ' ')
38
- @sql.gsub!(/\r\n/, ' ')
39
- @sql.gsub!(/\n/, ' ')
40
- end
41
- end
42
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Grafana
4
+ # @abstract
5
+ #
6
+ # Used as a superclass for all queries, which execute SQL queries against {Grafana}.
7
+ #
8
+ # @see AbstractQuery
9
+ class AbstractSqlQuery < AbstractQuery
10
+ attr_reader :sql, :datasource_id
11
+
12
+ # @param raw_sql [String] raw sql statement, as it can be sent to a SQL database
13
+ # @param datasource_id [Integer] ID of the datasource against which the query is run
14
+ def initialize(raw_sql, datasource_id)
15
+ super()
16
+ @sql = raw_sql
17
+ @datasource_id = datasource_id
18
+ end
19
+
20
+ # @return [String] relative URL, where the request has to be sent to.
21
+ def url
22
+ '/api/tsdb/query'
23
+ end
24
+
25
+ # @return [Hash] request, which executes the SQL statement against the specified datasource
26
+ def request
27
+ {
28
+ body: {
29
+ from: @from,
30
+ to: @to,
31
+ queries: [rawSql: @sql, datasourceId: @datasource_id.to_i, format: 'table']
32
+ }.to_json,
33
+ request: Net::HTTP::Post
34
+ }
35
+ end
36
+
37
+ # Replaces all variables in the SQL statement.
38
+ def pre_process(grafana)
39
+ raise MissingSqlQueryError if @sql.nil?
40
+ unless grafana.datasource_id_exists?(@datasource_id.to_i)
41
+ raise DatasourceDoesNotExistError.new('id', @datasource_id)
42
+ end
43
+
44
+ @sql = replace_variables(@sql, grafana_variables)
45
+ # remove comments in query
46
+ @sql.gsub!(/--[^\r\n]*(?:[\r\n]+|$)/, ' ')
47
+ @sql.gsub!(/\r\n/, ' ')
48
+ @sql.gsub!(/\n/, ' ')
49
+ end
50
+ end
51
+ end
@@ -1,66 +1,77 @@
1
- module Grafana
2
- # Representation of one specific dashboard in a {Grafana} instance.
3
- class Dashboard
4
- # @return [Grafana] parent {Grafana} object
5
- attr_reader :grafana
6
- attr_reader :panels, :variables
7
-
8
- # @param model [Hash] converted JSON Hash of the grafana dashboard
9
- # @param grafana [Grafana] parent {Grafana} object
10
- def initialize(model, grafana)
11
- @grafana = grafana
12
- @model = model
13
-
14
- # read panels
15
- @panels = []
16
- if @model.key?('panels')
17
- @model['panels'].each do |panel|
18
- if panel.key?('panels')
19
- panel['panels'].each do |subpanel|
20
- @panels << Panel.new(subpanel, self)
21
- end
22
- else
23
- @panels << Panel.new(panel, self)
24
- end
25
- end
26
- end
27
-
28
- # store variables in array as objects of type Variable
29
- @variables = []
30
- return unless @model.key?('templating')
31
-
32
- list = @model['templating']['list']
33
- return unless list.is_a? Array
34
-
35
- list.each do |item|
36
- @variables << Variable.new(item)
37
- end
38
- end
39
-
40
- # @return [String] +from+ time configured in the dashboard.
41
- def from_time
42
- return @model['time']['from'] if @model['time']
43
-
44
- nil
45
- end
46
-
47
- # @return [String] +to+ time configured in the dashboard.
48
- def to_time
49
- @model['time']['to'] if @model['time']
50
- nil
51
- end
52
-
53
- # @return [String] dashboard UID
54
- def id
55
- @model['uid']
56
- end
57
-
58
- # @return [Panel] panel for the specified ID
59
- def panel(id)
60
- panels = @panels.select { |item| item.field('id') == id.to_i }
61
- raise PanelDoesNotExistError.new(id, self) if panels.empty?
62
-
63
- panels.first
64
- end
65
- end
66
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Grafana
4
+ # Representation of one specific dashboard in a {Grafana} instance.
5
+ class Dashboard
6
+ # @return [Grafana] parent {Grafana} object
7
+ attr_reader :grafana
8
+ attr_reader :panels, :variables
9
+
10
+ # @param model [Hash] converted JSON Hash of the grafana dashboard
11
+ # @param grafana [Grafana] parent {Grafana} object
12
+ def initialize(model, grafana)
13
+ @grafana = grafana
14
+ @model = model
15
+
16
+ initialize_panels
17
+ initialize_variables
18
+ end
19
+
20
+ # @return [String] +from+ time configured in the dashboard.
21
+ def from_time
22
+ return @model['time']['from'] if @model['time']
23
+
24
+ nil
25
+ end
26
+
27
+ # @return [String] +to+ time configured in the dashboard.
28
+ def to_time
29
+ @model['time']['to'] if @model['time']
30
+ nil
31
+ end
32
+
33
+ # @return [String] dashboard UID
34
+ def id
35
+ @model['uid']
36
+ end
37
+
38
+ # @return [Panel] panel for the specified ID
39
+ def panel(id)
40
+ panels = @panels.select { |item| item.field('id') == id.to_i }
41
+ raise PanelDoesNotExistError.new(id, self) if panels.empty?
42
+
43
+ panels.first
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # store variables in array as objects of type Variable
50
+ def initialize_variables
51
+ @variables = []
52
+ return unless @model.key?('templating')
53
+
54
+ list = @model['templating']['list']
55
+ return unless list.is_a? Array
56
+
57
+ list.each do |item|
58
+ @variables << Variable.new(item)
59
+ end
60
+ end
61
+
62
+ # read panels
63
+ def initialize_panels
64
+ @panels = []
65
+ return unless @model.key?('panels')
66
+
67
+ @model['panels'].each do |panel|
68
+ if panel.key?('panels')
69
+ panel['panels'].each do |subpanel|
70
+ @panels << Panel.new(subpanel, self)
71
+ end
72
+ else
73
+ @panels << Panel.new(panel, self)
74
+ end
75
+ end
76
+ end
77
+ end