import debug from 'debug'; import React from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Map as makeMap } from 'immutable'; import { noop } from 'lodash'; import { clickCloseDetails, clickShowTopologyForNode } from '../actions/request-actions'; import { brightenColor, getNeutralColor, getNodeColorDark,getStatusColor,setNodeColor } from '../utils/color-utils'; import { isGenericTable, isPropertyList } from '../utils/node-details-utils'; import { resetDocumentTitle, setDocumentTitle } from '../utils/title-utils'; import Overlay from './overlay'; import MatchedText from './matched-text'; import NodeDetailsControls from './node-details/node-details-controls'; import NodeDetailsGenericTable from './node-details/node-details-generic-table'; import NodeDetailsPropertyList from './node-details/node-details-property-list'; import NodeDetailsHealth from './node-details/node-details-health'; import f from './node-details/node-details-info'; import NodeDetailsRelatives from './node-details/node-details-relatives'; import NodeDetailsTable from './node-details/node-details-table'; import Warning from './warning'; import * as echarts from 'echarts' import axios from 'axios' import moment from 'moment' import { Table,Radio,Checkbox,Button, Drawer, Descriptions } from "antd"; import "antd/dist/antd.css"; import '../../styles/nodeDetail.less' import getToken from '../utils/get-token' const log = debug('scope:node-details'); function getTruncationText(count) { return 'This section was too long to be handled efficiently and has been truncated' + ` (${count} extra entries not included). We are working to remove this limitation.`; } class NodeDetails extends React.Component { constructor(props, context) { super(props, context); this.state = { // baseUrl:'http://observe-server.cestong.com.cn', //本地调试使用 // traceUrl:'http://observe-front.cestong.com.cn', //本地调试使用 // coreBaseUrl: 'http://observe-front.cestong.com.cn/core', //本地调试使用 coreBaseUrl:'',//上线时打开 baseUrl:'/re', //上线时打开 traceUrl:'',//上线时打开 nodeData:{}, //节点基础信息 AnalystData:{},//散点图 queryParams:{ start_time:Math.round((new Date().getTime())/1000 - (5*60)), end_time:Math.round(new Date().getTime()/1000), app_alias:'opentelemetry-demo', service_name:'frontend', percentile:0.5, sort_field:'Timestamp', sort_type: 'DESC' }, traceData:[], livenessData:[], barData:[], tableData: [], bgColor:setNodeColor('R'), pagination: { pageIndex:1, pageSize:10, total:0, current:1, }, pagination2: { page_num:1, page_size:10, total:0, current:1, }, traceQuery:{ only_exception:0, only_database:0, }, timeoutId: null, messaging_stats: { topic_stats:[] }, cloudTable: [], cloudTable2: [], cloudPagination: { page_num:1, page_size:10, total:0, current:1, } } } handleClickClose = (ev) => { ev.preventDefault(); this.props.clickCloseDetails(this.props.nodeId); } handleShowTopologyForNode = (ev) => { ev.preventDefault(); this.props.clickShowTopologyForNode(this.props.topologyId, this.props.nodeId); } componentDidMount() { let _this = this //上线时打开开始 this.setQueryParams();//做为iframe嵌套时打开,上线时打开 const traceURL = `http://${parent.location.hostname}` const coreBaseURL = `http://${parent.location.hostname}/core` this.setState({ traceUrl:traceURL, coreBaseUrl:coreBaseURL },()=>{ }) //上线时打开结束 // 接受父组件参数 // window.top == window true 自己本身没有被嵌套 if(window.top !== window){// false 被嵌套 const data = JSON.parse(parent.localStorage.global_times) const queryParams = _this.state.queryParams queryParams.start_time = data.startTime queryParams.end_time = data.endTime _this.setState({ queryParams: queryParams },()=>{ }); } window.addEventListener('message', function(event) { // 处理接收到的消息 const data = event.data const queryParams = _this.state.queryParams if (data.eventType == 'globalTimesChange') { queryParams.start_time = data.data.startTime queryParams.end_time = data.data.endTime _this.setState({ queryParams: queryParams },()=>{ if (_this.props.shape == 'cylinder'){ _this.getTableData(); //table _this.getBarData(); // 柱形图 } if (_this.props.shape == 'dottedcylinder'){ _this.getDottBasicsData() // dottedcylinder 基础信息 } if (_this.props.shape == 'circle'){ _this.getNodeBasic(); _this.getNodeAnalyst();//获取散点图 _this.getNodeLiveness(); // 折线图 _this.getServiceSpans(); } if (_this.props.shape == 'cloud'){ _this.getCloudTableData() } }); } else if (data.eventType == 'getLoginAuth') { _this.setState({ getToken: data.data }, ()=>{}) } }, false); } componentWillUnmount() { clearTimeout(this.timeoutId); } setQueryParams(){ var strr = parent.location.href; //上线做为iframe嵌套时使用 let param = this.parseQueryString(strr); //全链路需要的参数多,因此解析成对象形式 const queryParams = this.state.queryParams; if(parseInt(param.start_time)!=0 && parseInt(param.end_time) !=0){ //上线时打开 let newStartTime = parseInt(param.start_time); // 设置新的属性值 let newEndTime = parseInt(param.end_time); // 设置新的属性值 queryParams.start_time = newStartTime queryParams.end_time = newEndTime } const newAppAlias = param.app_alias queryParams.app_alias = newAppAlias this.setState({ queryParams: queryParams },()=>{ if (this.props.shape == 'cylinder'){ this.getTableData(); //table this.getBarData(); // 柱形图 } if (this.props.shape == 'dottedcylinder'){ this.getDottBasicsData() // dottedcylinder 基础信息 } if (this.props.shape == 'circle'){ this.getNodeBasic(); this.getNodeAnalyst();//获取散点图 this.getNodeLiveness(); // 折线图 this.getServiceSpans(); } if (this.props.shape == 'cloud') { this.getCloudTableData() } }); } //解析URL parseQueryString(url){ var json = {}; var arr = url.substr(url.indexOf('?') + 1).split('&'); arr.forEach(item=>{ var tmp = item.split('='); json[tmp[0]] = tmp[1]; }); return json; } componentWillUnmount() { resetDocumentTitle(); } renderTools() { const showSwitchTopology = this.props.nodeId !== this.props.selectedNodeId; const topologyTitle = `View ${this.props.label} in ${this.props.topologyId}`; return (
{showSwitchTopology && ( Show in {/* {this.props.topologyId.replace(/-/g, ' ')} */} ) }
); } renderLoading() { const node = this.props.nodes.get(this.props.nodeId); const label = node ? node.get('label') : this.props.label; // NOTE: If we start the fa-spin animation before the node details panel has been // mounted, the spinner is displayed blurred the whole time in Chrome (possibly // caused by a bug having to do with animating the details panel). const spinnerClassName = classNames('fa fa-circle-notch', { 'fa-spin': this.props.mounted }); const nodeColor = (node ? getNodeColorDark(node.get('rank'), label, node.get('pseudo')) : getNeutralColor()); const tools = this.renderTools(); const styles = { header: { backgroundColor: nodeColor } }; return (
{tools}

{label}

Loading...
); } renderNotAvailable() { const tools = this.renderTools(); return (
{tools}

{this.props.label}

n/a

{this.props.label} {' '} not found!

); } render() { // if (this.props.notFound) { // return this.renderNotAvailable(); // } // if (this.props.details) { // return this.renderDetails(); // } // return this.renderLoading(); return this.renderNodeDetails(); } renderDetails() { const { details, nodeControlStatus, nodeMatches = makeMap(), topologyId } = this.props; const showControls = details.controls && details.controls.length > 0; const nodeColor = getNodeColorDark(details.rank, details.label, details.pseudo); // const nodeColor= setNodeColor(details.color) const {error, pending} = nodeControlStatus ? nodeControlStatus.toJS() : {}; const tools = this.renderTools(); const styles = { controls: { backgroundColor: brightenColor(nodeColor) }, header: { backgroundColor: nodeColor } }; return (
{tools}

{details.parents && ( )}
{showControls && (
) }
{details.metrics && (
Status
) } {details.metadata && (
Info
) } {details.connections && details.connections.filter(cs => cs.connections.length > 0) .map(connections => (
))} {details.children && details.children.map(children => (
))} {details.tables && details.tables.length > 0 && details.tables.map((table) => { if (table.rows.length > 0) { return (
{table.label && table.label.length > 0 && table.label} {table.truncationCount > 0 && ( ) }
{this.renderTable(table)}
); } return null; })} {this.props.renderNodeDetailsExtras({ details, topologyId })}
); } renderNodeDetails(){ const { details, nodeControlStatus, nodeMatches = makeMap(), topologyId } = this.props; const node = this.props.nodes.get(this.props.nodeId); const label = node ? node.get('label') : this.props.label; // const nodeColor = getNodeColorDark(details.rank, details.label, details.pseudo); // const nodeColor= setNodeColor(details.color) const {error, pending} = nodeControlStatus ? nodeControlStatus.toJS() : {}; const tools = this.renderTools(); const styles = { controls: { // backgroundColor: brightenColor(nodeColor) }, header: { // backgroundColor: '#5BB2FA' backgroundColor:this.state.bgColor } }; const columns = [ { title: 'TraceID', dataIndex: 'trace_id', key: 'trace_id', width:'20%', ellipsis:true, align:'center', // scopedSlots:{customRender:'trace_id'}, render: (text,record) => {text} }, { title: '方法', dataIndex: 'method', key: 'method', width:'15%', ellipsis:true, align:'center' }, { title: '状态码', dataIndex: 'code', key: 'code', width:'15%', ellipsis:true, align:'center' }, { title: '请求时长(ms)', dataIndex: 'duration', key: 'duration', width:'30%', ellipsis:true, align:'center', render:(text) => {text.toFixed(2)} }, { title: '日期', dataIndex: 'datetime', key: 'datetime', width:'30%', ellipsis:true, align:'center', defaultSortOrder: 'descend', sorter:true }, ] const colums2 = [ { title: '服务名', dataIndex: 'service_name', key: 'service_name', ellipsis:true, align:'center', render: (text, record) => ( {record.service_name_cn? record.service_name_cn: record.service_name} ) }, { title: '执行语句', dataIndex: 'query', key: 'query', width:'40%', ellipsis:true, align:'center', render: (text, record) => (