Merge branch 'master' of github.com:elastic/kibana into feature/hapi-server

This commit is contained in:
Chris Cowan 2015-06-15 08:09:34 -07:00
commit 90d4f862a7
18 changed files with 175 additions and 1880 deletions

View file

@ -27,9 +27,9 @@
"angular-mocks": "1.2.28",
"angular-route": "1.2.28",
"angular-ui-ace": "0.2.3",
"bluebird": "~2.1.3",
"bluebird": "~2.9.27",
"bootstrap": "3.3.4",
"d3": "3.4.13",
"d3": "3.5.5",
"elasticsearch": "4.1.0",
"Faker": "1.1.0",
"FileSaver": "babc6d9d8f",

View file

@ -1,7 +1,7 @@
[[kibana-guide]]
= Kibana User Guide
:ref: http://www.elastic.co/guide/en/elasticsearch/reference/current
:ref: http://www.elastic.co/guide/en/elasticsearch/reference/current/
:shield: https://www.elastic.co/guide/en/shield/current
:k4pull: https://github.com/elastic/kibana/pull/

View file

@ -9,7 +9,7 @@ All you need is:
** URL of the Elasticsearch instance you want to connect to.
** Which Elasticsearch indices you want to search.
NOTE: If your Elasticsearch installation is protected by http://www.elastic.co/overview/shield/[Shield] see
NOTE: If your Elasticsearch installation is protected by http://www.elastic.co/overview/shield/[Shield] see
{shield}/_shield_with_kibana_4.html[Shield with Kibana 4] for additional setup instructions.
[float]
@ -22,10 +22,10 @@ To get Kibana up and running:
. Extract the `.zip` or `tar.gz` archive file.
// On Unix, you can instead run the package manager suited for your distribution.
//
//
// [float]
// include::kibana-repositories.asciidoc[]
//
//
After installing, run Kibana from the install directory: `bin/kibana` (Linux/MacOSX) or `bin\kibana.bat` (Windows).
That's it! Kibana is now running on port 5601.
@ -33,12 +33,12 @@ That's it! Kibana is now running on port 5601.
[float]
[[kibana-dynamic-mapping]]
==== Kibana and Elasticsearch Dynamic Mapping
By default, Elasticsearch enables {ref}/dynamic-mapping.html[dynamic mapping] for fields. Kibana needs dynamic mapping
to use fields in visualizations correctly, as well as to manage the `.kibana` index where saved searches,
By default, Elasticsearch enables {ref}mapping-dynamic-mapping.html[dynamic mapping] for fields. Kibana needs dynamic mapping
to use fields in visualizations correctly, as well as to manage the `.kibana` index where saved searches,
visualizations, and dashboards are stored.
If your Elasticsearch use case requires you to disable dynamic mapping, you need to manually provide mappings for
fields that Kibana uses to create visualizations. You also need to manually enable dynamic mapping for the `.kibana`
If your Elasticsearch use case requires you to disable dynamic mapping, you need to manually provide mappings for
fields that Kibana uses to create visualizations. You also need to manually enable dynamic mapping for the `.kibana`
index.
The following procedure assumes that the `.kibana` index does not already exist in Elasticsearch and that the
@ -58,13 +58,13 @@ PUT .kibana
[float]
[[connect]]
=== Connect Kibana with Elasticsearch
Before you can start using Kibana, you need to tell it which Elasticsearch indices you want to explore. The first time
you access Kibana, you are prompted to define an _index pattern_ that matches the name of one or more of your indices.
That's it. That's all you need to configure to start using Kibana. You can add index patterns at any time from the
Before you can start using Kibana, you need to tell it which Elasticsearch indices you want to explore. The first time
you access Kibana, you are prompted to define an _index pattern_ that matches the name of one or more of your indices.
That's it. That's all you need to configure to start using Kibana. You can add index patterns at any time from the
<<settings-create-pattern,Settings tab>>.
TIP: By default, Kibana connects to the Elasticsearch instance running on `localhost`. To connect to a different
Elasticsearch instance, modify the Elasticsearch URL in the `kibana.yml` configuration file and restart Kibana. For
TIP: By default, Kibana connects to the Elasticsearch instance running on `localhost`. To connect to a different
Elasticsearch instance, modify the Elasticsearch URL in the `kibana.yml` configuration file and restart Kibana. For
information about using Kibana with your production nodes, see <<production>>.
To configure the Elasticsearch indices you want to access with Kibana:
@ -73,22 +73,22 @@ To configure the Elasticsearch indices you want to access with Kibana:
+
image:images/Start-Page.jpg[Kibana start page]
+
. Specify an index pattern that matches the name of one or more of your Elasticsearch indices. By default, Kibana
guesses that you're working with data being fed into Elasticsearch by Logstash. If that's the case, you can use the
default `logstash-*` as your index pattern. The asterisk (*) matches zero or more characters in an index's name. If
your Elasticsearch indices follow some other naming convention, enter an appropriate pattern. The "pattern" can also
. Specify an index pattern that matches the name of one or more of your Elasticsearch indices. By default, Kibana
guesses that you're working with data being fed into Elasticsearch by Logstash. If that's the case, you can use the
default `logstash-*` as your index pattern. The asterisk (*) matches zero or more characters in an index's name. If
your Elasticsearch indices follow some other naming convention, enter an appropriate pattern. The "pattern" can also
simply be the name of a single index.
. Select the index field that contains the timestamp that you want to use to perform time-based comparisons. Kibana
reads the index mapping to list all of the fields that contain a timestamp. If your index doesn't have time-based data,
. Select the index field that contains the timestamp that you want to use to perform time-based comparisons. Kibana
reads the index mapping to list all of the fields that contain a timestamp. If your index doesn't have time-based data,
disable the *Index contains time-based events* option.
. If new indices are generated periodically and have a timestamp appended to the name, select the *Use event times to
create index names* option and select the *Index pattern interval*. This improves search performance by enabling Kibana
to search only those indices that could contain data in the time range you specify. This is primarily applicable if you
. If new indices are generated periodically and have a timestamp appended to the name, select the *Use event times to
create index names* option and select the *Index pattern interval*. This improves search performance by enabling Kibana
to search only those indices that could contain data in the time range you specify. This is primarily applicable if you
are using Logstash to feed data into Elasticsearch.
. Click *Create* to add the index pattern. This first pattern is automatically configured as the default.
. Click *Create* to add the index pattern. This first pattern is automatically configured as the default.
When you have more than one index pattern, you can designate which one to use as the default from *Settings > Indices*.
Voila! Kibana is now connected to your Elasticsearch data. Kibana displays a read-only list of fields configured for
Voila! Kibana is now connected to your Elasticsearch data. Kibana displays a read-only list of fields configured for
the matching index.
[float]
@ -100,5 +100,5 @@ You're ready to dive in to your data:
* Chart and map your data from the <<visualize, Visualize>> page.
* Create and view custom dashboards from the <<dashboard, Dashboard>> page.
For a brief tutorial that explores these core Kibana concepts, take a look at the <<getting-started, Getting
For a brief tutorial that explores these core Kibana concepts, take a look at the <<getting-started, Getting
Started>> page.

1784
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@
},
"dependencies": {
"ansicolors": "^0.3.2",
"bluebird": "^2.0.7",
"bluebird": "^2.9.27",
"body-parser": "^1.10.1",
"bunyan": "^1.2.3",
"commander": "^2.6.0",
@ -97,12 +97,12 @@
"grunt-simple-mocha": "^0.4.0",
"html-entities": "^1.1.1",
"http-proxy": "^1.8.1",
"husky": "^0.6.0",
"istanbul": "^0.2.4",
"husky": "^0.8.1",
"istanbul": "^0.3.15",
"jade": "^1.8.2",
"license-checker": "3.0.3",
"load-grunt-config": "^0.7.0",
"marked": "^0.3.2",
"marked": "^0.3.3",
"marked-text-renderer": "^0.1.0",
"mkdirp": "^0.5.0",
"mocha": "^2.2.5",
@ -115,7 +115,7 @@
"progress": "^1.1.8",
"requirejs": "^2.1.14",
"rjs-build-analysis": "0.0.3",
"simple-git": "^0.11.0",
"simple-git": "^1.3.0",
"sinon": "^1.12.2",
"sinon-as-promised": "^2.0.3",
"tar": "^1.0.1"

View file

@ -1,29 +1,53 @@
define(function (require) {
var _ = require('lodash');
return function normalizeSortRequest(config) {
var defaultSortOptions = config.get('sort:options');
/**
* Decorate queries with default parameters
* @param {query} query object
* @returns {object}
*/
return function (sortObject) {
if (!_.isArray(sortObject)) sortObject = [sortObject];
var defaultSortOptions = config.get('sort:options');
return function (sortObject, indexPattern) {
var normalizedSort = [];
/*
Normalize the sort description to the more verbose format:
{ someField: "desc" } into { someField: { "order": "desc"}}
*/
_.each(sortObject, function (sortable) {
var sortField = _.keys(sortable)[0];
var sortValue = sortable[sortField];
if (_.isString(sortValue)) {
sortValue = sortable[sortField] = { order: sortValue };
}
_.defaults(sortValue, defaultSortOptions);
// [].concat({}) -> [{}], [].concat([{}]) -> [{}]
return [].concat(sortObject).map(function (sortable) {
return normalize(sortable, indexPattern);
});
return sortObject;
};
/*
Normalize the sort description to the more verbose format:
{ someField: "desc" } into { someField: { "order": "desc"}}
*/
function normalize(sortable, indexPattern) {
var normalized = {};
var sortField = _.keys(sortable)[0];
var sortValue = sortable[sortField];
var indexField = indexPattern.fields.byName[sortField];
if (indexField && indexField.scripted && indexField.sortable) {
var direction;
if (_.isString(sortValue)) direction = sortValue;
if (_.isObject(sortValue) && sortValue.order) direction = sortValue.order;
sortField = '_script';
sortValue = {
script: indexField.script,
type: indexField.type,
order: direction
};
} else {
if (_.isString(sortValue)) {
sortValue = { order: sortValue };
}
sortValue = _.defaults({}, sortValue, defaultSortOptions);
}
normalized[sortField] = sortValue;
return normalized;
}
};
});

View file

@ -8,7 +8,6 @@ define(function (require) {
var SegmentedRequest = Private(require('components/courier/fetch/request/segmented'));
var normalizeSortRequest = Private(require('components/courier/data_source/_normalize_sort_request'));
_(SearchSource).inherits(SourceAbstract);
function SearchSource(initialState) {
SearchSource.Super.call(this, initialState);
@ -179,7 +178,7 @@ define(function (require) {
key = '_source';
/* fall through */
case 'sort':
val = normalizeSortRequest(val);
val = normalizeSortRequest(val, this.get('index'));
/* fall through */
default:
state.body = state.body || {};

View file

@ -23,7 +23,8 @@ define(function (require) {
};
$scope.tooltip = function (column) {
if (!sortableField(column)) return ''; else return 'Sort by ' + shortDotsFilter(column);
if (!sortableField(column)) return '';
return 'Sort by ' + shortDotsFilter(column);
};
$scope.canRemove = function (name) {

View file

@ -40,4 +40,4 @@ define(function (require) {
};
return getSort;
});
});

View file

@ -38,7 +38,8 @@ define(function (require) {
var indexed = !!spec.indexed;
var scripted = !!spec.scripted;
var sortable = indexed && type.sortable;
var sortable = (indexed || scripted) && type.sortable;
var bucketable = indexed || scripted;
var filterable = spec.name === '_id' || scripted || (indexed && type.filterable);

View file

@ -29,7 +29,8 @@
var timeDefaults = {
from: 'now-15m',
to: 'now'
to: 'now',
mode: 'quick'
};
var refreshIntervalDefaults = {

View file

@ -844,7 +844,7 @@ define(function (require) {
var exp = 0.5;
var precisionBiasNumerator = 200;
var precisionBiasBase = 5;
var pct = value / max;
var pct = Math.abs(value) / Math.abs(max);
var constantZoomRadius = 0.5 * Math.pow(2, zoom);
var precisionScale = precisionBiasNumerator / Math.pow(precisionBiasBase, precision);

View file

@ -10,7 +10,7 @@ module.exports = function (grunt) {
'Run staged files through JSHint/JSCS',
function () {
diff('--name-only --cached')
diff(['--name-only', '--cached'])
.then(function (files) {
// match these patterns
var patterns = grunt.config.get('lintThese');

View file

@ -23,6 +23,7 @@ define(function (require) {
{ name: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false, sortable: false, filterable: true },
{ name: 'script string', type: 'string', scripted: true, script: '\'i am a string\'', lang: 'expression' },
{ name: 'script number', type: 'number', scripted: true, script: '1234', lang: 'expression' },
{ name: 'script murmur3', type: 'murmur3', scripted: true, script: '1234', lang: 'expression'},
].map(function (field) {
field.count = field.count || 0;
field.scripted = field.scripted || false;

View file

@ -38,6 +38,7 @@
mocha.setup({
ui: 'bdd',
timeout: 5000,
reporter: 'html'
});

View file

@ -4,45 +4,86 @@ define(function (require) {
require('angular').module('normalizeSortRequest', ['kibana']);
var normalizeSortRequest;
var indexPattern;
var normalizedSort;
beforeEach(module('kibana'));
beforeEach(inject(function (Private) {
normalizeSortRequest = Private(require('components/courier/data_source/_normalize_sort_request'));
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
normalizedSort = [{
someField: {
order: 'desc',
unmapped_type: 'boolean'
}
}];
}));
var normalizedSort = [{
someField: {
order: 'desc',
unmapped_type: 'boolean'
}
}];
it('make sure sort is an array', function () {
var result = normalizeSortRequest(
{ someField: 'desc'}
);
it('should return an array', function () {
var sortable = { someField: 'desc'};
var result = normalizeSortRequest(sortable, indexPattern);
expect(result).to.be.an(Array);
expect(result).to.eql(normalizedSort);
// ensure object passed in is not mutated
expect(result[0]).to.not.be.equal(sortable);
expect(sortable).to.eql({ someField: 'desc'});
});
it('makes plain string sort into the more verbose format', function () {
var result = normalizeSortRequest(
[{ someField: 'desc'}]
);
it('should make plain string sort into the more verbose format', function () {
var result = normalizeSortRequest([{ someField: 'desc'}], indexPattern);
expect(result).to.eql(normalizedSort);
});
it('appends default sort options', function () {
var result = normalizeSortRequest(
[{
someField: {
order: 'desc',
unmapped_type: 'boolean'
}
}]
);
it('should append default sort options', function () {
var sortState = [{
someField: {
order: 'desc',
unmapped_type: 'boolean'
}
}];
var result = normalizeSortRequest(sortState, indexPattern);
expect(result).to.eql(normalizedSort);
});
it('should enable script based sorting', function () {
var fieldName = 'script string';
var direction = 'desc';
var indexField = indexPattern.fields.byName[fieldName];
var sortState = {};
sortState[fieldName] = direction;
normalizedSort = {
_script: {
script: indexField.script,
type: indexField.type,
order: direction
}
};
var result = normalizeSortRequest(sortState, indexPattern);
expect(result).to.eql([normalizedSort]);
sortState[fieldName] = { order: direction };
result = normalizeSortRequest([sortState], indexPattern);
expect(result).to.eql([normalizedSort]);
});
it('should use script based sorting only on sortable types', function () {
var fieldName = 'script murmur3';
var direction = 'asc';
var indexField = indexPattern.fields.byName[fieldName];
var sortState = {};
sortState[fieldName] = direction;
normalizedSort = {};
normalizedSort[fieldName] = {
order: direction,
unmapped_type: 'boolean'
};
var result = normalizeSortRequest([sortState], indexPattern);
expect(result).to.eql([normalizedSort]);
});
});
});

View file

@ -1,15 +1,16 @@
define(function (require) {
var getSort = require('components/doc_table/lib/get_sort');
var indexPattern =
var defaultSort = {time: 'desc'};
var indexPattern;
describe('docTable', function () {
beforeEach(module('kibana'));
beforeEach(inject(function (Private, _$rootScope_, Promise) {
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
}));
describe('getSort function', function () {
beforeEach(module('kibana'));
beforeEach(inject(function (Private, _$rootScope_, Promise) {
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
}));
it('should be a function', function () {
expect(getSort).to.be.a(Function);
});
@ -22,17 +23,17 @@ define(function (require) {
});
it('should sort by the default when passed an unsortable field', function () {
expect(getSort(['_id', 'asc'], indexPattern)).to.eql({time: 'desc'});
expect(getSort(['lol_nope', 'asc'], indexPattern)).to.eql({time: 'desc'});
expect(getSort(['_id', 'asc'], indexPattern)).to.eql(defaultSort);
expect(getSort(['lol_nope', 'asc'], indexPattern)).to.eql(defaultSort);
delete indexPattern.timeFieldName;
expect(getSort(['_id', 'asc'], indexPattern)).to.eql({_score: 'desc'});
});
it('should sort in reverse chrono order otherwise on time based patterns', function () {
expect(getSort([], indexPattern)).to.eql({time: 'desc'});
expect(getSort(['foo'], indexPattern)).to.eql({time: 'desc'});
expect(getSort({foo: 'bar'}, indexPattern)).to.eql({time: 'desc'});
expect(getSort([], indexPattern)).to.eql(defaultSort);
expect(getSort(['foo'], indexPattern)).to.eql(defaultSort);
expect(getSort({foo: 'bar'}, indexPattern)).to.eql(defaultSort);
});
it('should sort by score on non-time patterns', function () {
@ -42,7 +43,16 @@ define(function (require) {
expect(getSort(['foo'], indexPattern)).to.eql({_score: 'desc'});
expect(getSort({foo: 'bar'}, indexPattern)).to.eql({_score: 'desc'});
});
});
describe('getSort.array function', function () {
it('should have an array method', function () {
expect(getSort.array).to.be.a(Function);
});
it('should return an array for sortable fields', function () {
expect(getSort.array(['bytes', 'desc'], indexPattern)).to.eql([ 'bytes', 'desc' ]);
});
});
});
});

View file

@ -16,8 +16,8 @@ define(function (require) {
vis = null;
}
function getEls(n, type) {
return d3.select().data(new Array(n)).enter().append(type);
function getEls(el, n, type) {
return d3.select(el).data(new Array(n)).enter().append(type);
}
describe('', function () {
@ -67,7 +67,7 @@ define(function (require) {
var apply = chart.events.addEvent('event', _.noop);
expect(apply).to.be.a('function');
var els = getEls(3, 'div');
var els = getEls(vis.el, 3, 'div');
apply(els);
els.each(function () {
expect(d3.select(this).on('event')).to.be(_.noop);
@ -90,7 +90,7 @@ define(function (require) {
var apply = chart.events[name](d3.select(document.createElement('svg')));
expect(apply).to.be.a('function');
var els = getEls(3, 'div');
var els = getEls(vis.el, 3, 'div');
apply(els);
els.each(function () {
expect(d3.select(this).on(event)).to.be.a('function');