123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824 |
- 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 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);
- }
- handleBeforeUnload = () => {
- // 在这里执行你需要的清理工作
- this.props.clickCloseDetails(this.props.nodeId);
- };
- componentDidMount() {
- let _this = this
- // //上线时打开开始
- 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.topoGlobalTimes)
- const appsItem = JSON.parse(parent.localStorage.appsItem)
- const queryParams = _this.state.queryParams
- queryParams.start_time = data.startTime
- queryParams.end_time = data.endTime
- queryParams.app_alias = appsItem.alias
- _this.setState({
- queryParams: queryParams
- },()=>{
- _this.getMethodByshape(_this)
- });
- }
- console.log(88888888888,'componentDidMount')
- this.props.clickCloseDetails(this.props.nodeId);
- window.addEventListener('message', function(event) {
- // 处理接收到的消息
- const data = event.data
- console.log('globalTimesChange------data.data=====', data.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
- },()=>{
- _this.getMethodByshape(_this)
- });
- }
- }, false);
- window.addEventListener('storage', function(event) {
- if ( event.key == 'topoGlobalTimes') {
- // 这里处理父项目 localStorage 值变化的情况
- const data = JSON.parse(event.newValue)
- console.log('JSON.parse(------', data)
- const queryParams = _this.state.queryParams
- queryParams.start_time = data.startTime
- queryParams.end_time = data.endTime
- _this.setState({
- queryParams: queryParams
- },()=>{
- setTimeout(()=>{
- _this.getMethodByshape(_this)
- },0)
- })
- }
- });
- }
- // setQueryParams(){
- // var strr = parent.location.href; //上线做为iframe嵌套时使用
- // let param = this.parseQueryString(strr); //全链路需要的参数多,因此解析成对象形式
- // const queryParams = this.state.queryParams;
- // const newAppAlias = param.app_alias
- // queryParams.app_alias = newAppAlias
- // this.setState({
- // queryParams: queryParams
- // },()=>{
- // this.getMethodByshape(this)
- // });
- // }
- getMethodByshape(_this){
- if (_this.props.shape == 'cylinder'){
- _this.getTableData(); //table
- setTimeout(()=>{
- _this.getBarData(); // 柱形图
- }, 0)
- }
- if (_this.props.shape == 'dottedcylinder'){
- _this.getDottBasicsData() // dottedcylinder 基础信息
- }
- if (_this.props.shape == 'circle'){
- _this.getNodeBasic();
- setTimeout(()=>{
- _this.getNodeAnalyst();//获取散点图
- _this.getNodeLiveness(); // 折线图
- },0)
- _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;
- }
- // ui test
- componentWillMount(){
- window.addEventListener('beforeunload',this.handleBeforeUnload)
- }
- componentWillUnmount() {
- console.log(2222222222222,'componentWillUnmount')
- window.removeEventListener('beforeunload', this.handleBeforeUnload);
- clearTimeout(this.timeoutId);
- resetDocumentTitle();
- }
- renderTools() {
- const showSwitchTopology = this.props.nodeId !== this.props.selectedNodeId;
- const topologyTitle = `View ${this.props.label} in ${this.props.topologyId}`;
- return (
- <div className="node-details-tools-wrapper">
- <div className="node-details-tools">
- {showSwitchTopology
- && (
- <i
- title={topologyTitle}
- className="fa fa-long-arrow-alt-left"
- onClick={this.handleShowTopologyForNode}>
- <span>
- Show in
- {/* <span>{this.props.topologyId.replace(/-/g, ' ')}</span> */}
- </span>
- </i>
- )
- }
- <i
- title="Close details"
- className="fa fa-times close-details"
- onClick={this.handleClickClose}
- />
- </div>
- </div>
- );
- }
- 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 (
- <div className="node-details">
- {tools}
- <div className="node-details-header" style={styles.header}>
- <div className="node-details-header-wrapper">
- <h2 className="node-details-header-label truncate">
- {label}
- </h2>
- <div className="node-details-relatives truncate">
- Loading...
- </div>
- </div>
- </div>
- <div className="node-details-content" style="padding:0 12px">
- <div className="node-details-content-loading">
- <span className={spinnerClassName} />
- </div>
- </div>
- </div>
- );
- }
- renderNotAvailable() {
- const tools = this.renderTools();
- return (
- <div className="node-details">
- {tools}
- <div className="node-details-header node-details-header-notavailable">
- <div className="node-details-header-wrapper">
- <h2 className="node-details-header-label">
- {this.props.label}
- </h2>
- <div className="node-details-relatives truncate">
- n/a
- </div>
- </div>
- </div>
- <div className="node-details-content">
- <p className="node-details-content-info">
- <strong>{this.props.label}</strong>
- {' '}
- not found!
- </p>
- </div>
- <Overlay faded={this.props.transitioning} />
- </div>
- );
- }
- 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 (
- <div className="tour-step-anchor node-details">
- {tools}
- <div className="node-details-header" style={styles.header}>
- <div className="node-details-header-wrapper">
- <h2 className="node-details-header-label truncate" title={details.label}>
- <MatchedText text={details.label} match={nodeMatches.get('label')} />
- </h2>
- <div className="node-details-header-relatives">
- {details.parents && (
- <NodeDetailsRelatives
- matches={nodeMatches.get('parents')}
- relatives={details.parents} />
- )}
- </div>
- </div>
- </div>
- {showControls
- && (
- <div className="tour-step-anchor node-details-controls-wrapper" style={styles.controls}>
- <NodeDetailsControls
- nodeId={this.props.nodeId}
- controls={details.controls}
- pending={pending}
- error={error} />
- </div>
- )
- }
- <div className="node-details-content">
- {details.metrics
- && (
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">Status</div>
- <NodeDetailsHealth
- metrics={details.metrics}
- topologyId={topologyId}
- />
- </div>
- )
- }
- {details.metadata
- && (
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">Info</div>
- <NodeDetailsInfo rows={details.metadata} matches={nodeMatches.get('metadata')} />
- </div>
- )
- }
- {details.connections && details.connections.filter(cs => cs.connections.length > 0)
- .map(connections => (
- <div className="node-details-content-section" key={connections.id}>
- <NodeDetailsTable
- {...connections}
- nodes={connections.connections}
- nodeIdKey="nodeId"
- />
- </div>
- ))}
- {details.children && details.children.map(children => (
- <div className="node-details-content-section" key={children.topologyId}>
- <NodeDetailsTable {...children} />
- </div>
- ))}
- {details.tables && details.tables.length > 0 && details.tables.map((table) => {
- if (table.rows.length > 0) {
- return (
- <div className="node-details-content-section" key={table.id}>
- <div className="node-details-content-section-header">
- {table.label && table.label.length > 0 && table.label}
- {table.truncationCount > 0
- && (
- <span
- className="node-details-content-section-header-warning">
- <Warning text={getTruncationText(table.truncationCount)} />
- </span>
- )
- }
- </div>
- {this.renderTable(table)}
- </div>
- );
- }
- return null;
- })}
- {this.props.renderNodeDetailsExtras({ details, topologyId })}
- </div>
- <Overlay faded={this.props.transitioning} />
- </div>
- );
- }
- 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: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) => <a target='_blank' href={`${this.state.traceUrl}/#/latency/index?traceId=${text}&app_alias=${this.state.queryParams.app_alias}&span_id=${record.span_id}&datetime=${Date.parse(record.datetime)/1000}`}>{text}</a>
- },
- {
- 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) => <span>{(text && Number(text.toFixed(2))) || 0 }</span>
- },
- {
- 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) => (
- <span>{record.service_name_cn? record.service_name_cn: record.service_name}</span>
- )
- },
- {
- title: '执行语句',
- dataIndex: 'query',
- key: 'query',
- width:'40%',
- ellipsis:true,
- align:'center',
- render: (text, record) => (
- <textarea value={record.query} disabled rows="2" />
- )
- },
- {
- title: '慢查询次数',
- dataIndex: 'slow_num',
- key: 'slow_num',
- ellipsis:true,
- align:'center'
- },
- {
- title: '错误数量',
- dataIndex: 'error_num',
- key: 'error_num',
- ellipsis:true,
- align:'center'
- }
- ]
- const cloudColums = [
- {
- title: '应用名称',
- dataIndex: 'app_name',
- align:'center',
- width: 200,
- key: 'app_name'
- },
- {
- title: '请求总数',
- width: 100,
- dataIndex: 'request_total',
- align:'center',
- key: 'request_total',
- },
- {
- title: '错误数',
- dataIndex: 'error_num',
- align:'center',
- width: 130,
- key: 'error_num',
- },
- {
- title: '平均延迟',
- dataIndex: 'duration_average',
- align:'center',
- key: 'duration_average',
- width: 130,
- render: (text, record) => (
- <span>{(record.duration_average && Number(record.duration_average).toFixed(2)) || 0}</span>
- )
- },
- {
- title: '中位延迟',
- dataIndex: 'duration_median',
- align:'center',
- width: 140,
- key: 'duration_median',
- render: (text, record) => (
- <span>{(record.duration_median && Number(record.duration_median).toFixed(2)) || 0 }</span>
- )
- }
- ];
- const cloudColums2 = [
- {
- title: '应用名称',
- align:'center',
- dataIndex: 'name',
- width: 210,
- key: 'name'
- },
- {
- title: '请求总数',
- align:'center',
- width: 100,
- dataIndex: 'request_total',
- key: 'request_total',
- },
- {
- title: '错误数',
- align:'center',
- width: 140,
- dataIndex: 'error_num',
- key: 'error_num',
- },
- {
- title: '平均延迟',
- dataIndex: 'duration_average',
- align:'center',
- width: 130,
- key: 'duration_average',
- render: (text, record) => (
- <span>{(record.duration_average && Number(record.duration_average).toFixed(2)) || 0}</span>
- )
- },
- {
- title: '中位延迟',
- dataIndex: 'duration_median',
- align:'center',
- width: 140,
- key: 'duration_median',
- render: (text, record) => (
- <span>{(record.duration_median && Number(record.duration_median).toFixed(2)) || 0 }</span>
- )
- }
- ];
- const expandedRowRender = (record) => {
- const columns = [
- {
- title: '服务名',
- dataIndex: 'service_name_cn',
- align:'center',
- width: 180,
- key: 'service_name_cn',
- },
- {
- title: '请求总数',
- dataIndex: 'request_total',
- align:'center',
- width: 114,
- key: 'request_total',
- },
- {
- title: '错误数',
- dataIndex: 'error_num',
- align:'center',
- width: 120,
- key: 'error_num',
- },
- {
- title: '平均延迟',
- dataIndex: 'duration_average',
- key: 'duration_average',
- align:'center',
- width: 130,
- render: (text, record) => (
- <span>{(record.duration_average && Number(record.duration_average).toFixed(2)) ||0 }</span>
- )
- },
- {
- title: '中位延迟',
- dataIndex: 'duration_median',
- key: 'duration_median',
- align:'center',
- width: 130,
- render: (text, record) => (
- <span>{(record.duration_median && Number(record.duration_median).toFixed(2)) || 0 }</span>
- )
- }
- ];
- return <Table columns={columns} rowKey={'service_name'} dataSource={record.service_list} pagination={false} size='small' />;
- };
- return (
- <Drawer placement="right"
- onClose={this.handleClickClose} visible={true}
- destroyOnClose={true}
- width="65%">
- <div className="tour-step-anchor node-details">
- {tools}
- <div className="node-details-header" style={styles.header}>
- <div className="node-details-header-wrapper">
- <h2 className="node-details-header-label truncate">
- {label}
- </h2>
- <div className="node-details-header-relatives">
- {this.state.nodeData.subtitle}
- </div>
- </div>
- </div>
- {/* {showControls
- && (
- <div className="tour-step-anchor node-details-controls-wrapper" style={styles.controls}>
- <NodeDetailsControls
- nodeId={this.props.nodeId}
- controls={details.controls}
- pending={pending}
- error={error} />
- </div>
- )
- } */}
- {
- this.props.shape == 'cylinder'&&
- <div className="node-details-content" >
- <div style={{marginTop:'16px'}}>
- <div className="node-details-content-section-header" style={{marginBottom:0}}>执行次数</div>
- <div id="chartContent" style={{width: '100%', height: '300px', borderRadius: '12px'}}></div>
- <div style={{paddingBottom:'20px'}}>
- <Table dataSource={this.state.tableData} columns={colums2} rowKey={(record, index) => `${record.service_name}${index}`} pagination={this.state.pagination2} onChange={this.handleTableChange2} size='small' >
- </Table>
- </div>
- </div>
- </div>
- }
- { this.props.shape == 'circle'&&
- (<div className="node-details-content">
- <div>
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">基本信息</div>
- <div className='node-details-info'>
- <div style={{textAlign:'right'}}>
- <Button size='small'><a target='_blank' style={{fontSize:'12px'}} href={`${this.state.traceUrl}/#/service/serviceDetail/index?app_alias=${this.state.queryParams.app_alias}&service_name=${this.props.id}&isShowBackBtn=false`}>服务详情</a></Button>
- </div>
- </div>
- </div>
- {/* https://zhongdian.feishu.cn/docx/HkXSdrGa2ou84zxPvvycGX5Fn3b 中让去掉的 */}
- {/* <div className="node-details-content-section">
- <div className="node-details-content-section-header">状态</div>
- <div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50' style={{width:"50%"}}>可用性</div>
- <div className='node-details-info-field-value truncate w50' style={{width:"50%"}}>
- {this.state.nodeData.apdex?Math.floor(this.state.nodeData.apdex*100):0}
- </div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50' style={{width:"50%"}}>成功率</div>
- <div className='node-details-info-field-value truncate w50' style={{width:"50%"}}>{this.state.nodeData.arc__success?Number(this.state.nodeData.arc__success*100).toFixed(2):0}%</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50' style={{width:"50%"}}>失败率</div>
- <div className='node-details-info-field-value truncate w50' style={{width:"50%"}}>{this.state.nodeData.arc__faild?Number(this.state.nodeData.arc__faild*100).toFixed(2):0}%</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50' style={{width:"50%"}}>接收数量</div>
- <div className='node-details-info-field-value truncate w50' style={{width:"50%"}}>{this.state.nodeData.receive?this.state.nodeData.receive:0}</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50' style={{width:"50%"}}>发送数量</div>
- <div className='node-details-info-field-value truncate w50' style={{width:"50%"}}>{this.state.nodeData.send?this.state.nodeData.send:0}</div>
- </div>
- </div>
- </div> */}
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">调用次数</div>
- <div className='node-details-info'>
- {
- <div>
- <div id='box' className="echartsbox"></div>
- </div>
- }
- </div>
- </div>
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">延迟比例</div>
- <div className='node-details-info' style={{marginTop: "-15px",position:'relative'}}>
- {
- <div>
- <div id='main' className="echartsbox" style={{height:'240px'}}></div>
- </div>
- }
- <div className='LatencySelect'>
- <Radio.Group onChange={this.onChange} value={this.state.queryParams.percentile} size="small">
- <Radio value={0.5}>50分位</Radio>
- {/* <Radio value={0.95}>p.95</Radio> */}
- <Radio value={0.99}>99分位</Radio>
- </Radio.Group>
- </div>
- </div>
- </div>
- <div className='node-details-content-section'>
- <div className="node-details-content-section-header">链路列表</div>
- <div className='node-serch'>
- <Checkbox onChange={this.onChangeError}>仅异常</Checkbox>
- <Checkbox onChange={this.onChangeSql}>仅SQL</Checkbox>
- </div>
- <Table dataSource={this.state.traceData} columns={columns} rowKey={(record, index) => `${record.span_id}${index}`} pagination={this.state.pagination} onChange={this.handleTableChange} size='small'>
- {/* <span slot='trace_id' slot-scope='text,record'>
- <template>
- <div>
- <a target='_blank' href={`${this.state.traceUrl}/#/latency/index?traceId=${record.trace_id}&app_alias=${this.state.queryParams.app_alias}&span_id=${record.span_id}`}>{record.trace_id}</a>
- </div>
- </template>
- </span> */}
- </Table>
- </div>
- </div>
- </div>)
- }
- {
- this.props.shape == 'dottedcylinder' && (
- <div className='ant-descriptions-header'>
- <Descriptions title="" >
- {/* <Descriptions.Item label="系统名称">{this.state.messaging_stats.name}</Descriptions.Item> */}
- <Descriptions.Item label="生产消息数量">{this.state.messaging_stats.produce_num || 0}</Descriptions.Item>
- <Descriptions.Item label="消费消息数量">{this.state.messaging_stats.consume_num || 0}</Descriptions.Item>
- <Descriptions.Item label="生产消息错误率">{this.state.messaging_stats.produce_error_rate?Number(this.state.messaging_stats.produce_error_rate*100).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="消费消息错误率">{this.state.messaging_stats.consume_error_rate?Number(this.state.messaging_stats.consume_error_rate*100).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="生产消息平均耗时">{this.state.messaging_stats.produce_duration_average?Number(this.state.messaging_stats.produce_duration_average).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="消费消息耗时">{this.state.messaging_stats.consume_duration_average?Number(this.state.messaging_stats.consume_duration_average).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="平均消息大小">{this.state.messaging_stats.message_size_average?Number(this.state.messaging_stats.message_size_average).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="主题数量">{this.state.messaging_stats.topic_num || 0}</Descriptions.Item>
- </Descriptions>
- <div className="bisic-title">主题统计信息</div>
- <div>
- {this.state.messaging_stats && this.state.messaging_stats.topic_stats && this.state.messaging_stats.topic_stats.length > 0 && this.state.messaging_stats.topic_stats.map((item, index)=>{
- return <Descriptions key={index+item.name} >
- <Descriptions.Item label="主题名称" >{item.name || '--'}</Descriptions.Item>
- <Descriptions.Item label="生产消息数量">{item.produce_num || 0}</Descriptions.Item>
- <Descriptions.Item label="消费消息数量">{item.consume_num || 0}</Descriptions.Item>
- <Descriptions.Item label="生产消息错误率">{item.produce_error_rate ? Number(item.produce_error_rate*100).toFixed(2)+'%' :0}</Descriptions.Item>
- <Descriptions.Item label="消费消息错误率">{item.consume_error_rate?Number(item.consume_error_rate*100).toFixed(2)+ '%' :0}</Descriptions.Item>
- <Descriptions.Item label="生产消息平均耗时">{item.produce_duration_average?Number(item.produce_duration_average).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="消费消息耗时">{item.consume_duration_average?Number(item.consume_duration_average).toFixed(2):0}</Descriptions.Item>
- <Descriptions.Item label="平均消息大小">{item.message_size_average?Number(item.message_size_average).toFixed(2):0}</Descriptions.Item>
- </Descriptions>
- })}
- </div>
- </div>
- )
- }
- {
- this.props.shape == 'cloud' && (
- <div className="node-details-content" >
- <div style={{marginTop:'30px'}}>
- <div style={{width:'100%'}}>
- <h4>已知应用</h4>
- <Table dataSource={this.state.cloudTable}
- columns={cloudColums}
- rowKey={'app_alias'}
- expandedRowRender={(record) => expandedRowRender(record)}
- size='small' bordered pagination={false}>
- </Table>
- </div>
- <div style={{marginTop:'40px'}}>
- <h4>未知应用</h4>
- <div style={{paddingLeft: '80px'}}>
- <Table dataSource={this.state.cloudTable2}
- columns={cloudColums2}
- rowKey={`name`} size='small' bordered pagination={false}>
- </Table>
- </div>
- </div>
- </div>
- </div>)
- }
- </div>
- </Drawer>
- );
- }
- //获取基础信息
- getNodeBasic(){
- axios({
- url: `${this.state.baseUrl}/api/v1/apps_score/${this.state.queryParams.app_alias}/svr`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- source_service:this.props.id,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const newObj= ((res ||{}).data || {}).data || {}
- this.setState({
- nodeData:{...newObj}
- },()=>{
- if(JSON.stringify(this.state.nodeData)!="{}"){
- this.state.nodeData.apdex>=0.94?this.setState({bgColor:setNodeColor('G')})
- :(this.state.nodeData.apdex>=0.85&&this.state.nodeData.apdex<0.94)?this.setState({bgColor:setNodeColor('B')})
- :(this.state.nodeData.apdex>=0.7&&this.state.nodeData.apdex<0.85)?this.setState({bgColor:setNodeColor('DI')})
- :(this.state.nodeData.apdex>=0.5&&this.state.nodeData.apdex<0.7)?this.setState({bgColor:setNodeColor('Y')})
- :this.setState({bgColor:setNodeColor('R')})
- }else{
- this.setState({bgColor:setNodeColor('R')})
- }
- })
- }
- });
- }
- //获取散点图--延迟比例
- getNodeAnalyst(){
- let chart = echarts.getInstanceByDom(document.getElementById("main"));
- if (chart == null) {
- chart = echarts.init(document.getElementById("main"));
- }else {
- chart.dispose();
- chart = echarts.init(document.getElementById("main"));
- }
- // 显示loading动画
- chart.showLoading(
- {
- text: ''
- }
- );
- axios({
- url: `${this.state.baseUrl}/api/v1/app/analyst/${this.state.queryParams.app_alias}/svr`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- source_service:this.props.id,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- percentile:this.state.queryParams.percentile
- }
- }).then(res => {
- chart.hideLoading();
- if(res && res.data.code == 200){
- const obj = ((res || {}).data ||{}).data || {}
- this.setState({
- AnalystData:{...obj}
- },()=>{
- if(JSON.stringify(this.state.AnalystData)!="{}"){
- this.initChart(this.state.AnalystData, chart)
- }
- })
- }
- });
- }
- // 散点图渲染
- initChart(tmpData, chart) {
- let option = {}
- if (tmpData?.success || tmpData?.failed){
- let successData = tmpData.success && tmpData.success.map(item => new Date(item[0]).toLocaleString()) || []
- let failedData = tmpData.failed && tmpData.failed.map(item => new Date(item[0]).toLocaleString()) || []
- option = {
- title: {
- text: '',
- subtext: '',
- textStyle:{
- fontSize:14
- },
- },
- grid: {
- top:'8%',
- left: '3%',
- right: '7%',
- bottom: '14%',
- containLabel: true
- },
- tooltip: {
- showDelay: 0,
- formatter: function (params) {
- let newParams = moment(params.data[0]).format('YYYY-MM-DD HH:mm:ss');
- let time = newParams+"<br/>"+ '延迟:' + params.data[1]+"ms"
- return time;
- }
- },
- toolbox: {
- show:true,
- showTitle: true,
- feature: {
- rect: {
- show: true,
- title: 'Trace选择'
- },
- brush: {
- type: ["rect"], // 开启矩形选择
- show: true,//是否显示 这里我们直接true
- iconStyle: {
- opacity: 0,//通过opacity设置为0隐藏图标
- },
- }
- },
- left:"40%", //组件离容器左侧的距离,'left', 'center', 'right','20%'
- top:"-3%", //组件离容器上侧的距离,'top', 'middle', 'bottom','20%'
- right:"auto", //组件离容器右侧的距离,'20%'
- bottom:"auto",
- },
- brush: {
- toolbox: ['rect'],
- brushLink: 'all', // 设置brush时同时选中x轴和y轴的数据
- throttleType:'debounce',
- throttleDelay:600
- },
- legend: {
- data: ['成功', '失败'],
- left: 'center',
- bottom: 0,
- itemGap: 100,
- textStyle: {//文字颜色
- fontSize: 12,
- padding:[0,3],//文字与图形之间的左右间距
- rich:{
- labelName:{
- fontSize:14,
- color:'#333',
- fontWeight:500
- }
- }
- },
- formatter: function (params) {
- // 获取legend显示内容
- let data = tmpData;
- let sl,fl;
- if(data.success!=null){
- sl = tmpData.success.length;
- }else{
- sl = 0
- }
- if( data.failed!=null){
- fl = tmpData.failed.length;
- }else{
- fl = 0
- }
- var target;
- if(params == '成功'){
- target = sl;
- }else if(params == '失败'){
- target = fl;
- }
- return target != undefined?params +' '+`{labelName|${target}}`:params
- },
- },
- xAxis: [
- {
- type: 'time',
- data: [
- ...successData,
- ...failedData
- ],
- gridIndex:0,
- axisLabel: {
- show:true,
- rotate: 45, // 旋转标签,适用于标签较长的情况
- interval: 'auto',
- margin: 10, // 增加刻度标签间隔
- textStyle: {
- fontSize: 10,
- textAlign:'center'
- },
- formatter: function(params) {
- let newParams = moment(params).format('HH:mm:ss');
- let time = newParams
- return time;
- }
- },
- splitLine: {
- show: true
- },
- }
- ],
- yAxis: [
- {
- type: 'value',
- // scale: true,
- gridIndex:0,
- boundaryGap: [0, '30%'],
- axisLabel: {
- formatter: '{value}'
- },
- axisLine:{
- show:true
- },
- axisTick:{
- show:true
- },
- splitLine: {
- show: true
- },
- data:[0,2500,5000,7500,10000],
- }
- ],
- series: [
- {
- name: '成功',
- type: 'scatter',
- emphasis: {
- focus: 'series'
- },
- //设置散点图样式
- itemStyle:{
- color:'#13ce66'
- },
- symbolSize:10,//设置散点的大小
- data:tmpData.success,
- markArea: {
- silent: true,
- itemStyle: {
- color: 'transparent',
- borderWidth: 0,
- borderType: 'dashed'
- },
- },
- },
- {
- name: '失败',
- type: 'scatter',
- emphasis: {
- focus: 'series'
- },
- itemStyle:{
- color:'#ff4949'
- },
- // prettier-ignore
- data:tmpData.failed,
- // data:[],
- markArea: {
- silent: true,
- itemStyle: {
- color: 'transparent',
- borderWidth: 0,
- borderType: 'dashed'
- },
- },
- }
- ]
- }
- } else {
- option = {
- title: {
- text: '暂无数据',
- x: 'center',
- y: 'center',
- textStyle: {
- color: '#999',
- fontSize: 14
- }
- }
- }
- }
- chart.setOption(option,true)
- // 默认开启框选
- chart.dispatchAction({
- type: 'takeGlobalCursor',
- key: 'brush',
- brushOption: {
- brushType: 'rect' // 指定选框类型
- }
- })
- chart.off("brushSelected");
- //框选选择数据
- chart.on('brushSelected', (params) => {
- var brushComponent = params.batch[0];
- let successIndexList=[];
- let failIndexList =[];
- let successList=[];
- let failList=[];
- if(brushComponent.selected.length>1){
- successIndexList = brushComponent.selected[0].dataIndex
- failIndexList = brushComponent.selected[1].dataIndex
- }else{
- if(brushComponent.selected[0].seriesName !=undefined){
- if(brushComponent.selected[0].seriesName =="失败"){
- failIndexList = brushComponent.selected[0].dataIndex
- }else{
- successIndexList = brushComponent.selected[0].dataIndex
- }
- }
- }
- if(successIndexList.length>0){
- for(let i = 0;i<tmpData.success.length;i++){
- for(let j=0;j<successIndexList.length;j++){
- if(successIndexList[j] == i){
- successList.push(tmpData.success[i])
- }
- }
- }
- }
- if(failIndexList.length>0){
- for(let k=0;k<tmpData.failed.length;k++){
- for(let l=0;l<failIndexList.length;l++){
- if(failIndexList[l] == k){
- failList.push(tmpData.failed[k])
- }
- }
- }
- }
- let arr =successList.concat(failList);
- let dataRange={};
- if(arr.length>0){
- let timeArr =[];
- let valueArr=[];
- for(let m=0;m<arr.length;m++){
- timeArr.push(Math.round(Date.parse(arr[m][0])/1000));
- valueArr.push(arr[m][1]);
- }
- let minTime = Math.min(...timeArr);
- let maxTime = Math.max(...timeArr);
- let minValue = Math.min(...valueArr);
- let maxValue = Math.max(...valueArr)
- if(minTime == maxTime){
- minTime = minTime-1;
- maxTime = maxTime+1;
- }
- if(minValue == maxValue){
- minValue = minValue-1;
- maxValue = maxValue+1;
- }
- //看是否有成功节点
- if(successIndexList.length>0){
- dataRange = {
- start_time:minTime,
- end_time:maxTime,
- min_duration:minValue,
- max_duration:maxValue,
- failed:false,
- app_alias:this.state.queryParams.app_alias,
- service_name:this.props.id,
- }
- }else{
- dataRange = {
- start_time:minTime,
- end_time:maxTime,
- min_duration:minValue,
- max_duration:maxValue,
- failed:true,
- app_alias:this.state.queryParams.app_alias,
- service_name:this.props.id,
- }
- }
- let timeAndDuration = JSON.stringify(dataRange);
- // let href = this.$router.resolve({
- // path:'/latency/index',
- // query:{
- // data:timeAndDuration
- // }
- // })
- // window.open(window.location.origin+"/"+href.href,"_blank")
- let href = `${this.state.traceUrl}/#/latency/index?start_time=${dataRange.start_time}&end_time=${dataRange.end_time}&min_duration=${dataRange.min_duration}&max_duration=${dataRange.max_duration}&failed=${dataRange.failed}&app_alias=${this.state.queryParams.app_alias}&service_name=${this.props.id}`
- window.open(href,"_blank")
- this.timeoutId = setTimeout(()=>{
- chart.dispatchAction({
- type: 'brush',//选择action行为
- areas:[]//areas表示选框的集合,此时为空即可。
- });
- },500)
- }
- });
- window.addEventListener("resize",function (){
- chart.resize();
- });
- }
- //获取折线图
- getNodeLiveness(){
- let liveChart = echarts.getInstanceByDom(document.getElementById("box"));
- if (liveChart == null) {
- liveChart = echarts.init(document.getElementById("box"));
- }else {
- liveChart.dispose();
- liveChart = echarts.init(document.getElementById("box"));
- }
- liveChart.showLoading(
- {
- text: ''
- }
- );
- axios({
- url: `${this.state.baseUrl}/api/v1/service/liveness`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- service_name:this.props.id,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- }
- }).then(res => {
- liveChart.hideLoading();
- if(res && res.data.code == 200){
- const list = ((res || {}).data || {}).data || []
- this.setState({
- livenessData:[...list]
- },()=>{
- this.initLiveness(this.state.livenessData, liveChart);
- })
- }
- });
- }
- //渲染折线图
- initLiveness(data, liveChart){
- let option = {}
- if (data.length > 0 ){
- const xAxisData = []
- const lineArr1 = []
- const lineArr2 = []
- data.forEach((item)=>{
- if (item){
- xAxisData.push(item[0])
- lineArr1.push(item[1])
- const num = item[2] && item[2].toFixed(2)
- lineArr2.push(num)
- }
- })
- option = {
- grid: {
- top:'15%',
- left: '3%',
- right: '7%',
- bottom: '14%',
- containLabel: true
- },
- tooltip: {
- trigger: 'axis',
- showDelay: 0,
- formatter: function (params) {
- if (params && params.length === 2) {
- let newParams = moment(params[0].name).format('YYYY-MM-DD HH:mm:ss');
- let time = newParams+"<br/>"+ params[0].seriesName +':'+ params[0].value + '<br/>' + params[1].seriesName +':'+ params[1].value
- return time;
- }
- return ''
- }
- },
- xAxis: {
- data: xAxisData,
- type: 'category',
- boundaryGap: false,
- axisLabel: {
- show:true,
- rotate: 45, // 旋转标签,适用于标签较长的情况
- interval: 10,
- margin: 10, // 增加刻度标签间隔
- textStyle: {
- fontSize: 10,
- textAlign:'center'
- },
- formatter: function(params) {
- let newParams = moment(params).format('HH:mm:ss');
- let time = newParams
- return time;
- }
- },
- splitLine: {
- show: true
- },
- },
- yAxis: [
- {
- boundaryGap: [0, '20%'],
- type: 'value',
- show:true,
- name: '调用次数',
- position: 'left',
- alignTicks: true,
- axisLine: {
- show: true
- },
- axisLabel: {
- formatter: '{value}'
- }
- },
- {
- boundaryGap: [0, '20%'],
- type: 'value',
- show:true,
- offset: 0, // 防止与第一个Y轴重叠
- // splitNumber: 5,
- nameGap: 20, // 设置 Y 轴名称和轴线之间的间距
- name: '中位延迟',
- position: 'right',
- alignTicks: true,
- axisLine: {
- show: true
- },
- axisLabel: {
- formatter: '{value} ms'
- }
- },
- ],
- legend: {
- data: ['调用次数', '中位延迟'],
- bottom: 0,
- itemGap: 100,
- },
- series: [
- {
- name: '调用次数',
- type: 'line',
- smooth: true,
- yAxisIndex: 0, // 使用第一条 Y 轴
- data: lineArr1
- },
- {
- name: '中位延迟',
- type: 'line',
- smooth: true,
- yAxisIndex: 1, // 使用第二条 Y 轴
- data: lineArr2
- }
- ]
- };
- } else {
- option = {
- title: {
- text: '暂无数据',
- x: 'center',
- y: 'center',
- textStyle: {
- color: '#999',
- fontSize: 14
- }
- }
- }
- }
- liveChart.setOption(option,true)
- }
- //获取异常trace列表 /api/v1/service/spans
- getServiceSpans(){
- this.setState({ loading: true });
- this.setState({
- traceData:[],
- pagination:{total:0}
- },()=>{
- })
- axios({
- url: `${this.state.baseUrl}/api/v1/service/spans`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- service_name:this.props.id,
- only_exception:this.state.traceQuery.only_exception, // 仅显示异常trace相关
- only_database:this.state.traceQuery.only_database,
- pageIndex:this.state.pagination.pageIndex,
- pageSize:this.state.pagination.pageSize,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- app_alias:this.state.queryParams.app_alias,
- sort_field:'Timestamp',
- sort_type: this.state.queryParams.sort_type
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const list = (((res || {}).data || {}).data || {}).list || []
- const total = Number((((res || {}).data || {}).data || {}).count || 0)
- this.setState({
- traceData:[...list],
- pagination:{...this.state.pagination,total:total}
- },()=>{
- })
- }
- });
- }
- //获取table 数据
- getTableData(){
- this.setState({ loading: true });
- this.setState({
- tableData:[],
- pagination2:{total:0}
- },()=>{
- })
- axios({
- url: `${this.state.coreBaseUrl}/v1/system-component/reqlist`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- page_num:this.state.pagination2.page_num,
- page_size:this.state.pagination2.page_size,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- app_alias:this.state.queryParams.app_alias,
- component: this.props.id//
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const list = (((res || {}).data || {}).data || {}).list || []
- const total = Number((((res || {}).data || {}).data || {}).total || 0)
- const page_num = (((res || {}).data || {}).data || {}).page_num || 1
- const page_size = (((res || {}).data || {}).data || {}).page_size || 10
- this.setState({
- tableData:[...list],
- pagination2:{page_num:page_num,page_size:page_size,total:total}
- },()=>{
- })
- }
- });
- }
- getBarData(){// 获取柱状图数据
- let liveChart = echarts.getInstanceByDom(document.getElementById("chartContent"));
- if (liveChart == null) {
- liveChart = echarts.init(document.getElementById("chartContent"));
- } else {
- liveChart.dispose();
- liveChart = echarts.init(document.getElementById("chartContent"));
- }
- this.setState({
- tableData:[],
- pagination2:{total:0}
- },()=>{
- })
- liveChart.showLoading(
- {
- text: ''
- }
- );
- axios({
- url: `${this.state.coreBaseUrl}/v1/system-component/stats`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- app_alias:this.state.queryParams.app_alias,
- component: this.props.id //
- }
- }).then(res => {
- liveChart.hideLoading();
- if(res && res.data.code == 200){
- const list = res?.data?.data?.database_stats?.request_bar || []
- this.setState({
- barData:list
- },()=>{
- if(this.state.barData.length>0){
- setTimeout(()=>{
- this.initLineBar(this.state.barData, liveChart);
- },0)
- }
- })
- }
- });
- }
- // 渲染调用统计 折线/柱形图
- initLineBar(data, liveChart){
- let xAxisArr = data.map(item => item.start_time) || []
- let dataArr = data.map(item => item.total) || []
- let option = {}
- if (data && data.length > 0) {
- option = {
- xAxis: {
- type: 'category',
- data: xAxisArr,
- axisLabel: {
- show:true,
- rotate: 45, // 旋转标签,适用于标签较长的情况
- interval: 'auto',
- margin: 10, // 增加刻度标签间隔
- textStyle: {
- fontSize: 10,
- textAlign:'center'
- },
- formatter: function(params) {
- let newParams = moment(params).format('HH:mm:ss');
- let time = newParams
- return time;
- }
- },
- },
- tooltip: {
- showDelay: 0,
- axisPointer: {
- show: true,
- type: 'cross',
- lineStyle: {
- type: 'dashed',
- width: 1
- }
- }
- },
- yAxis: {
- type: 'value'
- },
- series: [
- {
- data: dataArr,
- type: 'bar'
- }
- ]
- };
- } else {
- option = {
- title: {
- text: '暂无数据',
- x: 'center',
- y: 'center',
- textStyle: {
- color: '#999',
- fontSize: 14
- }
- }
- }
- }
- liveChart.setOption(option,true)
- }
- handleTableChange=(pagination,filters, sorter, extra)=>{
- const {current} = pagination
- let sort = ''
- if(sorter && sorter.order == 'ascend'){
- sort = 'ASC'
- } else if(sorter && sorter.order == 'descend'){
- sort = 'DESC'
- }
- this.setState({
- pagination: {...this.state.pagination,pageIndex:current,current:current},
- queryParams:{...this.state.queryParams,sort_type:sort}
- },()=>{
- this.getServiceSpans();
- });
- }
- handleTableChange2=(pagination,filters, sorter, extra)=>{
- const {current} = pagination
- this.setState({
- pagination2: {...this.state.pagination2,page_num:current}
- },()=>{
- this.getTableData();
- });
- }
- //仅异常
- onChangeError = e =>{
- const only_exception = e.target.checked ? 1:0;
- const pageIndex = 1
- const current = 1
- this.setState({
- traceQuery:{...this.state.traceQuery,only_exception:only_exception},
- pagination: {...this.state.pagination,pageIndex:pageIndex,current:current},
- },()=>{
- this.getServiceSpans();
- });
- }
- //仅sql
- onChangeSql = e =>{
- const only_database = e.target.checked ? 1:0;
- const pageIndex = 1
- const current = 1
- this.setState({
- traceQuery:{...this.state.traceQuery,only_database:only_database},
- pagination: {...this.state.pagination,pageIndex:pageIndex,current:current},
- },()=>{
- this.getServiceSpans(this.props.source,this.props.target);
- });
- }
- //单选按钮
- onChange = e => {
- const percentile = e.target.value
- this.setState({
- queryParams:{...this.state.queryParams,percentile:percentile},
- AnalystData:[]
- },()=>{
- this.getNodeAnalyst();
- });
- };
- renderTable(table) {
- const { nodeMatches = makeMap() } = this.props;
- if (isGenericTable(table)) {
- return (
- <NodeDetailsGenericTable
- rows={table.rows}
- columns={table.columns}
- matches={nodeMatches.get('tables')}
- />
- );
- } if (isPropertyList(table)) {
- return (
- <NodeDetailsPropertyList
- rows={table.rows}
- controls={table.controls}
- matches={nodeMatches.get('property-lists')}
- />
- );
- }
- log(`Undefined type '${table.type}' for table ${table.id}`);
- return null;
- }
- componentDidUpdate() {
- this.updateTitle();
- }
- updateTitle() {
- setDocumentTitle(this.props.details && this.props.details.label);
- }
- //dottedcylinder 类型 -获取基础信息
- getDottBasicsData(){
- this.setState({ loading: true });
- this.setState({
- messaging_stats:{
- topic_stats:[]
- }
- },()=>{
- })
- axios({
- url: `${this.state.coreBaseUrl}/v1/system-component/stats`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- app_alias:this.state.queryParams.app_alias,
- component: this.props.id//
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const messaging_stats = (((res || {}).data || {}).data || {}).messaging_stats || {}
- this.setState({
- messaging_stats:messaging_stats
- },()=>{
- })
- }
- });
- }
- // cloud 类型-获取嵌套table
- getCloudTableData(){// 获取柱状图数据
- this.setState({ loading: true });
- this.setState({
- cloudTable:[],
- cloudTable2:[],
- },()=>{
- })
- axios({
- url: `${this.state.coreBaseUrl}/v1/service/related-apps`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- start_time: this.state.queryParams.start_time, //1727366400
- end_time:this.state.queryParams.end_time, // 1727415703
- app_alias:this.state.queryParams.app_alias,
- type: this.props.id //
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const list = (((res || {}).data ||{}).data || {}).app_list || []
- const list2 = (((res ||{}).data ||{}).data ||{}).client_list || []
- this.setState({
- cloudTable:[...list],
- cloudTable2: [...list2]
- },()=>{
- })
- }
- });
- }
- }
- NodeDetails.propTypes = {
- renderNodeDetailsExtras: PropTypes.func,
- };
- NodeDetails.defaultProps = {
- renderNodeDetailsExtras: noop,
- };
- function mapStateToProps(state, ownProps) {
- const currentTopologyId = state.get('currentTopologyId');
- return {
- nodeMatches: state.getIn(['searchNodeMatches', currentTopologyId, ownProps.id]),
- nodes: state.get('nodes'),
- selectedNodeId: state.get('selectedNodeId'),
- transitioning: state.get('pausedAt') !== ownProps.timestamp,
- };
- }
- export default connect(
- mapStateToProps,
- { clickCloseDetails, clickShowTopologyForNode }
- )(NodeDetails);
|