Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion x-pack/plugins/ml/public/explorer/explorer_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import _ from 'lodash';
import $ from 'jquery';
import DragSelect from 'dragselect';
import moment from 'moment';
import moment from 'moment-timezone';

import 'plugins/ml/components/anomalies_table';
import 'plugins/ml/components/controls';
Expand Down Expand Up @@ -76,6 +76,7 @@ module.controller('MlExplorerController', function (
$timeout,
AppState,
Private,
config,
mlCheckboxShowChartsService,
mlSelectLimitService,
mlSelectIntervalService,
Expand All @@ -87,6 +88,10 @@ module.controller('MlExplorerController', function (
timefilter.enableTimeRangeSelector();
timefilter.enableAutoRefreshSelector();

// Pass the timezone to the server for use when aggregating anomalies (by day / hour) for the table.
const tzConfig = config.get('dateFormat:tz');
const dateFormatTz = (tzConfig !== 'Browser') ? tzConfig : moment.tz.guess();

const TimeBuckets = Private(IntervalHelperProvider);
const queryFilter = Private(FilterBarQueryFilterProvider);
const mlJobSelectService = Private(JobSelectServiceProvider);
Expand Down Expand Up @@ -945,6 +950,7 @@ module.controller('MlExplorerController', function (
mlSelectSeverityService.state.get('threshold').val,
timeRange.earliestMs,
timeRange.latestMs,
dateFormatTz,
500,
MAX_CATEGORY_EXAMPLES
).then((resp) => {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/public/services/ml_api_service/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const results = {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples) {

Expand All @@ -35,6 +36,7 @@ export const results = {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/

import _ from 'lodash';
import moment from 'moment';
import moment from 'moment-timezone';

import 'plugins/ml/components/anomalies_table';
import 'plugins/ml/components/controls';
Expand Down Expand Up @@ -71,6 +71,7 @@ module.controller('MlTimeSeriesExplorerController', function (
$timeout,
Private,
AppState,
config,
mlSelectIntervalService,
mlSelectSeverityService) {

Expand Down Expand Up @@ -98,6 +99,10 @@ module.controller('MlTimeSeriesExplorerController', function (
$scope.showForecast = true; // Toggles display of forecast data in the focus chart
$scope.showForecastCheckbox = false;

// Pass the timezone to the server for use when aggregating anomalies (by day / hour) for the table.
const tzConfig = config.get('dateFormat:tz');
const dateFormatTz = (tzConfig !== 'Browser') ? tzConfig : moment.tz.guess();

$scope.permissions = {
canForecastJob: checkPermission('canForecastJob')
};
Expand Down Expand Up @@ -681,6 +686,7 @@ module.controller('MlTimeSeriesExplorerController', function (
}

function loadAnomaliesTableData(earliestMs, latestMs) {

ml.results.getAnomaliesTableData(
[$scope.selectedJob.job_id],
$scope.criteriaFields,
Expand All @@ -689,6 +695,7 @@ module.controller('MlTimeSeriesExplorerController', function (
mlSelectSeverityService.state.get('threshold').val,
earliestMs,
latestMs,
dateFormatTz,
ANOMALIES_MAX_RESULTS
).then((resp) => {
const anomalies = resp.anomalies;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


import _ from 'lodash';
import moment from 'moment';
import moment from 'moment-timezone';

import {
getEntityFieldName,
Expand All @@ -17,13 +17,15 @@ import {


// Builds the items for display in the anomalies table from the supplied list of anomaly records.
export function buildAnomalyTableItems(anomalyRecords, aggregationInterval) {
// Provide the timezone to use for aggregating anomalies (by day or hour) as set in the
// Kibana dateFormat:tz setting.
export function buildAnomalyTableItems(anomalyRecords, aggregationInterval, dateFormatTz) {

// Aggregate the anomaly records if necessary, and create skeleton display records with
// time, detector (description) and source record properties set.
let displayRecords = [];
if (aggregationInterval !== 'second') {
displayRecords = aggregateAnomalies(anomalyRecords, aggregationInterval);
displayRecords = aggregateAnomalies(anomalyRecords, aggregationInterval, dateFormatTz);
} else {
// Show all anomaly records.
displayRecords = anomalyRecords.map((record) => {
Expand Down Expand Up @@ -115,7 +117,7 @@ export function buildAnomalyTableItems(anomalyRecords, aggregationInterval) {
});
}

function aggregateAnomalies(anomalyRecords, interval) {
function aggregateAnomalies(anomalyRecords, interval, dateFormatTz) {
// Aggregate the anomaly records by time, jobId, detectorIndex, and entity (by/over/partition).
// anomalyRecords assumed to be supplied in ascending time order.
if (anomalyRecords.length === 0) {
Expand All @@ -125,7 +127,9 @@ function aggregateAnomalies(anomalyRecords, interval) {
const aggregatedData = {};
anomalyRecords.forEach((record) => {
// Use moment.js to get start of interval.
const roundedTime = moment(record.timestamp).startOf(interval).valueOf();
const roundedTime = (dateFormatTz !== undefined) ?
moment(record.timestamp).tz(dateFormatTz).startOf(interval).valueOf() :
moment(record.timestamp).startOf(interval).valueOf();
if (aggregatedData[roundedTime] === undefined) {
aggregatedData[roundedTime] = {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function resultsServiceProvider(callWithRequest) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords = DEFAULT_QUERY_SIZE,
maxExamples = DEFAULT_MAX_EXAMPLES) {

Expand Down Expand Up @@ -163,7 +164,7 @@ export function resultsServiceProvider(callWithRequest) {
tableData.interval = (daysDiff < 2 ? 'hour' : 'day');
}

tableData.anomalies = buildAnomalyTableItems(records, tableData.interval);
tableData.anomalies = buildAnomalyTableItems(records, tableData.interval, dateFormatTz);

// Load examples for any categorization anomalies.
const categoryAnomalies = tableData.anomalies.filter(item => item.entityName === 'mlcategory');
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/server/routes/results_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function getAnomaliesTableData(callWithRequest, payload) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples } = payload;
return rs.getAnomaliesTableData(
Expand All @@ -31,6 +32,7 @@ function getAnomaliesTableData(callWithRequest, payload) {
threshold,
earliestMs,
latestMs,
dateFormatTz,
maxRecords,
maxExamples);
}
Expand Down