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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ed0c1b79ce0e155cc974eaa86c09221e106376660515903765cb9e78e9c00f1
4
- data.tar.gz: 5e6fb779aa14cfbcc75f4f6916b24013fdcb036bf1a9fb46f844bbf0eaa99771
3
+ metadata.gz: '00728deba4250ed327170393bbeaac1b1d6d1002463a5a243285ac570f09231f'
4
+ data.tar.gz: 2985a11f6404e622ff279dbe3e328b38e4202bf665b2fef9e23746bbfd6c3459
5
5
  SHA512:
6
- metadata.gz: caac9139284da4855b6ca4686b4283129ca455ad0ad3b68b0e06c0232e48facacd4e813efe0960cb277f1d8d8ce64e30209af04fd6ab7eadac778a973c0192a3
7
- data.tar.gz: b738db7b1bc73c95369682c977e7db4757920539ec07ba386f7b91af7ea3321403f759a75ad4041c3bd94756eea2c1e70bc24759e9a9ee72fcec871958c3d85f
6
+ metadata.gz: 92de552918a451f9bac1196dfbb05dc1ad64e0059f4c90fe06c079e5e181fee96a07858ae0c5815e3dbf37358c4aa271fcd8d129bb6721f3c8a53f285325fc25
7
+ data.tar.gz: aff95df6e4b5a8636905ec498433d1fcdae6d7b9aa2d26640815a68160c2f74c39078adfbe32a67c9115855ddd97683c6844ea0347e18cf010586e2bd036faed
data/LICENSE CHANGED
File without changes
data/README.md CHANGED
@@ -1,234 +1,155 @@
1
- [![MIT License](https://img.shields.io/github/license/divinity666/ruby-grafana-reporter.svg?style=flat-square)](https://github.com/divinity666/ruby-grafana-reporter/blob/main/LICENSE)
1
+ [![MIT License](https://img.shields.io/github/license/divinity666/ruby-grafana-reporter.svg?style=flat-square)](https://github.com/divinity666/ruby-grafana-reporter/blob/master/LICENSE)
2
+ [![Build Status](https://travis-ci.org/divinity666/ruby-grafana-reporter.svg?branch=master)](https://travis-ci.org/github/divinity666/ruby-grafana-reporter?branch=master)
3
+ [![Coverage Status](https://coveralls.io/repos/github/divinity666/ruby-grafana-reporter/badge.svg?branch=master)](https://coveralls.io/github/divinity666/ruby-grafana-reporter?branch=master)
4
+ [![Gem Version](https://badge.fury.io/rb/ruby-grafana-reporter.svg)](https://badge.fury.io/rb/ruby-grafana-reporter)
2
5
 
3
6
  # Ruby Grafana Reporter
4
- (Asciidoctor) Reporter Service for Grafana
7
+ Reporting Service for Grafana
5
8
 
6
- Did you ever want to create (professional) reports based on Grafana dashboards?
7
- I did so in order to being able to automatically get monthly reports of my
8
- home's energy usage. That's how it started.
9
-
10
- The reporter provides a full extension setup for the famous
11
- [Asciidoctor](https://github.com/asciidoctor/asciidoctor) and can perfectly
12
- integrate in a docker environment.
13
-
14
- As a result of the reporter, you receive PDF documents or any other format that
15
- is supported by [Asciidoctor](https://github.com/asciidoctor/asciidoctor).
16
-
17
- ## Documentation
18
-
19
- Find the complete
20
- [API documentation](https://rubydoc.info/github/divinity666/ruby-grafana-reporter)
21
- at this link.
22
-
23
- ## Installing
24
-
25
- There exist several ways of installing the reporter. All of them have in
26
- common, that they require a working ruby environment. Check with the following
27
- commands, that the tools are setup and run properly:
28
-
29
- ruby -v
30
- gem -v
9
+ ## Table of Contents
31
10
 
32
- Download the ruby grafana reporter to a folder of your choice.
11
+ * [About the project](#about-the-project)
12
+ * [Getting started](#getting-started)
13
+ * [Grafana integration](#grafana-integration)
14
+ * [Webservice overview](#webservice-overview)
15
+ * [Documentation](#documentation)
16
+ * [Features](#features)
17
+ * [Roadmap](#roadmap)
18
+ * [Contributing](#contributing)
19
+ * [Licensing](#licensing)
20
+ * [Acknowledgements](#acknowledgements)
21
+ * [Donations](#donations)
33
22
 
34
- You may want to use the single file application as well. BTW, you may build
35
- your own single file application by calling
23
+ ## About the project
36
24
 
37
- ruby bin/get_single_file_application.rb
38
-
39
- ### Barebone ruby installation
40
-
41
- To install on a plain ruby installation, follow these steps:
25
+ Did you ever want to create (professional) reports based on Grafana dashboards?
26
+ I did so in order to being able to automatically get monthly reports of my
27
+ home's energy usage. That's how it started.
42
28
 
43
- Install asciidoctor
29
+ The reporter provides reporting capabilities for Grafana. It is based on
30
+ (but not limited to) [asciidoctor](https://github.com/asciidoctor/asciidoctor)
31
+ report templates, which can dynamically integrate Grafana panels, queries,
32
+ images etc. to create dynamic PDF reports on the fly.
44
33
 
45
- gem install asciidoctor asciidoctor-pdf zip
34
+ The report may also be returned in any other format that asciidoctor supports.
46
35
 
47
- or simply use
36
+ The reporter can run standalone or as a webservice. It is built to
37
+ integrate without further dependencies with the asciidoctor docker image.
48
38
 
49
- bundle install
39
+ Can't wait to see, what functions the reporter provides within the asciidoctor
40
+ templates? Have a look at the [function documentation](FUNCTION_CALLS.md).
50
41
 
51
- To check if all dependencies are setup properly, run the following command
52
- in that folder:
42
+ ## Getting started
53
43
 
54
- ruby bin/ruby-grafana-reporter.rb -h
44
+ There exist several ways of installing the reporter. If you need further
45
+ installation help, or want to use a "baremetal" ruby setup or a docker
46
+ integration, please have a look at the more extended
47
+ [installation documentation](INSTALL.md).
55
48
 
56
- ### GEM installation
49
+ Windows users may directly use the provided executable.
57
50
 
58
- To install as a gem, simply run:
51
+ Following these steps sets up the reporter on a fresh Raspberry Pi installation:
59
52
 
53
+ sudo apt-get install ruby
60
54
  gem install ruby-grafana-reporter
61
55
 
62
- To see if it works properly, you may run:
63
-
64
- irb
65
- require 'ruby-grafana-reporter'
66
- GrafanaReporter::Application::Application.new.configure_and_run
67
-
68
- The gem installation might mainly be interesting, if you would like to use the
69
- reporter as a library and include it in other application setups.
70
-
71
- ### Docker integration
72
-
73
- Essentially you need to make the application available within your asciidoctor
74
- docker container and run the following command
75
-
76
- ruby bin/ruby-grafana-reporter.rb -h
77
-
78
- If you are unsure, on how to make it available in the container, you may refer
79
- to the information in chapter 'Run as a service' for the docker integration
80
- below.
56
+ That's it. Let's now configure a grafana setup with the configuration wizard:
81
57
 
82
- ## Initial Configuration
58
+ ruby-grafana-reporter -w
83
59
 
84
- Create a first configuration file, named e.g. `myconfig` with the following
85
- content:
60
+ It is strongly recommended, to also create the demo PDF file, as stated at the end
61
+ of the procedure, to get a detailed documentation of all the reporter capabilities.
62
+ The whole [function documentation](FUNCTION_CALLS.md) is also available at the
63
+ previous link.
86
64
 
87
- grafana-reporter:
88
- templates-folder: templates
89
- reports-folder: reports
90
-
91
- grafana:
92
- default:
93
- host: <<url to your grafana host, e.g. https://localhost:3000>>
94
- api_key: <<api key to be used by the reporter>>
95
- datasources: # mandatory, if the api_key has only viewer rights, optional otherwise
96
- "<<data source name in grafana>>": <<data source id in grafana>>
97
-
98
- default-document-attributes:
99
- imagesdir: .
65
+ To run the reporter as a service, you only need to call it like this:
100
66
 
101
- Check out if the configuration is valid and your grafana instance can be accessed
102
- properly.
67
+ ruby-grafana-reporter
103
68
 
104
- ### Barebone ruby installation
69
+ Neat, isn't it?
105
70
 
106
- ruby bin/ruby-grafana-reporter.rb myconfig --test default
71
+ ### Grafana integration
107
72
 
108
- ### GEM installation
73
+ The key feature of the report is, that it can easily be integrated with grafana
74
+ (I've not even been talking about the features it is providing for that, but
75
+ you'll find them having a look in the example results above).
109
76
 
110
- require 'ruby-grafana-reporter'
111
- GrafanaReporter::Application::Application.new.configure_and_run(["myconfig", "--test", "default"])
77
+ For accessing the reporter from grafana, you need to simply add a link to your
78
+ grafana dashboard:
112
79
 
113
- ### Docker integration
80
+ * Open the dashboard configuration
81
+ * Select `Links`
82
+ * Select `Add`
83
+ * Fill out as following:
84
+ * Type: `link`
85
+ * Url: `http://<<your-server-url>>:<<your-webservice-port>>/render?var-template=myfirsttemplate`
86
+ * Title: `MyFirstReport`
87
+ * Select `Time range`
88
+ * Select `Variable values`
89
+ * Select `Add`
114
90
 
115
- Same as in barebone ruby installation. Make sure you are running the command
116
- from inside the container, e.g. by using `docker exec`.
91
+ Now go back to your dashboard and click the newly generated 'MyFirstReport'
92
+ link on it. Now the renderer should start it's task and show you the expected
93
+ results.
117
94
 
118
- ## Hello World example
95
+ But now the fun just starts! Try out the functions stated in the
96
+ 'MyFirstReport' PDF file, to include the dynamic content in your asciidoctor
97
+ template.
119
98
 
120
- Create a first asciidoctor template file in your `templates-folder`, e.g.
121
- `myfirsttemplate.adoc` with the following content:
99
+ Additionally you might want to make the selection of the template variable.
100
+ Piece of cake: Just add a dashboard variable to your grafana dashboard named
101
+ `template` and let the user select or enter a template name. To make use of it,
102
+ you should change the link of the 'MyFirstReport' link to
103
+ `http://<<your-server-url>>:<<your-webservice-port>>/render?`
122
104
 
123
- = First Ruby Grafana Reporter Example
124
-
125
- include::grafana_help[]
105
+ That's it. Let me know your feedback!
126
106
 
127
- include::grafana_environment[]
128
-
129
- Now you're ready to go! Let's check it out!
130
-
131
- ### Barebone ruby installation
132
-
133
- ruby bin/ruby-grafana-reporter.rb myconfig --template myfirsttemplate.adoc --output myfirstrender.pdf
134
-
135
- You should now find a PDF document named `myfirstrender.pdf` which includes a detailed
136
- help page on how to use the ruby grafana reporter functions in asciidoctor, as well
137
- as a list of all environment variables that can be accessed.
138
-
139
- ### GEM installation
140
-
141
- require 'ruby-grafana-reporter'
142
- GrafanaReporter::Application::Application.new.configure_and_run(["myconfig", "--template", "myfirsttemplate.adoc", "--output", "myfirstrender.pdf"])
143
-
144
- ### Docker integration
145
-
146
- Same as in barebone ruby installation. Make sure you are running the command
147
- from inside the container, e.g. by using `docker exec`.
148
-
149
- ## Run as a service
107
+ ## Webservice overview
150
108
 
151
109
  Running the reporter as a webservice provides the following URLs
152
110
 
153
- /render - for rendering a template
154
111
  /overview - for all running or retained renderings
155
- /view_report - for viewing the status or receving the result of a specific rendering
156
- /cancel_report - for cancelling the rendering of a specific report
157
-
158
- ### Barebone ruby installation
159
-
160
- ruby bin/ruby-grafana-reporter.rb myconfig
112
+ /render - for rendering a template, 'var-template' is the only mandatory GET parameter
113
+ /view_report - for viewing the status or receving the result of a specific rendering, is automatically called after a successfull /render call
114
+ /cancel_report - for cancelling the rendering of a specific report, normally not called manually, but on user interaction in the /view_report or /overview URL
161
115
 
162
- Test your configuration by requesting the following URL in a browser of your
163
- choice:
116
+ The main endpoint to call for report generation is configured in the previous chapter [Grafana integration](#grafana-integration).
164
117
 
165
- http://<<your-server-url>>:8815/render?var-template=myfirsttemplate.adoc
118
+ However, if you would like to see, currently running report generations and previously generated reports, you may want to call the endpoint `/overview`.
166
119
 
167
- ### GEM installation
168
-
169
- require 'ruby-grafana-reporter'
170
- GrafanaReporter::Application::Application.new.configure_and_run(["myconfig"])
171
-
172
- Test your configuration by requesting the following URL in a browser of your
173
- choice:
174
-
175
- http://<<your-server-url>>:8815/render?var-template=myfirsttemplate.adoc
176
-
177
- ### Docker integration
178
-
179
- Assuming you have a `docker-compose` setup running, you may want to add the
180
- following to your services secion in your `docker-compose.yml`:
181
-
182
- asciidoctor:
183
- image: asciidoctor/docker-asciidoctor
184
- container_name: asciidoctor
185
- hostname: asciidoctor
186
- volumes:
187
- - /<<an-empty-local-path>>:/documents
188
- command:
189
- sh /documents/startup.sh
190
- restart: unless-stopped
191
-
192
- Additionally you need to create a `startup.sh` file in the folder
193
- `<<an-empty-local-path>>` with the following content:
194
-
195
- cd /documents
196
- ruby bin/ruby-grafana-reporter.rb myconfig
197
-
198
- After restarting the container, the service should be running.
120
+ ## Documentation
199
121
 
200
- Test your configuration by requesting the following URL in a browser of your
201
- choice:
122
+ The [function documentation](FUNCTION_CALLS.md) contains a complete overview of
123
+ all possible grafana calls, to generate dynamic report templates.
202
124
 
203
- http://<<your-server-url>>:8815/render?var-template=myfirsttemplate.adoc
125
+ The [API documentation](https://rubydoc.info/gems/ruby-grafana-reporter) can be
126
+ found here.
204
127
 
205
128
  ## Features
206
129
 
207
- * Integrate grafana panel images, grafana panel query results as table or single values,
208
- custom SQL query results as tables, alers, annotations and many more
209
- * Solid as a rock, also in case of template errors (at least it aims to be)
210
- * Runs standalone or as a webservice
130
+ * Build report template including all imaginable grafana content:
131
+ * panels as images
132
+ * panel table query or custom query results as real document tables (not images!)
133
+ * single panel value or custom query single value result integrated in texts
134
+ * Solid as a rock, also in case of template errors and whatever else may happen
135
+ * Fully controllable as command line application or as a webservice
211
136
  * Seamlessly integrates with asciidoctor docker container
212
- * Developed for being able to support other tools than asciidoctor as well
137
+ * Developed to support other tools than asciidoctor as well
213
138
 
214
139
  ## Roadmap
215
140
 
216
141
  This is just a collection of things, I am heading for in future, without a schedule.
217
142
 
218
- * Add documentation for configuration file
219
- * Share (anonymized) rspec tests in this repo
220
143
  * Add a simple plugin system to support specific asciidoctor modifications
221
144
  * Solve code TODOs
222
145
  * Become [rubocop](https://rubocop.org/) ready
146
+ * Clean and properly setup test cases
223
147
 
224
148
  ## Contributing
225
149
 
226
150
  If you'd like to contribute, please fork the repository and use a feature
227
151
  branch. Pull requests are warmly welcome.
228
152
 
229
- Though not yet valid for my code, I'd like to see the project become
230
- [rubocop](https://rubocop.org/) ready :-)
231
-
232
153
  ## Licensing
233
154
 
234
155
  The code in this project is licensed under MIT license.
@@ -236,6 +157,7 @@ The code in this project is licensed under MIT license.
236
157
  ## Acknowledgements
237
158
  * [asciidoctor](https://github.com/asciidoctor/asciidoctor)
238
159
  * [asciidoctor-pdf](https://github.com/asciidoctor/asciidoctor-pdf)
160
+ * [grafana](https://github.com/grafana/grafana)
239
161
 
240
162
  Inspired by [Izak Marai's grafana reporter](https://github.com/IzakMarais/reporter)
241
163
 
@@ -0,0 +1,5 @@
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) unless defined?(Ocra)
data/lib/VERSION.rb CHANGED
@@ -1,3 +1,5 @@
1
- # Version information
2
- GRAFANA_REPORTER_VERSION = [0, 1, 6].freeze
3
- GRAFANA_REPORTER_RELEASE_DATE = '2020-10-19'
1
+ # frozen_string_literal: true
2
+
3
+ # Version information
4
+ GRAFANA_REPORTER_VERSION = [0, 3, 0].freeze
5
+ GRAFANA_REPORTER_RELEASE_DATE = '2021-03-02'
@@ -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 ? $LAST_MATCH_INFO[:format] : nil)
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