import _ from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; import { withContext } from './util/AppContext.jsx'; import { Col, Icon, Row, Table } from 'antd'; import { directionColumn, srcDstColumn } from './util/TapUtils.jsx'; import { formatLatencySec, formatWithComma } from './util/Utils.js'; // 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 smallMetricColWidth = "120px"; const httpStatusCol = { title: "HTTP status", key: "http-status", width: smallMetricColWidth, dataIndex: "responseInit.http.responseInit", render: d => !d ? : d.httpStatus }; const responseInitLatencyCol = { title: "Latency", key: "rsp-latency", width: smallMetricColWidth, dataIndex: "responseInit.http.responseInit", render: d => !d ? : formatTapLatency(d.sinceRequestInit) }; const grpcStatusCol = { title: "GRPC status", key: "grpc-status", width: smallMetricColWidth, dataIndex: "responseEnd.http.responseEnd", render: d => !d ? : _.isNull(d.eos) ? "---" : grpcStatusCodes[_.get(d, "eos.grpcStatusCode")] }; const pathCol = { title: "Path", key: "path", dataIndex: "requestInit.http.requestInit", render: d => !d ? : d.path }; const methodCol = { title: "Method", key: "method", dataIndex: "requestInit.http.requestInit", render: d => !d ? : _.get(d, "method.registered") }; const topLevelColumns = (resourceType, ResourceLink) => [ { title: "Direction", key: "direction", dataIndex: "base.proxyDirection", width: "98px", filters: [ { text: "FROM", value: "INBOUND" }, { text: "TO", value: "OUTBOUND" } ], render: directionColumn, onFilter: (value, row) => _.get(row, "base.proxyDirection").includes(value) }, { title: "Name", key: "src-dst", render: d => { let datum = { direction: _.get(d, "base.proxyDirection"), source: _.get(d, "base.source"), destination: _.get(d, "base.destination"), sourceLabels: _.get(d, "base.sourceMeta.labels", {}), destinationLabels: _.get(d, "base.destinationMeta.labels", {}) }; return srcDstColumn(datum, resourceType, ResourceLink); } } ]; const tapColumns = (resourceType, ResourceLink) => { return _.concat( topLevelColumns(resourceType, ResourceLink), [ methodCol, pathCol, responseInitLatencyCol, httpStatusCol, grpcStatusCol ] ); }; const formatTapLatency = str => { return formatLatencySec(str.replace("s", "")); }; const requestInitSection = d => (

Request Init

Authority Path Scheme Method TLS {_.get(d, "requestInit.http.requestInit.authority")} {_.get(d, "requestInit.http.requestInit.path")} {_.get(d, "requestInit.http.requestInit.scheme.registered")} {_.get(d, "requestInit.http.requestInit.method.registered")} {_.get(d, "base.tls")}
); const responseInitSection = d => _.isEmpty(d.responseInit) ? null : (

Response Init

HTTP Status Latency {_.get(d, "responseInit.http.responseInit.httpStatus")} {formatTapLatency(_.get(d, "responseInit.http.responseInit.sinceRequestInit"))}
); const responseEndSection = d => _.isEmpty(d.responseEnd) ? null : (

Response End

GRPC Status Latency Response Length (B) {_.isNull(_.get(d, "responseEnd.http.responseEnd.eos")) ? "N/A" : grpcStatusCodes[_.get(d, "responseEnd.http.responseEnd.eos.grpcStatusCode")]} {formatTapLatency(_.get(d, "responseEnd.http.responseEnd.sinceResponseInit"))} {formatWithComma(_.get(d, "responseEnd.http.responseEnd.responseBytes"))}
); // hide verbose information const expandedRowRender = d => { return (
{requestInitSection(d)} {responseInitSection(d)} {responseEndSection(d)}
); }; class TapEventTable extends React.Component { static propTypes = { api: PropTypes.shape({ ResourceLink: PropTypes.func.isRequired, }).isRequired, resource: PropTypes.string, tableRows: PropTypes.arrayOf(PropTypes.shape({})), } static defaultProps = { resource: "", tableRows: [] } render() { let resourceType = this.props.resource.split("/")[0]; return ( r.base.id} pagination={false} className="tap-event-table" size="middle" /> ); } } export default withContext(TapEventTable);