[Uptime] Summary based monitors Page (#39751)

This implements the overview page changes described in elastic/uptime#41 and https://docs.google.com/document/d/1jlyOam08gC3oq0W8dim0BF-5QYEOXFqSg48nMwbirmg/edit

One change that was necessary was omitting the swimlane visualization. After speaking to the ML team it was discovered that incorporating this component isn't possible yet, as it requires cross-plugin code sharing. In its stead we have re-used the monitor checks over time graph. We may want to keep this, as the graph used here is superior for multiple IP use cases.
This commit is contained in:
Andrew Cholakian 2019-07-01 12:57:15 -05:00 committed by GitHub
parent 53273ecff4
commit 9949107a79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 1244 additions and 1282 deletions

View file

@ -154,6 +154,59 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "getSnapshotHistogram",
"description": "",
"args": [
{
"name": "dateRangeStart",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
},
"defaultValue": null
},
{
"name": "dateRangeEnd",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
},
"defaultValue": null
},
{
"name": "filters",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
},
{
"name": "monitorId",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"defaultValue": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "OBJECT", "name": "HistogramDataPoint", "ofType": null }
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "getMonitorChartsData",
"description": "",
@ -376,7 +429,7 @@
"fields": [
{
"name": "total",
"description": "",
"description": "Total number of matching pings",
"args": [],
"type": {
"kind": "NON_NULL",
@ -386,9 +439,29 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "locations",
"description": "Unique list of all locations the query matched",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pings",
"description": "",
"description": "List of pings ",
"args": [],
"type": {
"kind": "NON_NULL",
@ -1915,26 +1988,6 @@
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "histogram",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "OBJECT", "name": "HistogramDataPoint", "ofType": null }
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
@ -1999,27 +2052,7 @@
"description": "The data used to populate the monitor charts.",
"fields": [
{
"name": "durationArea",
"description": "The max and min values for the monitor duration.",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "OBJECT", "name": "MonitorDurationAreaPoint", "ofType": null }
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "durationLine",
"name": "locationDurationLines",
"description": "The average values for the monitor duration.",
"args": [],
"type": {
@ -2031,11 +2064,7 @@
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "MonitorDurationAveragePoint",
"ofType": null
}
"ofType": { "kind": "OBJECT", "name": "LocationDurationLine", "ofType": null }
}
}
},
@ -2094,34 +2123,42 @@
},
{
"kind": "OBJECT",
"name": "MonitorDurationAreaPoint",
"description": "Represents a monitor's duration performance in microseconds at a point in time.",
"name": "LocationDurationLine",
"description": "",
"fields": [
{
"name": "x",
"description": "The timeseries value for this point in time.",
"name": "name",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "yMin",
"description": "The min duration value in microseconds at this time.",
"name": "line",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "yMax",
"description": "The max duration value in microseconds at this point.",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "MonitorDurationAveragePoint",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
@ -2131,16 +2168,6 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Float",
"description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MonitorDurationAveragePoint",
@ -2172,6 +2199,16 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Float",
"description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "StatusData",
@ -3174,6 +3211,45 @@
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MonitorDurationAreaPoint",
"description": "Represents a monitor's duration performance in microseconds at a point in time.",
"fields": [
{
"name": "x",
"description": "The timeseries value for this point in time.",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "yMin",
"description": "The min duration value in microseconds at this time.",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "yMax",
"description": "The max duration value in microseconds at this point.",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
}
],
"directives": [

View file

@ -29,6 +29,8 @@ export interface Query {
getSnapshot?: Snapshot | null;
getSnapshotHistogram: HistogramDataPoint[];
getMonitorChartsData?: MonitorChart | null;
/** Fetch the most recent event data for a monitor ID, date range, location. */
getLatestMonitors: Ping[];
@ -41,8 +43,11 @@ export interface Query {
}
export interface PingResults {
/** Total number of matching pings */
total: UnsignedInteger;
/** Unique list of all locations the query matched */
locations: string[];
/** List of pings */
pings: Ping[];
}
/** A request sent from a monitor to a host */
@ -386,8 +391,6 @@ export interface Snapshot {
down?: number | null;
total?: number | null;
histogram: HistogramDataPoint[];
}
export interface HistogramDataPoint {
@ -403,10 +406,8 @@ export interface HistogramDataPoint {
}
/** The data used to populate the monitor charts. */
export interface MonitorChart {
/** The max and min values for the monitor duration. */
durationArea: MonitorDurationAreaPoint[];
/** The average values for the monitor duration. */
durationLine: MonitorDurationAveragePoint[];
locationDurationLines: LocationDurationLine[];
/** The counts of up/down checks for the monitor. */
status: StatusData[];
/** The maximum status doc count in this chart. */
@ -414,14 +415,11 @@ export interface MonitorChart {
/** The maximum duration value in this chart. */
durationMaxValue: number;
}
/** Represents a monitor's duration performance in microseconds at a point in time. */
export interface MonitorDurationAreaPoint {
/** The timeseries value for this point in time. */
x: UnsignedInteger;
/** The min duration value in microseconds at this time. */
yMin?: number | null;
/** The max duration value in microseconds at this point. */
yMax?: number | null;
export interface LocationDurationLine {
name: string;
line: MonitorDurationAveragePoint[];
}
/** Represents the average monitor duration ms at a point in time. */
export interface MonitorDurationAveragePoint {
@ -489,6 +487,15 @@ export interface DataPoint {
y?: number | null;
}
/** Represents a monitor's duration performance in microseconds at a point in time. */
export interface MonitorDurationAreaPoint {
/** The timeseries value for this point in time. */
x: UnsignedInteger;
/** The min duration value in microseconds at this time. */
yMin?: number | null;
/** The max duration value in microseconds at this point. */
yMax?: number | null;
}
// ====================================================
// Arguments
@ -524,6 +531,15 @@ export interface GetSnapshotQueryArgs {
filters?: string | null;
}
export interface GetSnapshotHistogramQueryArgs {
dateRangeStart: string;
dateRangeEnd: string;
filters?: string | null;
monitorId?: string | null;
}
export interface GetMonitorChartsDataQueryArgs {
monitorId: string;

View file

@ -11,110 +11,56 @@ exports[`MonitorCharts component renders the component without errors 1`] = `
}
>
<DurationChart
durationArea={
locationDurationLines={
Array [
Object {
"x": 1548697620000,
"yMax": 3120392,
"yMin": 106421,
},
Object {
"x": 1548697920000,
"yMax": 3955186,
"yMin": 121653,
},
Object {
"x": 1548698220000,
"yMax": 3705359,
"yMin": 118224,
},
Object {
"x": 1548698520000,
"yMax": 6669234,
"yMin": 123345,
},
Object {
"x": 1548698820000,
"yMax": 3955729,
"yMin": 117268,
},
Object {
"x": 1548699120000,
"yMax": 4045216,
"yMin": 122110,
},
Object {
"x": 1548699420000,
"yMax": 3682859,
"yMin": 120015,
},
Object {
"x": 1548699720000,
"yMax": 3701297,
"yMin": 114751,
},
Object {
"x": 1548700020000,
"yMax": 3632224,
"yMin": 111949,
},
Object {
"x": 1548700320000,
"yMax": 3801401,
"yMin": 105126,
},
Object {
"x": 1548700620000,
"yMax": 3925269,
"yMin": 123639,
},
]
}
durationLine={
Array [
Object {
"x": 1548697620000,
"y": 743928.2027027027,
},
Object {
"x": 1548697920000,
"y": 766840.0133333333,
},
Object {
"x": 1548698220000,
"y": 786970.8266666667,
},
Object {
"x": 1548698520000,
"y": 781064.7808219178,
},
Object {
"x": 1548698820000,
"y": 741563.04,
},
Object {
"x": 1548699120000,
"y": 759354.6756756756,
},
Object {
"x": 1548699420000,
"y": 737533.3866666667,
},
Object {
"x": 1548699720000,
"y": 728669.0266666666,
},
Object {
"x": 1548700020000,
"y": 719951.64,
},
Object {
"x": 1548700320000,
"y": 769181.7866666666,
},
Object {
"x": 1548700620000,
"y": 740805.2666666667,
"line": Array [
Object {
"x": 1548697620000,
"y": 743928.2027027027,
},
Object {
"x": 1548697920000,
"y": 766840.0133333333,
},
Object {
"x": 1548698220000,
"y": 786970.8266666667,
},
Object {
"x": 1548698520000,
"y": 781064.7808219178,
},
Object {
"x": 1548698820000,
"y": 741563.04,
},
Object {
"x": 1548699120000,
"y": 759354.6756756756,
},
Object {
"x": 1548699420000,
"y": 737533.3866666667,
},
Object {
"x": 1548699720000,
"y": 728669.0266666666,
},
Object {
"x": 1548700020000,
"y": 719951.64,
},
Object {
"x": 1548700320000,
"y": 769181.7866666666,
},
Object {
"x": 1548700620000,
"y": 740805.2666666667,
},
],
"name": "somewhere",
},
]
}
@ -123,79 +69,18 @@ exports[`MonitorCharts component renders the component without errors 1`] = `
/>
</EuiFlexItem>
<EuiFlexItem>
<ChecksChart
dangerColor="dangerColor"
status={
Array [
Object {
"down": null,
"total": 74,
"up": 74,
"x": 1548697620000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548697920000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548698220000,
},
Object {
"down": null,
"total": 73,
"up": 73,
"x": 1548698520000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548698820000,
},
Object {
"down": null,
"total": 74,
"up": 74,
"x": 1548699120000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548699420000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548699720000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548700020000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548700320000,
},
Object {
"down": null,
"total": 75,
"up": 75,
"x": 1548700620000,
},
]
<withApollo(Component)
absoluteEndDate={1322903730000}
absoluteStartDate={1322903730000}
dangerColor="#bd271e"
successColor="#017d73"
variables={
Object {
"dateRangeEnd": "2011-12-03T10:15:30+01:00",
"dateRangeStart": "2011-12-03T10:15:30+01:00",
"monitorId": "something",
}
}
successColor="success"
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -51,42 +51,98 @@ exports[`PingList component renders sorted list without errors 1`] = `
}
}
>
<EuiComboBox
aria-label="Status"
compressed={false}
fullWidth={false}
isClearable={false}
onChange={[Function]}
options={
Array [
Object {
"label": "All",
"value": "",
},
Object {
"label": "Up",
"value": "up",
},
Object {
"label": "Down",
"value": "down",
},
]
}
selectedOptions={
Array [
Object {
"label": "Down",
"value": "down",
},
]
}
singleSelection={
Object {
"asPlainText": true,
}
}
/>
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow
aria-label="Status"
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
label="Status"
labelType="label"
>
<EuiComboBox
aria-label="Status"
compressed={false}
fullWidth={false}
isClearable={false}
onChange={[Function]}
options={
Array [
Object {
"label": "All",
"value": "",
},
Object {
"label": "Up",
"value": "up",
},
Object {
"label": "Down",
"value": "down",
},
]
}
selectedOptions={
Array [
Object {
"label": "Down",
"value": "down",
},
]
}
singleSelection={
Object {
"asPlainText": true,
}
}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
aria-label="Location"
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
label="Location"
labelType="label"
>
<EuiComboBox
aria-label="Location"
compressed={false}
fullWidth={false}
isClearable={false}
onChange={[Function]}
options={
Array [
Object {
"label": "All",
"value": "All",
},
Object {
"label": "nyc",
"value": "nyc",
},
]
}
selectedOptions={
Array [
Object {
"label": "All",
"value": "All",
},
]
}
singleSelection={
Object {
"asPlainText": true,
}
}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
@ -102,6 +158,12 @@ exports[`PingList component renders sorted list without errors 1`] = `
"name": "Status",
"render": [Function],
},
Object {
"dataType": "number",
"field": "observer.geo.name",
"name": "Location",
"render": [Function],
},
Object {
"dataType": "number",
"field": "monitor.ip",

View file

@ -1,184 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Snapshot component renders without errors 1`] = `
<EuiFlexGroup
gutterSize="s"
>
<EuiFlexItem
grow={4}
<Fragment>
<EuiTitle
size="xs"
>
<EuiTitle
size="xs"
>
<h5>
<FormattedMessage
defaultMessage="Current status"
id="xpack.uptime.snapshot.endpointStatusTitle"
values={Object {}}
/>
</h5>
</EuiTitle>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="s"
>
<EuiFlexGroup
direction="column"
>
<EuiFlexItem
grow={false}
>
<EuiSpacer
size="s"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup
gutterSize="s"
justifyContent="spaceEvenly"
>
<EuiFlexItem>
<EuiStat
description="Up"
textAlign="center"
title={8}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description="Down"
textAlign="center"
title={2}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description="Total"
textAlign="center"
title={10}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
grow={8}
>
<EuiTitle
size="xs"
>
<h5>
<FormattedMessage
defaultMessage="Status over time"
id="xpack.uptime.snapshot.statusOverTimeTitle"
values={Object {}}
/>
</h5>
</EuiTitle>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="s"
style={
Object {
"height": 170,
}
}
>
<SnapshotHistogram
absoluteEndDate={1548700920000}
absoluteStartDate={1548697920000}
dangerColor="#F050F0"
histogram={
Array [
Object {
"downCount": 3,
"upCount": 7,
"x": 1548697920000,
"x0": 1548697620000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 7,
"x": 1548698220000,
"x0": 1548697920000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 7,
"x": 1548698520000,
"x0": 1548698220000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 7,
"x": 1548698820000,
"x0": 1548698520000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548699120000,
"x0": 1548698820000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548699420000,
"x0": 1548699120000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548699720000,
"x0": 1548699420000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548700020000,
"x0": 1548699720000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548700320000,
"x0": 1548700020000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548700620000,
"x0": 1548700320000,
"y": 1,
},
Object {
"downCount": 2,
"upCount": 8,
"x": 1548700920000,
"x0": 1548700620000,
"y": 1,
},
]
}
successColor="#000000"
<h5>
<FormattedMessage
defaultMessage="Current status"
id="xpack.uptime.snapshot.endpointStatusTitle"
values={Object {}}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</h5>
</EuiTitle>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="s"
>
<EuiFlexGroup
direction="column"
>
<EuiFlexItem
grow={false}
>
<EuiSpacer
size="s"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup
gutterSize="s"
justifyContent="spaceEvenly"
>
<EuiFlexItem>
<EuiStat
description="Up"
textAlign="center"
title={8}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description="Down"
textAlign="center"
title={2}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description="Total"
textAlign="center"
title={10}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</Fragment>
`;

View file

@ -12,31 +12,23 @@ import { MonitorChart } from '../../../../common/graphql/types';
describe('MonitorCharts component', () => {
const chartResponse: { monitorChartsData: MonitorChart } = {
monitorChartsData: {
durationArea: [
{ x: 1548697620000, yMin: 106421, yMax: 3120392 },
{ x: 1548697920000, yMin: 121653, yMax: 3955186 },
{ x: 1548698220000, yMin: 118224, yMax: 3705359 },
{ x: 1548698520000, yMin: 123345, yMax: 6669234 },
{ x: 1548698820000, yMin: 117268, yMax: 3955729 },
{ x: 1548699120000, yMin: 122110, yMax: 4045216 },
{ x: 1548699420000, yMin: 120015, yMax: 3682859 },
{ x: 1548699720000, yMin: 114751, yMax: 3701297 },
{ x: 1548700020000, yMin: 111949, yMax: 3632224 },
{ x: 1548700320000, yMin: 105126, yMax: 3801401 },
{ x: 1548700620000, yMin: 123639, yMax: 3925269 },
],
durationLine: [
{ x: 1548697620000, y: 743928.2027027027 },
{ x: 1548697920000, y: 766840.0133333333 },
{ x: 1548698220000, y: 786970.8266666667 },
{ x: 1548698520000, y: 781064.7808219178 },
{ x: 1548698820000, y: 741563.04 },
{ x: 1548699120000, y: 759354.6756756756 },
{ x: 1548699420000, y: 737533.3866666667 },
{ x: 1548699720000, y: 728669.0266666666 },
{ x: 1548700020000, y: 719951.64 },
{ x: 1548700320000, y: 769181.7866666666 },
{ x: 1548700620000, y: 740805.2666666667 },
locationDurationLines: [
{
name: 'somewhere',
line: [
{ x: 1548697620000, y: 743928.2027027027 },
{ x: 1548697920000, y: 766840.0133333333 },
{ x: 1548698220000, y: 786970.8266666667 },
{ x: 1548698520000, y: 781064.7808219178 },
{ x: 1548698820000, y: 741563.04 },
{ x: 1548699120000, y: 759354.6756756756 },
{ x: 1548699420000, y: 737533.3866666667 },
{ x: 1548699720000, y: 728669.0266666666 },
{ x: 1548700020000, y: 719951.64 },
{ x: 1548700320000, y: 769181.7866666666 },
{ x: 1548700620000, y: 740805.2666666667 },
],
},
],
status: [
{ x: 1548697620000, up: 74, down: null, total: 74 },
@ -65,6 +57,9 @@ describe('MonitorCharts component', () => {
mean="mean"
range="range"
success="success"
monitorId="something"
dateRangeStart="2011-12-03T10:15:30+01:00"
dateRangeEnd="2011-12-03T10:15:30+01:00"
/>
);
expect(component).toMatchSnapshot();

View file

@ -7,7 +7,8 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { PingResults } from '../../../../common/graphql/types';
import { PingListComponent } from '../ping_list';
import { PingListComponent, BaseLocationOptions } from '../ping_list';
import { EuiComboBoxProps } from '@elastic/eui';
describe('PingList component', () => {
let pingList: { allPings: PingResults };
@ -181,6 +182,7 @@ describe('PingList component', () => {
},
},
],
locations: ['nyc'],
},
};
});
@ -194,6 +196,8 @@ describe('PingList component', () => {
onUpdateApp={jest.fn()}
onSelectedStatusUpdate={jest.fn()}
selectedOption="down"
selectedLocation={BaseLocationOptions}
setSelectedLocation={(loc: EuiComboBoxProps[]) => {}}
/>
);
expect(component).toMatchSnapshot();

View file

@ -14,19 +14,6 @@ describe('Snapshot component', () => {
up: 8,
down: 2,
total: 10,
histogram: [
{ upCount: 7, downCount: 3, x: 1548697920000, x0: 1548697620000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698220000, x0: 1548697920000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698520000, x0: 1548698220000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698820000, x0: 1548698520000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699120000, x0: 1548698820000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699420000, x0: 1548699120000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699720000, x0: 1548699420000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700020000, x0: 1548699720000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700320000, x0: 1548700020000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700620000, x0: 1548700320000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700920000, x0: 1548700620000, y: 1 },
],
};
it('renders without errors', () => {

View file

@ -1,179 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SnapshotHistogram component renders the component without errors 1`] = `
<Fragment>
<Chart
renderer="canvas"
>
<inject-SettingsComponent-with-chartStore
showLegend={false}
xDomain={
Object {
"max": 1548700920000,
"min": 1548697920000,
}
}
/>
<inject-AxisSpec-with-chartStore
id="Snapshot X Axis"
position="bottom"
showOverlappingTicks={false}
tickFormat={[Function]}
/>
<inject-AxisSpec-with-chartStore
id="Snapshot Y Axis"
position="left"
showOverlappingTicks={true}
title="Monitors"
/>
<inject-BarSeriesSpecComponent-with-chartStore
customSeriesColors={
Map {
Object {
"colorValues": Array [],
"specId": "Up",
} => "#FEFEFE",
}
}
data={
Array [
Array [
1548697920000,
7,
],
Array [
1548698220000,
7,
],
Array [
1548698520000,
7,
],
Array [
1548698820000,
7,
],
Array [
1548699120000,
8,
],
Array [
1548699420000,
8,
],
Array [
1548699720000,
8,
],
Array [
1548700020000,
8,
],
Array [
1548700320000,
8,
],
Array [
1548700620000,
8,
],
Array [
1548700920000,
8,
],
]
}
id="Up"
name="Up"
stackAccessors={
Array [
0,
]
}
timeZone="local"
xAccessor={0}
xScaleType="time"
yAccessors={
Array [
1,
]
}
yScaleType="linear"
/>
<inject-BarSeriesSpecComponent-with-chartStore
customSeriesColors={
Map {
Object {
"colorValues": Array [],
"specId": "Down Monitors",
} => "#FF00FF",
}
}
data={
Array [
Array [
1548697920000,
3,
],
Array [
1548698220000,
3,
],
Array [
1548698520000,
3,
],
Array [
1548698820000,
3,
],
Array [
1548699120000,
2,
],
Array [
1548699420000,
2,
],
Array [
1548699720000,
2,
],
Array [
1548700020000,
2,
],
Array [
1548700320000,
2,
],
Array [
1548700620000,
2,
],
Array [
1548700920000,
2,
],
]
}
id="Down Monitors"
name="Down"
stackAccessors={
Array [
0,
]
}
timeZone="local"
xAccessor={0}
xScaleType="time"
yAccessors={
Array [
1,
]
}
yScaleType="linear"
/>
</Chart>
</Fragment>
<ApolloConsumer>
<Component />
</ApolloConsumer>
`;

View file

@ -14,23 +14,10 @@ describe('SnapshotHistogram component', () => {
absoluteEndDate: 1548700920000,
successColor: '#FEFEFE',
dangerColor: '#FF00FF',
histogram: [
{ upCount: 7, downCount: 3, x: 1548697920000, x0: 1548697620000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698220000, x0: 1548697920000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698520000, x0: 1548698220000, y: 1 },
{ upCount: 7, downCount: 3, x: 1548698820000, x0: 1548698520000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699120000, x0: 1548698820000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699420000, x0: 1548699120000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548699720000, x0: 1548699420000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700020000, x0: 1548699720000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700320000, x0: 1548700020000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700620000, x0: 1548700320000, y: 1 },
{ upCount: 8, downCount: 2, x: 1548700920000, x0: 1548700620000, y: 1 },
],
};
it('renders the component without errors', () => {
const component = shallowWithIntl(<SnapshotHistogram {...props} />);
const component = shallowWithIntl(<SnapshotHistogram {...props} variables={{}} />);
expect(component).toMatchSnapshot();
});
});

View file

@ -5,7 +5,6 @@
*/
import {
AreaSeries,
Axis,
Chart,
CurveType,
@ -25,24 +24,16 @@ import {
convertMicrosecondsToMilliseconds as microsToMillis,
getChartDateLabel,
} from '../../../lib/helper';
import {
MonitorDurationAreaPoint,
MonitorDurationAveragePoint,
} from '../../../../common/graphql/types';
import { LocationDurationLine } from '../../../../common/graphql/types';
import { UptimeSettingsContext } from '../../../contexts';
import { getColorsMap } from './get_colors_map';
interface DurationChartProps {
/**
* Timeseries data that is used to express a max/min area series
* on the duration chart.
*/
durationArea: MonitorDurationAreaPoint[];
/**
* Timeseries data that is used to express an average line series
* on the duration chart.
* on the duration chart. One entry per location
*/
durationLine: MonitorDurationAveragePoint[];
locationDurationLines: LocationDurationLine[];
/**
* The color to be used for the average duration series.
*/
@ -60,17 +51,32 @@ interface DurationChartProps {
* @param props The props required for this component to render properly
*/
export const DurationChart = ({
durationArea,
durationLine,
locationDurationLines,
meanColor,
rangeColor,
}: DurationChartProps) => {
const { absoluteStartDate, absoluteEndDate } = useContext(UptimeSettingsContext);
// this id is used for the area chart representing the max/min of check durations
const areaSpecId = getSpecId('area');
// this id is used for the line chart representing the average duration length
const averageSpecId = getSpecId('average');
const averageSpecId = getSpecId('average-');
const lineSeries = locationDurationLines.map(line => {
const locationSpecId = getSpecId('loc-avg' + line.name);
return (
<LineSeries
curve={CurveType.CURVE_MONOTONE_X}
customSeriesColors={getColorsMap(meanColor, averageSpecId)}
data={line.line.map(({ x, y }) => [x || 0, microsToMillis(y)])}
id={locationSpecId}
key={`locline-${line.name}`}
name={line.name}
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleToDataExtent={false}
yScaleType={ScaleType.Linear}
/>
);
});
return (
<React.Fragment>
@ -85,7 +91,11 @@ export const DurationChart = ({
</EuiTitle>
<EuiPanel>
<Chart>
<Settings xDomain={{ min: absoluteStartDate, max: absoluteEndDate }} showLegend={false} />
<Settings
xDomain={{ min: absoluteStartDate, max: absoluteEndDate }}
showLegend={true}
legendPosition={Position.Bottom}
/>
<Axis
id={getAxisId('bottom')}
position={Position.Bottom}
@ -104,45 +114,7 @@ export const DurationChart = ({
defaultMessage: 'Duration ms',
})}
/>
<AreaSeries
curve={CurveType.CURVE_MONOTONE_X}
customSeriesColors={getColorsMap(rangeColor, areaSpecId)}
data={durationArea.map(({ x, yMin, yMax }) => ({
x,
Min: microsToMillis(yMin),
Max: microsToMillis(yMax),
}))}
id={areaSpecId}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
xAccessor={'x'}
xScaleType={ScaleType.Time}
yAccessors={['Max']}
yScaleType={ScaleType.Linear}
y0Accessors={['Min']}
yScaleToDataExtent={false}
/>
<LineSeries
curve={CurveType.CURVE_MONOTONE_X}
customSeriesColors={getColorsMap(meanColor, averageSpecId)}
data={durationLine.map(({ x, y }) => [x || 0, microsToMillis(y)])}
id={averageSpecId}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleToDataExtent={false}
yScaleType={ScaleType.Linear}
/>
{lineSeries}
</Chart>
</EuiPanel>
</React.Fragment>

View file

@ -15,11 +15,15 @@ import {
timeFormatter,
Settings,
} from '@elastic/charts';
import { EuiEmptyPrompt, EuiTitle, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Fragment } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { HistogramDataPoint } from '../../../../common/graphql/types';
import { getColorsMap } from './get_colors_map';
import { getChartDateLabel } from '../../../lib/helper';
import { withUptimeGraphQL, UptimeGraphQLQueryProps } from '../../higher_order';
import { snapshotHistogramQuery } from '../../../queries/snapshot_histogram_query';
export interface SnapshotHistogramProps {
/**
@ -38,19 +42,61 @@ export interface SnapshotHistogramProps {
* The color value that is used to represent down checks.
*/
dangerColor: string;
/**
* The data the histogram will visualize.
*/
histogram: HistogramDataPoint[];
}
export const SnapshotHistogram = ({
interface SnapshotHistogramQueryResult {
histogram?: HistogramDataPoint[];
}
type Props = UptimeGraphQLQueryProps<SnapshotHistogramQueryResult> & SnapshotHistogramProps;
export const SnapshotHistogramComponent = ({
absoluteStartDate,
absoluteEndDate,
dangerColor,
histogram,
successColor,
}: SnapshotHistogramProps) => {
data,
}: Props) => {
if (!data || !data.histogram)
/**
* TODO: the Fragment, EuiTitle, and EuiPanel should be extractec to a dumb component
* that we can reuse in the subsequent return statement at the bottom of this function.
*/
return (
<Fragment>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="s" style={{ height: 170 }}>
<EuiEmptyPrompt
title={
<EuiTitle>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.noDataTitle"
defaultMessage="No histogram data available"
/>
</h5>
</EuiTitle>
}
body={
<p>
<FormattedMessage
id="xpack.uptime.snapshot.noDataDescription"
defaultMessage="Sorry, there is no data available for the histogram"
/>
</p>
}
/>
</EuiPanel>
</Fragment>
);
const { histogram } = data;
const downMonitorsName = i18n.translate('xpack.uptime.snapshotHistogram.downMonitorsId', {
defaultMessage: 'Down Monitors',
});
@ -62,57 +108,72 @@ export const SnapshotHistogram = ({
const upSpecId = getSpecId(upMonitorsId);
return (
<Fragment>
<Chart>
<Settings xDomain={{ min: absoluteStartDate, max: absoluteEndDate }} showLegend={false} />
<Axis
id={getAxisId(
i18n.translate('xpack.uptime.snapshotHistogram.xAxisId', {
defaultMessage: 'Snapshot X Axis',
})
)}
position={Position.Bottom}
showOverlappingTicks={false}
tickFormat={timeFormatter(getChartDateLabel(absoluteStartDate, absoluteEndDate))}
/>
<Axis
id={getAxisId(
i18n.translate('xpack.uptime.snapshotHistogram.yAxisId', {
defaultMessage: 'Snapshot Y Axis',
})
)}
position={Position.Left}
showOverlappingTicks={true}
title={i18n.translate('xpack.uptime.snapshotHistogram.yAxis.title', {
defaultMessage: 'Monitors',
})}
/>
<BarSeries
customSeriesColors={getColorsMap(successColor, upSpecId)}
data={histogram.map(({ x, upCount }) => [x, upCount || 0])}
id={upSpecId}
name={upMonitorsId}
stackAccessors={[0]}
timeZone="local"
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleType={ScaleType.Linear}
/>
<BarSeries
customSeriesColors={getColorsMap(dangerColor, downSpecId)}
data={histogram.map(({ x, downCount }) => [x, downCount || 0])}
id={downSpecId}
name={i18n.translate('xpack.uptime.snapshotHistogram.series.downLabel', {
defaultMessage: 'Down',
})}
stackAccessors={[0]}
timeZone="local"
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleType={ScaleType.Linear}
/>
</Chart>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="s" style={{ height: 170 }}>
<Chart>
<Settings xDomain={{ min: absoluteStartDate, max: absoluteEndDate }} showLegend={false} />
<Axis
id={getAxisId(
i18n.translate('xpack.uptime.snapshotHistogram.xAxisId', {
defaultMessage: 'Snapshot X Axis',
})
)}
position={Position.Bottom}
showOverlappingTicks={false}
tickFormat={timeFormatter(getChartDateLabel(absoluteStartDate, absoluteEndDate))}
/>
<Axis
id={getAxisId(
i18n.translate('xpack.uptime.snapshotHistogram.yAxisId', {
defaultMessage: 'Snapshot Y Axis',
})
)}
position={Position.Left}
showOverlappingTicks={true}
title={i18n.translate('xpack.uptime.snapshotHistogram.yAxis.title', {
defaultMessage: 'Monitors',
})}
/>
<BarSeries
customSeriesColors={getColorsMap(successColor, upSpecId)}
data={histogram.map(({ x, upCount }) => [x, upCount || 0])}
id={upSpecId}
name={upMonitorsId}
stackAccessors={[0]}
timeZone="local"
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleType={ScaleType.Linear}
/>
<BarSeries
customSeriesColors={getColorsMap(dangerColor, downSpecId)}
data={histogram.map(({ x, downCount }) => [x, downCount || 0])}
id={downSpecId}
name={i18n.translate('xpack.uptime.snapshotHistogram.series.downLabel', {
defaultMessage: 'Down',
})}
stackAccessors={[0]}
timeZone="local"
xAccessor={0}
xScaleType={ScaleType.Time}
yAccessors={[1]}
yScaleType={ScaleType.Linear}
/>
</Chart>
</EuiPanel>
</Fragment>
);
};
export const SnapshotHistogram = withUptimeGraphQL<
SnapshotHistogramQueryResult,
SnapshotHistogramProps
>(SnapshotHistogramComponent, snapshotHistogramQuery);

View file

@ -0,0 +1,30 @@
/*
* 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 { EuiIcon, EuiLink, EuiText } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
interface LocationNameProps {
location: string | null | undefined;
}
export const LocationName = ({ location }: LocationNameProps) =>
!!location ? (
<EuiText>{location}</EuiText>
) : (
<EuiLink
href="https://www.elastic.co/guide/en/beats/heartbeat/current/configuration-observer-options.html"
target="_blank"
>
{i18n.translate('xpack.uptime.locationName.helpLinkAnnotation', {
defaultMessage: 'Add location',
description:
'Text that instructs the user to navigate to our docs to add a geographic location to their data',
})}
&nbsp;
<EuiIcon size="s" type="popout" />
</EuiLink>
);

View file

@ -6,46 +6,62 @@
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Fragment } from 'react';
import React, { Fragment, useContext } from 'react';
import DateMath from '@elastic/datemath';
import { Moment } from 'moment';
import { MonitorChart } from '../../../common/graphql/types';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { monitorChartsQuery } from '../../queries';
import { DurationChart } from './charts';
import { ChecksChart } from './charts/checks_chart';
import { UptimeSettingsContext } from '../../contexts';
import { SnapshotHistogram } from './charts/snapshot_histogram';
interface MonitorChartsQueryResult {
monitorChartsData?: MonitorChart;
}
interface MonitorChartsProps {
monitorId: string;
danger: string;
mean: string;
range: string;
success: string;
dateRangeStart: string;
dateRangeEnd: string;
}
type Props = MonitorChartsProps & UptimeGraphQLQueryProps<MonitorChartsQueryResult>;
export const MonitorChartsComponent = (props: Props) => {
const { danger, data, mean, range, success } = props;
const { data, mean, range, monitorId, dateRangeStart, dateRangeEnd } = props;
if (data && data.monitorChartsData) {
const {
monitorChartsData: { durationArea, durationLine, status },
monitorChartsData: { locationDurationLines },
} = data;
const { colors } = useContext(UptimeSettingsContext);
const parseDateRange = (r: string): number => {
const parsed: Moment | undefined = DateMath.parse(r);
return parsed ? parsed.valueOf() : 0;
};
return (
<Fragment>
<EuiFlexGroup>
<EuiFlexItem style={{ height: 400 }}>
<DurationChart
durationArea={durationArea}
durationLine={durationLine}
locationDurationLines={locationDurationLines}
meanColor={mean}
rangeColor={range}
/>
</EuiFlexItem>
<EuiFlexItem>
<ChecksChart dangerColor={danger} status={status} successColor={success} />
<SnapshotHistogram
absoluteStartDate={parseDateRange(dateRangeStart)}
absoluteEndDate={parseDateRange(dateRangeEnd)}
successColor={colors.success}
dangerColor={colors.danger}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
/>
</EuiFlexItem>
</EuiFlexGroup>
</Fragment>

View file

@ -25,6 +25,7 @@ import { MonitorListActionsPopover } from './monitor_list_actions_popover';
import { MonitorPageLink } from './monitor_page_link';
import { MonitorListStatusColumn } from './monitor_list_status_column';
import { MonitorBarSeries } from './charts';
import { LocationName } from './location_name';
interface MonitorListQueryResult {
// TODO: clean up this ugly result data shape, there should be no nesting
@ -121,11 +122,7 @@ export const MonitorListComponent = ({
defaultMessage: 'ID',
}),
render: (id: string, monitor: LatestMonitor) => (
<MonitorPageLink
id={id}
location={get<string | undefined>(monitor, 'ping.observer.geo.name')}
linkParameters={linkParameters}
>
<MonitorPageLink id={id} location={undefined} linkParameters={linkParameters}>
{monitor.ping && monitor.ping.monitor && monitor.ping.monitor.name
? monitor.ping.monitor.name
: id}
@ -138,23 +135,7 @@ export const MonitorListComponent = ({
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/configuration-observer-options.html"
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',
})}
&nbsp;
<EuiIcon size="s" type="popout" />
</EuiLink>
),
render: (location: string) => <LocationName location={location} />,
},
{
field: 'ping.url.full',

View file

@ -28,11 +28,10 @@ type Props = MonitorStatusBarProps & UptimeGraphQLQueryProps<MonitorStatusBarQue
export const MonitorStatusBarComponent = ({ data, monitorId }: Props) => {
if (data && data.monitorStatus && data.monitorStatus.length) {
const { monitor, observer, timestamp } = data.monitorStatus[0];
const { monitor, 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');
const full = get<string>(data.monitorStatus[0], 'url.full');
return (
<EuiPanel>
<EuiFlexGroup gutterSize="l">
@ -98,16 +97,6 @@ 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>
);

View file

@ -17,6 +17,7 @@ import {
EuiText,
EuiTitle,
EuiToolTip,
EuiFormRow,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@ -27,6 +28,7 @@ import { Ping, PingResults } from '../../../common/graphql/types';
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { pingsQuery } from '../../queries';
import { LocationName } from './location_name';
interface PingListQueryResult {
allPings?: PingResults;
@ -36,16 +38,22 @@ interface PingListProps {
onUpdateApp: () => void;
onSelectedStatusUpdate: (status: string | null) => void;
selectedOption: string;
selectedLocation: EuiComboBoxOptionProps[];
setSelectedLocation: (location: EuiComboBoxOptionProps[]) => void;
}
type Props = UptimeGraphQLQueryProps<PingListQueryResult> & PingListProps;
export const BaseLocationOptions = [{ label: 'All', value: 'All' }];
export const PingListComponent = ({
data,
loading,
onSelectedStatusUpdate,
onUpdateApp,
selectedOption,
selectedLocation,
setSelectedLocation,
}: Props) => {
const statusOptions: EuiComboBoxOptionProps[] = [
{
@ -67,6 +75,15 @@ export const PingListComponent = ({
value: 'down',
},
];
const locations = get<string[]>(data, 'allPings.locations');
const locationOptions: EuiComboBoxOptionProps[] = !locations
? BaseLocationOptions
: BaseLocationOptions.concat(
locations.map(name => {
return { label: name, value: name };
})
);
const columns = [
{
field: 'monitor.status',
@ -95,6 +112,14 @@ export const PingListComponent = ({
</div>
),
},
{
field: 'observer.geo.name',
dataType: 'number',
name: i18n.translate('xpack.uptime.pingList.locationNameColumnLabel', {
defaultMessage: 'Location',
}),
render: (location: string) => <LocationName location={location} />,
},
{
field: 'monitor.ip',
dataType: 'number',
@ -191,25 +216,58 @@ export const PingListComponent = ({
<EuiFlexItem grow={false}>
<EuiFlexGroup>
<EuiFlexItem style={{ minWidth: 200 }}>
<EuiComboBox
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={[
statusOptions.find(({ value }) => value === selectedOption) || statusOptions[2],
]}
options={statusOptions}
aria-label={i18n.translate('xpack.uptime.pingList.statusLabel', {
defaultMessage: 'Status',
})}
onChange={(selectedOptions: EuiComboBoxOptionProps[]) => {
if (typeof selectedOptions[0].value === 'string') {
onSelectedStatusUpdate(
// @ts-ignore it's definitely a string
selectedOptions[0].value !== '' ? selectedOptions[0].value : null
);
}
}}
/>
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow
label="Status"
aria-label={i18n.translate('xpack.uptime.pingList.statusLabel', {
defaultMessage: 'Status',
})}
>
<EuiComboBox
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={[
statusOptions.find(({ value }) => value === selectedOption) ||
statusOptions[2],
]}
options={statusOptions}
aria-label={i18n.translate('xpack.uptime.pingList.statusLabel', {
defaultMessage: 'Status',
})}
onChange={(selectedOptions: EuiComboBoxOptionProps[]) => {
if (typeof selectedOptions[0].value === 'string') {
onSelectedStatusUpdate(
// @ts-ignore it's definitely a string
selectedOptions[0].value !== '' ? selectedOptions[0].value : null
);
}
}}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
label="Location"
aria-label={i18n.translate('xpack.uptime.pingList.locationLabel', {
defaultMessage: 'Location',
})}
>
<EuiComboBox
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={selectedLocation}
options={locationOptions}
aria-label={i18n.translate('xpack.uptime.pingList.locationLabel', {
defaultMessage: 'Location',
})}
onChange={(selectedOptions: EuiComboBoxOptionProps[]) => {
setSelectedLocation(selectedOptions);
}}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

View file

@ -4,14 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import {
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
EuiStat,
EuiTitle,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStat, EuiTitle } from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@ -20,7 +13,6 @@ import { Snapshot as SnapshotType } from '../../../common/graphql/types';
import { UptimeAppColors } from '../../uptime_app';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { snapshotQuery } from '../../queries';
import { SnapshotHistogram } from './charts';
import { SnapshotLoading } from './snapshot_loading';
interface SnapshotQueryResult {
@ -56,102 +48,57 @@ export const SnapshotComponent = ({
data,
}: Props) =>
data && data.snapshot ? (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.endpointStatusTitle"
defaultMessage="Current status"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="s">
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceEvenly" gutterSize="s">
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.upDescription', {
defaultMessage: 'Up',
})}
textAlign="center"
title={data.snapshot.up}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.downDescription', {
defaultMessage: 'Down',
})}
textAlign="center"
title={data.snapshot.down}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.totalDescription', {
defaultMessage: 'Total',
})}
textAlign="center"
title={data.snapshot.total}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={8}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="s" style={{ height: 170 }}>
{data.snapshot.histogram && (
<SnapshotHistogram
absoluteStartDate={absoluteStartDate}
absoluteEndDate={absoluteEndDate}
dangerColor={danger}
histogram={data.snapshot.histogram}
successColor={success}
/>
)}
{!data.snapshot.histogram && (
<EuiEmptyPrompt
title={
<EuiTitle>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.noDataTitle"
defaultMessage="No histogram data available"
/>
</h5>
</EuiTitle>
}
body={
<p>
<FormattedMessage
id="xpack.uptime.snapshot.noDataDescription"
defaultMessage="Sorry, there is no data available for the histogram"
/>
</p>
}
/>
)}
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
<React.Fragment>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.endpointStatusTitle"
defaultMessage="Current status"
/>
</h5>
</EuiTitle>
<EuiPanel paddingSize="s">
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceEvenly" gutterSize="s">
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.upDescription', {
defaultMessage: 'Up',
})}
textAlign="center"
title={data.snapshot.up}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.downDescription', {
defaultMessage: 'Down',
})}
textAlign="center"
title={data.snapshot.down}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.totalDescription', {
defaultMessage: 'Total',
})}
textAlign="center"
title={data.snapshot.total}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</React.Fragment>
) : (
<SnapshotLoading />
);

View file

@ -7,6 +7,7 @@
import {
// @ts-ignore No typings for EuiSpacer
EuiSpacer,
EuiComboBoxOptionProps,
} from '@elastic/eui';
import { ApolloQueryResult, OperationVariables, QueryOptions } from 'apollo-client';
import gql from 'graphql-tag';
@ -22,6 +23,7 @@ import { UMUpdateBreadcrumbs } from '../lib/lib';
import { UptimeSettingsContext } from '../contexts';
import { useUrlParams } from '../hooks';
import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
import { BaseLocationOptions } from '../components/functional/ping_list';
interface MonitorPageProps {
history: { push: any };
@ -44,9 +46,6 @@ export const MonitorPage = ({
}: MonitorPageProps) => {
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;
@ -76,18 +75,36 @@ export const MonitorPage = ({
[params]
);
const [selectedLocation, setSelectedLocation] = useState<EuiComboBoxOptionProps[]>(
BaseLocationOptions
);
const selLocationVal = selectedLocation[0].value === 'All' ? null : selectedLocation[0].value;
const sharedVariables = {
dateRangeStart,
dateRangeEnd,
location: selLocationVal,
monitorId,
};
useEffect(() => {
logMonitorPageLoad();
}, []);
const sharedVariables = { dateRangeStart, dateRangeEnd, location: geoLocation, monitorId };
return (
<Fragment>
<MonitorPageTitle monitorId={monitorId} variables={{ monitorId }} />
<EuiSpacer size="s" />
<MonitorStatusBar monitorId={monitorId} variables={sharedVariables} />
<EuiSpacer size="s" />
<MonitorCharts {...colors} variables={sharedVariables} />
<MonitorCharts
{...colors}
monitorId={monitorId}
variables={sharedVariables}
dateRangeStart={dateRangeStart}
dateRangeEnd={dateRangeEnd}
/>
<EuiSpacer size="s" />
<PingList
onSelectedStatusUpdate={(selectedStatus: string | null) =>
@ -95,6 +112,8 @@ export const MonitorPage = ({
}
onUpdateApp={refreshApp}
selectedOption={selectedPingStatus}
selectedLocation={selectedLocation}
setSelectedLocation={setSelectedLocation}
variables={{
...sharedVariables,
status: selectedPingStatus,

View file

@ -5,11 +5,18 @@
*/
// @ts-ignore EuiSearchBar missing
import { EuiSearchBar, EuiSpacer } from '@elastic/eui';
import { EuiSearchBar, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Fragment, useContext, useEffect } from 'react';
import { getOverviewPageBreadcrumbs } from '../breadcrumbs';
import { EmptyState, ErrorList, FilterBar, MonitorList, Snapshot } from '../components/functional';
import {
EmptyState,
ErrorList,
FilterBar,
MonitorList,
Snapshot,
SnapshotHistogram,
} from '../components/functional';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { UptimeSettingsContext } from '../contexts';
import { useUrlParams } from '../hooks';
@ -92,12 +99,25 @@ export const OverviewPage = ({
variables={sharedProps}
/>
<EuiSpacer size="s" />
<Snapshot
absoluteStartDate={absoluteStartDate}
absoluteEndDate={absoluteEndDate}
colors={colors}
variables={sharedProps}
/>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<Snapshot
absoluteStartDate={absoluteStartDate}
absoluteEndDate={absoluteEndDate}
colors={colors}
variables={sharedProps}
/>
</EuiFlexItem>
<EuiFlexItem grow={8}>
<SnapshotHistogram
absoluteStartDate={absoluteStartDate}
absoluteEndDate={absoluteEndDate}
successColor={colors.success}
dangerColor={colors.danger}
variables={sharedProps}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<MonitorList
absoluteStartDate={absoluteStartDate}

View file

@ -14,14 +14,12 @@ query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId
dateRangeEnd: $dateRangeEnd
location: $location
) {
durationArea {
x
yMin
yMax
}
durationLine {
x
y
locationDurationLines {
name
line {
x
y
}
}
status {
x

View file

@ -26,6 +26,7 @@ query PingList(
location: $location
) {
total
locations
pings {
timestamp
http {
@ -48,6 +49,11 @@ query PingList(
status
type
}
observer {
geo {
name
}
}
}
}
}

View file

@ -0,0 +1,33 @@
/*
* 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 gql from 'graphql-tag';
export const snapshotHistogramQueryString = `
query SnapshotHistogram(
$dateRangeStart: String!
$dateRangeEnd: String!
$filters: String
$monitorId: String
) {
histogram: getSnapshotHistogram(
dateRangeStart: $dateRangeStart
dateRangeEnd: $dateRangeEnd
filters: $filters
monitorId: $monitorId
) {
upCount
downCount
x
x0
y
}
}
`;
export const snapshotHistogramQuery = gql`
${snapshotHistogramQueryString}
`;

View file

@ -12,21 +12,14 @@ query Snapshot(
$dateRangeEnd: String!
$filters: String
) {
snapshot: getSnapshot(
dateRangeStart: $dateRangeStart
dateRangeEnd: $dateRangeEnd
filters: $filters
) {
up
down
total
histogram {
upCount
downCount
x
x0
y
}
snapshot: getSnapshot(
dateRangeStart: $dateRangeStart
dateRangeEnd: $dateRangeEnd
filters: $filters
) {
up
down
total
}
}
`;

View file

@ -19,6 +19,8 @@ import {
MonitorPageTitle,
Ping,
Snapshot,
HistogramDataPoint,
GetSnapshotHistogramQueryArgs,
} from '../../../common/graphql/types';
import { UMServerLibs } from '../../lib/lib';
import { CreateUMGraphQLResolvers, UMContext } from '../types';
@ -74,12 +76,20 @@ export type UMGetMontiorPageTitleResolver = UMResolver<
UMContext
>;
export type UMGetSnapshotHistogram = UMResolver<
HistogramDataPoint[] | Promise<HistogramDataPoint[]>,
any,
GetSnapshotHistogramQueryArgs,
UMContext
>;
export const createMonitorsResolvers: CreateUMGraphQLResolvers = (
libs: UMServerLibs
): {
Query: {
getMonitors: UMGetMonitorsResolver;
getSnapshot: UMSnapshotResolver;
getSnapshotHistogram: UMGetSnapshotHistogram;
getMonitorChartsData: UMGetMonitorChartsResolver;
getLatestMonitors: UMLatestMonitorsResolver;
getFilterBar: UMGetFilterBarResolver;
@ -95,7 +105,11 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = (
monitors: result,
};
},
async getSnapshot(resolver, { dateRangeStart, dateRangeEnd, filters }, { req }): Promise<any> {
async getSnapshot(
resolver,
{ dateRangeStart, dateRangeEnd, filters },
{ req }
): Promise<Snapshot> {
const { up, down, total } = await libs.monitors.getSnapshotCount(
req,
dateRangeStart,
@ -107,9 +121,21 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = (
up,
down,
total,
histogram: await libs.pings.getPingHistogram(req, dateRangeStart, dateRangeEnd, filters),
};
},
async getSnapshotHistogram(
resolver,
{ dateRangeStart, dateRangeEnd, filters, monitorId },
{ req }
): Promise<HistogramDataPoint[]> {
return await libs.pings.getPingHistogram(
req,
dateRangeStart,
dateRangeEnd,
filters,
monitorId
);
},
async getMonitorChartsData(
resolver,
{ monitorId, dateRangeStart, dateRangeEnd, location },

View file

@ -35,7 +35,6 @@ export const monitorsSchema = gql`
up: Int
down: Int
total: Int
histogram: [HistogramDataPoint!]!
}
type DataPoint {
@ -57,10 +56,8 @@ export const monitorsSchema = gql`
"The data used to populate the monitor charts."
type MonitorChart {
"The max and min values for the monitor duration."
durationArea: [MonitorDurationAreaPoint!]!
"The average values for the monitor duration."
durationLine: [MonitorDurationAveragePoint!]!
locationDurationLines: [LocationDurationLine!]!
"The counts of up/down checks for the monitor."
status: [StatusData!]!
"The maximum status doc count in this chart."
@ -69,6 +66,11 @@ export const monitorsSchema = gql`
durationMaxValue: Int!
}
type LocationDurationLine {
name: String!
line: [MonitorDurationAveragePoint!]!
}
type MonitorKey {
key: String!
url: String
@ -148,6 +150,13 @@ export const monitorsSchema = gql`
getSnapshot(dateRangeStart: String!, dateRangeEnd: String!, filters: String): Snapshot
getSnapshotHistogram(
dateRangeStart: String!
dateRangeEnd: String!
filters: String
monitorId: String
): [HistogramDataPoint!]!
getMonitorChartsData(
monitorId: String!
dateRangeStart: String!

View file

@ -12,7 +12,11 @@ export const pingsSchema = gql`
}
type PingResults {
"Total number of matching pings"
total: UnsignedInteger!
"Unique list of all locations the query matched"
locations: [String!]!
"List of pings "
pings: [Ping!]!
}

View file

@ -8,16 +8,24 @@ Array [
"aggs": Object {
"timeseries": Object {
"aggs": Object {
"duration": Object {
"stats": Object {
"field": "monitor.duration.us",
"location": Object {
"aggs": Object {
"duration": Object {
"stats": Object {
"field": "monitor.duration.us",
},
},
"status": Object {
"terms": Object {
"field": "monitor.status",
"shard_size": 2,
"size": 2,
},
},
},
},
"status": Object {
"terms": Object {
"field": "monitor.status",
"shard_size": 2,
"size": 2,
"field": "observer.geo.name",
"missing": "N/A",
},
},
},
@ -66,16 +74,24 @@ Array [
"aggs": Object {
"timeseries": Object {
"aggs": Object {
"duration": Object {
"stats": Object {
"field": "monitor.duration.us",
"location": Object {
"aggs": Object {
"duration": Object {
"stats": Object {
"field": "monitor.duration.us",
},
},
"status": Object {
"terms": Object {
"field": "monitor.status",
"shard_size": 2,
"size": 2,
},
},
},
},
"status": Object {
"terms": Object {
"field": "monitor.status",
"shard_size": 2,
"size": 2,
"field": "observer.geo.name",
"missing": "N/A",
},
},
},

View file

@ -15,6 +15,7 @@ import {
MonitorPageTitle,
MonitorSeriesPoint,
Ping,
LocationDurationLine,
} from '../../../../common/graphql/types';
import {
dropLatestBucket,
@ -85,8 +86,16 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
fixed_interval: getHistogramInterval(dateRangeStart, dateRangeEnd),
},
aggs: {
status: { terms: { field: 'monitor.status', size: 2, shard_size: 2 } },
duration: { stats: { field: 'monitor.duration.us' } },
location: {
terms: {
field: 'observer.geo.name',
missing: 'N/A',
},
aggs: {
status: { terms: { field: 'monitor.status', size: 2, shard_size: 2 } },
duration: { stats: { field: 'monitor.duration.us' } },
},
},
},
},
},
@ -94,7 +103,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
};
const result = await this.database.search(request, params);
const buckets = dropLatestBucket(get(result, 'aggregations.timeseries.buckets', []));
const dateBuckets = dropLatestBucket(get(result, 'aggregations.timeseries.buckets', []));
/**
* The code below is responsible for formatting the aggregation data we fetched above in a way
@ -108,34 +117,35 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
* what the domain size should be.
*/
const monitorChartsData: MonitorChart = {
durationArea: [],
durationLine: [],
locationDurationLines: [],
status: [],
durationMaxValue: 0,
statusMaxCount: 0,
};
buckets.forEach(bucket => {
const x = get(bucket, 'key');
const docCount = get(bucket, 'doc_count', 0);
// update the maximum value for each point
monitorChartsData.statusMaxCount = Math.max(docCount, monitorChartsData.statusMaxCount);
monitorChartsData.durationMaxValue = Math.max(
monitorChartsData.durationMaxValue,
get(bucket, 'duration.max', 0)
const linesByLocation: { [key: string]: LocationDurationLine } = {};
dateBuckets.forEach(dateBucket => {
const x = get(dateBucket, 'key');
const docCount = get(dateBucket, 'doc_count', 0);
dateBucket.location.buckets.forEach(
(locationBucket: { key: string; duration: { avg: number } }) => {
const locationName = locationBucket.key;
let ldl: LocationDurationLine = get(linesByLocation, locationName);
if (!ldl) {
ldl = { name: locationName, line: [] };
linesByLocation[locationName] = ldl;
monitorChartsData.locationDurationLines.push(ldl);
}
ldl.line.push({ x, y: get(locationBucket, 'duration.avg', null) });
}
);
// these points express a range that will be displayed as an area chart
monitorChartsData.durationArea.push({
x,
yMin: get(bucket, 'duration.min', null),
yMax: get(bucket, 'duration.max', null),
});
monitorChartsData.durationLine.push({ x, y: get(bucket, 'duration.avg', null) });
monitorChartsData.status.push(
formatStatusBuckets(x, get(bucket, 'status.buckets', []), docCount)
formatStatusBuckets(x, get(dateBucket, 'status.buckets', []), docCount)
);
});
return monitorChartsData;
}

View file

@ -41,6 +41,11 @@ describe('ElasticsearchPingsAdapter class', () => {
},
hits: mockHits,
},
aggregations: {
locations: {
buckets: [{ key: 'foo' }],
},
},
};
mockEsCountResult = {
count: mockHits.length,
@ -365,6 +370,15 @@ describe('ElasticsearchPingsAdapter class', () => {
filter: [{ range: { '@timestamp': { gte: 'now-1h', lte: 'now' } } }],
},
},
aggregations: {
locations: {
terms: {
field: 'observer.geo.name',
missing: 'N/A',
size: 1000,
},
},
},
sort: [{ '@timestamp': { order: 'desc' } }],
size: 12,
},

View file

@ -30,7 +30,8 @@ export interface UMPingsAdapter {
request: any,
dateRangeStart: string,
dateRangeEnd: string,
filters?: string | null
filters?: string | null,
monitorId?: string | null
): Promise<HistogramDataPoint[]>;
getDocCount(request: any): Promise<DocCount>;

View file

@ -49,8 +49,10 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
if (status) {
filter.push({ term: { 'monitor.status': status } });
}
let postFilterClause = {};
if (location) {
filter.push({ term: { 'observer.geo.name': location } });
postFilterClause = { post_filter: { term: { 'observer.geo.name': location } } };
}
const queryContext = { bool: { filter } };
const params = {
@ -61,12 +63,26 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
},
...sortParam,
...sizeParam,
aggregations: {
locations: {
terms: {
field: 'observer.geo.name',
missing: 'N/A',
size: 1000,
},
},
},
...postFilterClause,
},
};
const {
hits: { hits, total },
aggregations: aggs,
} = await this.database.search(request, params);
const locations = get(aggs, 'locations', { buckets: [{ key: 'N/A', doc_count: 0 }] });
const pings: Ping[] = hits.map(({ _source }: any) => {
const timestamp = _source['@timestamp'];
return { timestamp, ..._source };
@ -74,6 +90,7 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
const results: PingResults = {
total: total.value,
locations: locations.buckets.map((bucket: { key: string }) => bucket.key),
pings,
};
@ -163,17 +180,27 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter {
request: any,
dateRangeStart: string,
dateRangeEnd: string,
filters?: string | null
filters?: string | null,
monitorId?: string | null
): Promise<HistogramDataPoint[]> {
const { statusFilter, query } = getFilteredQueryAndStatusFilter(
dateRangeStart,
dateRangeEnd,
filters
);
const combinedQuery = !monitorId
? query
: {
bool: {
filter: [{ match: { 'monitor.id': monitorId } }, query],
},
};
const params = {
index: INDEX_NAMES.HEARTBEAT,
body: {
query,
query: combinedQuery,
size: 0,
aggs: {
timeseries: {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { take } from 'lodash';
import { get, take } from 'lodash';
import { DocCount, HistogramDataPoint, Ping, PingResults } from '../../../../common/graphql/types';
import { UMPingsAdapter } from './adapter_types';
@ -34,10 +34,17 @@ export class MemoryPingsAdapter implements UMPingsAdapter {
pings = pings.filter(ping => ping.monitor && ping.monitor.id === monitorId);
}
const locations =
this.pingsDB
.map(ping => {
return get<string>(ping, 'observer.geo.name');
})
.filter(location => !location) || [];
size = size ? size : 10;
return {
total: size,
pings: take(sort ? pings.sort(sortPings(sort)) : pings, size),
locations,
};
}
@ -56,7 +63,8 @@ export class MemoryPingsAdapter implements UMPingsAdapter {
request: any,
dateRangeStart: string,
dateRangeEnd: string,
filters?: string | null | undefined
filters?: string | null | undefined,
monitorId?: string | null | undefined
): Promise<HistogramDataPoint[]> {
throw new Error('Method not implemented.');
}

View file

@ -54,9 +54,10 @@ export class UMPingsDomain {
request: any,
dateRangeStart: string,
dateRangeEnd: string,
filters?: string | null
filters?: string | null,
monitorId?: string | null
): Promise<HistogramDataPoint[]> {
return this.adapter.getPingHistogram(request, dateRangeStart, dateRangeEnd, filters);
return this.adapter.getPingHistogram(request, dateRangeStart, dateRangeEnd, filters, monitorId);
}
public async getDocCount(request: any): Promise<DocCount> {

View file

@ -9533,8 +9533,6 @@
"xpack.uptime.monitorCharts.checkStatus.series.upCountLabel": "アップカウント",
"xpack.uptime.monitorCharts.checkStatus.title": "ステータスを確認",
"xpack.uptime.monitorCharts.loadingMessage": "読み込み中…",
"xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel": "期間",
"xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel": "平均期間",
"xpack.uptime.monitorCharts.monitorDuration.titleLabel": "ミリ秒単位の監視時間",
"xpack.uptime.monitorList.downLineSeries.downLabel": "ダウン",
"xpack.uptime.monitorList.idColumnLabel": "ID",

View file

@ -7494,8 +7494,6 @@
"xpack.uptime.monitorCharts.checkStatus.series.upCountLabel": "运行计数",
"xpack.uptime.monitorCharts.checkStatus.title": "检查状态",
"xpack.uptime.monitorCharts.loadingMessage": "正在加载……",
"xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel": "持续时间范围",
"xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel": "平均持续时间",
"xpack.uptime.monitorCharts.monitorDuration.titleLabel": "监测持续时间 (ms)",
"xpack.uptime.monitorList.downLineSeries.downLabel": "关闭",
"xpack.uptime.monitorList.monitorHistoryColumnLabel": "监测历史记录",

View file

@ -1,63 +1,49 @@
{
"monitorChartsData": {
"durationArea": [
{ "x": 1548697571840, "yMin": 106421, "yMax": 3083061 },
{ "x": 1548697764160, "yMin": 118349, "yMax": 3120392 },
{ "x": 1548697956480, "yMin": 121653, "yMax": 3955186 },
{ "x": 1548698148800, "yMin": 123670, "yMax": 3693429 },
{ "x": 1548698341120, "yMin": 118224, "yMax": 3705359 },
{ "x": 1548698533440, "yMin": 123345, "yMax": 4130464 },
{ "x": 1548698725760, "yMin": 118849, "yMax": 6669234 },
{ "x": 1548698918080, "yMin": 117268, "yMax": 3955729 },
{ "x": 1548699110400, "yMin": 122110, "yMax": 3704761 },
{ "x": 1548699302720, "yMin": 120015, "yMax": 4045216 },
{ "x": 1548699495040, "yMin": 121018, "yMax": 3682859 },
{ "x": 1548699687360, "yMin": 122788, "yMax": 3618679 },
{ "x": 1548699879680, "yMin": 114751, "yMax": 3701297 },
{ "x": 1548700072000, "yMin": 111949, "yMax": 3632224 },
{ "x": 1548700264320, "yMin": 106875, "yMax": 3801401 },
{ "x": 1548700456640, "yMin": 105126, "yMax": 3696367 },
{ "x": 1548700648960, "yMin": 123639, "yMax": 3925269 }
],
"durationLine": [
{ "x": 1548697571840, "y": 790701.3428571429 },
{ "x": 1548697764160, "y": 661065.4375 },
{ "x": 1548697956480, "y": 806260.8541666666 },
{ "x": 1548698148800, "y": 773767.7291666666 },
{ "x": 1548698341120, "y": 767945.0208333334 },
{ "x": 1548698533440, "y": 744078.7234042553 },
{ "x": 1548698725760, "y": 837049.4893617021 },
{ "x": 1548698918080, "y": 778723.1041666666 },
{ "x": 1548699110400, "y": 723974.1875 },
{ "x": 1548699302720, "y": 771744.3191489362 },
{ "x": 1548699495040, "y": 718773.081632653 },
{ "x": 1548699687360, "y": 724448.6458333334 },
{ "x": 1548699879680, "y": 747848.0833333334 },
{ "x": 1548700072000, "y": 748932.125 },
{ "x": 1548700264320, "y": 753010.2291666666 },
{ "x": 1548700456640, "y": 762055.6875 },
{ "x": 1548700648960, "y": 745954.7708333334 }
"locationDurationLines": [
{
"name": "N/A",
"line": [
{ "x": 1548697571840, "y": 790701.3428571429 },
{ "x": 1548697764160, "y": 661065.4375 },
{ "x": 1548697956480, "y": 806260.8541666666 },
{ "x": 1548698148800, "y": 773767.7291666666 },
{ "x": 1548698341120, "y": 767945.0208333334 },
{ "x": 1548698533440, "y": 744078.7234042553 },
{ "x": 1548698725760, "y": 837049.4893617021 },
{ "x": 1548698918080, "y": 778723.1041666666 },
{ "x": 1548699110400, "y": 723974.1875 },
{ "x": 1548699302720, "y": 771744.3191489362 },
{ "x": 1548699495040, "y": 718773.081632653 },
{ "x": 1548699687360, "y": 724448.6458333334 },
{ "x": 1548699879680, "y": 747848.0833333334 },
{ "x": 1548700072000, "y": 748932.125 },
{ "x": 1548700264320, "y": 753010.2291666666 },
{ "x": 1548700456640, "y": 762055.6875 },
{ "x": 1548700648960, "y": 745954.7708333334 }
]
}
],
"status": [
{ "x": 1548697571840, "up": 35, "down": null, "total": 35 },
{ "x": 1548697764160, "up": 48, "down": null, "total": 48 },
{ "x": 1548697956480, "up": 48, "down": null, "total": 48 },
{ "x": 1548698148800, "up": 48, "down": null, "total": 48 },
{ "x": 1548698341120, "up": 48, "down": null, "total": 48 },
{ "x": 1548698533440, "up": 47, "down": null, "total": 47 },
{ "x": 1548698725760, "up": 47, "down": null, "total": 47 },
{ "x": 1548698918080, "up": 48, "down": null, "total": 48 },
{ "x": 1548699110400, "up": 48, "down": null, "total": 48 },
{ "x": 1548699302720, "up": 47, "down": null, "total": 47 },
{ "x": 1548699495040, "up": 49, "down": null, "total": 49 },
{ "x": 1548699687360, "up": 48, "down": null, "total": 48 },
{ "x": 1548699879680, "up": 48, "down": null, "total": 48 },
{ "x": 1548700072000, "up": 48, "down": null, "total": 48 },
{ "x": 1548700264320, "up": 48, "down": null, "total": 48 },
{ "x": 1548700456640, "up": 48, "down": null, "total": 48 },
{ "x": 1548700648960, "up": 48, "down": null, "total": 48 }
{ "x": 1548697571840, "up": null, "down": null, "total": 35 },
{ "x": 1548697764160, "up": null, "down": null, "total": 48 },
{ "x": 1548697956480, "up": null, "down": null, "total": 48 },
{ "x": 1548698148800, "up": null, "down": null, "total": 48 },
{ "x": 1548698341120, "up": null, "down": null, "total": 48 },
{ "x": 1548698533440, "up": null, "down": null, "total": 47 },
{ "x": 1548698725760, "up": null, "down": null, "total": 47 },
{ "x": 1548698918080, "up": null, "down": null, "total": 48 },
{ "x": 1548699110400, "up": null, "down": null, "total": 48 },
{ "x": 1548699302720, "up": null, "down": null, "total": 47 },
{ "x": 1548699495040, "up": null, "down": null, "total": 49 },
{ "x": 1548699687360, "up": null, "down": null, "total": 48 },
{ "x": 1548699879680, "up": null, "down": null, "total": 48 },
{ "x": 1548700072000, "up": null, "down": null, "total": 48 },
{ "x": 1548700264320, "up": null, "down": null, "total": 48 },
{ "x": 1548700456640, "up": null, "down": null, "total": 48 },
{ "x": 1548700648960, "up": null, "down": null, "total": 48 }
],
"statusMaxCount": 49,
"durationMaxValue": 6669234
"statusMaxCount": 0,
"durationMaxValue": 0
}
}

View file

@ -1,8 +1,7 @@
{
"monitorChartsData": {
"durationArea": [],
"durationLine": [],
"status": [],
"locationDurationLines": [],
"statusMaxCount": 0,
"durationMaxValue": 0
}

View file

@ -1,6 +1,7 @@
{
"allPings": {
"total": 9231,
"locations": ["N/A"],
"pings": [
{
"timestamp": "2019-01-28T18:43:16.078Z",
@ -14,7 +15,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -31,7 +33,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -45,7 +48,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -59,7 +63,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -73,7 +78,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -87,7 +93,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:14.080Z",
@ -101,7 +108,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.075Z",
@ -115,7 +123,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.074Z",
@ -129,7 +138,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.074Z",
@ -143,7 +153,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
}
]
}

View file

@ -1,6 +1,7 @@
{
"allPings": {
"total": 9231,
"locations": ["N/A"],
"pings": [
{
"timestamp": "2019-01-28T18:43:16.078Z",
@ -14,7 +15,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -31,7 +33,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -45,7 +48,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -59,7 +63,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -73,7 +78,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -87,7 +93,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:14.080Z",
@ -101,7 +108,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.075Z",
@ -115,7 +123,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.074Z",
@ -129,7 +138,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.074Z",
@ -143,7 +153,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:12.075Z",
@ -157,7 +168,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:11.075Z",
@ -171,7 +183,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:11.074Z",
@ -188,7 +201,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:11.074Z",
@ -202,7 +216,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:11.074Z",
@ -216,7 +231,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:10.075Z",
@ -230,7 +246,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:10.074Z",
@ -244,7 +261,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:09.079Z",
@ -258,7 +276,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:08.075Z",
@ -272,7 +291,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -286,7 +306,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -303,7 +324,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -317,7 +339,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -331,7 +354,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -345,7 +369,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -359,7 +384,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -373,7 +399,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:06.075Z",
@ -387,7 +414,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:05.076Z",
@ -401,7 +429,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:05.076Z",
@ -415,7 +444,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:04.077Z",
@ -429,7 +459,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:04.077Z",
@ -443,7 +474,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:04.077Z",
@ -457,7 +489,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -471,7 +504,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -488,7 +522,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -502,7 +537,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -516,7 +552,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -530,7 +567,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:02.080Z",
@ -544,7 +582,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:01.077Z",
@ -558,7 +597,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:01.077Z",
@ -572,7 +612,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:01.077Z",
@ -586,7 +627,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:00.078Z",
@ -600,7 +642,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:00.078Z",
@ -614,7 +657,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:59.075Z",
@ -631,7 +675,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:59.075Z",
@ -645,7 +690,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:59.075Z",
@ -659,7 +705,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:59.075Z",
@ -673,7 +720,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:59.075Z",
@ -687,7 +735,8 @@
"scheme": null,
"status": "down",
"type": "http"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:58.075Z",
@ -701,7 +750,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:42:58.074Z",
@ -715,7 +765,8 @@
"scheme": null,
"status": "up",
"type": "http"
}
},
"observer": null
}
]
}

View file

@ -1,6 +1,7 @@
{
"allPings": {
"total": 3371,
"locations": ["N/A"],
"pings": [
{
"timestamp": "2019-01-28T18:43:16.078Z",
@ -14,7 +15,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:15.077Z",
@ -28,7 +30,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:14.080Z",
@ -42,7 +45,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:13.075Z",
@ -56,7 +60,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:12.075Z",
@ -70,7 +75,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:11.075Z",
@ -84,7 +90,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:10.075Z",
@ -98,7 +105,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:09.079Z",
@ -112,7 +120,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:08.075Z",
@ -126,7 +135,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:07.078Z",
@ -140,7 +150,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:06.075Z",
@ -154,7 +165,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:05.076Z",
@ -168,7 +180,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:04.077Z",
@ -182,7 +195,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:03.077Z",
@ -196,7 +210,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T18:43:02.080Z",
@ -210,7 +225,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
}
]
}

View file

@ -1,6 +1,7 @@
{
"allPings": {
"total": 3371,
"locations": ["N/A"],
"pings": [
{
"timestamp": "2019-01-28T17:47:06.077Z",
@ -14,7 +15,8 @@
"scheme": null,
"status": "up",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T17:47:07.075Z",
@ -31,7 +33,8 @@
"scheme": null,
"status": "down",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T17:47:08.078Z",
@ -48,7 +51,8 @@
"scheme": null,
"status": "down",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T17:47:09.075Z",
@ -65,7 +69,8 @@
"scheme": null,
"status": "down",
"type": "tcp"
}
},
"observer": null
},
{
"timestamp": "2019-01-28T17:47:10.075Z",
@ -82,7 +87,8 @@
"scheme": null,
"status": "down",
"type": "tcp"
}
},
"observer": null
}
]
}

View file

@ -2,25 +2,6 @@
"snapshot": {
"up": 8,
"down": 2,
"total": 10,
"histogram": [
{ "upCount": 7, "downCount": 3, "x": 1548697764160, "x0": 1548697571840, "y": 1 },
{ "upCount": 7, "downCount": 3, "x": 1548697956480, "x0": 1548697764160, "y": 1 },
{ "upCount": 7, "downCount": 3, "x": 1548698148800, "x0": 1548697956480, "y": 1 },
{ "upCount": 7, "downCount": 3, "x": 1548698341120, "x0": 1548698148800, "y": 1 },
{ "upCount": 7, "downCount": 3, "x": 1548698533440, "x0": 1548698341120, "y": 1 },
{ "upCount": 7, "downCount": 3, "x": 1548698725760, "x0": 1548698533440, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548698918080, "x0": 1548698725760, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548699110400, "x0": 1548698918080, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548699302720, "x0": 1548699110400, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548699495040, "x0": 1548699302720, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548699687360, "x0": 1548699495040, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548699879680, "x0": 1548699687360, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548700072000, "x0": 1548699879680, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548700264320, "x0": 1548700072000, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548700456640, "x0": 1548700264320, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548700648960, "x0": 1548700456640, "y": 1 },
{ "upCount": 8, "downCount": 2, "x": 1548700841280, "x0": 1548700648960, "y": 1 }
]
"total": 10
}
}

View file

@ -1 +1 @@
{ "snapshot": { "up": 0, "down": 0, "total": 0, "histogram": [] } }
{ "snapshot": { "up": 0, "down": 0, "total": 0 } }

View file

@ -1,26 +1 @@
{
"snapshot": {
"up": 0,
"down": 2,
"total": 2,
"histogram": [
{ "upCount": 0, "downCount": 3, "x": 1548697764160, "x0": 1548697571840, "y": 1 },
{ "upCount": 0, "downCount": 3, "x": 1548697956480, "x0": 1548697764160, "y": 1 },
{ "upCount": 0, "downCount": 3, "x": 1548698148800, "x0": 1548697956480, "y": 1 },
{ "upCount": 0, "downCount": 3, "x": 1548698341120, "x0": 1548698148800, "y": 1 },
{ "upCount": 0, "downCount": 3, "x": 1548698533440, "x0": 1548698341120, "y": 1 },
{ "upCount": 0, "downCount": 3, "x": 1548698725760, "x0": 1548698533440, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548698918080, "x0": 1548698725760, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548699110400, "x0": 1548698918080, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548699302720, "x0": 1548699110400, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548699495040, "x0": 1548699302720, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548699687360, "x0": 1548699495040, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548699879680, "x0": 1548699687360, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548700072000, "x0": 1548699879680, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548700264320, "x0": 1548700072000, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548700456640, "x0": 1548700264320, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548700648960, "x0": 1548700456640, "y": 1 },
{ "upCount": 0, "downCount": 2, "x": 1548700841280, "x0": 1548700648960, "y": 1 }
]
}
}
{ "snapshot": { "up": 0, "down": 2, "total": 2 } }

View file

@ -2,25 +2,6 @@
"snapshot": {
"up": 8,
"down": 0,
"total": 8,
"histogram": [
{ "upCount": 7, "downCount": 0, "x": 1548697764160, "x0": 1548697571840, "y": 1 },
{ "upCount": 7, "downCount": 0, "x": 1548697956480, "x0": 1548697764160, "y": 1 },
{ "upCount": 7, "downCount": 0, "x": 1548698148800, "x0": 1548697956480, "y": 1 },
{ "upCount": 7, "downCount": 0, "x": 1548698341120, "x0": 1548698148800, "y": 1 },
{ "upCount": 7, "downCount": 0, "x": 1548698533440, "x0": 1548698341120, "y": 1 },
{ "upCount": 7, "downCount": 0, "x": 1548698725760, "x0": 1548698533440, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548698918080, "x0": 1548698725760, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548699110400, "x0": 1548698918080, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548699302720, "x0": 1548699110400, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548699495040, "x0": 1548699302720, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548699687360, "x0": 1548699495040, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548699879680, "x0": 1548699687360, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548700072000, "x0": 1548699879680, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548700264320, "x0": 1548700072000, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548700456640, "x0": 1548700264320, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548700648960, "x0": 1548700456640, "y": 1 },
{ "upCount": 8, "downCount": 0, "x": 1548700841280, "x0": 1548700648960, "y": 1 }
]
"total": 8
}
}