├── dist ├── partials │ ├── query.options.html │ ├── annotations.editor.html │ ├── config.html │ └── query.editor.html ├── plugin.json ├── module.js.map ├── module.js ├── README.md ├── query_ctrl.js.map ├── images │ └── solr.svg ├── query_ctrl.js ├── datasource.js └── datasource.js.map ├── src ├── partials │ ├── query.options.html │ ├── annotations.editor.html │ ├── config.html │ └── query.editor.html ├── plugin.json ├── module.js ├── query_ctrl.js ├── images │ └── solr.svg └── datasource.js ├── .jshintrc ├── .gitignore ├── package.json ├── Gruntfile.js ├── README.md └── LICENSE /dist/partials/query.options.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/partials/query.options.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6, 3 | "node": true 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime* 2 | node_modules 3 | yarn.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /dist/partials/annotations.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /dist/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "datasource", 3 | "name": "Solr", 4 | "id": "pue-solr-datasource", 5 | 6 | "info": { 7 | "description": "Solr datasource", 8 | "author": { 9 | "name": "Sergio Rodriguez de Guzman - PUE Team", 10 | "url": "https://github.com/pueteam" 11 | }, 12 | "keywords": ["solr", "datasource"], 13 | "links": [ 14 | {"name": "Project site", "url": "https://github.com/pueteam/datasource-plugin-solr"}, 15 | {"name": "Apache License", "url": "https://github.com/pueteam/datasource-plugin-solr/blob/master/LICENSE"} 16 | ], 17 | "version": "1.0.2", 18 | "updated": "2018-09-09", 19 | "logos": { 20 | "small": "images/solr.svg", 21 | "large": "images/solr.svg" 22 | } 23 | }, 24 | 25 | "dependencies": { 26 | "grafanaVersion": "3.x.x", 27 | "plugins": [] 28 | }, 29 | 30 | "module": "plugins/pueteam-solr-datasource/module", 31 | "staticRoot": ".", 32 | 33 | "metrics": true, 34 | "annotations": true 35 | } 36 | -------------------------------------------------------------------------------- /src/partials/annotations.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /src/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "datasource", 3 | "name": "Solr", 4 | "id": "pue-solr-datasource", 5 | 6 | "info": { 7 | "description": "Solr datasource", 8 | "author": { 9 | "name": "Sergio Rodriguez de Guzman - PUE Team", 10 | "url": "https://github.com/pueteam" 11 | }, 12 | "keywords": ["solr", "datasource"], 13 | "links": [ 14 | {"name": "Project site", "url": "https://github.com/pueteam/datasource-plugin-solr"}, 15 | {"name": "Apache License", "url": "https://github.com/pueteam/datasource-plugin-solr/blob/master/LICENSE"} 16 | ], 17 | "version": "1.0.2", 18 | "updated": "2018-09-09", 19 | "logos": { 20 | "small": "images/solr.svg", 21 | "large": "images/solr.svg" 22 | } 23 | }, 24 | 25 | "dependencies": { 26 | "grafanaVersion": "3.x.x", 27 | "plugins": [] 28 | }, 29 | 30 | "module": "plugins/pueteam-solr-datasource/module", 31 | "staticRoot": ".", 32 | 33 | "metrics": true, 34 | "annotations": true 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datasource-plugin-solr", 3 | "version": "1.0.0", 4 | "description": "Solr datasource for Grafana 3.x.x", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/pueteam/datasource-plugin-solr" 8 | }, 9 | "author": "Sergio Rodriguez de Guzman", 10 | "license": "Apache-2.0", 11 | "bugs": { 12 | "url": "https://github.com/pueteam/datasource-plugin-solr/issues" 13 | }, 14 | "devDependencies": { 15 | "grunt": "^1.0.1", 16 | "babel-cli": "~6.23.0", 17 | "grunt-babel": "~6.0.0", 18 | "grunt-contrib-clean": "^1.1.0", 19 | "grunt-contrib-compress": "~1.4.3", 20 | "grunt-contrib-copy": "~1.0.0", 21 | "grunt-contrib-watch": "~1.0.0", 22 | "grunt-systemjs-builder": "^1.0.0", 23 | "load-grunt-tasks": "~3.5.2" 24 | }, 25 | "dependencies": { 26 | "babel-plugin-transform-es2015-modules-systemjs": "^6.6.0", 27 | "babel-preset-es2015": "^6.24.1", 28 | "lodash": "^4.17.4" 29 | }, 30 | "homepage": "https://github.com/pueteam/datasource-plugin-solr" 31 | } 32 | -------------------------------------------------------------------------------- /dist/partials/config.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
5 |

Solr settings

6 |
7 |
8 |
9 | Collection Name (Optional) 10 | 11 | 12 |

Specify the default Solr collection if you are going to use Grafana variables.

13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/partials/config.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
5 |

Solr settings

6 |
7 |
8 |
9 | Collection Name (Optional) 10 | 11 | 12 |

Specify the default Solr collection if you are going to use Grafana variables.

13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PUE. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import { 16 | SolrDatasource 17 | } from './datasource'; 18 | import { 19 | SolrQueryCtrl 20 | } from './query_ctrl'; 21 | 22 | class SolrMetricsQueryOptions {} 23 | SolrMetricsQueryOptions.templateUrl = 'partials/query.options.html'; 24 | 25 | class SolrConfigView {} 26 | SolrConfigView.templateUrl = 'partials/config.html'; 27 | 28 | class SolrAnnotationsQueryCtrl {} 29 | SolrAnnotationsQueryCtrl.templateUrl = "partials/annotations.editor.html"; 30 | 31 | export { 32 | SolrDatasource as Datasource, 33 | SolrConfigView as ConfigCtrl, 34 | SolrQueryCtrl as QueryCtrl, 35 | SolrMetricsQueryOptions as QueryOptionsCtrl, 36 | SolrAnnotationsQueryCtrl as AnnotationsQueryCtrl 37 | }; -------------------------------------------------------------------------------- /dist/module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/module.js"],"names":["SolrDatasource","SolrQueryCtrl","SolrMetricsQueryOptions","templateUrl","SolrConfigView","SolrAnnotationsQueryCtrl"],"mappings":";;;;;;;;;;;;;;;AAeEA,oB,eAAAA,c;;AAGAC,mB,eAAAA,a;;;kCAGIC,uB;;;;AACNA,8BAAwBC,WAAxB,GAAsC,6BAAtC;;4BAEMC,c;;;;AACNA,qBAAeD,WAAf,GAA6B,sBAA7B;;sCAEME,wB;;;;AACNA,+BAAyBF,WAAzB,GAAuC,kCAAvC;;4BAGEH,c;;4BACAI,c;;2BACAH,a;;kCACAC,uB;;sCACAG,wB","file":"module.js","sourcesContent":["// Copyright 2018 PUE.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n SolrDatasource\n} from './datasource';\nimport {\n SolrQueryCtrl\n} from './query_ctrl';\n\nclass SolrMetricsQueryOptions {}\nSolrMetricsQueryOptions.templateUrl = 'partials/query.options.html';\n\nclass SolrConfigView {}\nSolrConfigView.templateUrl = 'partials/config.html';\n\nclass SolrAnnotationsQueryCtrl {}\nSolrAnnotationsQueryCtrl.templateUrl = \"partials/annotations.editor.html\";\n\nexport {\n SolrDatasource as Datasource,\n SolrConfigView as ConfigCtrl,\n SolrQueryCtrl as QueryCtrl,\n SolrMetricsQueryOptions as QueryOptionsCtrl,\n SolrAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};"]} -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | pkg: grunt.file.readJSON('package.json'), 7 | 8 | clean: ["dist"], 9 | 10 | copy: { 11 | src_to_dist: { 12 | cwd: 'src', 13 | expand: true, 14 | src: ['**/*', '!**/*.js', '!**/*.scss'], 15 | dest: 'dist' 16 | }, 17 | readme: { 18 | expand: true, 19 | src: ['README.md'], 20 | dest: 'dist', 21 | }, 22 | }, 23 | 24 | watch: { 25 | rebuild_all: { 26 | files: ['src/**/*', 'plugin.json', 'readme.md'], 27 | tasks: ['default'], 28 | options: {spawn: false} 29 | }, 30 | }, 31 | 32 | babel: { 33 | options: { 34 | sourceMap: true, 35 | presets: ["es2015"], 36 | plugins: ['transform-es2015-modules-systemjs', "transform-es2015-for-of"], 37 | }, 38 | dist: { 39 | files: [{ 40 | cwd: 'src', 41 | expand: true, 42 | src: ['**/*.js'], 43 | dest: 'dist', 44 | ext:'.js' 45 | }] 46 | }, 47 | }, 48 | 49 | }); 50 | 51 | grunt.registerTask('default', [ 52 | 'clean', 53 | 'copy:src_to_dist', 54 | 'copy:readme', 55 | 'babel' 56 | ]); 57 | 58 | grunt.registerTask('release', function() { 59 | grunt.config('compress.release', { 60 | options: { 61 | archive: '<%= pkg.name %>-<%= pkg.version %>.tar.gz', 62 | }, 63 | expand: true, 64 | cwd: 'dist', 65 | src: '**/*', 66 | dest: '<%= pkg.name %>-<%= pkg.version %>/', 67 | }); 68 | 69 | grunt.task.run('default'); 70 | grunt.task.run('compress:release'); 71 | }); 72 | 73 | }; 74 | -------------------------------------------------------------------------------- /dist/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['./datasource', './query_ctrl'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var SolrDatasource, SolrQueryCtrl, SolrMetricsQueryOptions, SolrConfigView, SolrAnnotationsQueryCtrl; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | return { 15 | setters: [function (_datasource) { 16 | SolrDatasource = _datasource.SolrDatasource; 17 | }, function (_query_ctrl) { 18 | SolrQueryCtrl = _query_ctrl.SolrQueryCtrl; 19 | }], 20 | execute: function () { 21 | _export('QueryOptionsCtrl', SolrMetricsQueryOptions = function SolrMetricsQueryOptions() { 22 | _classCallCheck(this, SolrMetricsQueryOptions); 23 | }); 24 | 25 | SolrMetricsQueryOptions.templateUrl = 'partials/query.options.html'; 26 | 27 | _export('ConfigCtrl', SolrConfigView = function SolrConfigView() { 28 | _classCallCheck(this, SolrConfigView); 29 | }); 30 | 31 | SolrConfigView.templateUrl = 'partials/config.html'; 32 | 33 | _export('AnnotationsQueryCtrl', SolrAnnotationsQueryCtrl = function SolrAnnotationsQueryCtrl() { 34 | _classCallCheck(this, SolrAnnotationsQueryCtrl); 35 | }); 36 | 37 | SolrAnnotationsQueryCtrl.templateUrl = "partials/annotations.editor.html"; 38 | 39 | _export('Datasource', SolrDatasource); 40 | 41 | _export('ConfigCtrl', SolrConfigView); 42 | 43 | _export('QueryCtrl', SolrQueryCtrl); 44 | 45 | _export('QueryOptionsCtrl', SolrMetricsQueryOptions); 46 | 47 | _export('AnnotationsQueryCtrl', SolrAnnotationsQueryCtrl); 48 | } 49 | }; 50 | }); 51 | //# sourceMappingURL=module.js.map 52 | -------------------------------------------------------------------------------- /src/query_ctrl.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PUE. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import { 16 | QueryCtrl 17 | } from 'app/plugins/sdk'; 18 | 19 | export class SolrQueryCtrl extends QueryCtrl { 20 | /** @ngInject **/ 21 | constructor($scope, $injector) { 22 | super($scope, $injector); 23 | 24 | /* 25 | if (this.target) { 26 | this.target.target = this.target.target || ''; 27 | } 28 | */ 29 | this.scope = $scope; 30 | this.target.target = this.target.target || '*:*'; 31 | this.target.type = this.target.type || 'timeserie'; 32 | this.target.time = this.target.time || ''; 33 | this.target.fields = this.target.fields || ''; 34 | this.target.groupEnabled = this.target.groupEnabled || 'standard'; 35 | this.target.groupValueField = this.target.groupValueField || ''; 36 | this.target.groupByField = this.target.groupByField || ''; 37 | this.target.groupLimit = this.target.groupLimit || 100000; 38 | this.target.collection = this.target.collection || this.datasource.solrCollection || ''; 39 | this.target.solrCloudMode = this.target.solrCloudMode || this.datasource.solrCloudMode || true; 40 | } 41 | getOptions(query) { 42 | return this.datasource.listCollections(query || ''); 43 | } 44 | 45 | listCollection(query) { 46 | return this.datasource.listCollections(query || ''); 47 | } 48 | 49 | listFields(query, collection) { 50 | return this.datasource.listFields(query || '', collection); 51 | } 52 | 53 | toggleEditorMode() { 54 | this.target.rawQuery = !this.target.rawQuery; 55 | } 56 | 57 | onChangeInternal() { 58 | this.panelCtrl.refresh(); // Asks the panel to refresh data. 59 | } 60 | } 61 | 62 | SolrQueryCtrl.templateUrl = 'partials/query.editor.html'; -------------------------------------------------------------------------------- /dist/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 11 | 12 |
13 |
14 | 15 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 25 | 26 |
27 |
28 |
29 |
30 | 31 | 33 | 34 |
35 |
36 | 37 | 39 | 40 |
41 |
42 | 43 | 45 |
46 |
47 |
48 |
49 | 50 | 52 |
53 |
54 |
-------------------------------------------------------------------------------- /src/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 11 | 12 |
13 |
14 | 15 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 25 | 26 |
27 |
28 |
29 |
30 | 31 | 33 | 34 |
35 |
36 | 37 | 39 | 40 |
41 |
42 | 43 | 45 |
46 |
47 |
48 |
49 | 50 | 52 |
53 |
54 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Solr Datasource for Grafana 2 | =========================== 3 | 4 | This plugin for [Grafana](http://grafana.org) provides an advanced datasource for querying Solr server >= 4. This datasource also provides support for the Solr version bundled with [Cloudera CDH 5.X](https://www.cloudera.com). 5 | 6 | This project is open source pursuant to the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). 7 | It is copyright (C) 2018 by PUE Team. 8 | 9 | Installation 10 | ------------ 11 | 12 | The easiest way to install this plugin is to clone or unzip this repository on the grafana plugins folder. For example: 13 | 14 | ```bash 15 | cd /var/lib/grafana/plugins 16 | git clone https://github.com/pueteam/datasource-plugin-solr 17 | ``` 18 | 19 | Then restart grafana to reload the plugins folder. 20 | 21 | Configuration 22 | ------------- 23 | 24 | 1. Add a new datasource and choose "Solr" as the type. 25 | 26 | 2. Fill in the "Url" and other server parameters. If you run Solr in a kerberized cluster, you'll need LDAP authentication enabled, and provide the credentials here. 27 | 28 | 3. Optionally, add the collection to use. This is required if you plan to use templates. 29 | 30 | 4. Click "Test Connection" to verify that you entered the information correctly. 31 | 32 | 5. Cick "Save". 33 | 34 | Queries 35 | ------- 36 | 37 | First, select the query type. You can choose between `standard` and `group`. The `standard` query is the default. 38 | 39 | - **Standard Queries**: The `standard` queries will execute regular queries against Solr. You'll need to fill the `Collection`, the `Timestamp` field, the `Fields` list (space or comma separated) and the `Query` in the Solr format `*:*`. 40 | 41 | - **Group Queries**: The `group` type allows you to group results by `Group By Field` parameter. You'll also need to fill the `Group Value Field` and this parameter should be **numeric**. You can also limit the `Max Group Rows` results. 42 | 43 | Template Support 44 | ---------------- 45 | 46 | This plugin supports Templates/Variables to be used, for example, in the `Query` parameter. You'll need to specify the `Collection` parameter in the `Datasource` parameters. 47 | 48 | ```bash 49 | CR:$CR AND city:$city 50 | ``` 51 | 52 | Autocompletion Support 53 | ---------------------- 54 | 55 | This plugin supports auto completion for the Query Parameters. 56 | 57 | Annotation Support 58 | ------------------ 59 | 60 | This plugin also supports Annotations. You'll need to provide: 61 | 62 | - Collection 63 | - Query 64 | - Tags 65 | - Title 66 | - Text 67 | - Time 68 | 69 | Development 70 | ----------- 71 | 72 | To compile, run the following commands: 73 | 74 | ```bash 75 | npm install 76 | grunt 77 | ``` 78 | 79 | To install in your Grafana server locally, either point Grafana at the repository directory by 80 | editing `grafana.ini` to contain: 81 | 82 | ```bash 83 | [plugin.solr] 84 | path = /path/to/some/directory/datasource-plugin-solr 85 | ``` 86 | 87 | Or symlink the repository directory into the Grafana server's plugin directory: 88 | 89 | ```bash 90 | cd /path/to/grafana/data/plugins 91 | ln -s /path/to/some/directory/datasource-plugin-solr . 92 | ``` 93 | 94 | Then restart the Grafana server. 95 | 96 | Contributors 97 | ------------ 98 | 99 | - Sergio Rodriguez de Guzman 100 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | Solr Datasource for Grafana 2 | =========================== 3 | 4 | This plugin for [Grafana](http://grafana.org) provides an advanced datasource for querying Solr server >= 4. This datasource also provides support for the Solr version bundled with [Cloudera CDH 5.X](https://www.cloudera.com). 5 | 6 | This project is open source pursuant to the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). 7 | It is copyright (C) 2018 by PUE Team. 8 | 9 | Installation 10 | ------------ 11 | 12 | The easiest way to install this plugin is to clone or unzip this repository on the grafana plugins folder. For example: 13 | 14 | ```bash 15 | cd /var/lib/grafana/plugins 16 | git clone https://github.com/pueteam/datasource-plugin-solr 17 | ``` 18 | 19 | Then restart grafana to reload the plugins folder. 20 | 21 | Configuration 22 | ------------- 23 | 24 | 1. Add a new datasource and choose "Solr" as the type. 25 | 26 | 2. Fill in the "Url" and other server parameters. If you run Solr in a kerberized cluster, you'll need LDAP authentication enabled, and provide the credentials here. 27 | 28 | 3. Optionally, add the collection to use. This is required if you plan to use templates. 29 | 30 | 4. Click "Test Connection" to verify that you entered the information correctly. 31 | 32 | 5. Cick "Save". 33 | 34 | Queries 35 | ------- 36 | 37 | First, select the query type. You can choose between `standard` and `group`. The `standard` query is the default. 38 | 39 | - **Standard Queries**: The `standard` queries will execute regular queries against Solr. You'll need to fill the `Collection`, the `Timestamp` field, the `Fields` list (space or comma separated) and the `Query` in the Solr format `*:*`. 40 | 41 | - **Group Queries**: The `group` type allows you to group results by `Group By Field` parameter. You'll also need to fill the `Group Value Field` and this parameter should be **numeric**. You can also limit the `Max Group Rows` results. 42 | 43 | Template Support 44 | ---------------- 45 | 46 | This plugin supports Templates/Variables to be used, for example, in the `Query` parameter. You'll need to specify the `Collection` parameter in the `Datasource` parameters. 47 | 48 | ```bash 49 | CR:$CR AND city:$city 50 | ``` 51 | 52 | Autocompletion Support 53 | ---------------------- 54 | 55 | This plugin supports auto completion for the Query Parameters. 56 | 57 | Annotation Support 58 | ------------------ 59 | 60 | This plugin also supports Annotations. You'll need to provide: 61 | 62 | - Collection 63 | - Query 64 | - Tags 65 | - Title 66 | - Text 67 | - Time 68 | 69 | Development 70 | ----------- 71 | 72 | To compile, run the following commands: 73 | 74 | ```bash 75 | npm install 76 | grunt 77 | ``` 78 | 79 | To install in your Grafana server locally, either point Grafana at the repository directory by 80 | editing `grafana.ini` to contain: 81 | 82 | ```bash 83 | [plugin.solr] 84 | path = /path/to/some/directory/datasource-plugin-solr 85 | ``` 86 | 87 | Or symlink the repository directory into the Grafana server's plugin directory: 88 | 89 | ```bash 90 | cd /path/to/grafana/data/plugins 91 | ln -s /path/to/some/directory/datasource-plugin-solr . 92 | ``` 93 | 94 | Then restart the Grafana server. 95 | 96 | Contributors 97 | ------------ 98 | 99 | - Sergio Rodriguez de Guzman 100 | -------------------------------------------------------------------------------- /dist/query_ctrl.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/query_ctrl.js"],"names":["QueryCtrl","SolrQueryCtrl","$scope","$injector","scope","target","type","time","fields","groupEnabled","groupValueField","groupByField","groupLimit","collection","datasource","solrCollection","solrCloudMode","query","listCollections","listFields","rawQuery","panelCtrl","refresh","templateUrl"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeEA,e,kBAAAA,S;;;;;;;;;;;;;;;;;;;;;+BAGWC,a;;;AACX;AACA,+BAAYC,MAAZ,EAAoBC,SAApB,EAA+B;AAAA;;AAAA,oIACvBD,MADuB,EACfC,SADe;;AAG7B;;;;;AAKA,gBAAKC,KAAL,GAAaF,MAAb;AACA,gBAAKG,MAAL,CAAYA,MAAZ,GAAqB,MAAKA,MAAL,CAAYA,MAAZ,IAAsB,KAA3C;AACA,gBAAKA,MAAL,CAAYC,IAAZ,GAAmB,MAAKD,MAAL,CAAYC,IAAZ,IAAoB,WAAvC;AACA,gBAAKD,MAAL,CAAYE,IAAZ,GAAmB,MAAKF,MAAL,CAAYE,IAAZ,IAAoB,EAAvC;AACA,gBAAKF,MAAL,CAAYG,MAAZ,GAAqB,MAAKH,MAAL,CAAYG,MAAZ,IAAsB,EAA3C;AACA,gBAAKH,MAAL,CAAYI,YAAZ,GAA2B,MAAKJ,MAAL,CAAYI,YAAZ,IAA4B,UAAvD;AACA,gBAAKJ,MAAL,CAAYK,eAAZ,GAA8B,MAAKL,MAAL,CAAYK,eAAZ,IAA+B,EAA7D;AACA,gBAAKL,MAAL,CAAYM,YAAZ,GAA2B,MAAKN,MAAL,CAAYM,YAAZ,IAA4B,EAAvD;AACA,gBAAKN,MAAL,CAAYO,UAAZ,GAAyB,MAAKP,MAAL,CAAYO,UAAZ,IAA0B,MAAnD;AACA,gBAAKP,MAAL,CAAYQ,UAAZ,GAAyB,MAAKR,MAAL,CAAYQ,UAAZ,IAA0B,MAAKC,UAAL,CAAgBC,cAA1C,IAA4D,EAArF;AACA,gBAAKV,MAAL,CAAYW,aAAZ,GAA4B,MAAKX,MAAL,CAAYW,aAAZ,IAA6B,MAAKF,UAAL,CAAgBE,aAA7C,IAA8D,IAA1F;AAlB6B;AAmB9B;;;;qCACUC,K,EAAO;AAChB,mBAAO,KAAKH,UAAL,CAAgBI,eAAhB,CAAgCD,SAAS,EAAzC,CAAP;AACD;;;yCAEcA,K,EAAO;AACpB,mBAAO,KAAKH,UAAL,CAAgBI,eAAhB,CAAgCD,SAAS,EAAzC,CAAP;AACD;;;qCAEUA,K,EAAOJ,U,EAAY;AAC5B,mBAAO,KAAKC,UAAL,CAAgBK,UAAhB,CAA2BF,SAAS,EAApC,EAAwCJ,UAAxC,CAAP;AACD;;;6CAEkB;AACjB,iBAAKR,MAAL,CAAYe,QAAZ,GAAuB,CAAC,KAAKf,MAAL,CAAYe,QAApC;AACD;;;6CAEkB;AACjB,iBAAKC,SAAL,CAAeC,OAAf,GADiB,CACS;AAC3B;;;;QAxCgCtB,S;;;;AA2CnCC,oBAAcsB,WAAd,GAA4B,4BAA5B","file":"query_ctrl.js","sourcesContent":["// Copyright 2018 PUE.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n QueryCtrl\n} from 'app/plugins/sdk';\n\nexport class SolrQueryCtrl extends QueryCtrl {\n /** @ngInject **/\n constructor($scope, $injector) {\n super($scope, $injector);\n\n /*\n if (this.target) {\n this.target.target = this.target.target || '';\n }\n */\n this.scope = $scope;\n this.target.target = this.target.target || '*:*';\n this.target.type = this.target.type || 'timeserie';\n this.target.time = this.target.time || '';\n this.target.fields = this.target.fields || '';\n this.target.groupEnabled = this.target.groupEnabled || 'standard';\n this.target.groupValueField = this.target.groupValueField || '';\n this.target.groupByField = this.target.groupByField || '';\n this.target.groupLimit = this.target.groupLimit || 100000;\n this.target.collection = this.target.collection || this.datasource.solrCollection || '';\n this.target.solrCloudMode = this.target.solrCloudMode || this.datasource.solrCloudMode || true;\n }\n getOptions(query) {\n return this.datasource.listCollections(query || '');\n }\n\n listCollection(query) {\n return this.datasource.listCollections(query || '');\n }\n\n listFields(query, collection) {\n return this.datasource.listFields(query || '', collection);\n }\n\n toggleEditorMode() {\n this.target.rawQuery = !this.target.rawQuery;\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nSolrQueryCtrl.templateUrl = 'partials/query.editor.html';"]} -------------------------------------------------------------------------------- /src/images/solr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/images/solr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/query_ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['app/plugins/sdk'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var QueryCtrl, _createClass, SolrQueryCtrl; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | function _possibleConstructorReturn(self, call) { 15 | if (!self) { 16 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 17 | } 18 | 19 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 20 | } 21 | 22 | function _inherits(subClass, superClass) { 23 | if (typeof superClass !== "function" && superClass !== null) { 24 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 25 | } 26 | 27 | subClass.prototype = Object.create(superClass && superClass.prototype, { 28 | constructor: { 29 | value: subClass, 30 | enumerable: false, 31 | writable: true, 32 | configurable: true 33 | } 34 | }); 35 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 36 | } 37 | 38 | return { 39 | setters: [function (_appPluginsSdk) { 40 | QueryCtrl = _appPluginsSdk.QueryCtrl; 41 | }], 42 | execute: function () { 43 | _createClass = function () { 44 | function defineProperties(target, props) { 45 | for (var i = 0; i < props.length; i++) { 46 | var descriptor = props[i]; 47 | descriptor.enumerable = descriptor.enumerable || false; 48 | descriptor.configurable = true; 49 | if ("value" in descriptor) descriptor.writable = true; 50 | Object.defineProperty(target, descriptor.key, descriptor); 51 | } 52 | } 53 | 54 | return function (Constructor, protoProps, staticProps) { 55 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 56 | if (staticProps) defineProperties(Constructor, staticProps); 57 | return Constructor; 58 | }; 59 | }(); 60 | 61 | _export('SolrQueryCtrl', SolrQueryCtrl = function (_QueryCtrl) { 62 | _inherits(SolrQueryCtrl, _QueryCtrl); 63 | 64 | /** @ngInject **/ 65 | function SolrQueryCtrl($scope, $injector) { 66 | _classCallCheck(this, SolrQueryCtrl); 67 | 68 | var _this = _possibleConstructorReturn(this, (SolrQueryCtrl.__proto__ || Object.getPrototypeOf(SolrQueryCtrl)).call(this, $scope, $injector)); 69 | 70 | /* 71 | if (this.target) { 72 | this.target.target = this.target.target || ''; 73 | } 74 | */ 75 | _this.scope = $scope; 76 | _this.target.target = _this.target.target || '*:*'; 77 | _this.target.type = _this.target.type || 'timeserie'; 78 | _this.target.time = _this.target.time || ''; 79 | _this.target.fields = _this.target.fields || ''; 80 | _this.target.groupEnabled = _this.target.groupEnabled || 'standard'; 81 | _this.target.groupValueField = _this.target.groupValueField || ''; 82 | _this.target.groupByField = _this.target.groupByField || ''; 83 | _this.target.groupLimit = _this.target.groupLimit || 100000; 84 | _this.target.collection = _this.target.collection || _this.datasource.solrCollection || ''; 85 | _this.target.solrCloudMode = _this.target.solrCloudMode || _this.datasource.solrCloudMode || true; 86 | return _this; 87 | } 88 | 89 | _createClass(SolrQueryCtrl, [{ 90 | key: 'getOptions', 91 | value: function getOptions(query) { 92 | return this.datasource.listCollections(query || ''); 93 | } 94 | }, { 95 | key: 'listCollection', 96 | value: function listCollection(query) { 97 | return this.datasource.listCollections(query || ''); 98 | } 99 | }, { 100 | key: 'listFields', 101 | value: function listFields(query, collection) { 102 | return this.datasource.listFields(query || '', collection); 103 | } 104 | }, { 105 | key: 'toggleEditorMode', 106 | value: function toggleEditorMode() { 107 | this.target.rawQuery = !this.target.rawQuery; 108 | } 109 | }, { 110 | key: 'onChangeInternal', 111 | value: function onChangeInternal() { 112 | this.panelCtrl.refresh(); // Asks the panel to refresh data. 113 | } 114 | }]); 115 | 116 | return SolrQueryCtrl; 117 | }(QueryCtrl)); 118 | 119 | _export('SolrQueryCtrl', SolrQueryCtrl); 120 | 121 | SolrQueryCtrl.templateUrl = 'partials/query.editor.html'; 122 | } 123 | }; 124 | }); 125 | //# sourceMappingURL=query_ctrl.js.map 126 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/datasource.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PUE. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import _ from 'lodash'; 16 | import * as $ from 'jquery'; 17 | import moment from 'moment'; 18 | import * as dateMath from 'app/core/utils/datemath'; 19 | 20 | /** @ngInject */ 21 | export class SolrDatasource { 22 | constructor(instanceSettings, $q, backendSrv, templateSrv) { 23 | this.url = instanceSettings.url; 24 | if (this.url.endsWith('/')) { 25 | this.url = this.url.substr(0, this.url.length - 1); 26 | } 27 | this.basicAuth = instanceSettings.basicAuth; 28 | this.withCredentials = instanceSettings.withCredentials; 29 | this.name = instanceSettings.name; 30 | //this.collection = instanceSettings.jsonData.collection; 31 | this.$q = $q; 32 | this.templateSrv = templateSrv; 33 | this.backendSrv = backendSrv; 34 | this.solrCollection = instanceSettings.jsonData.solrCollection; 35 | this.solrCloudMode = instanceSettings.jsonData.solrCloudMode; 36 | 37 | // Helper to make API requests to Solr. To avoid CORS issues, the requests may be proxied 38 | // through Grafana's backend via `backendSrv.datasourceRequest`. 39 | this._request = function (options) { 40 | options.url = this.url + options.url; 41 | options.method = options.method || 'GET'; 42 | options.inspect = { 43 | 'type': 'solr' 44 | }; 45 | 46 | if (this.basicAuth) { 47 | options.withCredentials = true; 48 | options.headers = { 49 | "Authorization": this.basicAuth 50 | }; 51 | } 52 | 53 | return backendSrv.datasourceRequest(options); 54 | }; 55 | } 56 | 57 | // Test the connection to Solr by querying collection response. 58 | testDatasource() { 59 | return this.doRequest({ 60 | url: this.url + '/', 61 | method: 'GET', 62 | }).then(response => { 63 | if (response.status === 200) { 64 | return { 65 | status: "success", 66 | message: "Data source is working", 67 | title: "Success" 68 | }; 69 | } else { 70 | return { 71 | status: "error", 72 | message: "Data source is NOT working", 73 | title: "Error" 74 | }; 75 | } 76 | }); 77 | } 78 | 79 | // Query for metric targets within the specified time range. 80 | // Returns the promise of a result dictionary. 81 | query(queryOptions) { 82 | //console.log('QUERY: ' + JSON.stringify(queryOptions)); 83 | var self = this; 84 | 85 | var targetPromises = _(queryOptions.targets) 86 | .filter(function (target) { 87 | return target.target && !target.hide; 88 | }) 89 | .map(function (target) { 90 | if (!target.collection || !target.time) { 91 | return []; 92 | } 93 | if (target.groupEnabled === 'group' && !target.groupByField) { 94 | return []; 95 | } 96 | //var url = '/api/v' + self.apiVersion + '/timeseries'; 97 | //fq=time:[2018-01-24T02:59:10.000Z TO 2018-01-24T14:59:10.000Z] 98 | var url = '/solr/' + target.collection + '/select'; 99 | //var rows = queryOptions.maxDataPoints || '100000'; 100 | var rows = 100000; 101 | var q = self.templateSrv.replace(target.target, queryOptions.scopedVars); 102 | q = self.queryBuilder(q); 103 | var query = { 104 | wt: 'json', 105 | //query: templateSrv.replace(target.target, queryOptions.scopedVars), 106 | fq: target.time + ':[' + queryOptions.range.from.toJSON() + ' TO ' + queryOptions.range.to.toJSON() + ']', 107 | q: q, 108 | fl: target.time + ',' + target.fields, 109 | rows: rows, 110 | sort: target.time + ' desc' 111 | //from: queryOptions.range.from.toJSON(), 112 | //to: queryOptions.range.to.toJSON(), 113 | }; 114 | if (target.groupEnabled === 'group') { 115 | query.group = true; 116 | query['group.field'] = target.groupByField; 117 | self.groupByField = target.groupByField; 118 | query['group.limit'] = target.groupLimit; 119 | } 120 | 121 | self.time = target.time; 122 | 123 | var requestOptions; 124 | 125 | requestOptions = { 126 | method: 'GET', 127 | url: url, 128 | params: query 129 | }; 130 | 131 | return self._request(requestOptions).then(_.bind(self.convertResponse, self)); 132 | }) 133 | .value(); 134 | 135 | return this.$q.all(targetPromises).then(function (convertedResponses) { 136 | var result = { 137 | data: _.map(convertedResponses, function (convertedResponse) { 138 | return convertedResponse.data; 139 | }) 140 | }; 141 | result.data = _.flatten(result.data); 142 | //console.log('RESULT: ' + JSON.stringify(result)); 143 | return result; 144 | }); 145 | } 146 | 147 | queryBuilder(query) { 148 | return query.replace(/{/g, '(').replace(/}/g, ')').replace(/,/g, ' OR '); 149 | } 150 | 151 | getOptions(query) { 152 | return []; 153 | } 154 | 155 | listCollections(query) { 156 | // solr/admin/collections?action=LIST&wt=json 157 | if (!this.solrCloudMode) { 158 | return []; 159 | } 160 | var url = this.url + '/solr/admin/collections?action=LIST&wt=json'; 161 | var requestOptions; 162 | 163 | requestOptions = { 164 | method: 'GET', 165 | url: url 166 | }; 167 | 168 | return this.doRequest(requestOptions).then(this.mapToTextValue); 169 | } 170 | 171 | listFields(query, collection) { 172 | // solr/admin/collections?action=LIST&wt=json 173 | if (!collection) { 174 | return []; 175 | } 176 | var url = this.url + '/solr/' + collection + '/select?q=*:*&wt=csv&rows=1'; 177 | var requestOptions; 178 | 179 | requestOptions = { 180 | method: 'GET', 181 | url: url 182 | }; 183 | 184 | return this.doRequest(requestOptions).then(this.mapToTextValue); 185 | } 186 | 187 | metricFindQuery(query) { 188 | //q=*:*&facet=true&facet.field=CR&facet.field=product_type&facet.field=provincia&wt=json&rows=0 189 | if (!this.solrCollection) { 190 | return []; 191 | } 192 | var facetFields = query; 193 | var url = this.url + '/solr/' + this.solrCollection + '/select?q=*:*&facet=true&facet.field=' + facetFields + '&wt=json&rows=0'; 194 | 195 | return this.doRequest({ 196 | url: url, 197 | method: 'GET', 198 | }).then(this.mapToTextValue); 199 | } 200 | 201 | mapToTextValue(result) { 202 | if (result.data.collections) { 203 | return result.data.collections.map(function (collection) { 204 | return { 205 | text: collection, 206 | value: collection 207 | }; 208 | }); 209 | } 210 | if (result.data.facet_counts) { 211 | var ar = []; 212 | for (var key in result.data.facet_counts.facet_fields) { 213 | if (result.data.facet_counts.facet_fields.hasOwnProperty(key)) { 214 | var array = result.data.facet_counts.facet_fields[key]; 215 | for (var i = 0; i < array.length; i += 2) { // take every second element 216 | ar.push({ 217 | text: array[i], 218 | expandable: false 219 | }); 220 | } 221 | } 222 | } 223 | return ar; 224 | } 225 | if (result.data) { 226 | return result.data.split('\n')[0].split(',').map(function (field) { 227 | return { 228 | text: field, 229 | value: field 230 | }; 231 | }); 232 | } 233 | } 234 | 235 | convertResponseUngrouped(response) { 236 | var data = response.data; 237 | var seriesList = []; 238 | var series = {}; 239 | var self = this; 240 | _(data.response.docs).forEach(function (item) { 241 | for (var property in item) { 242 | if (item.hasOwnProperty(property) && property != self.time) { 243 | // do stuff 244 | if (typeof (series[property]) === 'undefined') { 245 | series[property] = []; 246 | } 247 | var ts = moment.utc(item[self.time]).unix() * 1000; 248 | series[property].push([item[property] || 0, ts]); 249 | } 250 | } 251 | }); 252 | for (var property in series) { 253 | seriesList.push({ 254 | target: property, 255 | datapoints: series[property].reverse() 256 | }); 257 | } 258 | return { 259 | data: seriesList 260 | }; 261 | } 262 | 263 | convertResponseGrouped(response) { 264 | var data = response.data; 265 | var groupBy = data.responseHeader.params['group.field']; 266 | var seriesList = []; 267 | // Recover the timestamp variable used for filtering 268 | var time = response.data.responseHeader.params.fl.split(',')[0]; 269 | _(data.grouped[groupBy].groups).forEach(function (item) { 270 | var target = item.groupValue || 'N/A'; 271 | var datapoints = []; 272 | for (var i = 0; i < item.doclist.docs.length; i++) { 273 | for (var property in item.doclist.docs[i]) { 274 | if (item.doclist.docs[i].hasOwnProperty(property) && property != time) { 275 | var t = moment.utc(item.doclist.docs[i][time]).unix() * 1000; 276 | datapoints.push([item.doclist.docs[i][property], t]); 277 | } 278 | } 279 | } 280 | seriesList.push({ 281 | target: target, 282 | datapoints: datapoints.reverse() 283 | }); 284 | }); 285 | return { 286 | data: seriesList 287 | }; 288 | } 289 | 290 | convertResponse(response) { 291 | 292 | var data = response.data; 293 | 294 | if (!data) { 295 | return []; 296 | } 297 | 298 | if (data.response) { 299 | return this.convertResponseUngrouped(response); 300 | } 301 | 302 | if (data.grouped) { 303 | return this.convertResponseGrouped(response); 304 | } 305 | 306 | return []; 307 | } 308 | 309 | annotationQuery(options) { 310 | const annotation = options.annotation; 311 | const baseQuery = this.templateSrv.replace(annotation.query, {}, "glob") || "*:*"; 312 | const timeField = annotation.timeField || "timestamp_dt"; 313 | const collection = annotation.collection || "annotations"; 314 | const tagsField = annotation.tagsField || "tags"; 315 | const titleField = annotation.titleField || "desc"; 316 | const textField = annotation.textField || null; 317 | const start = options.range.from.toISOString(); 318 | const end = options.range.to.toISOString(); 319 | const query = { 320 | q: `${baseQuery} AND ${timeField}:[${start} TO ${end}]`, 321 | limit: 10, 322 | wt: 'json', 323 | defType: 'edismax' 324 | }; 325 | 326 | var url = this.url + '/solr/' + collection + '/select'; 327 | 328 | var requestOptions; 329 | 330 | requestOptions = { 331 | method: 'GET', 332 | url: url, 333 | params: query 334 | }; 335 | 336 | return this.doRequest(requestOptions).then((result) => { 337 | return _.map(result.data.response.docs, (doc) => { 338 | return { 339 | annotation: annotation, 340 | time: moment(doc[timeField]).valueOf(), 341 | title: doc[titleField], 342 | tags: doc[tagsField], 343 | text: doc[textField] 344 | }; 345 | }); 346 | }); 347 | } 348 | 349 | doRequest(options) { 350 | options.withCredentials = this.withCredentials; 351 | options.headers = this.headers; 352 | if (this.basicAuth) { 353 | options.withCredentials = true; 354 | options.headers = { 355 | "Authorization": this.basicAuth 356 | }; 357 | } 358 | 359 | return this.backendSrv.datasourceRequest(options); 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /dist/datasource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['lodash', 'jquery', 'moment', 'app/core/utils/datemath'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var _, $, moment, dateMath, _createClass, SolrDatasource; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | return { 15 | setters: [function (_lodash) { 16 | _ = _lodash.default; 17 | }, function (_jquery) { 18 | $ = _jquery; 19 | }, function (_moment) { 20 | moment = _moment.default; 21 | }, function (_appCoreUtilsDatemath) { 22 | dateMath = _appCoreUtilsDatemath; 23 | }], 24 | execute: function () { 25 | _createClass = function () { 26 | function defineProperties(target, props) { 27 | for (var i = 0; i < props.length; i++) { 28 | var descriptor = props[i]; 29 | descriptor.enumerable = descriptor.enumerable || false; 30 | descriptor.configurable = true; 31 | if ("value" in descriptor) descriptor.writable = true; 32 | Object.defineProperty(target, descriptor.key, descriptor); 33 | } 34 | } 35 | 36 | return function (Constructor, protoProps, staticProps) { 37 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 38 | if (staticProps) defineProperties(Constructor, staticProps); 39 | return Constructor; 40 | }; 41 | }(); 42 | 43 | _export('SolrDatasource', SolrDatasource = function () { 44 | function SolrDatasource(instanceSettings, $q, backendSrv, templateSrv) { 45 | _classCallCheck(this, SolrDatasource); 46 | 47 | this.url = instanceSettings.url; 48 | if (this.url.endsWith('/')) { 49 | this.url = this.url.substr(0, this.url.length - 1); 50 | } 51 | this.basicAuth = instanceSettings.basicAuth; 52 | this.withCredentials = instanceSettings.withCredentials; 53 | this.name = instanceSettings.name; 54 | //this.collection = instanceSettings.jsonData.collection; 55 | this.$q = $q; 56 | this.templateSrv = templateSrv; 57 | this.backendSrv = backendSrv; 58 | this.solrCollection = instanceSettings.jsonData.solrCollection; 59 | this.solrCloudMode = instanceSettings.jsonData.solrCloudMode; 60 | 61 | // Helper to make API requests to Solr. To avoid CORS issues, the requests may be proxied 62 | // through Grafana's backend via `backendSrv.datasourceRequest`. 63 | this._request = function (options) { 64 | options.url = this.url + options.url; 65 | options.method = options.method || 'GET'; 66 | options.inspect = { 67 | 'type': 'solr' 68 | }; 69 | 70 | if (this.basicAuth) { 71 | options.withCredentials = true; 72 | options.headers = { 73 | "Authorization": this.basicAuth 74 | }; 75 | } 76 | 77 | return backendSrv.datasourceRequest(options); 78 | }; 79 | } 80 | 81 | // Test the connection to Solr by querying collection response. 82 | 83 | 84 | _createClass(SolrDatasource, [{ 85 | key: 'testDatasource', 86 | value: function testDatasource() { 87 | return this.doRequest({ 88 | url: this.url + '/', 89 | method: 'GET' 90 | }).then(function (response) { 91 | if (response.status === 200) { 92 | return { 93 | status: "success", 94 | message: "Data source is working", 95 | title: "Success" 96 | }; 97 | } else { 98 | return { 99 | status: "error", 100 | message: "Data source is NOT working", 101 | title: "Error" 102 | }; 103 | } 104 | }); 105 | } 106 | }, { 107 | key: 'query', 108 | value: function query(queryOptions) { 109 | //console.log('QUERY: ' + JSON.stringify(queryOptions)); 110 | var self = this; 111 | 112 | var targetPromises = _(queryOptions.targets).filter(function (target) { 113 | return target.target && !target.hide; 114 | }).map(function (target) { 115 | if (!target.collection || !target.time) { 116 | return []; 117 | } 118 | if (target.groupEnabled === 'group' && !target.groupByField) { 119 | return []; 120 | } 121 | //var url = '/api/v' + self.apiVersion + '/timeseries'; 122 | //fq=time:[2018-01-24T02:59:10.000Z TO 2018-01-24T14:59:10.000Z] 123 | var url = '/solr/' + target.collection + '/select?wt=json'; 124 | //var rows = queryOptions.maxDataPoints || '100000'; 125 | var rows = 100000; 126 | var q = self.templateSrv.replace(target.target, queryOptions.scopedVars); 127 | q = self.queryBuilder(q); 128 | var query = { 129 | //query: templateSrv.replace(target.target, queryOptions.scopedVars), 130 | fq: target.time + ':[' + queryOptions.range.from.toJSON() + ' TO ' + queryOptions.range.to.toJSON() + ']', 131 | q: q, 132 | fl: target.time + ',' + target.fields, 133 | rows: rows, 134 | sort: target.time + ' desc' 135 | //from: queryOptions.range.from.toJSON(), 136 | //to: queryOptions.range.to.toJSON(), 137 | }; 138 | if (target.groupEnabled === 'group') { 139 | query.group = true; 140 | query['group.field'] = target.groupByField; 141 | self.groupByField = target.groupByField; 142 | query['group.limit'] = target.groupLimit; 143 | } 144 | 145 | self.time = target.time; 146 | 147 | var requestOptions; 148 | 149 | requestOptions = { 150 | method: 'GET', 151 | url: url, 152 | params: query 153 | }; 154 | 155 | return self._request(requestOptions).then(_.bind(self.convertResponse, self)); 156 | }).value(); 157 | 158 | return this.$q.all(targetPromises).then(function (convertedResponses) { 159 | var result = { 160 | data: _.map(convertedResponses, function (convertedResponse) { 161 | return convertedResponse.data; 162 | }) 163 | }; 164 | result.data = _.flatten(result.data); 165 | //console.log('RESULT: ' + JSON.stringify(result)); 166 | return result; 167 | }); 168 | } 169 | }, { 170 | key: 'queryBuilder', 171 | value: function queryBuilder(query) { 172 | return query.replace(/{/g, '(').replace(/}/g, ')').replace(/,/g, ' OR '); 173 | } 174 | }, { 175 | key: 'getOptions', 176 | value: function getOptions(query) { 177 | return []; 178 | } 179 | }, { 180 | key: 'listCollections', 181 | value: function listCollections(query) { 182 | // solr/admin/collections?action=LIST&wt=json 183 | if (!this.solrCloudMode) { 184 | return []; 185 | } 186 | var url = this.url + '/solr/admin/collections?action=LIST&wt=json'; 187 | var requestOptions; 188 | 189 | requestOptions = { 190 | method: 'GET', 191 | url: url 192 | }; 193 | 194 | return this.doRequest(requestOptions).then(this.mapToTextValue); 195 | } 196 | }, { 197 | key: 'listFields', 198 | value: function listFields(query, collection) { 199 | // solr/admin/collections?action=LIST&wt=json 200 | if (!collection) { 201 | return []; 202 | } 203 | var url = this.url + '/solr/' + collection + '/select?q=*:*&wt=csv&rows=1'; 204 | var requestOptions; 205 | 206 | requestOptions = { 207 | method: 'GET', 208 | url: url 209 | }; 210 | 211 | return this.doRequest(requestOptions).then(this.mapToTextValue); 212 | } 213 | }, { 214 | key: 'metricFindQuery', 215 | value: function metricFindQuery(query) { 216 | //q=*:*&facet=true&facet.field=CR&facet.field=product_type&facet.field=provincia&wt=json&rows=0 217 | if (!this.solrCollection) { 218 | return []; 219 | } 220 | var facetFields = query; 221 | var url = this.url + '/solr/' + this.solrCollection + '/select?q=*:*&facet=true&facet.field=' + facetFields + '&wt=json&rows=0'; 222 | 223 | return this.doRequest({ 224 | url: url, 225 | method: 'GET' 226 | }).then(this.mapToTextValue); 227 | } 228 | }, { 229 | key: 'mapToTextValue', 230 | value: function mapToTextValue(result) { 231 | if (result.data.collections) { 232 | return result.data.collections.map(function (collection) { 233 | return { 234 | text: collection, 235 | value: collection 236 | }; 237 | }); 238 | } 239 | if (result.data.facet_counts) { 240 | var ar = []; 241 | for (var key in result.data.facet_counts.facet_fields) { 242 | if (result.data.facet_counts.facet_fields.hasOwnProperty(key)) { 243 | var array = result.data.facet_counts.facet_fields[key]; 244 | for (var i = 0; i < array.length; i += 2) { 245 | // take every second element 246 | ar.push({ 247 | text: array[i], 248 | expandable: false 249 | }); 250 | } 251 | } 252 | } 253 | return ar; 254 | } 255 | if (result.data) { 256 | return result.data.split('\n')[0].split(',').map(function (field) { 257 | return { 258 | text: field, 259 | value: field 260 | }; 261 | }); 262 | } 263 | } 264 | }, { 265 | key: 'convertResponseUngrouped', 266 | value: function convertResponseUngrouped(response) { 267 | var data = response.data; 268 | var seriesList = []; 269 | var series = {}; 270 | var self = this; 271 | _(data.response.docs).forEach(function (item) { 272 | for (var property in item) { 273 | if (item.hasOwnProperty(property) && property != self.time) { 274 | // do stuff 275 | if (typeof series[property] === 'undefined') { 276 | series[property] = []; 277 | } 278 | var ts = moment.utc(item[self.time]).unix() * 1000; 279 | series[property].push([item[property] || 0, ts]); 280 | } 281 | } 282 | }); 283 | for (var property in series) { 284 | seriesList.push({ 285 | target: property, 286 | datapoints: series[property].reverse() 287 | }); 288 | } 289 | return { 290 | data: seriesList 291 | }; 292 | } 293 | }, { 294 | key: 'convertResponseGrouped', 295 | value: function convertResponseGrouped(response) { 296 | var data = response.data; 297 | var groupBy = data.responseHeader.params['group.field']; 298 | var seriesList = []; 299 | // Recover the timestamp variable used for filtering 300 | var time = response.data.responseHeader.params.fl.split(',')[0]; 301 | _(data.grouped[groupBy].groups).forEach(function (item) { 302 | var target = item.groupValue || 'N/A'; 303 | var datapoints = []; 304 | for (var i = 0; i < item.doclist.docs.length; i++) { 305 | for (var property in item.doclist.docs[i]) { 306 | if (item.doclist.docs[i].hasOwnProperty(property) && property != time) { 307 | var t = moment.utc(item.doclist.docs[i][time]).unix() * 1000; 308 | datapoints.push([item.doclist.docs[i][property], t]); 309 | } 310 | } 311 | } 312 | seriesList.push({ 313 | target: target, 314 | datapoints: datapoints.reverse() 315 | }); 316 | }); 317 | return { 318 | data: seriesList 319 | }; 320 | } 321 | }, { 322 | key: 'convertResponse', 323 | value: function convertResponse(response) { 324 | 325 | var data = response.data; 326 | 327 | if (!data) { 328 | return []; 329 | } 330 | 331 | if (data.response) { 332 | return this.convertResponseUngrouped(response); 333 | } 334 | 335 | if (data.grouped) { 336 | return this.convertResponseGrouped(response); 337 | } 338 | 339 | return []; 340 | } 341 | }, { 342 | key: 'annotationQuery', 343 | value: function annotationQuery(options) { 344 | var annotation = options.annotation; 345 | var baseQuery = this.templateSrv.replace(annotation.query, {}, "glob") || "*:*"; 346 | var timeField = annotation.timeField || "timestamp_dt"; 347 | var collection = annotation.collection || "annotations"; 348 | var tagsField = annotation.tagsField || "tags"; 349 | var titleField = annotation.titleField || "desc"; 350 | var textField = annotation.textField || null; 351 | var start = options.range.from.toISOString(); 352 | var end = options.range.to.toISOString(); 353 | var query = { 354 | q: baseQuery + ' AND ' + timeField + ':[' + start + ' TO ' + end + ']', 355 | limit: 10 356 | }; 357 | 358 | var url = this.url + '/solr/' + collection + '/select?wt=json&defType=edismax'; 359 | 360 | var requestOptions; 361 | 362 | requestOptions = { 363 | method: 'GET', 364 | url: url, 365 | params: query 366 | }; 367 | 368 | return this.doRequest(requestOptions).then(function (result) { 369 | return _.map(result.data.response.docs, function (doc) { 370 | return { 371 | annotation: annotation, 372 | time: moment(doc[timeField]).valueOf(), 373 | title: doc[titleField], 374 | tags: doc[tagsField], 375 | text: doc[textField] 376 | }; 377 | }); 378 | }); 379 | } 380 | }, { 381 | key: 'doRequest', 382 | value: function doRequest(options) { 383 | options.withCredentials = this.withCredentials; 384 | options.headers = this.headers; 385 | if (this.basicAuth) { 386 | options.withCredentials = true; 387 | options.headers = { 388 | "Authorization": this.basicAuth 389 | }; 390 | } 391 | 392 | return this.backendSrv.datasourceRequest(options); 393 | } 394 | }]); 395 | 396 | return SolrDatasource; 397 | }()); 398 | 399 | _export('SolrDatasource', SolrDatasource); 400 | } 401 | }; 402 | }); 403 | //# sourceMappingURL=datasource.js.map 404 | -------------------------------------------------------------------------------- /dist/datasource.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/datasource.js"],"names":["_","$","moment","dateMath","SolrDatasource","instanceSettings","$q","backendSrv","templateSrv","url","endsWith","substr","length","basicAuth","withCredentials","name","solrCollection","jsonData","solrCloudMode","_request","options","method","inspect","headers","datasourceRequest","doRequest","then","response","status","message","title","queryOptions","self","targetPromises","targets","filter","target","hide","map","collection","time","groupEnabled","groupByField","rows","q","replace","scopedVars","queryBuilder","query","fq","range","from","toJSON","to","fl","fields","sort","group","groupLimit","requestOptions","params","bind","convertResponse","value","all","convertedResponses","result","data","convertedResponse","flatten","mapToTextValue","facetFields","collections","text","facet_counts","ar","key","facet_fields","hasOwnProperty","array","i","push","expandable","split","field","seriesList","series","docs","forEach","item","property","ts","utc","unix","datapoints","reverse","groupBy","responseHeader","grouped","groups","groupValue","doclist","t","convertResponseUngrouped","convertResponseGrouped","annotation","baseQuery","timeField","tagsField","titleField","textField","start","toISOString","end","limit","doc","valueOf","tags"],"mappings":"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","file":"datasource.js","sourcesContent":["// Copyright 2018 PUE.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport _ from 'lodash';\nimport * as $ from 'jquery';\nimport moment from 'moment';\nimport * as dateMath from 'app/core/utils/datemath';\n\n/** @ngInject */\nexport class SolrDatasource {\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.url = instanceSettings.url;\n if (this.url.endsWith('/')) {\n this.url = this.url.substr(0, this.url.length - 1);\n }\n this.basicAuth = instanceSettings.basicAuth;\n this.withCredentials = instanceSettings.withCredentials;\n this.name = instanceSettings.name;\n //this.collection = instanceSettings.jsonData.collection;\n this.$q = $q;\n this.templateSrv = templateSrv;\n this.backendSrv = backendSrv;\n this.solrCollection = instanceSettings.jsonData.solrCollection;\n this.solrCloudMode = instanceSettings.jsonData.solrCloudMode;\n\n // Helper to make API requests to Solr. To avoid CORS issues, the requests may be proxied\n // through Grafana's backend via `backendSrv.datasourceRequest`.\n this._request = function (options) {\n options.url = this.url + options.url;\n options.method = options.method || 'GET';\n options.inspect = {\n 'type': 'solr'\n };\n\n if (this.basicAuth) {\n options.withCredentials = true;\n options.headers = {\n \"Authorization\": this.basicAuth\n };\n }\n\n return backendSrv.datasourceRequest(options);\n };\n }\n\n // Test the connection to Solr by querying collection response.\n testDatasource() {\n return this.doRequest({\n url: this.url + '/',\n method: 'GET',\n }).then(response => {\n if (response.status === 200) {\n return {\n status: \"success\",\n message: \"Data source is working\",\n title: \"Success\"\n };\n } else {\n return {\n status: \"error\",\n message: \"Data source is NOT working\",\n title: \"Error\"\n };\n }\n });\n }\n\n // Query for metric targets within the specified time range.\n // Returns the promise of a result dictionary.\n query(queryOptions) {\n //console.log('QUERY: ' + JSON.stringify(queryOptions));\n var self = this;\n\n var targetPromises = _(queryOptions.targets)\n .filter(function (target) {\n return target.target && !target.hide;\n })\n .map(function (target) {\n if (!target.collection || !target.time) {\n return [];\n }\n if (target.groupEnabled === 'group' && !target.groupByField) {\n return [];\n }\n //var url = '/api/v' + self.apiVersion + '/timeseries';\n //fq=time:[2018-01-24T02:59:10.000Z TO 2018-01-24T14:59:10.000Z]\n var url = '/solr/' + target.collection + '/select?wt=json';\n //var rows = queryOptions.maxDataPoints || '100000';\n var rows = 100000;\n var q = self.templateSrv.replace(target.target, queryOptions.scopedVars);\n q = self.queryBuilder(q);\n var query = {\n //query: templateSrv.replace(target.target, queryOptions.scopedVars),\n fq: target.time + ':[' + queryOptions.range.from.toJSON() + ' TO ' + queryOptions.range.to.toJSON() + ']',\n q: q,\n fl: target.time + ',' + target.fields,\n rows: rows,\n sort: target.time + ' desc'\n //from: queryOptions.range.from.toJSON(),\n //to: queryOptions.range.to.toJSON(),\n };\n if (target.groupEnabled === 'group') {\n query.group = true;\n query['group.field'] = target.groupByField;\n self.groupByField = target.groupByField;\n query['group.limit'] = target.groupLimit;\n }\n\n self.time = target.time;\n\n var requestOptions;\n\n requestOptions = {\n method: 'GET',\n url: url,\n params: query\n };\n\n return self._request(requestOptions).then(_.bind(self.convertResponse, self));\n })\n .value();\n\n return this.$q.all(targetPromises).then(function (convertedResponses) {\n var result = {\n data: _.map(convertedResponses, function (convertedResponse) {\n return convertedResponse.data;\n })\n };\n result.data = _.flatten(result.data);\n //console.log('RESULT: ' + JSON.stringify(result));\n return result;\n });\n }\n\n queryBuilder(query) {\n return query.replace(/{/g, '(').replace(/}/g, ')').replace(/,/g, ' OR ');\n }\n\n getOptions(query) {\n return [];\n }\n\n listCollections(query) {\n // solr/admin/collections?action=LIST&wt=json\n if (!this.solrCloudMode) {\n return [];\n }\n var url = this.url + '/solr/admin/collections?action=LIST&wt=json';\n var requestOptions;\n\n requestOptions = {\n method: 'GET',\n url: url\n };\n\n return this.doRequest(requestOptions).then(this.mapToTextValue);\n }\n\n listFields(query, collection) {\n // solr/admin/collections?action=LIST&wt=json\n if (!collection) {\n return [];\n }\n var url = this.url + '/solr/' + collection + '/select?q=*:*&wt=csv&rows=1';\n var requestOptions;\n\n requestOptions = {\n method: 'GET',\n url: url\n };\n\n return this.doRequest(requestOptions).then(this.mapToTextValue);\n }\n\n metricFindQuery(query) {\n //q=*:*&facet=true&facet.field=CR&facet.field=product_type&facet.field=provincia&wt=json&rows=0\n if (!this.solrCollection) {\n return [];\n }\n var facetFields = query;\n var url = this.url + '/solr/' + this.solrCollection + '/select?q=*:*&facet=true&facet.field=' + facetFields + '&wt=json&rows=0';\n\n return this.doRequest({\n url: url,\n method: 'GET',\n }).then(this.mapToTextValue);\n }\n\n mapToTextValue(result) {\n if (result.data.collections) {\n return result.data.collections.map(function (collection) {\n return {\n text: collection,\n value: collection\n };\n });\n }\n if (result.data.facet_counts) {\n var ar = [];\n for (var key in result.data.facet_counts.facet_fields) {\n if (result.data.facet_counts.facet_fields.hasOwnProperty(key)) {\n var array = result.data.facet_counts.facet_fields[key];\n for (var i = 0; i < array.length; i += 2) { // take every second element\n ar.push({\n text: array[i],\n expandable: false\n });\n }\n }\n }\n return ar;\n }\n if (result.data) {\n return result.data.split('\\n')[0].split(',').map(function (field) {\n return {\n text: field,\n value: field\n };\n });\n }\n }\n\n convertResponseUngrouped(response) {\n var data = response.data;\n var seriesList = [];\n var series = {};\n var self = this;\n _(data.response.docs).forEach(function (item) {\n for (var property in item) {\n if (item.hasOwnProperty(property) && property != self.time) {\n // do stuff\n if (typeof (series[property]) === 'undefined') {\n series[property] = [];\n }\n var ts = moment.utc(item[self.time]).unix() * 1000;\n series[property].push([item[property] || 0, ts]);\n }\n }\n });\n for (var property in series) {\n seriesList.push({\n target: property,\n datapoints: series[property].reverse()\n });\n }\n return {\n data: seriesList\n };\n }\n\n convertResponseGrouped(response) {\n var data = response.data;\n var groupBy = data.responseHeader.params['group.field'];\n var seriesList = [];\n // Recover the timestamp variable used for filtering\n var time = response.data.responseHeader.params.fl.split(',')[0];\n _(data.grouped[groupBy].groups).forEach(function (item) {\n var target = item.groupValue || 'N/A';\n var datapoints = [];\n for (var i = 0; i < item.doclist.docs.length; i++) {\n for (var property in item.doclist.docs[i]) {\n if (item.doclist.docs[i].hasOwnProperty(property) && property != time) {\n var t = moment.utc(item.doclist.docs[i][time]).unix() * 1000;\n datapoints.push([item.doclist.docs[i][property], t]);\n }\n }\n }\n seriesList.push({\n target: target,\n datapoints: datapoints.reverse()\n });\n });\n return {\n data: seriesList\n };\n }\n\n convertResponse(response) {\n\n var data = response.data;\n\n if (!data) {\n return [];\n }\n\n if (data.response) {\n return this.convertResponseUngrouped(response);\n }\n\n if (data.grouped) {\n return this.convertResponseGrouped(response);\n }\n\n return [];\n }\n\n annotationQuery(options) {\n const annotation = options.annotation;\n const baseQuery = this.templateSrv.replace(annotation.query, {}, \"glob\") || \"*:*\";\n const timeField = annotation.timeField || \"timestamp_dt\";\n const collection = annotation.collection || \"annotations\";\n const tagsField = annotation.tagsField || \"tags\";\n const titleField = annotation.titleField || \"desc\";\n const textField = annotation.textField || null;\n const start = options.range.from.toISOString();\n const end = options.range.to.toISOString();\n const query = {\n q: `${baseQuery} AND ${timeField}:[${start} TO ${end}]`,\n limit: 10\n };\n\n var url = this.url + '/solr/' + collection + '/select?wt=json&defType=edismax';\n\n var requestOptions;\n\n requestOptions = {\n method: 'GET',\n url: url,\n params: query\n };\n\n return this.doRequest(requestOptions).then((result) => {\n return _.map(result.data.response.docs, (doc) => {\n return {\n annotation: annotation,\n time: moment(doc[timeField]).valueOf(),\n title: doc[titleField],\n tags: doc[tagsField],\n text: doc[textField]\n };\n });\n });\n }\n\n doRequest(options) {\n options.withCredentials = this.withCredentials;\n options.headers = this.headers;\n if (this.basicAuth) {\n options.withCredentials = true;\n options.headers = {\n \"Authorization\": this.basicAuth\n };\n }\n\n return this.backendSrv.datasourceRequest(options);\n }\n}"]} --------------------------------------------------------------------------------