* Adding id and name to metadata response * Adding name to response * update to types * Adding support for displayNames to waffle map * fixing a bug when _source is missing * Fixing tests * making the metadata response manditory * Fixes from PR review * Fixing typing errors related to displayName being required part of path * Changing 'Loading data for xxx' to 'Loading data' * Changing InfraNodePath.displayName to InfraNodePath.label * Change groups to use the label instead of value * Fixing merge changes
This commit is contained in:
parent
5425d289aa
commit
489119cbbe
|
@ -18,7 +18,8 @@ interface Props {
|
||||||
metrics: InfraMetricData[];
|
metrics: InfraMetricData[];
|
||||||
layouts: InfraMetricLayout[];
|
layouts: InfraMetricLayout[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
|
label: string;
|
||||||
onChangeRangeTime?: (time: metricTimeActions.MetricRangeTimeState) => void;
|
onChangeRangeTime?: (time: metricTimeActions.MetricRangeTimeState) => void;
|
||||||
intl: InjectedIntl;
|
intl: InjectedIntl;
|
||||||
}
|
}
|
||||||
|
@ -41,15 +42,10 @@ export const Metrics = injectI18n(
|
||||||
<InfraLoadingPanel
|
<InfraLoadingPanel
|
||||||
height="100vh"
|
height="100vh"
|
||||||
width="auto"
|
width="auto"
|
||||||
text={intl.formatMessage(
|
text={intl.formatMessage({
|
||||||
{
|
id: 'xpack.infra.metrics.loadingNodeDataText',
|
||||||
id: 'xpack.infra.metrics.loadingNodeDataText',
|
defaultMessage: 'Loading data',
|
||||||
defaultMessage: 'Loading data for {nodeName}',
|
})}
|
||||||
},
|
|
||||||
{
|
|
||||||
nodeName: this.props.nodeName,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const GroupOfNodes: React.SFC<Props> = ({
|
||||||
<Nodes>
|
<Nodes>
|
||||||
{group.nodes.map(node => (
|
{group.nodes.map(node => (
|
||||||
<Node
|
<Node
|
||||||
key={node.id}
|
key={node.pathId}
|
||||||
options={options}
|
options={options}
|
||||||
squareSize={group.squareSize}
|
squareSize={group.squareSize}
|
||||||
node={node}
|
node={node}
|
||||||
|
|
|
@ -25,18 +25,18 @@ interface Props {
|
||||||
|
|
||||||
export const NodeContextMenu = injectI18n(
|
export const NodeContextMenu = injectI18n(
|
||||||
({ options, timeRange, children, node, isPopoverOpen, closePopover, nodeType, intl }: Props) => {
|
({ options, timeRange, children, node, isPopoverOpen, closePopover, nodeType, intl }: Props) => {
|
||||||
const nodeName = node.path.length > 0 ? node.path[node.path.length - 1].value : undefined;
|
const nodeId = node.path.length > 0 ? node.path[node.path.length - 1].value : undefined;
|
||||||
const nodeLogsUrl = nodeName
|
const nodeLogsUrl = nodeId
|
||||||
? getNodeLogsUrl({
|
? getNodeLogsUrl({
|
||||||
nodeType,
|
nodeType,
|
||||||
nodeName,
|
nodeId,
|
||||||
time: timeRange.to,
|
time: timeRange.to,
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
const nodeDetailUrl = nodeName
|
const nodeDetailUrl = nodeId
|
||||||
? getNodeDetailUrl({
|
? getNodeDetailUrl({
|
||||||
nodeType,
|
nodeType,
|
||||||
nodeName,
|
nodeId,
|
||||||
from: timeRange.from,
|
from: timeRange.from,
|
||||||
to: timeRange.to,
|
to: timeRange.to,
|
||||||
})
|
})
|
||||||
|
@ -76,7 +76,7 @@ export const NodeContextMenu = injectI18n(
|
||||||
return (
|
return (
|
||||||
<EuiPopover
|
<EuiPopover
|
||||||
closePopover={closePopover}
|
closePopover={closePopover}
|
||||||
id={`${node.id}-popover`}
|
id={`${node.pathId}-popover`}
|
||||||
isOpen={isPopoverOpen}
|
isOpen={isPopoverOpen}
|
||||||
button={children}
|
button={children}
|
||||||
panelPaddingSize="none"
|
panelPaddingSize="none"
|
||||||
|
|
|
@ -10,9 +10,12 @@ export const metadataQuery = gql`
|
||||||
query MetadataQuery($sourceId: ID!, $nodeId: String!, $nodeType: InfraNodeType!) {
|
query MetadataQuery($sourceId: ID!, $nodeId: String!, $nodeType: InfraNodeType!) {
|
||||||
source(id: $sourceId) {
|
source(id: $sourceId) {
|
||||||
id
|
id
|
||||||
metadataByNode(nodeName: $nodeId, nodeType: $nodeType) {
|
metadataByNode(nodeId: $nodeId, nodeType: $nodeType) {
|
||||||
name
|
name
|
||||||
source
|
features {
|
||||||
|
name
|
||||||
|
source
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ interface WithMetadataProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WithMetadataArgs {
|
interface WithMetadataArgs {
|
||||||
|
name: string;
|
||||||
filteredLayouts: InfraMetricLayout[];
|
filteredLayouts: InfraMetricLayout[];
|
||||||
error?: string | undefined;
|
error?: string | undefined;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -45,8 +46,9 @@ export const WithMetadata = ({
|
||||||
>
|
>
|
||||||
{({ data, error, loading }) => {
|
{({ data, error, loading }) => {
|
||||||
const metadata = data && data.source && data.source.metadataByNode;
|
const metadata = data && data.source && data.source.metadataByNode;
|
||||||
const filteredLayouts = getFilteredLayouts(layouts, metadata);
|
const filteredLayouts = (metadata && getFilteredLayouts(layouts, metadata.features)) || [];
|
||||||
return children({
|
return children({
|
||||||
|
name: (metadata && metadata.name) || '',
|
||||||
filteredLayouts,
|
filteredLayouts,
|
||||||
error: error && error.message,
|
error: error && error.message,
|
||||||
loading,
|
loading,
|
||||||
|
@ -58,7 +60,7 @@ export const WithMetadata = ({
|
||||||
|
|
||||||
const getFilteredLayouts = (
|
const getFilteredLayouts = (
|
||||||
layouts: InfraMetricLayout[],
|
layouts: InfraMetricLayout[],
|
||||||
metadata: Array<MetadataQuery.MetadataByNode | null> | undefined
|
metadata: Array<MetadataQuery.Features | null> | undefined
|
||||||
): InfraMetricLayout[] => {
|
): InfraMetricLayout[] => {
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return layouts;
|
return layouts;
|
||||||
|
|
|
@ -51,7 +51,7 @@ function findOrCreateGroupWithNodes(
|
||||||
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithNodes.allName', {
|
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithNodes.allName', {
|
||||||
defaultMessage: 'All',
|
defaultMessage: 'All',
|
||||||
})
|
})
|
||||||
: last(path).value,
|
: last(path).label,
|
||||||
count: 0,
|
count: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
squareSize: 0,
|
squareSize: 0,
|
||||||
|
@ -75,7 +75,7 @@ function findOrCreateGroupWithGroups(
|
||||||
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithGroups.allName', {
|
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithGroups.allName', {
|
||||||
defaultMessage: 'All',
|
defaultMessage: 'All',
|
||||||
})
|
})
|
||||||
: last(path).value,
|
: last(path).label,
|
||||||
count: 0,
|
count: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
squareSize: 0,
|
squareSize: 0,
|
||||||
|
@ -84,10 +84,12 @@ function findOrCreateGroupWithGroups(
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWaffleMapNode(node: InfraNode): InfraWaffleMapNode {
|
function createWaffleMapNode(node: InfraNode): InfraWaffleMapNode {
|
||||||
|
const nodePathItem = last(node.path);
|
||||||
return {
|
return {
|
||||||
id: node.path.map(p => p.value).join('/'),
|
pathId: node.path.map(p => p.value).join('/'),
|
||||||
path: node.path,
|
path: node.path,
|
||||||
name: last(node.path).value,
|
id: nodePathItem.value,
|
||||||
|
name: nodePathItem.label,
|
||||||
metric: node.metric,
|
metric: node.metric,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ export const waffleNodesQuery = gql`
|
||||||
nodes(path: $path, metric: $metric) {
|
nodes(path: $path, metric: $metric) {
|
||||||
path {
|
path {
|
||||||
value
|
value
|
||||||
|
label
|
||||||
}
|
}
|
||||||
metric {
|
metric {
|
||||||
name
|
name
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
"description": "A hierarchy of metadata entries by node",
|
"description": "A hierarchy of metadata entries by node",
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
"name": "nodeName",
|
"name": "nodeId",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "NON_NULL",
|
"kind": "NON_NULL",
|
||||||
|
@ -137,11 +137,7 @@
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "NON_NULL",
|
"kind": "NON_NULL",
|
||||||
"name": null,
|
"name": null,
|
||||||
"ofType": {
|
"ofType": { "kind": "OBJECT", "name": "InfraNodeMetadata", "ofType": null }
|
||||||
"kind": "LIST",
|
|
||||||
"name": null,
|
|
||||||
"ofType": { "kind": "OBJECT", "name": "InfraNodeMetadata", "ofType": null }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
@ -775,6 +771,61 @@
|
||||||
"kind": "OBJECT",
|
"kind": "OBJECT",
|
||||||
"name": "InfraNodeMetadata",
|
"name": "InfraNodeMetadata",
|
||||||
"description": "One metadata entry for a node.",
|
"description": "One metadata entry for a node.",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"description": "",
|
||||||
|
"args": [],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": { "kind": "SCALAR", "name": "ID", "ofType": null }
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"description": "",
|
||||||
|
"args": [],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "features",
|
||||||
|
"description": "",
|
||||||
|
"args": [],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "LIST",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": { "kind": "OBJECT", "name": "InfraNodeFeature", "ofType": null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [],
|
||||||
|
"enumValues": null,
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "InfraNodeFeature",
|
||||||
|
"description": "",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "name",
|
"name": "name",
|
||||||
|
@ -1542,6 +1593,18 @@
|
||||||
},
|
},
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "displayName",
|
||||||
|
"description": "",
|
||||||
|
"args": [],
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"inputFields": null,
|
"inputFields": null,
|
||||||
|
|
|
@ -23,7 +23,7 @@ export interface InfraSource {
|
||||||
/** The status of the source */
|
/** The status of the source */
|
||||||
status: InfraSourceStatus;
|
status: InfraSourceStatus;
|
||||||
/** A hierarchy of metadata entries by node */
|
/** A hierarchy of metadata entries by node */
|
||||||
metadataByNode: (InfraNodeMetadata | null)[];
|
metadataByNode: InfraNodeMetadata;
|
||||||
/** A consecutive span of log entries surrounding a point in time */
|
/** A consecutive span of log entries surrounding a point in time */
|
||||||
logEntriesAround: InfraLogEntryInterval;
|
logEntriesAround: InfraLogEntryInterval;
|
||||||
/** A consecutive span of log entries within an interval */
|
/** A consecutive span of log entries within an interval */
|
||||||
|
@ -89,6 +89,14 @@ export interface InfraIndexField {
|
||||||
}
|
}
|
||||||
/** One metadata entry for a node. */
|
/** One metadata entry for a node. */
|
||||||
export interface InfraNodeMetadata {
|
export interface InfraNodeMetadata {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
features: InfraNodeFeature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InfraNodeFeature {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
source: string;
|
source: string;
|
||||||
|
@ -175,6 +183,8 @@ export interface InfraNode {
|
||||||
|
|
||||||
export interface InfraNodePath {
|
export interface InfraNodePath {
|
||||||
value: string;
|
value: string;
|
||||||
|
|
||||||
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfraNodeMetric {
|
export interface InfraNodeMetric {
|
||||||
|
@ -252,7 +262,7 @@ export interface SourceQueryArgs {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
export interface MetadataByNodeInfraSourceArgs {
|
export interface MetadataByNodeInfraSourceArgs {
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
|
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +426,7 @@ export namespace MetadataQuery {
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
metadataByNode: (MetadataByNode | null)[];
|
metadataByNode: MetadataByNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MetadataByNode = {
|
export type MetadataByNode = {
|
||||||
|
@ -424,6 +434,14 @@ export namespace MetadataQuery {
|
||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
features: Features[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Features = {
|
||||||
|
__typename?: 'InfraNodeFeature';
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
source: string;
|
source: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -517,6 +535,8 @@ export namespace WaffleNodesQuery {
|
||||||
__typename?: 'InfraNodePath';
|
__typename?: 'InfraNodePath';
|
||||||
|
|
||||||
value: string;
|
value: string;
|
||||||
|
|
||||||
|
label: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Metric = {
|
export type Metric = {
|
||||||
|
|
|
@ -100,6 +100,7 @@ export interface InfraField {
|
||||||
export type InfraWaffleData = InfraWaffleMapGroup[];
|
export type InfraWaffleData = InfraWaffleMapGroup[];
|
||||||
|
|
||||||
export interface InfraWaffleMapNode {
|
export interface InfraWaffleMapNode {
|
||||||
|
pathId: string;
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
path: InfraNodePath[];
|
path: InfraNodePath[];
|
||||||
|
|
|
@ -21,11 +21,11 @@ export class LinkToPage extends React.Component<LinkToPageProps> {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path={`${match.url}/:nodeType(host|container|pod)-logs/:nodeName`}
|
path={`${match.url}/:nodeType(host|container|pod)-logs/:nodeId`}
|
||||||
component={RedirectToNodeLogs}
|
component={RedirectToNodeLogs}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${match.url}/:nodeType(host|container|pod)-detail/:nodeName`}
|
path={`${match.url}/:nodeType(host|container|pod)-detail/:nodeId`}
|
||||||
component={RedirectToNodeDetail}
|
component={RedirectToNodeDetail}
|
||||||
/>
|
/>
|
||||||
<Redirect to="/home" />
|
<Redirect to="/home" />
|
||||||
|
|
|
@ -12,13 +12,13 @@ import { InfraNodeType } from '../../graphql/types';
|
||||||
import { getFromFromLocation, getToFromLocation } from './query_params';
|
import { getFromFromLocation, getToFromLocation } from './query_params';
|
||||||
|
|
||||||
type RedirectToNodeDetailProps = RouteComponentProps<{
|
type RedirectToNodeDetailProps = RouteComponentProps<{
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const RedirectToNodeDetail = ({
|
export const RedirectToNodeDetail = ({
|
||||||
match: {
|
match: {
|
||||||
params: { nodeName, nodeType },
|
params: { nodeId, nodeType },
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
}: RedirectToNodeDetailProps) => {
|
}: RedirectToNodeDetailProps) => {
|
||||||
|
@ -27,20 +27,20 @@ export const RedirectToNodeDetail = ({
|
||||||
getToFromLocation(location)
|
getToFromLocation(location)
|
||||||
)('');
|
)('');
|
||||||
|
|
||||||
return <Redirect to={`/metrics/${nodeType}/${nodeName}?${searchString}`} />;
|
return <Redirect to={`/metrics/${nodeType}/${nodeId}?${searchString}`} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNodeDetailUrl = ({
|
export const getNodeDetailUrl = ({
|
||||||
nodeType,
|
nodeType,
|
||||||
nodeName,
|
nodeId,
|
||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
}: {
|
}: {
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
to?: number;
|
to?: number;
|
||||||
from?: number;
|
from?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const args = to && from ? `?to=${to}&from=${from}` : '';
|
const args = to && from ? `?to=${to}&from=${from}` : '';
|
||||||
return `#/link-to/${nodeType}-detail/${nodeName}${args}`;
|
return `#/link-to/${nodeType}-detail/${nodeId}${args}`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { InfraNodeType } from '../../graphql/types';
|
||||||
import { getTimeFromLocation } from './query_params';
|
import { getTimeFromLocation } from './query_params';
|
||||||
|
|
||||||
type RedirectToNodeLogsType = RouteComponentProps<{
|
type RedirectToNodeLogsType = RouteComponentProps<{
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ interface RedirectToNodeLogsProps extends RedirectToNodeLogsType {
|
||||||
export const RedirectToNodeLogs = injectI18n(
|
export const RedirectToNodeLogs = injectI18n(
|
||||||
({
|
({
|
||||||
match: {
|
match: {
|
||||||
params: { nodeName, nodeType },
|
params: { nodeId, nodeType },
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
intl,
|
intl,
|
||||||
|
@ -52,7 +52,7 @@ export const RedirectToNodeLogs = injectI18n(
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchString = compose(
|
const searchString = compose(
|
||||||
replaceLogFilterInQueryString(`${configuredFields[nodeType]}: ${nodeName}`),
|
replaceLogFilterInQueryString(`${configuredFields[nodeType]}: ${nodeId}`),
|
||||||
replaceLogPositionInQueryString(getTimeFromLocation(location))
|
replaceLogPositionInQueryString(getTimeFromLocation(location))
|
||||||
)('');
|
)('');
|
||||||
|
|
||||||
|
@ -63,11 +63,11 @@ export const RedirectToNodeLogs = injectI18n(
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getNodeLogsUrl = ({
|
export const getNodeLogsUrl = ({
|
||||||
nodeName,
|
nodeId,
|
||||||
nodeType,
|
nodeType,
|
||||||
time,
|
time,
|
||||||
}: {
|
}: {
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
time?: number;
|
time?: number;
|
||||||
}) => [`#/link-to/${nodeType}-logs/`, nodeName, ...(time ? [`?time=${time}`] : [])].join('');
|
}) => [`#/link-to/${nodeType}-logs/`, nodeId, ...(time ? [`?time=${time}`] : [])].join('');
|
||||||
|
|
|
@ -63,7 +63,7 @@ export const MetricDetail = withTheme(
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
const nodeName = this.props.match.params.node;
|
const nodeId = this.props.match.params.node;
|
||||||
const nodeType = this.props.match.params.type as InfraNodeType;
|
const nodeType = this.props.match.params.type as InfraNodeType;
|
||||||
const layoutCreator = layoutCreators[nodeType];
|
const layoutCreator = layoutCreators[nodeType];
|
||||||
if (!layoutCreator) {
|
if (!layoutCreator) {
|
||||||
|
@ -82,40 +82,40 @@ export const MetricDetail = withTheme(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const layouts = layoutCreator(this.props.theme);
|
const layouts = layoutCreator(this.props.theme);
|
||||||
const breadcrumbs = [{ text: nodeName }];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColumnarPage>
|
<WithOptions>
|
||||||
<Header
|
{({ sourceId }) => (
|
||||||
appendSections={<InfrastructureBetaBadgeHeaderSection />}
|
<WithMetricsTime resetOnUnmount>
|
||||||
breadcrumbs={breadcrumbs}
|
{({
|
||||||
/>
|
currentTimeRange,
|
||||||
<WithMetricsTimeUrlState />
|
isAutoReloading,
|
||||||
<DetailPageContent>
|
setRangeTime,
|
||||||
<WithOptions>
|
startMetricsAutoReload,
|
||||||
{({ sourceId }) => (
|
stopMetricsAutoReload,
|
||||||
<WithMetricsTime resetOnUnmount>
|
}) => (
|
||||||
{({
|
<WithMetadata
|
||||||
currentTimeRange,
|
layouts={layouts}
|
||||||
isAutoReloading,
|
sourceId={sourceId}
|
||||||
setRangeTime,
|
nodeType={nodeType}
|
||||||
startMetricsAutoReload,
|
nodeId={nodeId}
|
||||||
stopMetricsAutoReload,
|
>
|
||||||
}) => (
|
{({ name, filteredLayouts, loading: metadataLoading }) => {
|
||||||
<WithMetadata
|
const breadcrumbs = [{ text: name }];
|
||||||
layouts={layouts}
|
return (
|
||||||
sourceId={sourceId}
|
<ColumnarPage>
|
||||||
nodeType={nodeType}
|
<Header
|
||||||
nodeId={nodeName}
|
appendSections={<InfrastructureBetaBadgeHeaderSection />}
|
||||||
>
|
breadcrumbs={breadcrumbs}
|
||||||
{({ filteredLayouts, loading: metadataLoading }) => {
|
/>
|
||||||
return (
|
<WithMetricsTimeUrlState />
|
||||||
|
<DetailPageContent>
|
||||||
<WithMetrics
|
<WithMetrics
|
||||||
layouts={filteredLayouts}
|
layouts={filteredLayouts}
|
||||||
sourceId={sourceId}
|
sourceId={sourceId}
|
||||||
timerange={currentTimeRange as InfraTimerangeInput}
|
timerange={currentTimeRange as InfraTimerangeInput}
|
||||||
nodeType={nodeType}
|
nodeType={nodeType}
|
||||||
nodeId={nodeName}
|
nodeId={nodeId}
|
||||||
>
|
>
|
||||||
{({ metrics, error, loading }) => {
|
{({ metrics, error, loading }) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -126,7 +126,7 @@ export const MetricDetail = withTheme(
|
||||||
<MetricsSideNav
|
<MetricsSideNav
|
||||||
layouts={filteredLayouts}
|
layouts={filteredLayouts}
|
||||||
loading={metadataLoading}
|
loading={metadataLoading}
|
||||||
nodeName={nodeName}
|
nodeName={name}
|
||||||
handleClick={this.handleClick}
|
handleClick={this.handleClick}
|
||||||
/>
|
/>
|
||||||
<AutoSizer content={false} bounds detectAnyWindowResize>
|
<AutoSizer content={false} bounds detectAnyWindowResize>
|
||||||
|
@ -139,7 +139,7 @@ export const MetricDetail = withTheme(
|
||||||
<MetricsTitleTimeRangeContainer>
|
<MetricsTitleTimeRangeContainer>
|
||||||
<EuiHideFor sizes={['xs', 's']}>
|
<EuiHideFor sizes={['xs', 's']}>
|
||||||
<EuiTitle size="m">
|
<EuiTitle size="m">
|
||||||
<h1>{nodeName}</h1>
|
<h1>{name}</h1>
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
</EuiHideFor>
|
</EuiHideFor>
|
||||||
<MetricsTimeControls
|
<MetricsTimeControls
|
||||||
|
@ -155,7 +155,8 @@ export const MetricDetail = withTheme(
|
||||||
|
|
||||||
<EuiPageContentWithRelative>
|
<EuiPageContentWithRelative>
|
||||||
<Metrics
|
<Metrics
|
||||||
nodeName={nodeName}
|
label={name}
|
||||||
|
nodeId={nodeId}
|
||||||
layouts={filteredLayouts}
|
layouts={filteredLayouts}
|
||||||
metrics={metrics}
|
metrics={metrics}
|
||||||
loading={
|
loading={
|
||||||
|
@ -175,15 +176,15 @@ export const MetricDetail = withTheme(
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</WithMetrics>
|
</WithMetrics>
|
||||||
);
|
</DetailPageContent>
|
||||||
}}
|
</ColumnarPage>
|
||||||
</WithMetadata>
|
);
|
||||||
)}
|
}}
|
||||||
</WithMetricsTime>
|
</WithMetadata>
|
||||||
)}
|
)}
|
||||||
</WithOptions>
|
</WithMetricsTime>
|
||||||
</DetailPageContent>
|
)}
|
||||||
</ColumnarPage>
|
</WithOptions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const createMetadataResolvers = (libs: {
|
||||||
} => ({
|
} => ({
|
||||||
InfraSource: {
|
InfraSource: {
|
||||||
async metadataByNode(source, args, { req }) {
|
async metadataByNode(source, args, { req }) {
|
||||||
const result = await libs.metadata.getMetadata(req, source.id, args.nodeName, args.nodeType);
|
const result = await libs.metadata.getMetadata(req, source.id, args.nodeId, args.nodeType);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,12 +9,18 @@ import gql from 'graphql-tag';
|
||||||
export const metadataSchema = gql`
|
export const metadataSchema = gql`
|
||||||
"One metadata entry for a node."
|
"One metadata entry for a node."
|
||||||
type InfraNodeMetadata {
|
type InfraNodeMetadata {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
features: [InfraNodeFeature!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InfraNodeFeature {
|
||||||
name: String!
|
name: String!
|
||||||
source: String!
|
source: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
extend type InfraSource {
|
extend type InfraSource {
|
||||||
"A hierarchy of metadata entries by node"
|
"A hierarchy of metadata entries by node"
|
||||||
metadataByNode(nodeName: String!, nodeType: InfraNodeType!): [InfraNodeMetadata]!
|
metadataByNode(nodeId: String!, nodeType: InfraNodeType!): InfraNodeMetadata!
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -14,6 +14,7 @@ export const nodesSchema: any = gql`
|
||||||
|
|
||||||
type InfraNodePath {
|
type InfraNodePath {
|
||||||
value: String!
|
value: String!
|
||||||
|
label: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type InfraNode {
|
type InfraNode {
|
||||||
|
|
|
@ -51,7 +51,7 @@ export interface InfraSource {
|
||||||
/** The status of the source */
|
/** The status of the source */
|
||||||
status: InfraSourceStatus;
|
status: InfraSourceStatus;
|
||||||
/** A hierarchy of metadata entries by node */
|
/** A hierarchy of metadata entries by node */
|
||||||
metadataByNode: (InfraNodeMetadata | null)[];
|
metadataByNode: InfraNodeMetadata;
|
||||||
/** A consecutive span of log entries surrounding a point in time */
|
/** A consecutive span of log entries surrounding a point in time */
|
||||||
logEntriesAround: InfraLogEntryInterval;
|
logEntriesAround: InfraLogEntryInterval;
|
||||||
/** A consecutive span of log entries within an interval */
|
/** A consecutive span of log entries within an interval */
|
||||||
|
@ -117,6 +117,14 @@ export interface InfraIndexField {
|
||||||
}
|
}
|
||||||
/** One metadata entry for a node. */
|
/** One metadata entry for a node. */
|
||||||
export interface InfraNodeMetadata {
|
export interface InfraNodeMetadata {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
features: InfraNodeFeature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InfraNodeFeature {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
source: string;
|
source: string;
|
||||||
|
@ -203,6 +211,8 @@ export interface InfraNode {
|
||||||
|
|
||||||
export interface InfraNodePath {
|
export interface InfraNodePath {
|
||||||
value: string;
|
value: string;
|
||||||
|
|
||||||
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfraNodeMetric {
|
export interface InfraNodeMetric {
|
||||||
|
@ -280,7 +290,7 @@ export interface SourceQueryArgs {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
export interface MetadataByNodeInfraSourceArgs {
|
export interface MetadataByNodeInfraSourceArgs {
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
|
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
}
|
}
|
||||||
|
@ -461,7 +471,7 @@ export namespace InfraSourceResolvers {
|
||||||
/** The status of the source */
|
/** The status of the source */
|
||||||
status?: StatusResolver<InfraSourceStatus, TypeParent, Context>;
|
status?: StatusResolver<InfraSourceStatus, TypeParent, Context>;
|
||||||
/** A hierarchy of metadata entries by node */
|
/** A hierarchy of metadata entries by node */
|
||||||
metadataByNode?: MetadataByNodeResolver<(InfraNodeMetadata | null)[], TypeParent, Context>;
|
metadataByNode?: MetadataByNodeResolver<InfraNodeMetadata, TypeParent, Context>;
|
||||||
/** A consecutive span of log entries surrounding a point in time */
|
/** A consecutive span of log entries surrounding a point in time */
|
||||||
logEntriesAround?: LogEntriesAroundResolver<InfraLogEntryInterval, TypeParent, Context>;
|
logEntriesAround?: LogEntriesAroundResolver<InfraLogEntryInterval, TypeParent, Context>;
|
||||||
/** A consecutive span of log entries within an interval */
|
/** A consecutive span of log entries within an interval */
|
||||||
|
@ -490,12 +500,12 @@ export namespace InfraSourceResolvers {
|
||||||
Context = InfraContext
|
Context = InfraContext
|
||||||
> = Resolver<R, Parent, Context>;
|
> = Resolver<R, Parent, Context>;
|
||||||
export type MetadataByNodeResolver<
|
export type MetadataByNodeResolver<
|
||||||
R = (InfraNodeMetadata | null)[],
|
R = InfraNodeMetadata,
|
||||||
Parent = InfraSource,
|
Parent = InfraSource,
|
||||||
Context = InfraContext
|
Context = InfraContext
|
||||||
> = Resolver<R, Parent, Context, MetadataByNodeArgs>;
|
> = Resolver<R, Parent, Context, MetadataByNodeArgs>;
|
||||||
export interface MetadataByNodeArgs {
|
export interface MetadataByNodeArgs {
|
||||||
nodeName: string;
|
nodeId: string;
|
||||||
|
|
||||||
nodeType: InfraNodeType;
|
nodeType: InfraNodeType;
|
||||||
}
|
}
|
||||||
|
@ -746,6 +756,32 @@ export namespace InfraIndexFieldResolvers {
|
||||||
/** One metadata entry for a node. */
|
/** One metadata entry for a node. */
|
||||||
export namespace InfraNodeMetadataResolvers {
|
export namespace InfraNodeMetadataResolvers {
|
||||||
export interface Resolvers<Context = InfraContext, TypeParent = InfraNodeMetadata> {
|
export interface Resolvers<Context = InfraContext, TypeParent = InfraNodeMetadata> {
|
||||||
|
id?: IdResolver<string, TypeParent, Context>;
|
||||||
|
|
||||||
|
name?: NameResolver<string, TypeParent, Context>;
|
||||||
|
|
||||||
|
features?: FeaturesResolver<InfraNodeFeature[], TypeParent, Context>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IdResolver<R = string, Parent = InfraNodeMetadata, Context = InfraContext> = Resolver<
|
||||||
|
R,
|
||||||
|
Parent,
|
||||||
|
Context
|
||||||
|
>;
|
||||||
|
export type NameResolver<
|
||||||
|
R = string,
|
||||||
|
Parent = InfraNodeMetadata,
|
||||||
|
Context = InfraContext
|
||||||
|
> = Resolver<R, Parent, Context>;
|
||||||
|
export type FeaturesResolver<
|
||||||
|
R = InfraNodeFeature[],
|
||||||
|
Parent = InfraNodeMetadata,
|
||||||
|
Context = InfraContext
|
||||||
|
> = Resolver<R, Parent, Context>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace InfraNodeFeatureResolvers {
|
||||||
|
export interface Resolvers<Context = InfraContext, TypeParent = InfraNodeFeature> {
|
||||||
name?: NameResolver<string, TypeParent, Context>;
|
name?: NameResolver<string, TypeParent, Context>;
|
||||||
|
|
||||||
source?: SourceResolver<string, TypeParent, Context>;
|
source?: SourceResolver<string, TypeParent, Context>;
|
||||||
|
@ -753,12 +789,12 @@ export namespace InfraNodeMetadataResolvers {
|
||||||
|
|
||||||
export type NameResolver<
|
export type NameResolver<
|
||||||
R = string,
|
R = string,
|
||||||
Parent = InfraNodeMetadata,
|
Parent = InfraNodeFeature,
|
||||||
Context = InfraContext
|
Context = InfraContext
|
||||||
> = Resolver<R, Parent, Context>;
|
> = Resolver<R, Parent, Context>;
|
||||||
export type SourceResolver<
|
export type SourceResolver<
|
||||||
R = string,
|
R = string,
|
||||||
Parent = InfraNodeMetadata,
|
Parent = InfraNodeFeature,
|
||||||
Context = InfraContext
|
Context = InfraContext
|
||||||
> = Resolver<R, Parent, Context>;
|
> = Resolver<R, Parent, Context>;
|
||||||
}
|
}
|
||||||
|
@ -1012,6 +1048,8 @@ export namespace InfraNodeResolvers {
|
||||||
export namespace InfraNodePathResolvers {
|
export namespace InfraNodePathResolvers {
|
||||||
export interface Resolvers<Context = InfraContext, TypeParent = InfraNodePath> {
|
export interface Resolvers<Context = InfraContext, TypeParent = InfraNodePath> {
|
||||||
value?: ValueResolver<string, TypeParent, Context>;
|
value?: ValueResolver<string, TypeParent, Context>;
|
||||||
|
|
||||||
|
label?: DisplayNameResolver<string, TypeParent, Context>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ValueResolver<R = string, Parent = InfraNodePath, Context = InfraContext> = Resolver<
|
export type ValueResolver<R = string, Parent = InfraNodePath, Context = InfraContext> = Resolver<
|
||||||
|
@ -1019,6 +1057,11 @@ export namespace InfraNodePathResolvers {
|
||||||
Parent,
|
Parent,
|
||||||
Context
|
Context
|
||||||
>;
|
>;
|
||||||
|
export type DisplayNameResolver<
|
||||||
|
R = string,
|
||||||
|
Parent = InfraNodePath,
|
||||||
|
Context = InfraContext
|
||||||
|
> = Resolver<R, Parent, Context>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace InfraNodeMetricResolvers {
|
export namespace InfraNodeMetricResolvers {
|
||||||
|
|
|
@ -7,17 +7,23 @@
|
||||||
import { InfraSourceConfiguration } from '../../sources';
|
import { InfraSourceConfiguration } from '../../sources';
|
||||||
import { InfraFrameworkRequest, InfraMetadataAggregationBucket } from '../framework';
|
import { InfraFrameworkRequest, InfraMetadataAggregationBucket } from '../framework';
|
||||||
|
|
||||||
|
export interface InfraMetricsAdapterResponse {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
buckets: InfraMetadataAggregationBucket[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface InfraMetadataAdapter {
|
export interface InfraMetadataAdapter {
|
||||||
getMetricMetadata(
|
getMetricMetadata(
|
||||||
req: InfraFrameworkRequest,
|
req: InfraFrameworkRequest,
|
||||||
sourceConfiguration: InfraSourceConfiguration,
|
sourceConfiguration: InfraSourceConfiguration,
|
||||||
nodeName: string,
|
nodeId: string,
|
||||||
nodeType: string
|
nodeType: string
|
||||||
): Promise<InfraMetadataAggregationBucket[]>;
|
): Promise<InfraMetricsAdapterResponse>;
|
||||||
getLogMetadata(
|
getLogMetadata(
|
||||||
req: InfraFrameworkRequest,
|
req: InfraFrameworkRequest,
|
||||||
sourceConfiguration: InfraSourceConfiguration,
|
sourceConfiguration: InfraSourceConfiguration,
|
||||||
nodeName: string,
|
nodeId: string,
|
||||||
nodeType: string
|
nodeType: string
|
||||||
): Promise<InfraMetadataAggregationBucket[]>;
|
): Promise<InfraMetricsAdapterResponse>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { first, get } from 'lodash';
|
||||||
import { InfraSourceConfiguration } from '../../sources';
|
import { InfraSourceConfiguration } from '../../sources';
|
||||||
import {
|
import {
|
||||||
InfraBackendFrameworkAdapter,
|
InfraBackendFrameworkAdapter,
|
||||||
InfraFrameworkRequest,
|
InfraFrameworkRequest,
|
||||||
InfraMetadataAggregationBucket,
|
|
||||||
InfraMetadataAggregationResponse,
|
InfraMetadataAggregationResponse,
|
||||||
} from '../framework';
|
} from '../framework';
|
||||||
import { InfraMetadataAdapter } from './adapter_types';
|
import { NAME_FIELDS } from '../nodes/constants';
|
||||||
|
import { InfraMetadataAdapter, InfraMetricsAdapterResponse } from './adapter_types';
|
||||||
|
|
||||||
export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
private framework: InfraBackendFrameworkAdapter;
|
private framework: InfraBackendFrameworkAdapter;
|
||||||
|
@ -22,9 +23,9 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
public async getMetricMetadata(
|
public async getMetricMetadata(
|
||||||
req: InfraFrameworkRequest,
|
req: InfraFrameworkRequest,
|
||||||
sourceConfiguration: InfraSourceConfiguration,
|
sourceConfiguration: InfraSourceConfiguration,
|
||||||
nodeName: string,
|
nodeId: string,
|
||||||
nodeType: 'host' | 'container' | 'pod'
|
nodeType: 'host' | 'container' | 'pod'
|
||||||
): Promise<InfraMetadataAggregationBucket[]> {
|
): Promise<InfraMetricsAdapterResponse> {
|
||||||
const idFieldName = getIdFieldName(sourceConfiguration, nodeType);
|
const idFieldName = getIdFieldName(sourceConfiguration, nodeType);
|
||||||
const metricQuery = {
|
const metricQuery = {
|
||||||
index: sourceConfiguration.metricAlias,
|
index: sourceConfiguration.metricAlias,
|
||||||
|
@ -32,11 +33,12 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
query: {
|
query: {
|
||||||
bool: {
|
bool: {
|
||||||
filter: {
|
filter: {
|
||||||
term: { [idFieldName]: nodeName },
|
term: { [idFieldName]: nodeId },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
size: 0,
|
size: 1,
|
||||||
|
_source: [NAME_FIELDS[nodeType]],
|
||||||
aggs: {
|
aggs: {
|
||||||
metrics: {
|
metrics: {
|
||||||
terms: {
|
terms: {
|
||||||
|
@ -61,17 +63,26 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
{ metrics?: InfraMetadataAggregationResponse }
|
{ metrics?: InfraMetadataAggregationResponse }
|
||||||
>(req, 'search', metricQuery);
|
>(req, 'search', metricQuery);
|
||||||
|
|
||||||
return response.aggregations && response.aggregations.metrics
|
const buckets =
|
||||||
? response.aggregations.metrics.buckets
|
response.aggregations && response.aggregations.metrics
|
||||||
: [];
|
? response.aggregations.metrics.buckets
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const sampleDoc = first(response.hits.hits);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: nodeId,
|
||||||
|
name: get(sampleDoc, `_source.${NAME_FIELDS[nodeType]}`),
|
||||||
|
buckets,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getLogMetadata(
|
public async getLogMetadata(
|
||||||
req: InfraFrameworkRequest,
|
req: InfraFrameworkRequest,
|
||||||
sourceConfiguration: InfraSourceConfiguration,
|
sourceConfiguration: InfraSourceConfiguration,
|
||||||
nodeName: string,
|
nodeId: string,
|
||||||
nodeType: 'host' | 'container' | 'pod'
|
nodeType: 'host' | 'container' | 'pod'
|
||||||
): Promise<InfraMetadataAggregationBucket[]> {
|
): Promise<InfraMetricsAdapterResponse> {
|
||||||
const idFieldName = getIdFieldName(sourceConfiguration, nodeType);
|
const idFieldName = getIdFieldName(sourceConfiguration, nodeType);
|
||||||
const logQuery = {
|
const logQuery = {
|
||||||
index: sourceConfiguration.logAlias,
|
index: sourceConfiguration.logAlias,
|
||||||
|
@ -79,11 +90,12 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
query: {
|
query: {
|
||||||
bool: {
|
bool: {
|
||||||
filter: {
|
filter: {
|
||||||
term: { [idFieldName]: nodeName },
|
term: { [idFieldName]: nodeId },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
size: 0,
|
size: 1,
|
||||||
|
_source: [NAME_FIELDS[nodeType]],
|
||||||
aggs: {
|
aggs: {
|
||||||
metrics: {
|
metrics: {
|
||||||
terms: {
|
terms: {
|
||||||
|
@ -108,9 +120,18 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter {
|
||||||
{ metrics?: InfraMetadataAggregationResponse }
|
{ metrics?: InfraMetadataAggregationResponse }
|
||||||
>(req, 'search', logQuery);
|
>(req, 'search', logQuery);
|
||||||
|
|
||||||
return response.aggregations && response.aggregations.metrics
|
const buckets =
|
||||||
? response.aggregations.metrics.buckets
|
response.aggregations && response.aggregations.metrics
|
||||||
: [];
|
? response.aggregations.metrics.buckets
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const sampleDoc = first(response.hits.hits);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: nodeId,
|
||||||
|
name: get(sampleDoc, `_source.${NAME_FIELDS[nodeType]}`),
|
||||||
|
buckets,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { InfraNodeType } from '../../../graphql/types';
|
||||||
// TODO: Make NODE_REQUEST_PARTITION_SIZE configurable from kibana.yml
|
// TODO: Make NODE_REQUEST_PARTITION_SIZE configurable from kibana.yml
|
||||||
export const NODE_REQUEST_PARTITION_SIZE = 75;
|
export const NODE_REQUEST_PARTITION_SIZE = 75;
|
||||||
export const NODE_REQUEST_PARTITION_FACTOR = 1.2;
|
export const NODE_REQUEST_PARTITION_FACTOR = 1.2;
|
||||||
|
export const NAME_FIELDS = {
|
||||||
|
[InfraNodeType.host]: 'host.name',
|
||||||
|
[InfraNodeType.pod]: 'kubernetes.pod.name',
|
||||||
|
[InfraNodeType.container]: 'docker.container.name',
|
||||||
|
};
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { last } from 'lodash';
|
import { get, last } from 'lodash';
|
||||||
import { isNumber } from 'lodash';
|
import { isNumber } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { InfraNode, InfraNodeMetric } from '../../../../graphql/types';
|
import { InfraNode, InfraNodeMetric } from '../../../../graphql/types';
|
||||||
import { InfraBucket, InfraNodeRequestOptions } from '../adapter_types';
|
import { InfraBucket, InfraNodeRequestOptions } from '../adapter_types';
|
||||||
|
import { NAME_FIELDS } from '../constants';
|
||||||
import { getBucketSizeInSeconds } from './get_bucket_size_in_seconds';
|
import { getBucketSizeInSeconds } from './get_bucket_size_in_seconds';
|
||||||
|
|
||||||
// TODO: Break these function into seperate files and expand beyond just documnet count
|
// TODO: Break these function into seperate files and expand beyond just documnet count
|
||||||
|
@ -57,8 +58,9 @@ export function createNodeItem(
|
||||||
node: InfraBucket,
|
node: InfraBucket,
|
||||||
bucket: InfraBucket
|
bucket: InfraBucket
|
||||||
): InfraNode {
|
): InfraNode {
|
||||||
|
const nodeDoc = get(node, ['nodeDetails', 'hits', 'hits', 0]);
|
||||||
return {
|
return {
|
||||||
metric: createNodeMetrics(options, node, bucket),
|
metric: createNodeMetrics(options, node, bucket),
|
||||||
path: [{ value: node.key }],
|
path: [{ value: node.key, label: get(nodeDoc, `_source.${NAME_FIELDS[options.nodeType]}`) }],
|
||||||
} as InfraNode;
|
} as InfraNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ export function extractGroupPaths(
|
||||||
(b: InfraBucket): InfraNode => {
|
(b: InfraBucket): InfraNode => {
|
||||||
const innerNode = createNodeItem(options, node, b);
|
const innerNode = createNodeItem(options, node, b);
|
||||||
const nodePath = [
|
const nodePath = [
|
||||||
{ value: bucket.key.toString() },
|
{ value: bucket.key.toString(), label: bucket.key.toString() },
|
||||||
{ value: b.key.toString() },
|
{ value: b.key.toString(), label: b.key.toString() },
|
||||||
].concat(innerNode.path);
|
].concat(innerNode.path);
|
||||||
return {
|
return {
|
||||||
...innerNode,
|
...innerNode,
|
||||||
|
@ -40,7 +40,7 @@ export function extractGroupPaths(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const nodeItem = createNodeItem(options, node, bucket);
|
const nodeItem = createNodeItem(options, node, bucket);
|
||||||
const path = [{ value: key }].concat(nodeItem.path);
|
const path = [{ value: key, label: key }].concat(nodeItem.path);
|
||||||
return acc.concat({
|
return acc.concat({
|
||||||
...nodeItem,
|
...nodeItem,
|
||||||
path,
|
path,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { cloneDeep, set } from 'lodash';
|
import { cloneDeep, get, set } from 'lodash';
|
||||||
|
|
||||||
import { InfraPathFilterInput, InfraPathInput } from '../../../../../graphql/types';
|
import { InfraPathFilterInput, InfraPathInput } from '../../../../../graphql/types';
|
||||||
import {
|
import {
|
||||||
|
@ -18,7 +18,7 @@ export const groupByProcessor = (options: InfraProcesorRequestOptions) => {
|
||||||
return (doc: InfraESSearchBody) => {
|
return (doc: InfraESSearchBody) => {
|
||||||
const result = cloneDeep(doc);
|
const result = cloneDeep(doc);
|
||||||
const { groupBy } = options.nodeOptions;
|
const { groupBy } = options.nodeOptions;
|
||||||
let aggs = {};
|
let aggs = get(result, 'aggs.waffle.aggs.nodes.aggs', {});
|
||||||
set(result, 'aggs.waffle.aggs.nodes.aggs', aggs);
|
set(result, 'aggs.waffle.aggs.nodes.aggs', aggs);
|
||||||
groupBy.forEach((grouping: InfraPathInput, index: number) => {
|
groupBy.forEach((grouping: InfraPathInput, index: number) => {
|
||||||
if (isGroupByTerms(grouping)) {
|
if (isGroupByTerms(grouping)) {
|
||||||
|
@ -49,7 +49,7 @@ export const groupByProcessor = (options: InfraProcesorRequestOptions) => {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
set(aggs, `${grouping.id}`, filtersAgg);
|
set(aggs, `path_${index}`, filtersAgg);
|
||||||
aggs = filtersAgg.aggs;
|
aggs = filtersAgg.aggs;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
import { cloneDeep, set } from 'lodash';
|
import { cloneDeep, set } from 'lodash';
|
||||||
|
|
||||||
import { InfraESSearchBody, InfraNodeType, InfraProcesorRequestOptions } from '../../adapter_types';
|
import { InfraESSearchBody, InfraNodeType, InfraProcesorRequestOptions } from '../../adapter_types';
|
||||||
import { NODE_REQUEST_PARTITION_FACTOR, NODE_REQUEST_PARTITION_SIZE } from '../../constants';
|
import {
|
||||||
|
NAME_FIELDS,
|
||||||
|
NODE_REQUEST_PARTITION_FACTOR,
|
||||||
|
NODE_REQUEST_PARTITION_SIZE,
|
||||||
|
} from '../../constants';
|
||||||
|
|
||||||
const nodeTypeToField = (options: InfraProcesorRequestOptions): string => {
|
const nodeTypeToField = (options: InfraProcesorRequestOptions): string => {
|
||||||
const { fields } = options.nodeOptions.sourceConfiguration;
|
const { fields } = options.nodeOptions.sourceConfiguration;
|
||||||
|
@ -22,6 +26,7 @@ const nodeTypeToField = (options: InfraProcesorRequestOptions): string => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const nodesProcessor = (options: InfraProcesorRequestOptions) => {
|
export const nodesProcessor = (options: InfraProcesorRequestOptions) => {
|
||||||
|
const { fields } = options.nodeOptions.sourceConfiguration;
|
||||||
return (doc: InfraESSearchBody) => {
|
return (doc: InfraESSearchBody) => {
|
||||||
const result = cloneDeep(doc);
|
const result = cloneDeep(doc);
|
||||||
const field = nodeTypeToField(options);
|
const field = nodeTypeToField(options);
|
||||||
|
@ -35,6 +40,16 @@ export const nodesProcessor = (options: InfraProcesorRequestOptions) => {
|
||||||
order: { _key: 'asc' },
|
order: { _key: 'asc' },
|
||||||
size: NODE_REQUEST_PARTITION_SIZE * NODE_REQUEST_PARTITION_FACTOR,
|
size: NODE_REQUEST_PARTITION_SIZE * NODE_REQUEST_PARTITION_FACTOR,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
set(result, 'aggs.waffle.aggs.nodes.aggs', {
|
||||||
|
nodeDetails: {
|
||||||
|
top_hits: {
|
||||||
|
size: 1,
|
||||||
|
_source: { includes: [NAME_FIELDS[options.nodeType]] },
|
||||||
|
sort: [{ [fields.timestamp]: { order: 'desc' } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,10 +49,10 @@ export class InfraConfigurationSourcesAdapter implements InfraSourcesAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_FIELDS = {
|
const DEFAULT_FIELDS = {
|
||||||
container: 'docker.container.name',
|
container: 'docker.container.id',
|
||||||
host: 'beat.hostname',
|
host: 'host.name',
|
||||||
message: ['message', '@message'],
|
message: ['message', '@message'],
|
||||||
pod: 'kubernetes.pod.name',
|
pod: 'kubernetes.pod.uid',
|
||||||
tiebreaker: '_doc',
|
tiebreaker: '_doc',
|
||||||
timestamp: '@timestamp',
|
timestamp: '@timestamp',
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,30 +17,32 @@ export class InfraMetadataDomain {
|
||||||
public async getMetadata(
|
public async getMetadata(
|
||||||
req: InfraFrameworkRequest,
|
req: InfraFrameworkRequest,
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
nodeName: string,
|
nodeId: string,
|
||||||
nodeType: string
|
nodeType: string
|
||||||
) {
|
) {
|
||||||
const sourceConfiguration = await this.libs.sources.getConfiguration(sourceId);
|
const sourceConfiguration = await this.libs.sources.getConfiguration(sourceId);
|
||||||
const metricsPromise = this.adapter.getMetricMetadata(
|
const metricsPromise = this.adapter.getMetricMetadata(
|
||||||
req,
|
req,
|
||||||
sourceConfiguration,
|
sourceConfiguration,
|
||||||
nodeName,
|
nodeId,
|
||||||
nodeType
|
nodeType
|
||||||
);
|
);
|
||||||
const logsPromise = this.adapter.getLogMetadata(req, sourceConfiguration, nodeName, nodeType);
|
const logsPromise = this.adapter.getLogMetadata(req, sourceConfiguration, nodeId, nodeType);
|
||||||
|
|
||||||
const metrics = await metricsPromise;
|
const metrics = await metricsPromise;
|
||||||
const logs = await logsPromise;
|
const logs = await logsPromise;
|
||||||
|
|
||||||
const metricMetadata = pickMetadata(metrics).map(entry => {
|
const metricMetadata = pickMetadata(metrics.buckets).map(entry => {
|
||||||
return { name: entry, source: 'metrics' };
|
return { name: entry, source: 'metrics' };
|
||||||
});
|
});
|
||||||
|
|
||||||
const logMetadata = pickMetadata(logs).map(entry => {
|
const logMetadata = pickMetadata(logs.buckets).map(entry => {
|
||||||
return { name: entry, source: 'logs' };
|
return { name: entry, source: 'logs' };
|
||||||
});
|
});
|
||||||
|
|
||||||
return metricMetadata.concat(logMetadata);
|
const id = metrics.id || logs.id;
|
||||||
|
const name = metrics.name || logs.name || id;
|
||||||
|
return { id, name, features: metricMetadata.concat(logMetadata) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,12 @@ const metadataTests: KbnTestProvider = ({ getService }) => {
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
const metadata = resp.data.source.metadataByNode;
|
const metadata = resp.data.source.metadataByNode;
|
||||||
expect(metadata.length).to.be(14);
|
if (metadata) {
|
||||||
|
expect(metadata.features.length).to.be(14);
|
||||||
|
expect(metadata.name).to.equal('demo-stack-nginx-01');
|
||||||
|
} else {
|
||||||
|
throw new Error('Metadata should never be empty');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,9 +33,9 @@ const sourcesTests: KbnTestProvider = ({ getService }) => {
|
||||||
// shipped default values
|
// shipped default values
|
||||||
expect(sourceConfiguration.metricAlias).to.be('metricbeat-*');
|
expect(sourceConfiguration.metricAlias).to.be('metricbeat-*');
|
||||||
expect(sourceConfiguration.logAlias).to.be('filebeat-*');
|
expect(sourceConfiguration.logAlias).to.be('filebeat-*');
|
||||||
expect(sourceConfiguration.fields.container).to.be('docker.container.name');
|
expect(sourceConfiguration.fields.container).to.be('docker.container.id');
|
||||||
expect(sourceConfiguration.fields.host).to.be('beat.hostname');
|
expect(sourceConfiguration.fields.host).to.be('host.name');
|
||||||
expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.name');
|
expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid');
|
||||||
|
|
||||||
// test data in x-pack/test/functional/es_archives/infra/data.json.gz
|
// test data in x-pack/test/functional/es_archives/infra/data.json.gz
|
||||||
expect(sourceStatus.indexFields.length).to.be(1765);
|
expect(sourceStatus.indexFields.length).to.be(1765);
|
||||||
|
|
Loading…
Reference in a new issue