ruby-grafana-reporter 0.1.6 → 0.3.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -0
  3. data/README.md +95 -173
  4. data/bin/ruby-grafana-reporter +5 -0
  5. data/lib/VERSION.rb +5 -3
  6. data/lib/grafana/abstract_panel_query.rb +22 -20
  7. data/lib/grafana/abstract_query.rb +132 -127
  8. data/lib/grafana/abstract_sql_query.rb +51 -42
  9. data/lib/grafana/dashboard.rb +77 -66
  10. data/lib/grafana/errors.rb +66 -61
  11. data/lib/grafana/grafana.rb +133 -131
  12. data/lib/grafana/panel.rb +41 -39
  13. data/lib/grafana/panel_image_query.rb +52 -49
  14. data/lib/grafana/variable.rb +217 -259
  15. data/lib/grafana_reporter/abstract_report.rb +112 -109
  16. data/lib/grafana_reporter/application/application.rb +158 -229
  17. data/lib/grafana_reporter/application/errors.rb +33 -30
  18. data/lib/grafana_reporter/application/webservice.rb +230 -0
  19. data/lib/grafana_reporter/asciidoctor/alerts_table_query.rb +101 -99
  20. data/lib/grafana_reporter/asciidoctor/annotations_table_query.rb +96 -96
  21. data/lib/grafana_reporter/asciidoctor/errors.rb +40 -37
  22. data/lib/grafana_reporter/asciidoctor/extensions/alerts_table_include_processor.rb +92 -86
  23. data/lib/grafana_reporter/asciidoctor/extensions/annotations_table_include_processor.rb +91 -86
  24. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_block_macro.rb +69 -67
  25. data/lib/grafana_reporter/asciidoctor/extensions/panel_image_inline_macro.rb +68 -65
  26. data/lib/grafana_reporter/asciidoctor/extensions/panel_property_inline_macro.rb +61 -58
  27. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_table_include_processor.rb +78 -75
  28. data/lib/grafana_reporter/asciidoctor/extensions/panel_query_value_inline_macro.rb +73 -70
  29. data/lib/grafana_reporter/asciidoctor/extensions/processor_mixin.rb +20 -18
  30. data/lib/grafana_reporter/asciidoctor/extensions/show_environment_include_processor.rb +43 -41
  31. data/lib/grafana_reporter/asciidoctor/extensions/show_help_include_processor.rb +30 -202
  32. data/lib/grafana_reporter/asciidoctor/extensions/sql_table_include_processor.rb +70 -67
  33. data/lib/grafana_reporter/asciidoctor/extensions/sql_value_inline_macro.rb +66 -65
  34. data/lib/grafana_reporter/asciidoctor/extensions/value_as_variable_include_processor.rb +88 -57
  35. data/lib/grafana_reporter/asciidoctor/help.rb +435 -0
  36. data/lib/grafana_reporter/asciidoctor/panel_first_value_query.rb +36 -32
  37. data/lib/grafana_reporter/asciidoctor/panel_image_query.rb +28 -23
  38. data/lib/grafana_reporter/asciidoctor/panel_property_query.rb +44 -43
  39. data/lib/grafana_reporter/asciidoctor/panel_table_query.rb +40 -36
  40. data/lib/grafana_reporter/asciidoctor/query_mixin.rb +312 -309
  41. data/lib/grafana_reporter/asciidoctor/report.rb +179 -159
  42. data/lib/grafana_reporter/asciidoctor/sql_first_value_query.rb +42 -34
  43. data/lib/grafana_reporter/asciidoctor/sql_table_query.rb +44 -32
  44. data/lib/grafana_reporter/configuration.rb +304 -326
  45. data/lib/grafana_reporter/console_configuration_wizard.rb +269 -0
  46. data/lib/grafana_reporter/errors.rb +48 -38
  47. data/lib/grafana_reporter/logger/two_way_logger.rb +58 -52
  48. data/lib/ruby-grafana-reporter.rb +32 -27
  49. metadata +116 -16
@@ -1,159 +1,179 @@
1
- module GrafanaReporter
2
- module Asciidoctor
3
- # Implementation of a specific {AbstractReport}. It is used to
4
- # build reports specifically for asciidoctor results.
5
- class Report < GrafanaReporter::AbstractReport
6
- # (see AbstractReport#initialize)
7
- def initialize(config, template, destination_file_or_path = nil, custom_attributes = {})
8
- super
9
- @current_pos = 0
10
- @image_files = []
11
- @grafana_instances = {}
12
- end
13
-
14
- # Starts to create an asciidoctor report. It utilizes all {Extensions} to
15
- # realize the conversion.
16
- # @see AbstractReport#create_report
17
- # @return [void]
18
- def create_report
19
- @start_time = Time.now
20
- attrs = {'convert-backend' => 'pdf'}.merge(@config.default_document_attributes.merge(@custom_attributes))
21
- attrs['grafana-report-timestamp'] = @start_time.to_s
22
- logger.info('Report started at ' + @start_time.to_s)
23
- logger.debug('Document attributes: ' + attrs.to_s)
24
-
25
- initialize_step_counter
26
-
27
- # register necessary extensions for the current report
28
- ::Asciidoctor::LoggerManager.logger = logger
29
-
30
- registry = ::Asciidoctor::Extensions::Registry.new
31
- #TODO dynamically register macros, which is also needed when supporting custom macros
32
- registry.inline_macro Extensions::PanelImageInlineMacro.new.current_report(self)
33
- registry.inline_macro Extensions::PanelQueryValueInlineMacro.new.current_report(self)
34
- registry.inline_macro Extensions::PanelPropertyInlineMacro.new.current_report(self)
35
- registry.inline_macro Extensions::SqlValueInlineMacro.new.current_report(self)
36
- registry.block_macro Extensions::PanelImageBlockMacro.new.current_report(self)
37
- registry.include_processor Extensions::ValueAsVariableIncludeProcessor.new.current_report(self)
38
- registry.include_processor Extensions::PanelQueryTableIncludeProcessor.new.current_report(self)
39
- registry.include_processor Extensions::SqlTableIncludeProcessor.new.current_report(self)
40
- registry.include_processor Extensions::ShowEnvironmentIncludeProcessor.new.current_report(self)
41
- registry.include_processor Extensions::ShowHelpIncludeProcessor.new.current_report(self)
42
- registry.include_processor Extensions::AnnotationsTableIncludeProcessor.new.current_report(self)
43
- registry.include_processor Extensions::AlertsTableIncludeProcessor.new.current_report(self)
44
-
45
- ::Asciidoctor.convert_file(@template, extension_registry: registry, backend: attrs['convert-backend'], to_file: path, attributes: attrs, header_footer: true)
46
-
47
- @destination_file_or_path.close if @destination_file_or_path.is_a?(File)
48
-
49
- # store report including als images as ZIP file, if the result is not a PDF
50
- # TODO add tests for zipping results
51
- if attrs['convert-backend'] != 'pdf'
52
- dest_path = @destination_file_or_path
53
- dest_path = @destination_file_or_path.path if @destination_file_or_path.is_a?(File)
54
-
55
- # build zip file
56
- zip_file = Tempfile.new("gf_zip")
57
- Zip::File.open(zip_file.path, Zip::File::CREATE) do |zipfile|
58
- # add report file
59
- zipfile.get_output_stream(dest_path.gsub(@config.reports_folder, '') + ".#{attrs['convert-backend']}") { |f| f.puts File.read(dest_path) }
60
-
61
- # add image files
62
- @image_files.each do |file|
63
- zipfile.get_output_stream(file.path.gsub(@config.images_folder, '')) { |f| f.puts File.read(file.path) }
64
- end
65
- end
66
-
67
- # replace original file with zip file
68
- zip_file.rewind
69
- begin
70
- File.write(dest_path, zip_file.read)
71
- rescue => e
72
- logger.fatal("Could not overwrite report file '#{dest_path}' with ZIP file. (#{e.message}).")
73
- end
74
-
75
- # cleanup temporary zip file
76
- zip_file.close
77
- zip_file.unlink
78
- end
79
-
80
- clean_image_files
81
- @end_time = Time.now
82
- logger.info('Report finished after ' + (@end_time - @start_time).to_s + ' seconds.')
83
- @done = true
84
- rescue StandardError => e
85
- # catch all errors during execution
86
- died_with_error(e)
87
- raise e
88
- end
89
-
90
- # @see AbstractReport#progress
91
- # @return [Float] number between 0 and 1 reflecting the current progress.
92
- def progress
93
- return 0 if @total_steps.to_i.zero?
94
-
95
- @current_pos.to_f / @total_steps
96
- end
97
-
98
- # @param instance [String] requested grafana instance
99
- # @return [Grafana::Grafana] the requested grafana instance.
100
- def grafana(instance)
101
- unless @grafana_instances[instance]
102
- @grafana_instances[instance] = ::Grafana::Grafana.new(@config.grafana_host(instance), @config.grafana_api_key(instance), logger: @logger, datasources: @config.grafana_datasources(instance))
103
- end
104
- @grafana_instances[instance]
105
- end
106
-
107
- # Increments the progress.
108
- # @return [Integer] number of the current progress position.
109
- def next_step
110
- @current_pos += 1
111
- @current_pos
112
- end
113
-
114
- # Called to save a temporary image file. After the final generation of the
115
- # report, these temporary files will automatically be removed.
116
- # @param img_data [String] image file raw data, which shall be saved
117
- # @return [String] path to the temporary file.
118
- def save_image_file(img_data)
119
- file = Tempfile.new(['gf_image_', '.png'], @config.images_folder.to_s)
120
- file.write(img_data)
121
- path = file.path.gsub(/#{@config.images_folder}/, '')
122
-
123
- @image_files << file
124
- file.close
125
-
126
- path
127
- end
128
-
129
- # Called, if the report generation has died with an error.
130
- # @param e [StandardError] occured error
131
- # @return [void]
132
- def died_with_error(e)
133
- @error = [e.message] << [e.backtrace]
134
- @end_time = Time.now
135
- @done = true
136
- end
137
-
138
- private
139
-
140
- def clean_image_files
141
- @image_files.each(&:unlink)
142
- @image_files = []
143
- end
144
-
145
- def initialize_step_counter
146
- @total_steps = 0
147
- File.readlines(@template).each do |line|
148
- begin
149
- @total_steps += line.gsub(%r{//.*}, '').scan(/(?:grafana_panel_image|grafana_panel_query_value|grafana_panel_query_table|grafana_sql_value|grafana_sql_table|grafana_environment|grafana_help|grafana_panel_property|grafana_annotations|grafana_alerts|grafana_value_as_variable)/).length
150
- rescue => e
151
- logger.error("Could not process line '#{line}' (Error: #{e.message})")
152
- raise e
153
- end
154
- end
155
- logger.debug("Template #{@template} contains #{@total_steps.to_s} calls of grafana reporter functions.")
156
- end
157
- end
158
- end
159
- end
1
+ # frozen_string_literal: true
2
+
3
+ module GrafanaReporter
4
+ module Asciidoctor
5
+ # Implementation of a specific {AbstractReport}. It is used to
6
+ # build reports specifically for asciidoctor results.
7
+ class Report < GrafanaReporter::AbstractReport
8
+ # (see AbstractReport#initialize)
9
+ def initialize(config, template, destination_file_or_path = nil, custom_attributes = {})
10
+ super
11
+ @current_pos = 0
12
+ @image_files = []
13
+ @grafana_instances = {}
14
+ end
15
+
16
+ # Starts to create an asciidoctor report. It utilizes all {Extensions} to
17
+ # realize the conversion.
18
+ # @see AbstractReport#create_report
19
+ # @return [void]
20
+ def create_report
21
+ @start_time = Time.now
22
+ 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
+ logger.debug("Document attributes: #{attrs}")
26
+
27
+ initialize_step_counter
28
+
29
+ # register necessary extensions for the current report
30
+ ::Asciidoctor::LoggerManager.logger = logger
31
+
32
+ registry = ::Asciidoctor::Extensions::Registry.new
33
+ # TODO: dynamically register macros, which is also needed when supporting custom macros
34
+ registry.inline_macro Extensions::PanelImageInlineMacro.new.current_report(self)
35
+ registry.inline_macro Extensions::PanelQueryValueInlineMacro.new.current_report(self)
36
+ registry.inline_macro Extensions::PanelPropertyInlineMacro.new.current_report(self)
37
+ registry.inline_macro Extensions::SqlValueInlineMacro.new.current_report(self)
38
+ registry.block_macro Extensions::PanelImageBlockMacro.new.current_report(self)
39
+ registry.include_processor Extensions::ValueAsVariableIncludeProcessor.new.current_report(self)
40
+ registry.include_processor Extensions::PanelQueryTableIncludeProcessor.new.current_report(self)
41
+ registry.include_processor Extensions::SqlTableIncludeProcessor.new.current_report(self)
42
+ registry.include_processor Extensions::ShowEnvironmentIncludeProcessor.new.current_report(self)
43
+ registry.include_processor Extensions::ShowHelpIncludeProcessor.new.current_report(self)
44
+ registry.include_processor Extensions::AnnotationsTableIncludeProcessor.new.current_report(self)
45
+ registry.include_processor Extensions::AlertsTableIncludeProcessor.new.current_report(self)
46
+
47
+ ::Asciidoctor.convert_file(@template, extension_registry: registry, backend: attrs['convert-backend'],
48
+ to_file: path, attributes: attrs, header_footer: true)
49
+
50
+ @destination_file_or_path.close if @destination_file_or_path.is_a?(File)
51
+
52
+ # store report including als images as ZIP file, if the result is not a PDF
53
+ 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
+ # build zip file
65
+ zip_file = Tempfile.new('gf_zip')
66
+ buffer = Zip::OutputStream.write_buffer do |zipfile|
67
+ # add report file
68
+ zipfile.put_next_entry("#{dest_path.gsub(@config.reports_folder, '')}.#{attrs['convert-backend']}")
69
+ zipfile.write File.read(dest_path)
70
+
71
+ # add image files
72
+ @image_files.each do |file|
73
+ zipfile.put_next_entry(file.path.gsub(@config.images_folder, ''))
74
+ zipfile.write File.read(file.path)
75
+ end
76
+ end
77
+ File.open(zip_file, 'wb') do |f|
78
+ f.write buffer.string
79
+ end
80
+
81
+ # replace original file with zip file
82
+ zip_file.rewind
83
+ begin
84
+ File.write(dest_path, zip_file.read)
85
+ rescue StandardError => e
86
+ logger.fatal("Could not overwrite report file '#{dest_path}' with ZIP file. (#{e.message}).")
87
+ end
88
+
89
+ # cleanup temporary zip file
90
+ zip_file.close
91
+ zip_file.unlink
92
+ end
93
+
94
+ 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
+ end
129
+
130
+ # Called to save a temporary image file. After the final generation of the
131
+ # report, these temporary files will automatically be removed.
132
+ # @param img_data [String] image file raw data, which shall be saved
133
+ # @return [String] path to the temporary file.
134
+ def save_image_file(img_data)
135
+ file = Tempfile.new(['gf_image_', '.png'], @config.images_folder.to_s)
136
+ file.write(img_data)
137
+ path = file.path.gsub(/#{@config.images_folder}/, '')
138
+
139
+ @image_files << file
140
+ file.close
141
+
142
+ path
143
+ end
144
+
145
+ # Called, if the report generation has died with an error.
146
+ # @param error [StandardError] occured error
147
+ # @return [void]
148
+ def died_with_error(error)
149
+ @error = [error.message] << [error.backtrace]
150
+ @end_time = Time.now
151
+ @done = true
152
+ end
153
+
154
+ private
155
+
156
+ def clean_image_files
157
+ @image_files.each(&:unlink)
158
+ @image_files = []
159
+ end
160
+
161
+ def initialize_step_counter
162
+ @total_steps = 0
163
+ File.readlines(@template).each do |line|
164
+ begin
165
+ @total_steps += line.gsub(%r{//.*}, '').scan(/(?:grafana_panel_image|grafana_panel_query_value|
166
+ grafana_panel_query_table|grafana_sql_value|
167
+ grafana_sql_table|grafana_environment|grafana_help|
168
+ grafana_panel_property|grafana_annotations|grafana_alerts|
169
+ grafana_value_as_variable)/x).length
170
+ rescue StandardError => e
171
+ logger.error("Could not process line '#{line}' (Error: #{e.message})")
172
+ raise e
173
+ end
174
+ end
175
+ logger.debug("Template #{@template} contains #{@total_steps} calls of grafana reporter functions.")
176
+ end
177
+ end
178
+ end
179
+ end
@@ -1,34 +1,42 @@
1
- module GrafanaReporter
2
- module Asciidoctor
3
- # This class is being used to execute a SQL query against a grafana datasource.
4
- # Only the first result in the first column will be returned as a single value.
5
- class SqlFirstValueQuery < Grafana::AbstractSqlQuery
6
- include QueryMixin
7
-
8
- # Executes {QueryMixin#format_columns}, {QueryMixin#replace_values} and
9
- # {QueryMixin#filter_columns} on the query results.
10
- #
11
- # Finally only the first value in the first row and the first column of
12
- # will be returned.
13
- # @return [void]
14
- def post_process
15
- results = preformat_sql_result(@result.body)
16
- results = format_columns(results, @variables['format'])
17
- results = replace_values(results, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
18
- results = filter_columns(results, @variables['filter_columns'])
19
- if @variables['filter_column']
20
- @report.logger.warn("DEPRECATED: Call of no longer supported function 'filter_column' has been found. Rename to 'filter_columns'")
21
- results = filter_columns(results, @variables['filter_column'])
22
- end
23
-
24
- unless results[:content].empty?
25
- unless results[:content][0].empty?
26
- @result = results[:content][0][0]
27
- return
28
- end
29
- end
30
- @result = ''
31
- end
32
- end
33
- end
34
- end
1
+ # frozen_string_literal: true
2
+
3
+ module GrafanaReporter
4
+ module Asciidoctor
5
+ # This class is being used to execute a SQL query against a grafana datasource.
6
+ # Only the first result in the first column will be returned as a single value.
7
+ class SqlFirstValueQuery < Grafana::AbstractSqlQuery
8
+ include QueryMixin
9
+
10
+ # Executes {QueryMixin#format_columns}, {QueryMixin#replace_values} and
11
+ # {QueryMixin#filter_columns} on the query results.
12
+ #
13
+ # Finally only the first value in the first row and the first column of
14
+ # will be returned.
15
+ # @return [void]
16
+ def post_process
17
+ results = preformat_sql_result(@result.body)
18
+ results = format_columns(results, @variables['format'])
19
+ results = replace_values(results, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
20
+ results = filter_columns(results, @variables['filter_columns'])
21
+
22
+ @result = ''
23
+ return if results[:content].empty?
24
+ return if results[:content][0].empty?
25
+
26
+ @result = results[:content][0][0]
27
+ end
28
+
29
+ # Translates the from and to times.
30
+ # @see Grafana::AbstractSqlQuery#pre_process
31
+ # @param grafana [Grafana::Grafana] grafana instance against which the query shall be executed
32
+ # @return [void]
33
+ def pre_process(grafana)
34
+ super(grafana)
35
+ @from = translate_date(@from, @variables['grafana-report-timestamp'], false, @variables['from_timezone'] ||
36
+ @variables['grafana_default_from_timezone'])
37
+ @to = translate_date(@to, @variables['grafana-report-timestamp'], true, @variables['to_timezone'] ||
38
+ @variables['grafana_default_to_timezone'])
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,32 +1,44 @@
1
- module GrafanaReporter
2
- module Asciidoctor
3
- # This class is being used to execute a SQL query against a grafana datasource.
4
- # The results will be formatted as as asciidoctor table.
5
- class SqlTableQuery < Grafana::AbstractSqlQuery
6
- include QueryMixin
7
-
8
- # Executes {QueryMixin#format_columns}, {QueryMixin#replace_values} and
9
- # {QueryMixin#filter_columns} on the query results.
10
- #
11
- # Finally the results are formatted as a asciidoctor table.
12
- # @return [void]
13
- def post_process
14
- results = preformat_sql_result(@result.body)
15
- results = format_columns(results, @variables['format'])
16
- results = replace_values(results, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
17
- results = filter_columns(results, @variables['filter_columns'])
18
- if @variables['filter_column']
19
- @report.logger.warn("DEPRECATED: Call of no longer supported function 'filter_column' has been found. Rename to 'filter_columns'")
20
- results = filter_columns(results, @variables['filter_column'])
21
- end
22
- results = transpose(results, @variables['transpose'])
23
- row_divider = '| '
24
- row_divider = @variables['row_divider'].raw_value if @variables['row_divider'].is_a?(Grafana::Variable)
25
- column_divider = ' | '
26
- column_divider = @variables['column_divider'].raw_value if @variables['column_divider'].is_a?(Grafana::Variable)
27
-
28
- @result = results[:content].map { |row| row_divider + row.map { |item| column_divider == ' | ' ? item.to_s.gsub('|', '\\|') : item.to_s }.join(column_divider) }
29
- end
30
- end
31
- end
32
- end
1
+ # frozen_string_literal: true
2
+
3
+ module GrafanaReporter
4
+ module Asciidoctor
5
+ # This class is being used to execute a SQL query against a grafana datasource.
6
+ # The results will be formatted as as asciidoctor table.
7
+ class SqlTableQuery < Grafana::AbstractSqlQuery
8
+ include QueryMixin
9
+
10
+ # Executes {QueryMixin#format_columns}, {QueryMixin#replace_values} and
11
+ # {QueryMixin#filter_columns} on the query results.
12
+ #
13
+ # Finally the results are formatted as a asciidoctor table.
14
+ # @return [void]
15
+ def post_process
16
+ results = preformat_sql_result(@result.body)
17
+ results = format_columns(results, @variables['format'])
18
+ results = replace_values(results, @variables.select { |k, _v| k =~ /^replace_values_\d+/ })
19
+ results = filter_columns(results, @variables['filter_columns'])
20
+ results = transpose(results, @variables['transpose'])
21
+ row_div = @variables['row_divider'].is_a?(Grafana::Variable) ? @variables['row_divider'].raw_value : '| '
22
+ col_div = @variables['column_divider'].is_a?(Grafana::Variable) ? @variables['column_divider'].raw_value : ' | '
23
+
24
+ @result = results[:content].map do |row|
25
+ row_div + row.map do |item|
26
+ col_div == ' | ' ? item.to_s.gsub('|', '\\|') : item.to_s
27
+ end.join(col_div)
28
+ end
29
+ end
30
+
31
+ # Translates the from and to times.
32
+ # @see Grafana::AbstractSqlQuery#pre_process
33
+ # @param grafana [Grafana::Grafana] grafana instance against which the query shall be executed
34
+ # @return [void]
35
+ def pre_process(grafana)
36
+ super(grafana)
37
+ @from = translate_date(@from, @variables['grafana-report-timestamp'], false, @variables['from_timezone'] ||
38
+ @variables['grafana_default_from_timezone'])
39
+ @to = translate_date(@to, @variables['grafana-report-timestamp'], true, @variables['to_timezone'] ||
40
+ @variables['grafana_default_to_timezone'])
41
+ end
42
+ end
43
+ end
44
+ end