123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997 |
- import React from 'react';
- import ReactDOM from 'react-dom';
- import { connect } from 'react-redux';
- import classNames from 'classnames';
- import { enterEdge, leaveEdge } from '../actions/app-actions';
- import { encodeIdAttribute, decodeIdAttribute } from '../utils/dom-utils';
- import {
- DETAILS_PANEL_WIDTH as WIDTH,
- DETAILS_PANEL_OFFSET as OFFSET,
- DETAILS_PANEL_MARGINS as MARGINS
- } from '../constants/styles';
- import { setNodeColor } from '../utils/color-utils';
- import '../../styles/index.less'
- import '../../styles/iconfont.css'
- // import { GlobalIcon } from '../../styles/icon.js';
- // import echarts from 'echarts'
- import * as echarts from 'echarts'
- import axios from 'axios'
- import moment from 'moment'
- import { Table,Icon,Radio,Drawer, Button,Switch,Checkbox } from "antd";
- import "antd/dist/antd.css";
- import getToken from '../utils/get-token'
- function isStorageComponent(id) {
- const storageComponents = ['<persistent_volume>', '<storage_class>', '<persistent_volume_claim>', '<volume_snapshot>', '<volume_snapshot_data>'];
- return storageComponents.includes(id);
- }
- // getAdjacencyClass takes id which contains information about edge as a topology
- // of parent and child node.
- // For example: id is of form "nodeA;<storage_class>---nodeB;<persistent_volume_claim>"
- function getAdjacencyClass(id) {
- const topologyId = id.split('---');
- const fromNode = topologyId[0].split(';');
- const toNode = topologyId[1].split(';');
- if (fromNode[1] !== undefined && toNode[1] !== undefined) {
- if (isStorageComponent(fromNode[1]) || isStorageComponent(toNode[1])) {
- return 'link-storage';
- }
- }
- return 'link-none';
- }
- class Edge extends React.Component {
- constructor(props, context) {
- super(props, context);
- this.handleMouseEnter = this.handleMouseEnter.bind(this);
- this.handleMouseLeave = this.handleMouseLeave.bind(this);
- this.handleClick = this.handleClick.bind(this)
- this.state = {
- showElem:false,
- x:0,
- y:'30%',
- lineTip:'',
- visible: false, //控制弹窗显示隐藏
- AnalystData:{}, //延迟分位图数据存储
- queryParams:{
- start_time:Math.round((new Date().getTime())/1000 - (5*60)),
- end_time:Math.round(new Date().getTime()/1000),
- app_alias:'UNSET',
- service_name:'frontend',
- percentile:0.95
- },
- traceData:[],
- // traceUrl:'http://observe-front.cestong.com.cn', //本地调试使用
- // baseUrl:'http://observe-server.cestong.com.cn', //本地调试使用
- baseUrl:'/re', //上线时打开
- traceUrl:'', //上线时打开
- scoreObj:[],
- bgColor:setNodeColor('R'),
- pagination: {
- pageIndex:1,
- pageSize:10,
- total:0,
- current:1,
- },
- traceQuery:{
- only_exception:0,
- only_database:0,
- },
- loading: false,
- value:0.95,
- total:0,
- getToken: ''
- }
- }
- render() {
- let transform;
- const panelHeight = window.innerHeight - MARGINS.bottom - MARGINS.top;
- const {
- id, path, highlighted, focused, thickness, source, target
- } = this.props;
- const shouldRenderMarker = (focused || highlighted) && (source !== target);
- const className = classNames('edge', { highlighted });
- const spinnerClassName = classNames('fa fa-circle-notch', { 'fa-spin': this.props.mounted });
- const wrapStyle = {
- left: this.state.showElem ? MARGINS.right : null,
- width: this.state.showElem ? null : WIDTH,
- zIndex: 9999,
- }
- // const bgColor = setNodeColor('B')
- const styles = {
- header: {
- backgroundColor: this.state.bgColor
- },
- headerColor:{
- color:this.state.bgColor
- }
- }
- let labelsContainer = {
- // transform: 'scale(2)',
- pointerEvents: 'none',
- position:'absolute',
- wordWrap: 'break-word', /* 当单词过长时进行断开 */
- overflowWrap: 'break-word', /* 支持更多语言的断开 */
- borderRadius: '8px',
- }
- let TipboxStyle={
- borderRadius: '8px',
- padding: '10px',
- zIndex: 9999,
- background:'#fff',
- width:'100%',
- border:'1px solid #f1f1f1',
- // color:'#fff',
- // boxShadow:'0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05)',
- boxShadow: '0px 0px 22px 2px rgba(0, 0, 0, 0.1)'
- }
- let box={
- position: 'fixed',
- display: 'flex',
- right: '30px',
- top: '100px',
- bottom: '48px',
- transition: 'transform 0.33333s cubic-bezier(0, 0, 0.21, 1) 0s, margin-top 0.15s ease-in-out 0s !important',
- transform: 'translateX(0px)',
- width: '420px',
- height:'100%'
- }
- const columns = [
- {
- title: 'TraceID',
- dataIndex: 'trace_id',
- key: 'trace_id',
- width:'27%',
- ellipsis:true,
- align:'left',
- 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>
- // scopedSlots:{customRender:'trace_id'},
- // render:traceID => <a target='_blank' href={`${this.state.traceUrl}/#/latency/index?traceId=${traceID}&app_alias=${this.state.queryParams.app_alias}`}>{traceID}</a>
- // render: traceID => <a target='_blank' href={`${grafanaRoot}/explore?orgId=1&left={"datasource":"sV_Dh0LVz","queries":[{"refId":"A","datasource":{"type":"tempo","uid":"sV_Dh0LVz"},"queryType":"nativeSearch","serviceName":"${this.props.selectedNodeId}"}],"range":{"from":"now-1h","to":"now"}}`}>{traceID}</a>,
- },
- {
- title: 'Service',
- dataIndex: 'service_name',
- key: 'service_name',
- width:'20%',
- ellipsis:true,
- align:'right'
- },
- {
- title: 'Meth.',
- dataIndex: 'method',
- key: 'method',
- width:'18%',
- ellipsis:true,
- align:'right'
- },
- {
- title: 'Code',
- dataIndex: 'code',
- key: 'code',
- width:'15%',
- ellipsis:true,
- align:'right'
- },
- {
- title: 'Dur.(ms)',
- dataIndex: 'duration',
- key: 'duration',
- width:'20%',
- ellipsis:true,
- align:'right',
- render:(text) => <span>{text.toFixed(2)}</span>,
- },
- ]
- return (
- <g
- id={encodeIdAttribute(id)}
- className={className}
- onMouseEnter={this.handleMouseEnter}
- onMouseLeave={this.handleMouseLeave}
- onClick={this.handleClick}
- style={{position:'relative'}}
- >
- {/* {this.state.showElem?
- <foreignObject
- style={labelsContainer}
- y={this.state.y}
- x={(this.state.x)-10}
- width={300}
- height={100}
- >
- <div className='Tipbox' style={TipboxStyle} dangerouslySetInnerHTML={{ __html:this.state.lineTip }}>
- </div>
- </foreignObject>:null
- } */}
- <path className="shadow" d={path} style={{ strokeWidth: 10 * thickness }} />
- <path
- className={getAdjacencyClass(id)}
- d={path}
- style={{ strokeWidth: 5 }}
- />
- <path
- className="link"
- d={path}
- markerEnd={shouldRenderMarker ? 'url(#end-arrow)' : null}
- style={{ strokeWidth: thickness }}
- />
- {this.state.showElem?
- <div className='drawerBox'>
- <Drawer
- placement="right"
- onClose={this.onClose}
- visible={this.state.showElem}
- destroyOnClose={true}
- width="420px"
- >
- <div className="tour-step-anchor node-details">
- {/* {tools} */}
- <div className="node-details-header" style={styles.header}>
- <div className='node-details-header-flex'>
- <div className="node-details-header-wrapper">
- <div className='node-details-header-icon'>
- {/* <div className='fa fa-level-down'></div> */}
- <div className='roll_box'><Icon className='roll' type='swap-right'></Icon></div>
- {/* <div className='roll_box'>
- <span className='iconfont icon-chehui2'></span>
- </div> */}
- </div>
- <div style={{width:'85%'}}>
- <h2 className="node-details-header-label truncate" title='标题部分'>
- {source}
- </h2>
- <div className="node-details-header-relatives truncate ">
- </div>
- <h2 className="node-details-header-label truncate" title='标题部分'>
- {target}
- </h2>
- <div className="node-details-header-relatives truncate">
- </div>
- </div>
- </div>
- <div className='node-details-header-apdex' style={styles.headerColor}>
- Apdex:
- {
- this.state.scoreObj.length>0?
- this.state.scoreObj.map((item,i)=>{
- return <div key={i} className='node-details-header-score'>{Math.floor(item.apdex*100)}</div>
- }):<div className='node-details-header-score'>0</div>
- }
- </div>
- </div>
- </div>
- <div className="node-details-content" style={{marginTop:'123px'}}>
- {/* 状态 */}
- <div className="node-details-content-section">
- <div className="node-details-content-section-header">状态</div>
- <div className='node-details-info'>
- {
- this.state.scoreObj.length>0?
- this.state.scoreObj.map((v,i)=>{
- return (
- <div key={i} className='node-details-info-field-flex'>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Total:</div>
- <div className='node-details-info-field-value truncate w50'>
- {v.total_num?v.total_num:0}
- </div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Avg:</div>
- <div className='node-details-info-field-value truncate w50'>{v.duration_average?v.duration_average:0}</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Qps:</div>
- <div className='node-details-info-field-value truncate w50'>{v.qps?v.qps:0}r/s</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.50:</div>
- <div className='node-details-info-field-value truncate w50'>{v.duration_median?v.duration_median:0}</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>ErrRate:</div>
- <div className='node-details-info-field-value truncate w50'>{v.error_rate?v.error_rate.toFixed(2):0}%</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.90:</div>
- <div className='node-details-info-field-value truncate w50'>{v.duration_p90?v.duration_p90:0}</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>ErrNum:</div>
- <div className='node-details-info-field-value truncate w50'>{v.error_num?v.error_num:0}</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.99:</div>
- <div className='node-details-info-field-value truncate w50'>{v.duration_p99?v.duration_p99:0}</div>
- </div>
- </div>
- )
- }):(
- <div className='node-details-info-field-flex'>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Total:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Avg:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>Qps:</div>
- <div className='node-details-info-field-value truncate w50'>0r/s</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.50:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>ErrRate:</div>
- <div className='node-details-info-field-value truncate w50'>0%</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.90:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>ErrNum:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </div>
- <div className='node-details-info-field'>
- <div className='node-details-info-field-label truncate w50'>P.99:</div>
- <div className='node-details-info-field-value truncate w50'>0</div>
- </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'}}>
- {
- JSON.stringify(this.state.AnalystData)!="{}"?
- (<div>
- <div id='main' className="echartsbox" style={{height:'240px'}}></div>
- </div>)
- :(
- <div className='noData'>暂无数据</div>
- )
- }
- <div className='LatencySelect'>
- <Radio.Group onChange={this.onChange} value={this.state.queryParams.percentile} size="small">
- <Radio value={0.5}>p.50</Radio>
- <Radio value={0.95}>p.95</Radio>
- <Radio value={0.99}>p.99</Radio>
- </Radio.Group>
- </div>
- </div>
- </div>
- <div className='node-details-content-section'>
- <div className="node-details-content-section-header">异常Trace</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='span_id' 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>
- </Drawer>
- </div> :null
- }
- </g>
- );
- }
- onClose = (e) => {
- e.stopPropagation();
- e.preventDefault();
- this.setState({
- showElem: false,
- },()=>{
- // console.log(this.state.showElem,'关闭按钮的值')
- });
- }
- componentDidMount() {
- let _this = this
- //上线时打开开始
- this.setQueryParams();
- const traceURL = `http://${parent.location.hostname}`
- this.setState({
- traceUrl:traceURL
- },()=>{
- })
- //上线时打开结束
- }
- 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
- },()=>{
- });
- }
- //解析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;
- }
- // 散点图渲染
- initChart(tmpData) {
- // let chart = id+'Chart';
- var chart;
- chart = echarts.init(document.getElementById('main'))
- chart.clear();
- let option = {
- title: {
- text: '',
- subtext: '',
- textStyle:{
- fontSize:14
- },
- },
- grid: {
- top:'8%',
- left: '3%',
- right: '2%',
- bottom: '14%',
- containLabel: true
- },
- tooltip: {
- // trigger: 'axis',
- 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;
- },
- axisPointer: {
- show: true,
- type: 'cross',
- lineStyle: {
- type: 'dashed',
- width: 1
- }
- }
- },
- toolbox: {
- show:true,
- showTitle: true,
- feature: {
- rect: {
- show: true,
- title: 'Trace选择'
- },
- },
- left:"40%", //组件离容器左侧的距离,'left', 'center', 'right','20%'
- top:"-3%", //组件离容器上侧的距离,'top', 'middle', 'bottom','20%'
- right:"auto", //组件离容器右侧的距离,'20%'
- bottom:"auto",
- },
- brush: {
- toolbox: ['rect'],
- xAxisIndex: 0,
- throttleType:'debounce',
- throttleDelay:600,
- // 'brush': () => {
- // //手动触发缩放 解决数据显示不全问题
- // let echartsInstance = document.getElementById('main').getEchartsInstance()
- // //首先获取当前缩放位置
- // let {start, end} = echartsInstance.getOption().dataZoom[0]
- // echartsInstance.dispatchAction({
- // type: 'dataZoom',
- // // 可选,dataZoom 组件的 index,多个 dataZoom 组件时有用,默认为 0
- // dataZoomIndex: 0,
- // // 开始位置的百分比,0 - 100
- // start: start,
- // // 结束位置的百分比,0 - 100
- // end: end,
- // // // 开始位置的数值
- // // startValue: 0,
- // // // 结束位置的数值
- // // endValue: 100
- // })
- // }
- },
- legend: {
- data: ['Success', 'Failed'],
- 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 == 'Success'){
- target = sl;
- }else if(params == 'Failed'){
- target = fl;
- }
- return target != undefined?params +' '+`{labelName|${target}}`:params
- },
- },
- xAxis: [
- {
- // type: 'category',
- type:'time',
- // scale: true,
- gridIndex:0,
- // splitNumber: 4,
- axisLabel: {
- show:false,
- textStyle: {
- fontSize: 12,
- textAlign:'center'
- },
- formatter: function(params) {
- let newParams = moment(params).format('YYYY-MM-DD HH:mm:ss');
- let newArr = newParams.split(' ')
- let time = newArr[0] + "\n" + newArr[1]
- return time;
- }
- },
- splitLine: {
- show: true
- },
- }
- ],
- yAxis: [
- {
- type: 'value',
- // scale: true,
- gridIndex:0,
- axisLabel: {
- formatter: '{value}'
- },
- axisLine:{
- show:true
- },
- axisTick:{
- show:true
- },
- splitLine: {
- show: true
- },
- data:[0,2500,5000,7500,10000],
- }
- ],
- series: [
- {
- name: 'Success',
- type: 'scatter',
- emphasis: {
- focus: 'series'
- },
- //设置散点图样式
- itemStyle:{
- color:'#13ce66'
- },
- symbolSize:10,//设置散点的大小
- data:tmpData.success,
- markArea: {
- silent: true,
- itemStyle: {
- color: 'transparent',
- borderWidth: 0,
- borderType: 'dashed'
- },
- },
- },
- {
- name: 'Failed',
- type: 'scatter',
- emphasis: {
- focus: 'series'
- },
- itemStyle:{
- color:'#ff4949'
- },
- // prettier-ignore
- data:tmpData.failed,
- // data:[],
- markArea: {
- silent: true,
- itemStyle: {
- color: 'transparent',
- borderWidth: 0,
- borderType: 'dashed'
- },
- },
- }
- ]
- }
- chart.setOption(option,true)
- 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 =="Failed"){
- 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")
- setTimeout(()=>{
- chart.dispatchAction({
- type: 'brush',//选择action行为
- areas:[]//areas表示选框的集合,此时为空即可。
- });
- },500)
- }
- });
- window.addEventListener("resize",function (){
- chart.resize();
- });
- }
- handleMouseEnter(ev) {
- ev.stopPropagation();
- ev.preventDefault();
- this.props.enterEdge(decodeIdAttribute(ev.currentTarget.id));
- }
- handleMouseLeave(ev) {
- ev.stopPropagation();
- ev.preventDefault();
- this.props.leaveEdge(decodeIdAttribute(ev.currentTarget.id));
- }
- //点击事件
- handleClick(ev){
- if(ev.target.tagName=='path'){
- ev.stopPropagation();
- ev.preventDefault();
- // this.setQueryParams();
- this.getEdgeAppsScore(this.props.source,this.props.target)
- this.getEdgeAnalyst(this.props.source,this.props.target)
- this.getServiceSpans(this.props.source,this.props.target)
- this.setState({
- showElem:true,
- },()=>{
- })
- }
- }
- //获取边线弹窗内的信息
- getEdgeAppsScore(sourceService,targetService){
- axios({
- url: `${this.state.baseUrl}/api/v1/apps_score/${this.state.queryParams.app_alias}/edge`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- source_service:sourceService,
- target_service:targetService,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const newArr= ((res || {}).data || {}).data || []
- this.setState({
- scoreObj:[...newArr]
- },()=>{
- if(this.state.scoreObj.length>0){
- for(let i=0;i<this.state.scoreObj.length;i++){
- this.state.scoreObj[i].apdex>=0.94?this.setState({bgColor:setNodeColor('G')})
- :(this.state.scoreObj[i].apdex>=0.85&&this.state.scoreObj[i].apdex<0.94)?this.setState({bgColor:setNodeColor('B')})
- :(this.state.scoreObj[i].apdex>=0.7&&this.state.scoreObj[i].apdex<0.85)?this.setState({bgColor:setNodeColor('DI')})
- :(this.state.scoreObj[i].apdex>=0.5&&this.state.scoreObj[i].apdex<0.7)?this.setState({bgColor:setNodeColor('Y')})
- :this.setState({bgColor:setNodeColor('R')})
- }
- }else{
- this.setState({bgColor:setNodeColor('R')})
- }
- })
- }
- });
- }
- //获取边线散点图
- getEdgeAnalyst(sourceService,targetService){
- axios({
- url: `${this.state.baseUrl}/api/v1/app/analyst/${this.state.queryParams.app_alias}/edge`,
- method: "get",
- headers: { 'Authorization': getToken },
- params: {
- source_service:sourceService,
- target_service:targetService,
- start_time:this.state.queryParams.start_time,
- end_time:this.state.queryParams.end_time,
- percentile:this.state.queryParams.percentile
- }
- }).then(res => {
- 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)
- }
- })
- }
- });
- }
- //获取异常trace列表 /api/v1/service/spans
- getServiceSpans(sourceService,targetService){
- 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: {
- // source_service:sourceService,
- // target_service:targetService,
- service_name:sourceService,
- service_name:targetService,
- 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
- }
- }).then(res => {
- if(res && res.data.code == 200){
- const list = (((res || {}).data || {}).data || {}).list || []
- const total = (((res || {}).data || {}).data || {}).count
- this.setState({
- loading:false,
- traceData:[...list],
- pagination:{...this.state.pagination,total:total}
- },()=>{
- })
- }
- });
- }
- handleTableChange=(pagination,pageSize)=>{
- const {current} = pagination
- this.setState({
- pagination: {...this.state.pagination,pageIndex:current,current:current},
- },()=>{
- this.getServiceSpans(this.props.source,this.props.target);
- });
- }
- //仅异常
- 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(this.props.source,this.props.target);
- });
- }
- //仅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}
- },()=>{
- this.getEdgeAnalyst(this.props.source,this.props.target);
- });
- }
- }
- function mapStateToProps(state) {
- return {
- contrastMode: state.get('contrastMode')
- };
- }
- export default connect(
- mapStateToProps,
- { enterEdge, leaveEdge }
- )(Edge);
|