linkerd2/web/app/js/components/TapEventTable.jsx

195 lines
5.4 KiB
JavaScript

import _ from 'lodash';
import BaseTable from './BaseTable.jsx';
import { formatLatencySec } from './util/Utils.js';
import React from 'react';
import { Col, Icon, Row } from 'antd';
// https://godoc.org/google.golang.org/grpc/codes#Code
const grpcStatusCodes = {
0: "OK",
1: "Canceled",
2: "Unknown",
3: "InvalidArgument",
4: "DeadlineExceeded",
5: "NotFound",
6: "AlreadyExists",
7: "PermissionDenied",
8: "ResourceExhausted",
9: "FailedPrecondition",
10: "Aborted",
11: "OutOfRange",
12: "Unimplemented",
13: "Internal",
14: "Unavailable",
15: "DataLoss",
16: "Unauthenticated"
};
const grpcStatusCodeFilters = _.map(grpcStatusCodes, (description, code) => {
return { text: `${code}: ${description}`, value: code };
});
const genFilterOptionList = options => _.map(options, (_v, k) => {
return { text: k, value: k };
});
let tapColumns = filterOptions => [
{
title: "ID",
dataIndex: "base.id"
},
{
title: "Direction",
dataIndex: "base.proxyDirection",
filters: [
{ text: "Inbound", value: "INBOUND" },
{ text: "Outbound", value: "OUTBOUND" }
],
onFilter: (value, row) => _.get(row, "base.proxyDirection").includes(value)
},
{
title: "Source",
dataIndex: "base.source.str",
filters: genFilterOptionList(filterOptions.source),
onFilter: (value, row) => row.base.source.str === value
},
{
title: "Destination",
dataIndex: "base.destination.str",
filters: genFilterOptionList(filterOptions.destination),
onFilter: (value, row) => row.base.destination.str === value
},
{
title: "TLS",
dataIndex: "base.tls",
filters: genFilterOptionList(filterOptions.tls),
onFilter: (value, row) => row.tls === value
},
{
title: "Request Init",
children: [
{
title: "Authority",
key: "authority",
dataIndex: "req.http.requestInit",
filters: genFilterOptionList(filterOptions.authority),
onFilter: (value, row) =>
_.get(row, "req.http.requestInit.authority") === value,
render: d => !d ? <Icon type="loading" /> : d.authority
},
{
title: "Path",
key: "path",
dataIndex: "req.http.requestInit",
filters: genFilterOptionList(filterOptions.path),
onFilter: (value, row) =>
_.get(row, "req.http.requestInit.path") === value,
render: d => !d ? <Icon type="loading" /> : d.path
},
{
title: "Scheme",
key: "scheme",
dataIndex: "req.http.requestInit",
filters: genFilterOptionList(filterOptions.scheme),
onFilter: (value, row) =>
_.get(row, "req.http.requestInit.scheme.registered") === value,
render: d => !d ? <Icon type="loading" /> : _.get(d, "scheme.registered")
},
{
title: "Method",
key: "method",
dataIndex: "req.http.requestInit",
filters: _.map(filterOptions.httpMethod, d => {
return { text: d, value: d};
}),
onFilter: (value, row) =>
_.get(row, "req.http.requestInit.method.registered") === value,
render: d => !d ? <Icon type="loading" /> : _.get(d, "method.registered")
}
]
},
{
title: "Response Init",
children: [
{
title: "HTTP status",
key: "http-status",
dataIndex: "rsp.http.responseInit",
filters: genFilterOptionList(filterOptions.httpStatus),
onFilter: (value, row) =>
_.get(row, "rsp.http.responseInit.httpStatus") + "" === value,
render: d => !d ? <Icon type="loading" /> : d.httpStatus
},
{
title: "Latency",
key: "rsp-latency",
dataIndex: "rsp.http.responseInit",
render: d => !d ? <Icon type="loading" /> : formatTapLatency(d.sinceRequestInit)
},
]
},
{
title: "Response End",
children: [
{
title: "GRPC status",
key: "grpc-status",
dataIndex: "end.http.responseEnd",
filters: grpcStatusCodeFilters,
onFilter: (value, row) =>
(_.get(row, "end.http.responseEnd.eos.grpcStatusCode") + "") === value,
render: d => !d ? <Icon type="loading" /> : _.get(d, "eos.grpcStatusCode")
},
{
title: "Latency",
key: "end-latency",
dataIndex: "end.http.responseEnd",
render: d => !d ? <Icon type="loading" /> : formatTapLatency(d.sinceResponseInit)
},
{
title: "Response Length (B)",
key: "rsp-length",
dataIndex: "end.http.responseEnd",
render: d => !d ? <Icon type="loading" /> : d.responseBytes
},
]
}
];
const formatTapLatency = str => {
return formatLatencySec(str.replace("s", ""));
};
// hide verbose information
const expandedRowRender = d => {
return (
<div>
<p style={{ margin: 0 }}>Destination Meta</p>
{
_.map(_.get(d, "base.destinationMeta.labels", []), (v, k) => (
<Row key={k}>
<Col span={6}>{k}</Col>
<Col cpan={6}>{v}</Col>
</Row>
))
}
</div>
);
};
export default class TapEventTable extends BaseTable {
render() {
return (
<BaseTable
dataSource={this.props.tableRows}
columns={tapColumns(this.props.filterOptions)}
expandedRowRender={expandedRowRender}
rowKey={r => r.base.id}
pagination={false}
className="tap-event-table"
size="middle" />
);
}
}