mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Adds support for a user-configured location name, so users can more easily differentiate their monitors if they're watching hosts across multiple locations.
This commit is contained in:
parent
680f52af83
commit
09102cd17e
43 changed files with 907 additions and 246 deletions
|
@ -15,31 +15,31 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "sort",
|
||||
"description": "",
|
||||
"description": "Optional: the direction to sort by. Accepts 'asc' and 'desc'. Defaults to 'desc'.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"description": "",
|
||||
"description": "Optional: the number of results to return.",
|
||||
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "monitorId",
|
||||
"description": "",
|
||||
"description": "Optional: the monitor ID filter.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"description": "",
|
||||
"description": "Optional: the check status to filter by.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "dateRangeStart",
|
||||
"description": "",
|
||||
"description": "The lower limit of the date range.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
|
@ -49,13 +49,19 @@
|
|||
},
|
||||
{
|
||||
"name": "dateRangeEnd",
|
||||
"description": "",
|
||||
"description": "The upper limit of the date range.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": "Optional: agent location to filter by.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
|
@ -181,6 +187,12 @@
|
|||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": "",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": { "kind": "OBJECT", "name": "MonitorChart", "ofType": null },
|
||||
|
@ -189,11 +201,11 @@
|
|||
},
|
||||
{
|
||||
"name": "getLatestMonitors",
|
||||
"description": "",
|
||||
"description": "Fetch the most recent event data for a monitor ID, date range, location.",
|
||||
"args": [
|
||||
{
|
||||
"name": "dateRangeStart",
|
||||
"description": "",
|
||||
"description": "The lower limit of the date range.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
|
@ -203,7 +215,7 @@
|
|||
},
|
||||
{
|
||||
"name": "dateRangeEnd",
|
||||
"description": "",
|
||||
"description": "The upper limit of the date range.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
|
@ -213,7 +225,13 @@
|
|||
},
|
||||
{
|
||||
"name": "monitorId",
|
||||
"description": "",
|
||||
"description": "Optional: a specific monitor ID filter.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": "Optional: a specific instance location filter.",
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"defaultValue": null
|
||||
}
|
||||
|
@ -517,6 +535,14 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "observer",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "Observer", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "resolve",
|
||||
"description": "",
|
||||
|
@ -1351,6 +1377,100 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Observer",
|
||||
"description": "Metadata added by a proccessor, which is specified in its configuration.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "geo",
|
||||
"description": "Geolocation data for the agent.",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "Geo", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Geo",
|
||||
"description": "Geolocation data added via processors to enrich events.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "city_name",
|
||||
"description": "Name of the city in which the agent is running.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "continent_name",
|
||||
"description": "The name of the continent on which the agent is running.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "country_iso_code",
|
||||
"description": "ISO designation for the agent's country.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "country_name",
|
||||
"description": "The name of the agent's country.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": "The lat/long of the agent.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"description": "A name for the host's location, e.g. 'us-east-1' or 'LAX'.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "region_iso_code",
|
||||
"description": "ISO designation of the agent's region.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "region_name",
|
||||
"description": "Name of the region hosting the agent.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Resolve",
|
||||
|
@ -2102,11 +2222,11 @@
|
|||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "FilterBar",
|
||||
"description": "",
|
||||
"description": "The data used to enrich the filter bar.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "ids",
|
||||
"description": "",
|
||||
"description": "A series of monitor IDs in the heartbeat indices.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -2120,9 +2240,25 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "locations",
|
||||
"description": "The location values users have configured for the agents.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "names",
|
||||
"description": "",
|
||||
"description": "The names users have configured for the monitors.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -2138,7 +2274,7 @@
|
|||
},
|
||||
{
|
||||
"name": "ports",
|
||||
"description": "",
|
||||
"description": "The ports of the monitored endpoints.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -2154,7 +2290,7 @@
|
|||
},
|
||||
{
|
||||
"name": "schemes",
|
||||
"description": "",
|
||||
"description": "The schemes used by the monitors.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -2170,7 +2306,7 @@
|
|||
},
|
||||
{
|
||||
"name": "statuses",
|
||||
"description": "",
|
||||
"description": "The possible status values contained in the indices.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -2193,11 +2329,31 @@
|
|||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "ErrorListItem",
|
||||
"description": "",
|
||||
"description": "A representation of an error state for a monitor.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "count",
|
||||
"description": "The number of times this error has occurred.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "latestMessage",
|
||||
"description": "",
|
||||
"description": "The most recent message associated with this error type.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": "The location assigned to the agent reporting this error.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -2205,43 +2361,7 @@
|
|||
},
|
||||
{
|
||||
"name": "monitorId",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "count",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "statusCode",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "timestamp",
|
||||
"description": "",
|
||||
"description": "The ID of the monitor reporting the error.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -2249,11 +2369,39 @@
|
|||
},
|
||||
{
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"description": "The name configured for the monitor by the user.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "statusCode",
|
||||
"description": "The status code, if available, of the error request.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "timestamp",
|
||||
"description": "When the most recent error state occurred.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"description": "What kind of error the monitor reported.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
|
|
|
@ -30,7 +30,7 @@ export interface Query {
|
|||
getSnapshot?: Snapshot | null;
|
||||
|
||||
getMonitorChartsData?: MonitorChart | null;
|
||||
|
||||
/** Fetch the most recent event data for a monitor ID, date range, location. */
|
||||
getLatestMonitors: Ping[];
|
||||
|
||||
getFilterBar?: FilterBar | null;
|
||||
|
@ -74,6 +74,8 @@ export interface Ping {
|
|||
|
||||
monitor?: Monitor | null;
|
||||
|
||||
observer?: Observer | null;
|
||||
|
||||
resolve?: Resolve | null;
|
||||
|
||||
socks5?: Socks5 | null;
|
||||
|
@ -266,6 +268,30 @@ export interface Monitor {
|
|||
|
||||
check_group?: string | null;
|
||||
}
|
||||
/** Metadata added by a proccessor, which is specified in its configuration. */
|
||||
export interface Observer {
|
||||
/** Geolocation data for the agent. */
|
||||
geo?: Geo | null;
|
||||
}
|
||||
/** Geolocation data added via processors to enrich events. */
|
||||
export interface Geo {
|
||||
/** Name of the city in which the agent is running. */
|
||||
city_name?: string | null;
|
||||
/** The name of the continent on which the agent is running. */
|
||||
continent_name?: string | null;
|
||||
/** ISO designation for the agent's country. */
|
||||
country_iso_code?: string | null;
|
||||
/** The name of the agent's country. */
|
||||
country_name?: string | null;
|
||||
/** The lat/long of the agent. */
|
||||
location?: string | null;
|
||||
/** A name for the host's location, e.g. 'us-east-1' or 'LAX'. */
|
||||
name?: string | null;
|
||||
/** ISO designation of the agent's region. */
|
||||
region_iso_code?: string | null;
|
||||
/** Name of the region hosting the agent. */
|
||||
region_name?: string | null;
|
||||
}
|
||||
|
||||
export interface Resolve {
|
||||
host?: string | null;
|
||||
|
@ -415,33 +441,39 @@ export interface StatusData {
|
|||
/** The total down counts for this point. */
|
||||
total?: number | null;
|
||||
}
|
||||
|
||||
/** The data used to enrich the filter bar. */
|
||||
export interface FilterBar {
|
||||
/** A series of monitor IDs in the heartbeat indices. */
|
||||
ids?: MonitorKey[] | null;
|
||||
|
||||
/** The location values users have configured for the agents. */
|
||||
locations?: string[] | null;
|
||||
/** The names users have configured for the monitors. */
|
||||
names?: string[] | null;
|
||||
|
||||
/** The ports of the monitored endpoints. */
|
||||
ports?: number[] | null;
|
||||
|
||||
/** The schemes used by the monitors. */
|
||||
schemes?: string[] | null;
|
||||
|
||||
/** The possible status values contained in the indices. */
|
||||
statuses?: string[] | null;
|
||||
}
|
||||
|
||||
/** A representation of an error state for a monitor. */
|
||||
export interface ErrorListItem {
|
||||
/** The number of times this error has occurred. */
|
||||
count: number;
|
||||
/** The most recent message associated with this error type. */
|
||||
latestMessage?: string | null;
|
||||
|
||||
/** The location assigned to the agent reporting this error. */
|
||||
location?: string | null;
|
||||
/** The ID of the monitor reporting the error. */
|
||||
monitorId?: string | null;
|
||||
|
||||
type: string;
|
||||
|
||||
count?: number | null;
|
||||
|
||||
statusCode?: string | null;
|
||||
|
||||
timestamp?: string | null;
|
||||
|
||||
/** The name configured for the monitor by the user. */
|
||||
name?: string | null;
|
||||
/** The status code, if available, of the error request. */
|
||||
statusCode?: string | null;
|
||||
/** When the most recent error state occurred. */
|
||||
timestamp?: string | null;
|
||||
/** What kind of error the monitor reported. */
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface MonitorPageTitle {
|
||||
|
@ -463,17 +495,20 @@ export interface DataPoint {
|
|||
// ====================================================
|
||||
|
||||
export interface AllPingsQueryArgs {
|
||||
/** Optional: the direction to sort by. Accepts 'asc' and 'desc'. Defaults to 'desc'. */
|
||||
sort?: string | null;
|
||||
|
||||
/** Optional: the number of results to return. */
|
||||
size?: number | null;
|
||||
|
||||
/** Optional: the monitor ID filter. */
|
||||
monitorId?: string | null;
|
||||
|
||||
/** Optional: the check status to filter by. */
|
||||
status?: string | null;
|
||||
|
||||
/** The lower limit of the date range. */
|
||||
dateRangeStart: string;
|
||||
|
||||
/** The upper limit of the date range. */
|
||||
dateRangeEnd: string;
|
||||
/** Optional: agent location to filter by. */
|
||||
location?: string | null;
|
||||
}
|
||||
export interface GetMonitorsQueryArgs {
|
||||
dateRangeStart: string;
|
||||
|
@ -495,13 +530,18 @@ export interface GetMonitorChartsDataQueryArgs {
|
|||
dateRangeStart: string;
|
||||
|
||||
dateRangeEnd: string;
|
||||
|
||||
location?: string | null;
|
||||
}
|
||||
export interface GetLatestMonitorsQueryArgs {
|
||||
/** The lower limit of the date range. */
|
||||
dateRangeStart: string;
|
||||
|
||||
/** The upper limit of the date range. */
|
||||
dateRangeEnd: string;
|
||||
|
||||
/** Optional: a specific monitor ID filter. */
|
||||
monitorId?: string | null;
|
||||
/** Optional: a specific instance location filter. */
|
||||
location?: string | null;
|
||||
}
|
||||
export interface GetFilterBarQueryArgs {
|
||||
dateRangeStart: string;
|
||||
|
|
|
@ -34,7 +34,12 @@ exports[`ErrorList component renders the error list without errors 1`] = `
|
|||
"field": "monitorId",
|
||||
"name": "Monitor ID",
|
||||
"render": [Function],
|
||||
"width": "25%",
|
||||
"width": "12.5%",
|
||||
},
|
||||
Object {
|
||||
"field": "location",
|
||||
"name": "Location",
|
||||
"width": "12.5%",
|
||||
},
|
||||
Object {
|
||||
"field": "statusCode",
|
||||
|
|
|
@ -27,6 +27,12 @@ exports[`FilterBar component renders the component without errors 1`] = `
|
|||
],
|
||||
"type": "field_value_toggle_group",
|
||||
},
|
||||
Object {
|
||||
"field": "observer.geo.name",
|
||||
"name": "Location",
|
||||
"options": Array [],
|
||||
"type": "field_value_selection",
|
||||
},
|
||||
Object {
|
||||
"field": "monitor.id",
|
||||
"multiSelect": false,
|
||||
|
|
|
@ -34,6 +34,11 @@ exports[`MonitorList component renders a monitor list without errors 1`] = `
|
|||
"name": "ID",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"field": "ping.observer.geo.name",
|
||||
"name": "Location",
|
||||
"render": [Function],
|
||||
},
|
||||
Object {
|
||||
"field": "ping.url.full",
|
||||
"name": "URL",
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
EuiBadge,
|
||||
EuiCodeBlock,
|
||||
EuiInMemoryTable,
|
||||
EuiLink,
|
||||
EuiPanel,
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
|
@ -18,10 +17,10 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ErrorListItem, Ping } from '../../../common/graphql/types';
|
||||
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
|
||||
import { errorListQuery } from '../../queries';
|
||||
import { MonitorPageLink } from './monitor_page_link';
|
||||
|
||||
interface ErrorListProps {
|
||||
linkParameters?: string;
|
||||
|
@ -72,12 +71,25 @@ export const ErrorListComponent = ({ data, linkParameters, loading }: Props) =>
|
|||
name: i18n.translate('xpack.uptime.errorList.monitorIdColumnLabel', {
|
||||
defaultMessage: 'Monitor ID',
|
||||
}),
|
||||
render: (id: string, { name }: ErrorListItem) => (
|
||||
<EuiLink>
|
||||
<Link to={`/monitor/${id}${linkParameters}`}>{name || id}</Link>
|
||||
</EuiLink>
|
||||
render: (id: string, { name, location }: ErrorListItem) => (
|
||||
<MonitorPageLink
|
||||
id={id}
|
||||
location={location || undefined}
|
||||
linkParameters={linkParameters}
|
||||
>
|
||||
{name || id}
|
||||
</MonitorPageLink>
|
||||
),
|
||||
width: '25%',
|
||||
width: '12.5%',
|
||||
},
|
||||
{
|
||||
field: 'location',
|
||||
name: i18n.translate('xpack.uptime.errorList.location', {
|
||||
defaultMessage: 'Location',
|
||||
description:
|
||||
"The heading of a column that displays the location of a Heartbeat instance's host machine.",
|
||||
}),
|
||||
width: '12.5%',
|
||||
},
|
||||
{
|
||||
field: 'statusCode',
|
||||
|
|
|
@ -33,7 +33,7 @@ export const FilterBarComponent = ({ currentQuery, data, updateQuery }: Props) =
|
|||
return <FilterBarLoading />;
|
||||
}
|
||||
const {
|
||||
filterBar: { ids, names, ports, schemes },
|
||||
filterBar: { ids, locations, names, ports, schemes },
|
||||
} = data;
|
||||
// TODO: add a factory function + type for these filter options
|
||||
const filters = [
|
||||
|
@ -55,7 +55,16 @@ export const FilterBarComponent = ({ currentQuery, data, updateQuery }: Props) =
|
|||
},
|
||||
],
|
||||
},
|
||||
// TODO: add health to this select
|
||||
{
|
||||
type: 'field_value_selection',
|
||||
field: 'observer.geo.name',
|
||||
name: i18n.translate('xpack.uptime.filterBar.options.location.name', {
|
||||
defaultMessage: 'Location',
|
||||
description:
|
||||
'A label applied to a button that lets users filter monitors by their location.',
|
||||
}),
|
||||
options: locations ? locations.map(location => ({ value: location, view: location })) : [],
|
||||
},
|
||||
{
|
||||
type: 'field_value_selection',
|
||||
field: 'monitor.id',
|
||||
|
|
|
@ -12,6 +12,7 @@ export { FilterBarLoading } from './filter_bar_loading';
|
|||
export { IntegrationLink } from './integration_link';
|
||||
export { MonitorCharts } from './monitor_charts';
|
||||
export { MonitorList } from './monitor_list';
|
||||
export { MonitorPageLink } from './monitor_page_link';
|
||||
export { MonitorPageTitle } from './monitor_page_title';
|
||||
export { MonitorStatusBar } from './monitor_status_bar';
|
||||
export { PingList } from './ping_list';
|
||||
|
|
|
@ -26,12 +26,12 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { get } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { LatestMonitor, MonitorSeriesPoint, Ping } from '../../../common/graphql/types';
|
||||
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
|
||||
import { monitorListQuery } from '../../queries';
|
||||
import { MonitorSparkline } from './monitor_sparkline';
|
||||
import { MonitorListActionsPopover } from './monitor_list_actions_popover';
|
||||
import { MonitorPageLink } from './monitor_page_link';
|
||||
|
||||
interface MonitorListQueryResult {
|
||||
// TODO: clean up this ugly result data shape, there should be no nesting
|
||||
|
@ -111,18 +111,41 @@ export const MonitorListComponent = ({
|
|||
defaultMessage: 'ID',
|
||||
}),
|
||||
render: (id: string, monitor: LatestMonitor) => (
|
||||
<EuiLink>
|
||||
<Link
|
||||
data-test-subj={`monitor-page-link-${id}`}
|
||||
to={`/monitor/${id}${linkParameters}`}
|
||||
>
|
||||
{monitor.ping && monitor.ping.monitor && monitor.ping.monitor.name
|
||||
? monitor.ping.monitor.name
|
||||
: id}
|
||||
</Link>
|
||||
</EuiLink>
|
||||
<MonitorPageLink
|
||||
id={id}
|
||||
location={get<string | undefined>(monitor, 'ping.observer.geo.name')}
|
||||
linkParameters={linkParameters}
|
||||
>
|
||||
{monitor.ping && monitor.ping.monitor && monitor.ping.monitor.name
|
||||
? monitor.ping.monitor.name
|
||||
: id}
|
||||
</MonitorPageLink>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'ping.observer.geo.name',
|
||||
name: i18n.translate('xpack.uptime.monitorList.geoName', {
|
||||
defaultMessage: 'Location',
|
||||
description: 'Users can specify a name for a location',
|
||||
}),
|
||||
render: (locationName: string | null | undefined) =>
|
||||
!!locationName ? (
|
||||
locationName
|
||||
) : (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/beats/heartbeat/current/add-host-metadata.html#add-host-metadata"
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate('xpack.uptime.monitorList.geoName.helpLinkAnnotation', {
|
||||
defaultMessage: 'Add location',
|
||||
description:
|
||||
'Text that instructs the user to navigate to our docs to add a geographic location to their data',
|
||||
})}
|
||||
|
||||
<EuiIcon size="s" type="popout" />
|
||||
</EuiLink>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'ping.url.full',
|
||||
name: i18n.translate('xpack.uptime.monitorList.urlColumnLabel', {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiLink } from '@elastic/eui';
|
||||
import { Link } from 'react-router-dom';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
interface DetailPageLinkProps {
|
||||
id: string;
|
||||
location: string | undefined;
|
||||
linkParameters: string | undefined;
|
||||
}
|
||||
|
||||
export const MonitorPageLink: FunctionComponent<DetailPageLinkProps> = ({
|
||||
children,
|
||||
id,
|
||||
location,
|
||||
linkParameters,
|
||||
}) => (
|
||||
<EuiLink>
|
||||
<Link
|
||||
data-test-subj={`monitor-page-link-${id}`}
|
||||
to={
|
||||
location === undefined
|
||||
? `/monitor/${id}${linkParameters}`
|
||||
: `/monitor/${id}/${encodeURI(location)}/${linkParameters}`
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</EuiLink>
|
||||
);
|
|
@ -28,10 +28,11 @@ type Props = MonitorStatusBarProps & UptimeGraphQLQueryProps<MonitorStatusBarQue
|
|||
|
||||
export const MonitorStatusBarComponent = ({ data, monitorId }: Props) => {
|
||||
if (data && data.monitorStatus && data.monitorStatus.length) {
|
||||
const { monitor, timestamp } = data.monitorStatus[0];
|
||||
const { monitor, observer, timestamp } = data.monitorStatus[0];
|
||||
const duration = get(monitor, 'duration.us', undefined);
|
||||
const status = get<'up' | 'down'>(monitor, 'status', 'down');
|
||||
const full = get(data.monitorStatus[0], 'url.full');
|
||||
const location = get(observer, 'geo.name');
|
||||
return (
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup gutterSize="l">
|
||||
|
@ -97,6 +98,16 @@ export const MonitorStatusBarComponent = ({ data, monitorId }: Props) => {
|
|||
>
|
||||
{moment(new Date(timestamp).valueOf()).fromNow()}
|
||||
</EuiFlexItem>
|
||||
{!!location && (
|
||||
<EuiFlexItem
|
||||
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.locationName', {
|
||||
defaultMessage: 'Location',
|
||||
})}
|
||||
grow={false}
|
||||
>
|
||||
{location}
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
|
|
|
@ -37,7 +37,11 @@ interface MonitorPageProps {
|
|||
}
|
||||
|
||||
export const MonitorPage = ({ history, location, query, setBreadcrumbs }: MonitorPageProps) => {
|
||||
const [monitorId] = useState<string>(location.pathname.replace(/^(\/monitor\/)/, ''));
|
||||
const parsedPath = location.pathname.replace(/^(\/monitor\/)/, '').split('/');
|
||||
const [monitorId] = useState<string>(decodeURI(parsedPath[0]));
|
||||
const [geoLocation] = useState<string | undefined>(
|
||||
parsedPath[1] ? decodeURI(parsedPath[1]) : undefined
|
||||
);
|
||||
const { colors, refreshApp, setHeadingText } = useContext(UptimeSettingsContext);
|
||||
const [params, updateUrlParams] = useUrlParams(history, location);
|
||||
const { dateRangeStart, dateRangeEnd, selectedPingStatus } = params;
|
||||
|
@ -66,16 +70,14 @@ export const MonitorPage = ({ history, location, query, setBreadcrumbs }: Monito
|
|||
},
|
||||
[params]
|
||||
);
|
||||
const sharedVariables = { dateRangeStart, dateRangeEnd, location: geoLocation, monitorId };
|
||||
return (
|
||||
<Fragment>
|
||||
<MonitorPageTitle monitorId={monitorId} variables={{ monitorId }} />
|
||||
<EuiSpacer size="s" />
|
||||
<MonitorStatusBar
|
||||
monitorId={monitorId}
|
||||
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
|
||||
/>
|
||||
<MonitorStatusBar monitorId={monitorId} variables={sharedVariables} />
|
||||
<EuiSpacer size="s" />
|
||||
<MonitorCharts {...colors} variables={{ dateRangeStart, dateRangeEnd, monitorId }} />
|
||||
<MonitorCharts {...colors} variables={sharedVariables} />
|
||||
<EuiSpacer size="s" />
|
||||
<PingList
|
||||
onSelectedStatusUpdate={(selectedStatus: string | null) =>
|
||||
|
@ -84,9 +86,7 @@ export const MonitorPage = ({ history, location, query, setBreadcrumbs }: Monito
|
|||
onUpdateApp={refreshApp}
|
||||
selectedOption={selectedPingStatus}
|
||||
variables={{
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
monitorId,
|
||||
...sharedVariables,
|
||||
status: selectedPingStatus,
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -13,13 +13,14 @@ query ErrorList($dateRangeStart: String!, $dateRangeEnd: String!, $filters: Stri
|
|||
dateRangeEnd: $dateRangeEnd
|
||||
filters: $filters
|
||||
) {
|
||||
latestMessage
|
||||
monitorId
|
||||
type
|
||||
count
|
||||
latestMessage
|
||||
location
|
||||
monitorId
|
||||
name
|
||||
statusCode
|
||||
timestamp
|
||||
name
|
||||
type
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -9,15 +9,16 @@ import gql from 'graphql-tag';
|
|||
export const filterBarQueryString = `
|
||||
query FilterBar($dateRangeStart: String!, $dateRangeEnd: String!) {
|
||||
filterBar: getFilterBar(dateRangeStart: $dateRangeStart, dateRangeEnd: $dateRangeEnd) {
|
||||
ports
|
||||
ids {
|
||||
key
|
||||
url
|
||||
}
|
||||
names
|
||||
schemes
|
||||
ids {
|
||||
key
|
||||
url
|
||||
}
|
||||
locations
|
||||
names
|
||||
ports
|
||||
schemes
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const filterBarQuery = gql`
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
import gql from 'graphql-tag';
|
||||
|
||||
export const monitorChartsQueryString = `
|
||||
query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String!) {
|
||||
query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String!, $location: String) {
|
||||
monitorChartsData: getMonitorChartsData(
|
||||
monitorId: $monitorId
|
||||
dateRangeStart: $dateRangeStart
|
||||
dateRangeEnd: $dateRangeEnd
|
||||
location: $location
|
||||
) {
|
||||
durationArea {
|
||||
x
|
||||
|
|
|
@ -37,6 +37,12 @@ export const monitorListQueryString = `
|
|||
name
|
||||
status
|
||||
}
|
||||
observer {
|
||||
geo {
|
||||
location
|
||||
name
|
||||
}
|
||||
}
|
||||
url {
|
||||
domain
|
||||
full
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
import gql from 'graphql-tag';
|
||||
|
||||
export const monitorStatusBarQueryString = `
|
||||
query MonitorStatus($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String) {
|
||||
query MonitorStatus($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String, $location: String) {
|
||||
monitorStatus: getLatestMonitors(
|
||||
dateRangeStart: $dateRangeStart
|
||||
dateRangeEnd: $dateRangeEnd
|
||||
monitorId: $monitorId
|
||||
location: $location
|
||||
) {
|
||||
timestamp
|
||||
millisFromNow
|
||||
|
@ -21,6 +22,11 @@ query MonitorStatus($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId
|
|||
us
|
||||
}
|
||||
}
|
||||
observer {
|
||||
geo {
|
||||
name
|
||||
}
|
||||
}
|
||||
url {
|
||||
full
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ query PingList(
|
|||
$status: String
|
||||
$sort: String
|
||||
$size: Int
|
||||
$location: String
|
||||
) {
|
||||
allPings(
|
||||
dateRangeStart: $dateRangeStart
|
||||
|
@ -22,6 +23,7 @@ query PingList(
|
|||
status: $status
|
||||
sort: $sort
|
||||
size: $size
|
||||
location: $location
|
||||
) {
|
||||
total
|
||||
pings {
|
||||
|
|
|
@ -162,7 +162,7 @@ const Application = (props: UptimeAppProps) => {
|
|||
)}
|
||||
/>
|
||||
<Route
|
||||
path="/monitor/:id"
|
||||
path="/monitor/:id/:location?"
|
||||
render={routerProps => (
|
||||
<MonitorPage
|
||||
query={client.query}
|
||||
|
|
|
@ -112,27 +112,39 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = (
|
|||
},
|
||||
async getMonitorChartsData(
|
||||
resolver,
|
||||
{ monitorId, dateRangeStart, dateRangeEnd },
|
||||
{ monitorId, dateRangeStart, dateRangeEnd, location },
|
||||
{ req }
|
||||
): Promise<MonitorChart> {
|
||||
return await libs.monitors.getMonitorChartsData(req, monitorId, dateRangeStart, dateRangeEnd);
|
||||
return await libs.monitors.getMonitorChartsData(
|
||||
req,
|
||||
monitorId,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
location
|
||||
);
|
||||
},
|
||||
async getLatestMonitors(
|
||||
resolver,
|
||||
{ dateRangeStart, dateRangeEnd, monitorId },
|
||||
{ dateRangeStart, dateRangeEnd, monitorId, location },
|
||||
{ req }
|
||||
): Promise<Ping[]> {
|
||||
return libs.pings.getLatestMonitorDocs(req, dateRangeStart, dateRangeEnd, monitorId);
|
||||
return await libs.pings.getLatestMonitorDocs(
|
||||
req,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
monitorId,
|
||||
location
|
||||
);
|
||||
},
|
||||
async getFilterBar(resolver, { dateRangeStart, dateRangeEnd }, { req }): Promise<FilterBar> {
|
||||
return libs.monitors.getFilterBar(req, dateRangeStart, dateRangeEnd);
|
||||
return await libs.monitors.getFilterBar(req, dateRangeStart, dateRangeEnd);
|
||||
},
|
||||
async getErrorsList(
|
||||
resolver,
|
||||
{ dateRangeStart, dateRangeEnd, filters },
|
||||
{ req }
|
||||
): Promise<any> {
|
||||
return libs.monitors.getErrorsList(req, dateRangeStart, dateRangeEnd, filters);
|
||||
return await libs.monitors.getErrorsList(req, dateRangeStart, dateRangeEnd, filters);
|
||||
},
|
||||
async getMonitorPageTitle(
|
||||
resolver: any,
|
||||
|
|
|
@ -7,11 +7,19 @@
|
|||
import gql from 'graphql-tag';
|
||||
|
||||
export const monitorsSchema = gql`
|
||||
"The data used to enrich the filter bar."
|
||||
type FilterBar {
|
||||
"A series of monitor IDs in the heartbeat indices."
|
||||
ids: [MonitorKey!]
|
||||
"The location values users have configured for the agents."
|
||||
locations: [String!]
|
||||
"The names users have configured for the monitors."
|
||||
names: [String!]
|
||||
"The ports of the monitored endpoints."
|
||||
ports: [Int!]
|
||||
"The schemes used by the monitors."
|
||||
schemes: [String!]
|
||||
"The possible status values contained in the indices."
|
||||
statuses: [String!]
|
||||
}
|
||||
|
||||
|
@ -105,14 +113,24 @@ export const monitorsSchema = gql`
|
|||
monitors: [LatestMonitor!]
|
||||
}
|
||||
|
||||
"A representation of an error state for a monitor."
|
||||
type ErrorListItem {
|
||||
"The number of times this error has occurred."
|
||||
count: Int!
|
||||
"The most recent message associated with this error type."
|
||||
latestMessage: String
|
||||
"The location assigned to the agent reporting this error."
|
||||
location: String
|
||||
"The ID of the monitor reporting the error."
|
||||
monitorId: String
|
||||
type: String!
|
||||
count: Int
|
||||
statusCode: String
|
||||
timestamp: String
|
||||
"The name configured for the monitor by the user."
|
||||
name: String
|
||||
"The status code, if available, of the error request."
|
||||
statusCode: String
|
||||
"When the most recent error state occurred."
|
||||
timestamp: String
|
||||
"What kind of error the monitor reported."
|
||||
type: String!
|
||||
}
|
||||
|
||||
type MonitorPageTitle {
|
||||
|
@ -134,9 +152,20 @@ export const monitorsSchema = gql`
|
|||
monitorId: String!
|
||||
dateRangeStart: String!
|
||||
dateRangeEnd: String!
|
||||
location: String
|
||||
): MonitorChart
|
||||
|
||||
getLatestMonitors(dateRangeStart: String!, dateRangeEnd: String!, monitorId: String): [Ping!]!
|
||||
"Fetch the most recent event data for a monitor ID, date range, location."
|
||||
getLatestMonitors(
|
||||
"The lower limit of the date range."
|
||||
dateRangeStart: String!
|
||||
"The upper limit of the date range."
|
||||
dateRangeEnd: String!
|
||||
"Optional: a specific monitor ID filter."
|
||||
monitorId: String
|
||||
"Optional: a specific instance location filter."
|
||||
location: String
|
||||
): [Ping!]!
|
||||
|
||||
getFilterBar(dateRangeStart: String!, dateRangeEnd: String!): FilterBar
|
||||
|
||||
|
|
|
@ -35,10 +35,19 @@ export const createPingsResolvers: CreateUMGraphQLResolvers = (
|
|||
Query: {
|
||||
async allPings(
|
||||
resolver,
|
||||
{ monitorId, sort, size, status, dateRangeStart, dateRangeEnd },
|
||||
{ monitorId, sort, size, status, dateRangeStart, dateRangeEnd, location },
|
||||
{ req }
|
||||
): Promise<PingResults> {
|
||||
return libs.pings.getAll(req, dateRangeStart, dateRangeEnd, monitorId, status, sort, size);
|
||||
return await libs.pings.getAll(
|
||||
req,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
monitorId,
|
||||
status,
|
||||
sort,
|
||||
size,
|
||||
location
|
||||
);
|
||||
},
|
||||
async getDocCount(resolver, args, { req }): Promise<DocCount> {
|
||||
return libs.pings.getDocCount(req);
|
||||
|
|
|
@ -19,12 +19,20 @@ export const pingsSchema = gql`
|
|||
type Query {
|
||||
"Get a list of all recorded pings for all monitors"
|
||||
allPings(
|
||||
"Optional: the direction to sort by. Accepts 'asc' and 'desc'. Defaults to 'desc'."
|
||||
sort: String
|
||||
"Optional: the number of results to return."
|
||||
size: Int
|
||||
"Optional: the monitor ID filter."
|
||||
monitorId: String
|
||||
"Optional: the check status to filter by."
|
||||
status: String
|
||||
"The lower limit of the date range."
|
||||
dateRangeStart: String!
|
||||
"The upper limit of the date range."
|
||||
dateRangeEnd: String!
|
||||
"Optional: agent location to filter by."
|
||||
location: String
|
||||
): PingResults!
|
||||
|
||||
"Gets the number of documents in the target index"
|
||||
|
@ -89,6 +97,26 @@ export const pingsSchema = gql`
|
|||
build: String
|
||||
}
|
||||
|
||||
"Geolocation data added via processors to enrich events."
|
||||
type Geo {
|
||||
"Name of the city in which the agent is running."
|
||||
city_name: String
|
||||
"The name of the continent on which the agent is running."
|
||||
continent_name: String
|
||||
"ISO designation for the agent's country."
|
||||
country_iso_code: String
|
||||
"The name of the agent's country."
|
||||
country_name: String
|
||||
"The lat/long of the agent."
|
||||
location: String
|
||||
"A name for the host's location, e.g. 'us-east-1' or 'LAX'."
|
||||
name: String
|
||||
"ISO designation of the agent's region."
|
||||
region_iso_code: String
|
||||
"Name of the region hosting the agent."
|
||||
region_name: String
|
||||
}
|
||||
|
||||
type Host {
|
||||
architecture: String
|
||||
id: String
|
||||
|
@ -172,6 +200,12 @@ export const pingsSchema = gql`
|
|||
check_group: String
|
||||
}
|
||||
|
||||
"Metadata added by a proccessor, which is specified in its configuration."
|
||||
type Observer {
|
||||
"Geolocation data for the agent."
|
||||
geo: Geo
|
||||
}
|
||||
|
||||
type Resolve {
|
||||
host: String
|
||||
ip: String
|
||||
|
@ -232,6 +266,7 @@ export const pingsSchema = gql`
|
|||
kubernetes: Kubernetes
|
||||
meta: Meta
|
||||
monitor: Monitor
|
||||
observer: Observer
|
||||
resolve: Resolve
|
||||
socks5: Socks5
|
||||
summary: Summary
|
||||
|
|
|
@ -1,5 +1,116 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ElasticsearchMonitorsAdapter getMonitorChartsData will provide expected filters when a location is specified 1`] = `
|
||||
Array [
|
||||
Object {},
|
||||
Object {
|
||||
"body": Object {
|
||||
"aggs": Object {
|
||||
"timeseries": Object {
|
||||
"aggs": Object {
|
||||
"duration": Object {
|
||||
"stats": Object {
|
||||
"field": "monitor.duration.us",
|
||||
},
|
||||
},
|
||||
"status": Object {
|
||||
"terms": Object {
|
||||
"field": "monitor.status",
|
||||
"shard_size": 2,
|
||||
"size": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"interval": "36000ms",
|
||||
},
|
||||
},
|
||||
},
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"@timestamp": Object {
|
||||
"gte": "now-15m",
|
||||
"lte": "now",
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"monitor.id": "fooID",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"observer.geo.name": "Philadelphia",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"size": 0,
|
||||
},
|
||||
"index": "heartbeat*",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ElasticsearchMonitorsAdapter getMonitorChartsData will run expected parameters when no location is specified 1`] = `
|
||||
Array [
|
||||
Object {},
|
||||
Object {
|
||||
"body": Object {
|
||||
"aggs": Object {
|
||||
"timeseries": Object {
|
||||
"aggs": Object {
|
||||
"duration": Object {
|
||||
"stats": Object {
|
||||
"field": "monitor.duration.us",
|
||||
},
|
||||
},
|
||||
"status": Object {
|
||||
"terms": Object {
|
||||
"field": "monitor.status",
|
||||
"shard_size": 2,
|
||||
"size": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"interval": "36000ms",
|
||||
},
|
||||
},
|
||||
},
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"@timestamp": Object {
|
||||
"gte": "now-15m",
|
||||
"lte": "now",
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"monitor.id": "fooID",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"size": 0,
|
||||
},
|
||||
"index": "heartbeat*",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ElasticsearchMonitorsAdapter will return kubernetes information if contained in hits 1`] = `
|
||||
Object {
|
||||
"downSeries": Array [],
|
||||
|
|
|
@ -62,4 +62,32 @@ describe('ElasticsearchMonitorsAdapter', () => {
|
|||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('getMonitorChartsData will run expected parameters when no location is specified', async () => {
|
||||
expect.assertions(2);
|
||||
const searchMock = jest.fn();
|
||||
const search = searchMock.bind({});
|
||||
const database = {
|
||||
search,
|
||||
count: async (request: any, params: any) => null,
|
||||
};
|
||||
const adapter = new ElasticsearchMonitorsAdapter(database);
|
||||
await adapter.getMonitorChartsData({}, 'fooID', 'now-15m', 'now');
|
||||
expect(searchMock).toHaveBeenCalledTimes(1);
|
||||
expect(searchMock.mock.calls[0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('getMonitorChartsData will provide expected filters when a location is specified', async () => {
|
||||
expect.assertions(2);
|
||||
const searchMock = jest.fn();
|
||||
const search = searchMock.bind({});
|
||||
const database = {
|
||||
search,
|
||||
count: async (request: any, params: any) => null,
|
||||
};
|
||||
const adapter = new ElasticsearchMonitorsAdapter(database);
|
||||
await adapter.getMonitorChartsData({}, 'fooID', 'now-15m', 'now', 'Philadelphia');
|
||||
expect(searchMock).toHaveBeenCalledTimes(1);
|
||||
expect(searchMock.mock.calls[0]).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,7 +11,8 @@ export interface UMMonitorsAdapter {
|
|||
request: any,
|
||||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
dateRangeEnd: string,
|
||||
location?: string | null
|
||||
): Promise<MonitorChart>;
|
||||
getMonitors(
|
||||
request: any,
|
||||
|
|
|
@ -16,10 +16,14 @@ import {
|
|||
MonitorSeriesPoint,
|
||||
Ping,
|
||||
} from '../../../../common/graphql/types';
|
||||
import { dropLatestBucket, getFilteredQuery, getFilteredQueryAndStatusFilter } from '../../helper';
|
||||
import {
|
||||
dropLatestBucket,
|
||||
getFilteredQuery,
|
||||
getFilteredQueryAndStatusFilter,
|
||||
getHistogramInterval,
|
||||
} from '../../helper';
|
||||
import { DatabaseAdapter } from '../database';
|
||||
import { UMMonitorsAdapter } from './adapter_types';
|
||||
import { getHistogramInterval } from '../../helper/get_histogram_interval';
|
||||
|
||||
const formatStatusBuckets = (time: any, buckets: any, docCount: any) => {
|
||||
let up = null;
|
||||
|
@ -57,7 +61,8 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
request: any,
|
||||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
dateRangeEnd: string,
|
||||
location?: string | null
|
||||
): Promise<MonitorChart> {
|
||||
const params = {
|
||||
index: INDEX_NAMES.HEARTBEAT,
|
||||
|
@ -67,6 +72,8 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
filter: [
|
||||
{ range: { '@timestamp': { gte: dateRangeStart, lte: dateRangeEnd } } },
|
||||
{ term: { 'monitor.id': monitorId } },
|
||||
// if location is truthy, add it as a filter. otherwise add nothing
|
||||
...(!!location ? [{ term: { 'observer.geo.name': location } }] : []),
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -166,6 +173,14 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
missing_bucket: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
size: 10000,
|
||||
},
|
||||
|
@ -257,8 +272,16 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
missing_bucket: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
size: 50,
|
||||
size: 40,
|
||||
},
|
||||
aggs: {
|
||||
latest: {
|
||||
|
@ -275,6 +298,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
interval: getHistogramInterval(dateRangeStart, dateRangeEnd),
|
||||
missing: 0,
|
||||
},
|
||||
aggs: {
|
||||
status: {
|
||||
|
@ -350,7 +374,14 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
const params = {
|
||||
index: INDEX_NAMES.HEARTBEAT,
|
||||
body: {
|
||||
_source: ['monitor.id', 'monitor.type', 'url.full', 'url.port', 'monitor.name'],
|
||||
_source: [
|
||||
'monitor.id',
|
||||
'monitor.type',
|
||||
'url.full',
|
||||
'url.port',
|
||||
'monitor.name',
|
||||
'observer.geo.name',
|
||||
],
|
||||
size: 1000,
|
||||
query: {
|
||||
range: {
|
||||
|
@ -373,6 +404,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
const ports = new Set<number>();
|
||||
const types = new Set<string>();
|
||||
const names = new Set<string>();
|
||||
const locations = new Set<string>();
|
||||
|
||||
const hits = get(result, 'hits.hits', []);
|
||||
hits.forEach((hit: any) => {
|
||||
|
@ -381,6 +413,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
const port: number | undefined = get(hit, '_source.url.port', undefined);
|
||||
const type: string | undefined = get(hit, '_source.monitor.type', undefined);
|
||||
const name: string | null = get(hit, '_source.monitor.name', null);
|
||||
const location: string | null = get(hit, '_source.observer.geo.name', null);
|
||||
|
||||
if (key) {
|
||||
ids.push({ key, url });
|
||||
|
@ -394,13 +427,17 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
if (name) {
|
||||
names.add(name);
|
||||
}
|
||||
if (location) {
|
||||
locations.add(location);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
ids,
|
||||
locations: Array.from(locations),
|
||||
names: Array.from(names),
|
||||
ports: Array.from(ports),
|
||||
schemes: Array.from(types),
|
||||
names: Array.from(names),
|
||||
statuses: ['up', 'down'],
|
||||
};
|
||||
}
|
||||
|
@ -439,65 +476,78 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
query,
|
||||
size: 0,
|
||||
aggs: {
|
||||
error_type: {
|
||||
terms: {
|
||||
field: 'error.type',
|
||||
size: 100,
|
||||
},
|
||||
aggs: {
|
||||
by_id: {
|
||||
terms: {
|
||||
field: 'monitor.id',
|
||||
size: 100,
|
||||
},
|
||||
aggs: {
|
||||
latest: {
|
||||
top_hits: {
|
||||
sort: [{ '@timestamp': { order: 'desc' } }],
|
||||
size: 1,
|
||||
errors: {
|
||||
composite: {
|
||||
sources: [
|
||||
{
|
||||
id: {
|
||||
terms: {
|
||||
field: 'monitor.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
error_type: {
|
||||
terms: {
|
||||
field: 'error.type',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
missing_bucket: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
size: 50,
|
||||
},
|
||||
aggs: {
|
||||
latest: {
|
||||
top_hits: {
|
||||
sort: [
|
||||
{
|
||||
'@timestamp': {
|
||||
order: 'desc',
|
||||
},
|
||||
},
|
||||
],
|
||||
size: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await this.database.search(request, params);
|
||||
const buckets = get(result, 'aggregations.error_type.buckets', []);
|
||||
const buckets = get(result, 'aggregations.errors.buckets', []);
|
||||
|
||||
const errorsList: ErrorListItem[] = [];
|
||||
buckets.forEach(
|
||||
({
|
||||
key: errorType,
|
||||
by_id: { buckets: monitorBuckets },
|
||||
}: {
|
||||
key: string;
|
||||
by_id: { buckets: any[] };
|
||||
}) => {
|
||||
monitorBuckets.forEach(bucket => {
|
||||
const count = get(bucket, 'doc_count', null);
|
||||
const monitorId = get(bucket, 'key', null);
|
||||
const source = get(bucket, 'latest.hits.hits[0]._source', null);
|
||||
const errorMessage = get(source, 'error.message', null);
|
||||
const statusCode = get(source, 'http.response.status_code', null);
|
||||
const timestamp = get(source, '@timestamp', null);
|
||||
const name = get(source, 'monitor.name', null);
|
||||
errorsList.push({
|
||||
latestMessage: errorMessage,
|
||||
monitorId,
|
||||
type: errorType,
|
||||
count,
|
||||
statusCode,
|
||||
timestamp,
|
||||
name: name === '' ? null : name,
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
return errorsList;
|
||||
buckets.forEach((bucket: any) => {
|
||||
const count = get<number>(bucket, 'doc_count', 0);
|
||||
const monitorId = get<string | null>(bucket, 'key.id', null);
|
||||
const errorType = get<string | null>(bucket, 'key.error_type', null);
|
||||
const location = get<string | null>(bucket, 'key.location', null);
|
||||
const source = get<string | null>(bucket, 'latest.hits.hits[0]._source', null);
|
||||
const errorMessage = get(source, 'error.message', null);
|
||||
const statusCode = get(source, 'http.response.status_code', null);
|
||||
const timestamp = get(source, '@timestamp', null);
|
||||
const name = get(source, 'monitor.name', null);
|
||||
errorsList.push({
|
||||
count,
|
||||
latestMessage: errorMessage,
|
||||
location,
|
||||
monitorId,
|
||||
name: name === '' ? null : name,
|
||||
statusCode,
|
||||
timestamp,
|
||||
type: errorType || '',
|
||||
});
|
||||
});
|
||||
return errorsList.sort(({ count: A }, { count: B }) => B - A);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,14 +14,16 @@ export interface UMPingsAdapter {
|
|||
monitorId?: string | null,
|
||||
status?: string | null,
|
||||
sort?: string | null,
|
||||
size?: number | null
|
||||
size?: number | null,
|
||||
location?: string | null
|
||||
): Promise<PingResults>;
|
||||
|
||||
getLatestMonitorDocs(
|
||||
request: any,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string,
|
||||
monitorId?: string | null
|
||||
monitorId?: string | null,
|
||||
location?: string | null
|
||||
): Promise<Ping[]>;
|
||||
|
||||
getPingHistogram(
|
||||
|
|
|
@ -37,7 +37,8 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
|
|||
monitorId?: string | null,
|
||||
status?: string | null,
|
||||
sort: string | null = 'desc',
|
||||
size?: number | null
|
||||
size?: number | null,
|
||||
location?: string | null
|
||||
): Promise<PingResults> {
|
||||
const sortParam = { sort: [{ '@timestamp': { order: sort } }] };
|
||||
const sizeParam = size ? { size } : undefined;
|
||||
|
@ -48,6 +49,9 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
|
|||
if (status) {
|
||||
filter.push({ term: { 'monitor.status': status } });
|
||||
}
|
||||
if (location) {
|
||||
filter.push({ term: { 'observer.geo.name': location } });
|
||||
}
|
||||
const queryContext = { bool: { filter } };
|
||||
const params = {
|
||||
index: INDEX_NAMES.HEARTBEAT,
|
||||
|
@ -87,12 +91,10 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
|
|||
request: any,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string,
|
||||
monitorId?: string | null
|
||||
monitorId?: string | null,
|
||||
location?: string | null
|
||||
): Promise<Ping[]> {
|
||||
const filter: any[] = [];
|
||||
if (monitorId) {
|
||||
filter.push({ term: { 'monitor.id': monitorId } });
|
||||
}
|
||||
// TODO: Write tests for this function
|
||||
const params = {
|
||||
index: INDEX_NAMES.HEARTBEAT,
|
||||
body: {
|
||||
|
@ -107,6 +109,8 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
|
|||
},
|
||||
},
|
||||
},
|
||||
...(monitorId ? [{ term: { 'monitor.id': monitorId } }] : []),
|
||||
...(location ? [{ term: { 'observer.geo.name': location } }] : []),
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -132,10 +136,6 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
|
|||
},
|
||||
};
|
||||
|
||||
if (filter.length) {
|
||||
params.body.query.bool.filter.push(...filter);
|
||||
}
|
||||
|
||||
const result = await this.database.search(request, params);
|
||||
const buckets: any[] = get(result, 'aggregations.by_id.buckets', []);
|
||||
|
||||
|
|
|
@ -16,9 +16,16 @@ export class UMMonitorsDomain {
|
|||
request: any,
|
||||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
dateRangeEnd: string,
|
||||
location?: string | null
|
||||
): Promise<MonitorChart> {
|
||||
return this.adapter.getMonitorChartsData(request, monitorId, dateRangeStart, dateRangeEnd);
|
||||
return this.adapter.getMonitorChartsData(
|
||||
request,
|
||||
monitorId,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
public async getMonitors(
|
||||
|
|
|
@ -19,7 +19,8 @@ export class UMPingsDomain {
|
|||
monitorId?: string | null,
|
||||
status?: string | null,
|
||||
sort?: string | null,
|
||||
size?: number | null
|
||||
size?: number | null,
|
||||
location?: string | null
|
||||
): Promise<PingResults> {
|
||||
return this.adapter.getAll(
|
||||
request,
|
||||
|
@ -28,7 +29,8 @@ export class UMPingsDomain {
|
|||
monitorId,
|
||||
status,
|
||||
sort,
|
||||
size
|
||||
size,
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -36,9 +38,16 @@ export class UMPingsDomain {
|
|||
request: any,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string,
|
||||
monitorId?: string | null
|
||||
monitorId?: string | null,
|
||||
location?: string | null
|
||||
): Promise<Ping[]> {
|
||||
return this.adapter.getLatestMonitorDocs(request, dateRangeStart, dateRangeEnd, monitorId);
|
||||
return this.adapter.getLatestMonitorDocs(
|
||||
request,
|
||||
dateRangeStart,
|
||||
dateRangeEnd,
|
||||
monitorId,
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
public async getPingHistogram(
|
||||
|
|
|
@ -8,12 +8,28 @@ import { getHistogramInterval } from '../get_histogram_interval';
|
|||
|
||||
describe('getHistogramInterval', () => {
|
||||
it('specifies the interval necessary to divide a given timespan into equal buckets, rounded to the nearest integer, expressed in ms', () => {
|
||||
expect.assertions(3);
|
||||
const result = getHistogramInterval('now-15m', 'now', 10);
|
||||
expect(result).toEqual('90000ms');
|
||||
/**
|
||||
* These assertions were verbatim comparisons but that introduced
|
||||
* some flakiness at the ms resolution, sometimes values like "9001ms"
|
||||
* are returned.
|
||||
*/
|
||||
expect(result.startsWith('9000')).toBeTruthy();
|
||||
expect(result.endsWith('ms')).toBeTruthy();
|
||||
expect(result).toHaveLength(7);
|
||||
});
|
||||
|
||||
it('will supply a default constant value for bucketCount when none is provided', () => {
|
||||
expect.assertions(3);
|
||||
const result = getHistogramInterval('now-15m', 'now');
|
||||
expect(result).toEqual('36000ms');
|
||||
/**
|
||||
* These assertions were verbatim comparisons but that introduced
|
||||
* some flakiness at the ms resolution, sometimes values like "9001ms"
|
||||
* are returned.
|
||||
*/
|
||||
expect(result.startsWith('3600')).toBeTruthy();
|
||||
expect(result.endsWith('ms')).toBeTruthy();
|
||||
expect(result).toHaveLength(7);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,3 +9,4 @@ export { formatEsBucketsForHistogram } from './format_es_buckets_for_histogram';
|
|||
export { getFilteredQuery } from './get_filtered_query';
|
||||
export { getFilteredQueryAndStatusFilter } from './get_filtered_query_and_status';
|
||||
export { getFilterFromMust } from './get_filter_from_must';
|
||||
export { getHistogramInterval } from './get_histogram_interval';
|
||||
|
|
|
@ -1,40 +1,44 @@
|
|||
{
|
||||
"errorList": [
|
||||
{
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"type": "io",
|
||||
"count": 843,
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"location": null,
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"name": null
|
||||
"type": "io"
|
||||
},
|
||||
{
|
||||
"latestMessage": "dial tcp 127.0.0.1:9200: connect: connection refused",
|
||||
"monitorId": "auto-tcp-0X81440A68E839814C",
|
||||
"type": "io",
|
||||
"count": 748,
|
||||
"latestMessage": "dial tcp 127.0.0.1:9200: connect: connection refused",
|
||||
"location": null,
|
||||
"monitorId": "auto-tcp-0X81440A68E839814C",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T17:59:34.075Z",
|
||||
"name": null
|
||||
"type": "io"
|
||||
},
|
||||
{
|
||||
"latestMessage": "lookup www.reddit.com: no such host",
|
||||
"monitorId": "auto-http-0XD9AE729FC1C1E04A",
|
||||
"type": "io",
|
||||
"count": 1,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T18:03:10.077Z",
|
||||
"name": null
|
||||
},
|
||||
{
|
||||
"latestMessage": "received status code 301 expecting 200",
|
||||
"monitorId": "auto-http-0XA8096548ECEB85B7",
|
||||
"type": "validate",
|
||||
"count": 645,
|
||||
"latestMessage": "received status code 301 expecting 200",
|
||||
"location": null,
|
||||
"monitorId": "auto-http-0XA8096548ECEB85B7",
|
||||
"name": null,
|
||||
"statusCode": "301",
|
||||
"timestamp": "2019-01-28T18:43:07.078Z",
|
||||
"name": null
|
||||
"type": "validate"
|
||||
},
|
||||
{
|
||||
"count": 1,
|
||||
"latestMessage": "lookup www.reddit.com: no such host",
|
||||
"location": null,
|
||||
"monitorId": "auto-http-0XD9AE729FC1C1E04A",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T18:03:10.077Z",
|
||||
"type": "io"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
"errorList": [
|
||||
{
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"type": "io",
|
||||
"count": 843,
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"location": null,
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"name": null
|
||||
"type": "io"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
"errorList": [
|
||||
{
|
||||
"latestMessage": "dial tcp 127.0.0.1:9200: connect: connection refused",
|
||||
"monitorId": "auto-tcp-0X81440A68E839814C",
|
||||
"type": "io",
|
||||
"count": 748,
|
||||
"latestMessage": "dial tcp 127.0.0.1:9200: connect: connection refused",
|
||||
"location": null,
|
||||
"monitorId": "auto-tcp-0X81440A68E839814C",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T17:59:34.075Z",
|
||||
"name": null
|
||||
"type": "io"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
"errorList": [
|
||||
{
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"type": "io",
|
||||
"count": 843,
|
||||
"latestMessage": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused",
|
||||
"location": null,
|
||||
"monitorId": "auto-http-0X3675F89EF0612091",
|
||||
"name": null,
|
||||
"statusCode": null,
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"name": null
|
||||
"type": "io"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"filterBar": {
|
||||
"ports": [9200, 12349],
|
||||
"ids": [
|
||||
{ "key": "auto-tcp-0X81440A68E839814C", "url": "tcp://localhost:9200" },
|
||||
{ "key": "auto-http-0X3675F89EF0612091", "url": "http://localhost:12349/" },
|
||||
|
@ -13,7 +12,9 @@
|
|||
{ "key": "auto-http-0XC9CDA429418EDC2B", "url": "https://www.wikipedia.org/" },
|
||||
{ "key": "auto-http-0XE3B163481423197D", "url": "https://news.google.com/" }
|
||||
],
|
||||
"locations": [],
|
||||
"names": [],
|
||||
"ports": [9200, 12349],
|
||||
"schemes": ["tcp", "http"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.google.com", "full": "https://www.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -70,6 +71,7 @@
|
|||
"name": "",
|
||||
"status": "down"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "localhost", "full": "http://localhost:12349/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -126,6 +128,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.google.com", "full": "http://www.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -182,6 +185,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.github.com", "full": "https://www.github.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -238,6 +242,7 @@
|
|||
"name": "",
|
||||
"status": "down"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.example.com", "full": "http://www.example.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -294,6 +299,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.wikipedia.org", "full": "https://www.wikipedia.org/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -350,6 +356,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.reddit.com", "full": "http://www.reddit.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -406,6 +413,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.elastic.co", "full": "https://www.elastic.co" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -462,6 +470,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "news.google.com", "full": "https://news.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -518,6 +527,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "localhost", "full": "tcp://localhost:9200" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"name": "",
|
||||
"status": "down"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "localhost", "full": "http://localhost:12349/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -70,6 +71,7 @@
|
|||
"name": "",
|
||||
"status": "down"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.example.com", "full": "http://www.example.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.google.com", "full": "https://www.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -70,6 +71,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.google.com", "full": "http://www.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -126,6 +128,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.github.com", "full": "https://www.github.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -182,6 +185,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.wikipedia.org", "full": "https://www.wikipedia.org/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -238,6 +242,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.reddit.com", "full": "http://www.reddit.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -294,6 +299,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "www.elastic.co", "full": "https://www.elastic.co" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -350,6 +356,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "news.google.com", "full": "https://news.google.com/" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
@ -406,6 +413,7 @@
|
|||
"name": "",
|
||||
"status": "up"
|
||||
},
|
||||
"observer": null,
|
||||
"url": { "domain": "localhost", "full": "tcp://localhost:9200" }
|
||||
},
|
||||
"upSeries": [
|
||||
|
|
|
@ -3,51 +3,61 @@
|
|||
{
|
||||
"timestamp": "2019-01-28T18:43:16.078Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 3328 } },
|
||||
"observer": null,
|
||||
"url": { "full": "tcp://localhost:9200" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:13.074Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 299586 } },
|
||||
"observer": null,
|
||||
"url": { "full": "http://www.reddit.com/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:13.074Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 850870 } },
|
||||
"observer": null,
|
||||
"url": { "full": "https://www.elastic.co" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"monitor": { "status": "down", "duration": { "us": 3331 } },
|
||||
"observer": null,
|
||||
"url": { "full": "http://localhost:12349/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 132169 } },
|
||||
"observer": null,
|
||||
"url": { "full": "https://www.google.com/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 247244 } },
|
||||
"observer": null,
|
||||
"url": { "full": "https://www.github.com/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:15.077Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 118727 } },
|
||||
"observer": null,
|
||||
"url": { "full": "http://www.google.com/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:43:07.078Z",
|
||||
"monitor": { "status": "down", "duration": { "us": 4751074 } },
|
||||
"observer": null,
|
||||
"url": { "full": "http://www.example.com/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:42:55.074Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 1164812 } },
|
||||
"observer": null,
|
||||
"url": { "full": "https://www.wikipedia.org/" }
|
||||
},
|
||||
{
|
||||
"timestamp": "2019-01-28T18:42:55.074Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 2059606 } },
|
||||
"observer": null,
|
||||
"url": { "full": "https://news.google.com/" }
|
||||
}
|
||||
]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
{
|
||||
"timestamp": "2019-01-28T18:43:16.078Z",
|
||||
"monitor": { "status": "up", "duration": { "us": 3328 } },
|
||||
"observer": null,
|
||||
"url": { "full": "tcp://localhost:9200" }
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue