" @@ -64,16 +91,14 @@ function (angular, app, _, kbn, moment) { queries : { mode : 'all', ids : [], - query : 'q=*:*', + query : '*:*', + basic_query : '', custom : '' }, size : 100, // Per page pages : 5, // Pages available offset : 0, - - // sort : ['_score','desc'], sort : ['event_timestamp','desc'], - group : "default", style : {'font-size': '9pt'}, overflow: 'min-height', @@ -86,14 +111,14 @@ function (angular, app, _, kbn, moment) { trimFactor: 300, normTimes : true, spyable : true, - time_field : 'event_timestamp' + time_field : 'event_timestamp', + saveOption : 'json' }; _.defaults($scope.panel,_d); $scope.init = function () { $scope.Math = Math; // Solr - // $scope.sjs = $scope.sjs || sjsResource(config.solr + config.solr_collection); $scope.sjs = $scope.sjs || sjsResource(dashboard.current.solr.server + dashboard.current.solr.core_name); $scope.$on('refresh',function(){$scope.get_data();}); @@ -197,12 +222,8 @@ function (angular, app, _, kbn, moment) { var _segment = _.isUndefined(segment) ? 0 : segment; $scope.segment = _segment; - if(DEBUG) { - var dummy = new Date(dashboard.current.services.filter.list[0].from).toISOString(); - console.log('table: Begin of get_data():\n\t$scope=',$scope,'\n\t$scope.panel=',$scope.panel,'\n\t_segment='+_segment,'\n\tdashboard.indices[_segment]=',dashboard.indices[_segment],'\n\tdashboard=',dashboard,'\n\tdashboard.current.services.filter.list[0].from='+ dummy,'\n\tquerySrv=',querySrv,'\n\tfilterSrv=',filterSrv); - } + if (DEBUG) { console.debug('table: Begin of get_data():\n\t$scope=',$scope,'\n\t$scope.panel=',$scope.panel,'\n\t_segment='+_segment,'\n\tdashboard.indices[_segment]=',dashboard.indices[_segment],'\n\tdashboard=',dashboard,'\n\tquerySrv=',querySrv,'\n\tfilterSrv=',filterSrv); } - // Solr $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); var request = $scope.sjs.Request().indices(dashboard.indices[_segment]); @@ -225,57 +246,15 @@ function (angular, app, _, kbn, moment) { .size($scope.panel.size*$scope.panel.pages) // Set the size of query result .sort($scope.panel.sort[0],$scope.panel.sort[1]); - $scope.populate_modal(request); + $scope.panel_request = request; - // Create a facet to store and pass on time_field value to request.doSearch() - // var facet = $scope.sjs.RangeFacet('time_facet'); - // facet = facet.field($scope.panel.time_field); - // request = request.facet(facet); + if (DEBUG) { console.debug('table:\n\trequest=',request,'\n\trequest.toString()=',request.toString()); } - if (DEBUG) { - console.log('table:\n\trequest=',request,'\n\trequest.toString()=',request.toString()); - } - - // TODO: Parse query here and send to request.doSearch() - // declare default Solr params here - // get query - // get from and to time range - // get query.size - // construct the query - // set queryData - // request = request.setQuery(q); - // TODO: Validate dashboard.current.services.filter.list[0], what if it is not the timestamp field? - // This will cause error. - var start_time = new Date(dashboard.current.services.filter.list[0].from).toISOString(); - var end_time = new Date(dashboard.current.services.filter.list[0].to).toISOString(); - var fq = '&fq=' + $scope.panel.time_field + ':[' + start_time + '%20TO%20' + end_time + ']'; + var fq = '&' + filterSrv.getSolrFq(); var query_size = $scope.panel.size * $scope.panel.pages; - var df = '&df=message&df=host&df=path&df=type'; var wt_json = '&wt=json'; var rows_limit; var sorting = ''; - var filter_fq = ''; - var filter_either = []; - - // Apply filters to the query - _.each(dashboard.current.services.filter.list, function(v,k) { - // Skip the timestamp filter because it's already applied to the query using fq param. - // timestamp filter should be in k = 0 - if (k > 0 && v.field != $scope.panel.time_field && v.active) { - if (DEBUG) { console.log('terms: k=',k,' v=',v); } - if (v.mandate == 'must') { - filter_fq = filter_fq + '&fq=' + v.field + ':"' + v.value + '"'; - } else if (v.mandate == 'mustNot') { - filter_fq = filter_fq + '&fq=-' + v.field + ':"' + v.value + '"'; - } else if (v.mandate == 'either') { - filter_either.push(v.field + ':"' + v.value + '"'); - } - } - }); - // parse filter_either array values, if exists - if (filter_either.length > 0) { - filter_fq = filter_fq + '&fq=(' + filter_either.join(' OR ') + ')'; - } if ($scope.panel.sort[0] !== undefined && $scope.panel.sort[1] !== undefined) { sorting = '&sort=' + $scope.panel.sort[0] + ' ' + $scope.panel.sort[1]; @@ -284,18 +263,18 @@ function (angular, app, _, kbn, moment) { // set the size of query result if (query_size !== undefined && query_size !== 0) { rows_limit = '&rows=' + query_size; - // facet_limit = '&facet.limit=' + query_size; } else { // default rows_limit = '&rows=25'; - // facet_limit = '&facet.limit=10'; } // Set the panel's query - $scope.panel.queries.query = 'q=' + dashboard.current.services.query.list[0].query + df + wt_json + rows_limit + fq + sorting + filter_fq; + $scope.panel.queries.basic_query = querySrv.getQuery(0) + fq + sorting + rows_limit; + $scope.panel.queries.query = $scope.panel.queries.basic_query + wt_json; + + if (DEBUG) { console.debug('table: query=',$scope.panel.queries.query); } // Set the additional custom query if ($scope.panel.queries.custom != null) { - // request = request.customQuery($scope.panel.queries.custom); request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); } else { request = request.setQuery($scope.panel.queries.query); @@ -316,61 +295,31 @@ function (angular, app, _, kbn, moment) { $scope.data = []; } - if(DEBUG) { - console.log('table: results=',results); - console.log('\t_segment='+_segment+', $scope.hits='+$scope.hits+', $scope.data=',$scope.data,', query_id='+query_id+'\n\t$scope.panel',$scope.panel); - } + if(DEBUG) { console.debug('table:\n\tresults=',results,'\n\t_segment=',_segment,', $scope.hits=',$scope.hits,', $scope.data=',$scope.data,', query_id=',query_id,'\n\t$scope.panel',$scope.panel); } // Check for error and abort if found if(!(_.isUndefined(results.error))) { - // $scope.panel.error = $scope.parse_error(results.error); $scope.panel.error = $scope.parse_error(results.error.msg); // There's also results.error.code return; } // Check that we're still on the same query, if not stop if($scope.query_id === query_id) { - // $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) { - $scope.data = $scope.data.concat(_.map(results.response.docs, function(hit) { + $scope.data = $scope.data.concat(_.map(results.response.docs, function(hit) { var _h = _.clone(hit); - //_h._source = kbn.flatten_json(hit._source); - //_h.highlight = kbn.flatten_json(hit.highlight||{}); - - _h.kibana = { - // _source : kbn.flatten_json(hit._source), - // highlight : kbn.flatten_json(hit.highlight||{}) - - // _source : kbn.flatten_json(hit_object), - _source : kbn.flatten_json(hit), - highlight : kbn.flatten_json(hit.highlight||{}) - }; - return _h; - })); + _h.kibana = { + _source : kbn.flatten_json(hit), + highlight : kbn.flatten_json(hit.highlight||{}) + }; + + return _h; + })); // Solr does not need to accumulate hits count because it can get total count // from a single faceted query. - // $scope.hits += results.hits.total; $scope.hits = results.response.numFound; - if (DEBUG) { - console.log('\t$scope.hits='+$scope.hits+', $scope.data=',$scope.data); - } - - // NO NEED for sorting here. Solr result is already sorted. - // Sort the data - // $scope.data = _.sortBy($scope.data, function(v){ - // if(!_.isUndefined(v.sort)) { - // return v.sort[0]; - // } else { - // return 0; - // } - // }); - - // We DO NOT need to reverse here because Solr's result is already sorted. - // if($scope.panel.sort[1] === 'desc') { - // if (DEBUG) { console.log('\tREVERSE IT!!'); } - // $scope.data.reverse(); - // } + if (DEBUG) { console.debug('table: $scope.hits=',$scope.hits,', $scope.data=',$scope.data); } // Keep only what we need for the set $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages); @@ -386,14 +335,41 @@ function (angular, app, _, kbn, moment) { _segment+1 < dashboard.indices.length) { $scope.get_data(_segment+1,$scope.query_id); - if (DEBUG) { - console.log('\tnot sorting in reverse chrono order!'); - } + if (DEBUG) { console.debug('\tnot sorting in reverse chrono order!'); } } }); }; + $scope.exportfile = function(filetype) { + var omitHeader = '&omitHeader=true'; + var exportQuery = $scope.panel.queries.basic_query + '&wt=' + filetype + omitHeader; + var request = $scope.panel_request; + request = request.setQuery(exportQuery); + var response = request.doSearch(); + + response.then(function(response) { + var blob; // the file to be written + // TODO: manipulating solr requests + // pagination (batch downloading) + // example: 1,000,000 rows will explode the memory ! + if(filetype === 'json') { + blob = new Blob([angular.toJson(response,true)], {type: "application/json;charset=utf-8"}); + } else if(filetype === 'csv') { + blob = new Blob([response.toString()], {type: "text/csv;charset=utf-8"}); + } else if(filetype === 'xml'){ + blob = new Blob([response.toString()], {type: "application/xml;charset=utf-8"}); + } else { + // incorrect file type + alert('incorrect file type'); + return false; + } + // from filesaver.js + window.saveAs(blob, "table"+"-"+new Date().getTime()+"."+filetype); + return true; + }); + }; + $scope.populate_modal = function(request) { $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); }; @@ -429,7 +405,6 @@ function (angular, app, _, kbn, moment) { return obj; }; - }); // This also escapes some xml sequences @@ -457,8 +432,6 @@ function (angular, app, _, kbn, moment) { }; }); - - module.filter('tableJson', function() { var json; return function(text,prettyLevel) { @@ -506,4 +479,4 @@ function (angular, app, _, kbn, moment) { }; }); -}); \ No newline at end of file +}); diff --git a/src/app/panels/terms/module.js b/src/app/panels/terms/module.js index 5f2953968..cb5cc7489 100755 --- a/src/app/panels/terms/module.js +++ b/src/app/panels/terms/module.js @@ -48,7 +48,7 @@ function (angular, app, _, $, kbn) { queries : { mode : 'all', ids : [], - query : 'q=*:*', + query : '*:*', custom : '' }, field : 'type', @@ -93,9 +93,7 @@ function (angular, app, _, $, kbn) { //Solr $scope.sjs.client.server(dashboard.current.solr.server + dashboard.current.solr.core_name); - if (DEBUG) { - console.log('terms:\n\tdashboard',dashboard,'\n\tquerySrv=',querySrv,'\n\tfilterSrv=',filterSrv); - } + if (DEBUG) { console.debug('terms:\n\tdashboard',dashboard,'\n\tquerySrv=',querySrv,'\n\tfilterSrv=',filterSrv); } request = $scope.sjs.Request().indices(dashboard.indices); @@ -119,64 +117,30 @@ function (angular, app, _, $, kbn) { filterSrv.getBoolFilter(filterSrv.ids) )))).size(0); - // Use request.size to limit the facet query (is this a good idea?) - request = request.size($scope.panel.size); - // Populate the inspector panel $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - // Create a facet to store and pass on time_field value to request.doSearch() - var facet = $scope.sjs.RangeFacet('time_facet'); - facet = facet.field($scope.panel.time_field); - request = request.facet(facet); - // Build Solr query - // TODO: Validate dashboard.current.services.filter.list[0], what if it is not the timestamp field? - // This will cause error. - var start_time = new Date(dashboard.current.services.filter.list[0].from).toISOString(); - var end_time = new Date(dashboard.current.services.filter.list[0].to).toISOString(); - var fq = '&fq=' + $scope.panel.time_field + ':[' + start_time + '%20TO%20' + end_time + ']'; - // var query_size = $scope.panel.size * $scope.panel.pages; - var df = '&df=message&df=host&df=path&df=type'; + var fq = '&' + filterSrv.getSolrFq(); + var time_field = filterSrv.getTimeField(); + var start_time = filterSrv.getStartTime(); + var end_time = filterSrv.getEndTime(); var wt_json = '&wt=json'; var rows_limit = '&rows=0' // for terms, we do not need the actual response doc, so set rows=0 var facet_gap = '%2B1DAY'; var facet = '&facet=true' + '&facet.field=' + $scope.panel.field + - '&facet.range=' + $scope.panel.time_field + + '&facet.range=' + time_field + '&facet.range.start=' + start_time + '&facet.range.end=' + end_time + '&facet.range.gap=' + facet_gap + '&facet.limit=' + $scope.panel.size; - var filter_fq = ''; - var filter_either = []; - - // Apply filters to the query - _.each(dashboard.current.services.filter.list, function(v,k) { - // Skip the timestamp filter because it's already applied to the query using fq param. - // timestamp filter should be in k = 0 - if (k > 0 && v.field != $scope.panel.time_field && v.active) { - if (DEBUG) { console.log('terms: k=',k,' v=',v); } - if (v.mandate == 'must') { - filter_fq = filter_fq + '&fq=' + v.field + ':"' + v.value + '"'; - } else if (v.mandate == 'mustNot') { - filter_fq = filter_fq + '&fq=-' + v.field + ':"' + v.value + '"'; - } else if (v.mandate == 'either') { - filter_either.push(v.field + ':"' + v.value + '"'); - } - } - }); - // parse filter_either array values, if exists - if (filter_either.length > 0) { - filter_fq = filter_fq + '&fq=(' + filter_either.join(' OR ') + ')'; - } // Set the panel's query - $scope.panel.queries.query = 'q=' + dashboard.current.services.query.list[0].query + df + wt_json + rows_limit + fq + facet + filter_fq; + $scope.panel.queries.query = querySrv.getQuery(0) + wt_json + rows_limit + fq + facet; // Set the additional custom query if ($scope.panel.queries.custom != null) { - // request = request.customQuery($scope.panel.queries.custom); request = request.setQuery($scope.panel.queries.query + $scope.panel.queries.custom); } else { request = request.setQuery($scope.panel.queries.query); @@ -186,21 +150,14 @@ function (angular, app, _, $, kbn) { // Populate scope when we have results results.then(function(results) { - if (DEBUG) { - console.log('terms: results=',results); - } + if (DEBUG) { console.debug('terms: results=',results); } var k = 0; $scope.panelMeta.loading = false; - // $scope.hits = results.hits.total; $scope.hits = results.response.numFound; $scope.data = []; - // _.each(results.facets.terms.terms, function(v) { - // var slice = { label : v.term, data : [[k,v.count]], actions: true}; - // $scope.data.push(slice); - // k = k + 1; - // }); + _.each(results.facet_counts.facet_fields, function(v) { for (var i = 0; i < v.length; i++) { var term = v[i]; @@ -216,12 +173,10 @@ function (angular, app, _, $, kbn) { $scope.data.push({label:'Missing field', // data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); - // TODO: Hard coded to 0 for now. Solr faceting does not provide 'missing' value. data:[[k,0]],meta:"missing",color:'#aaa',opacity:0}); $scope.data.push({label:'Other values', // data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); - // TODO: Hard coded to 0 for now. Solr faceting does not provide 'other' value. data:[[k+1,0]],meta:"other",color:'#444'}); diff --git a/src/app/panels/timepicker/module.html b/src/app/panels/timepicker/module.html index 786bcc447..498e959af 100755 --- a/src/app/panels/timepicker/module.html +++ b/src/app/panels/timepicker/module.html @@ -34,7 +34,7 @@
{{panel.queries.query}}
{{panel.queries.custom}}