Unverified Commit e1ae623f authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #147 from Microsoft/master

merge master
parents f796c60b 63697ec5
...@@ -75,7 +75,7 @@ def _pack_parameter(parameter_id, params, customized=False, trial_job_id=None, p ...@@ -75,7 +75,7 @@ def _pack_parameter(parameter_id, params, customized=False, trial_job_id=None, p
class MultiPhaseMsgDispatcher(MsgDispatcherBase): class MultiPhaseMsgDispatcher(MsgDispatcherBase):
def __init__(self, tuner, assessor=None): def __init__(self, tuner, assessor=None):
super() super(MultiPhaseMsgDispatcher, self).__init__()
self.tuner = tuner self.tuner = tuner
self.assessor = assessor self.assessor = assessor
if assessor is None: if assessor is None:
......
...@@ -42,11 +42,10 @@ class CommandType(Enum): ...@@ -42,11 +42,10 @@ class CommandType(Enum):
NoMoreTrialJobs = b'NO' NoMoreTrialJobs = b'NO'
KillTrialJob = b'KI' KillTrialJob = b'KI'
_lock = threading.Lock()
try: try:
_in_file = open(3, 'rb') _in_file = open(3, 'rb')
_out_file = open(4, 'wb') _out_file = open(4, 'wb')
_lock = threading.Lock()
except OSError: except OSError:
_msg = 'IPC pipeline not exists, maybe you are importing tuner/assessor from trial code?' _msg = 'IPC pipeline not exists, maybe you are importing tuner/assessor from trial code?'
import logging import logging
...@@ -60,7 +59,6 @@ def send(command, data): ...@@ -60,7 +59,6 @@ def send(command, data):
""" """
global _lock global _lock
try: try:
if multi_thread_enabled():
_lock.acquire() _lock.acquire()
data = data.encode('utf8') data = data.encode('utf8')
assert len(data) < 1000000, 'Command too long' assert len(data) < 1000000, 'Command too long'
...@@ -69,7 +67,6 @@ def send(command, data): ...@@ -69,7 +67,6 @@ def send(command, data):
_out_file.write(msg) _out_file.write(msg)
_out_file.flush() _out_file.flush()
finally: finally:
if multi_thread_enabled():
_lock.release() _lock.release()
......
...@@ -73,9 +73,10 @@ class AssessorTestCase(TestCase): ...@@ -73,9 +73,10 @@ class AssessorTestCase(TestCase):
assessor = NaiveAssessor() assessor = NaiveAssessor()
dispatcher = MsgDispatcher(None, assessor) dispatcher = MsgDispatcher(None, assessor)
try: nni.msg_dispatcher_base._worker_fast_exit_on_terminate = False
dispatcher.run() dispatcher.run()
except Exception as e: e = dispatcher.worker_exceptions[0]
self.assertIs(type(e), AssertionError) self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.NewTrialJob') self.assertEqual(e.args[0], 'Unsupported command: CommandType.NewTrialJob')
......
...@@ -88,9 +88,10 @@ class TunerTestCase(TestCase): ...@@ -88,9 +88,10 @@ class TunerTestCase(TestCase):
tuner = NaiveTuner() tuner = NaiveTuner()
dispatcher = MsgDispatcher(tuner) dispatcher = MsgDispatcher(tuner)
try: nni.msg_dispatcher_base._worker_fast_exit_on_terminate = False
dispatcher.run() dispatcher.run()
except Exception as e: e = dispatcher.worker_exceptions[0]
self.assertIs(type(e), AssertionError) self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.KillTrialJob') self.assertEqual(e.args[0], 'Unsupported command: CommandType.KillTrialJob')
......
...@@ -2,10 +2,7 @@ import * as React from 'react'; ...@@ -2,10 +2,7 @@ import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { Row, Col } from 'antd'; import { Row, Col } from 'antd';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import { import { Experiment, TableObj, Parameters, TrialNumber } from '../static/interface';
Experiment, TableObj,
Parameters, TrialNumber
} from '../static/interface';
import { getFinal } from '../static/function'; import { getFinal } from '../static/function';
import SuccessTable from './overview/SuccessTable'; import SuccessTable from './overview/SuccessTable';
import Title1 from './overview/Title1'; import Title1 from './overview/Title1';
...@@ -117,7 +114,9 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -117,7 +114,9 @@ class Overview extends React.Component<{}, OverviewState> {
clusterMetaData: clusterMetaData ? clusterMetaData : undefined clusterMetaData: clusterMetaData ? clusterMetaData : undefined
}); });
// search space format loguniform max and min // search space format loguniform max and min
const searchSpace = JSON.parse(sessionData.params.searchSpace); const temp = sessionData.params.searchSpace;
const searchSpace = temp !== undefined
? JSON.parse(temp) : {};
Object.keys(searchSpace).map(item => { Object.keys(searchSpace).map(item => {
const key = searchSpace[item]._type; const key = searchSpace[item]._type;
let value = searchSpace[item]._value; let value = searchSpace[item]._value;
......
...@@ -141,6 +141,7 @@ class SlideBar extends React.Component<{}, SliderState> { ...@@ -141,6 +141,7 @@ class SlideBar extends React.Component<{}, SliderState> {
} }
}); });
} }
getNNIversion = () => { getNNIversion = () => {
axios(`${MANAGER_IP}/version`, { axios(`${MANAGER_IP}/version`, {
method: 'GET' method: 'GET'
...@@ -233,7 +234,6 @@ class SlideBar extends React.Component<{}, SliderState> { ...@@ -233,7 +234,6 @@ class SlideBar extends React.Component<{}, SliderState> {
</a> </a>
<span className="version">Version: {version}</span> <span className="version">Version: {version}</span>
</Col> </Col>
</Row> </Row>
); );
} }
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ import * as React from 'react'; ...@@ -2,7 +2,7 @@ import * as React from 'react';
interface Title1Props { interface Title1Props {
text: string; text: string;
icon: string; icon?: string;
bgcolor?: string; bgcolor?: string;
} }
......
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { TableObj, DetailAccurPoint, TooltipForAccuracy } from '../../static/interface';
require('echarts/lib/chart/scatter');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface DefaultPointProps {
showSource: Array<TableObj>;
height: number;
}
interface DefaultPointState {
defaultSource: object;
accNodata: string;
}
class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState> {
public _isMounted = false;
constructor(props: DefaultPointProps) {
super(props);
this.state = {
defaultSource: {},
accNodata: 'No data'
};
}
defaultMetric = (showSource: Array<TableObj>) => {
const accSource: Array<DetailAccurPoint> = [];
Object.keys(showSource).map(item => {
const temp = showSource[item];
if (temp.status === 'SUCCEEDED' && temp.acc.default !== undefined) {
const searchSpace = temp.description.parameters;
accSource.push({
acc: temp.acc.default,
index: temp.sequenceId,
searchSpace: JSON.stringify(searchSpace)
});
}
});
const resultList: Array<number | string>[] = [];
Object.keys(accSource).map(item => {
const items = accSource[item];
let temp: Array<number | string>;
temp = [items.index, items.acc, JSON.parse(items.searchSpace)];
resultList.push(temp);
});
const allAcuracy = {
grid: {
left: '8%'
},
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForAccuracy) {
if (data.data[0] < resultList.length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForAccuracy) {
const result = '<div class="tooldetailAccuracy">' +
'<div>Trial No: ' + data.data[0] + '</div>' +
'<div>Default Metric: ' + data.data[1] + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(data.data[2], null, 4) + '</pre>' +
'</div>' +
'</div>';
return result;
}
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default Metric',
type: 'value',
},
series: [{
symbolSize: 6,
type: 'scatter',
data: resultList
}]
};
if (this._isMounted === true) {
this.setState({ defaultSource: allAcuracy }, () => {
if (resultList.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: ''
});
}
});
}
}
// update parent component state
componentWillReceiveProps(nextProps: DefaultPointProps) {
const showSource = nextProps.showSource;
this.defaultMetric(showSource);
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const { height } = this.props;
const { defaultSource, accNodata } = this.state;
return (
<div>
<ReactEcharts
option={defaultSource}
style={{
width: '100%',
height: height,
margin: '0 auto',
}}
theme="my_theme"
notMerge={true} // update now
/>
<div className="showMess">{accNodata}</div>
</div>
);
}
}
export default DefaultPoint;
\ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
const echarts = require('echarts/lib/echarts'); import { TableObj } from 'src/static/interface';
require('echarts/lib/chart/bar'); require('echarts/lib/chart/bar');
require('echarts/lib/component/tooltip'); require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); require('echarts/lib/component/title');
echarts.registerTheme('my_theme', {
color: '#3c8dbc'
});
interface Runtrial { interface Runtrial {
trialId: Array<string>; trialId: Array<string>;
trialTime: Array<number>; trialTime: Array<number>;
} }
interface DurationProps {
source: Array<TableObj>;
}
interface DurationState { interface DurationState {
durationSource: {}; durationSource: {};
} }
class Duration extends React.Component<{}, DurationState> { class Duration extends React.Component<DurationProps, DurationState> {
static intervalDuration = 1;
public _isMounted = false; public _isMounted = false;
constructor(props: {}) { constructor(props: DurationProps) {
super(props);
super(props);
this.state = { this.state = {
durationSource: {} durationSource: {}
}; };
} }
getOption = (dataObj: Runtrial) => { getOption = (dataObj: Runtrial) => {
let xAxis = dataObj.trialTime; return {
let yAxis = dataObj.trialId;
let option = {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
...@@ -50,6 +45,7 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -50,6 +45,7 @@ class Duration extends React.Component<{}, DurationState> {
left: '1%', left: '1%',
right: '4%' right: '4%'
}, },
dataZoom: [{ dataZoom: [{
type: 'slider', type: 'slider',
name: 'trial', name: 'trial',
...@@ -69,65 +65,52 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -69,65 +65,52 @@ class Duration extends React.Component<{}, DurationState> {
yAxis: { yAxis: {
name: 'Trial', name: 'Trial',
type: 'category', type: 'category',
data: yAxis data: dataObj.trialId
}, },
series: [{ series: [{
type: 'bar', type: 'bar',
data: xAxis data: dataObj.trialTime
}] }]
}; };
return option;
} }
drawRunGraph = () => { drawDurationGraph = (trialJobs: Array<TableObj>) => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialId: Array<string> = []; const trialId: Array<string> = [];
const trialTime: Array<number> = []; const trialTime: Array<number> = [];
const trialRun: Array<Runtrial> = []; const trialRun: Array<Runtrial> = [];
Object.keys(trialJobs).map(item => { Object.keys(trialJobs).map(item => {
if (trialJobs[item].status !== 'WAITING') { const temp = trialJobs[item];
let duration: number = 0; if (temp.status !== 'WAITING') {
const end = trialJobs[item].endTime; trialId.push(temp.sequenceId);
const start = trialJobs[item].startTime; trialTime.push(temp.duration);
if (start && end) {
duration = (end - start) / 1000;
} else {
duration = (new Date().getTime() - start) / 1000;
}
trialId.push(trialJobs[item].sequenceId);
trialTime.push(duration);
} }
}); });
trialRun.push({ trialRun.push({
trialId: trialId, trialId: trialId,
trialTime: trialTime trialTime: trialTime
}); });
if (this._isMounted && res.status === 200) { if (this._isMounted) {
this.setState({ this.setState({
durationSource: this.getOption(trialRun[0]) durationSource: this.getOption(trialRun[0])
}); });
} }
} }
});
componentWillReceiveProps(nextProps: DurationProps) {
const trialJobs = nextProps.source;
this.drawDurationGraph(trialJobs);
} }
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.drawRunGraph(); // init: user don't search
Duration.intervalDuration = window.setInterval(this.drawRunGraph, 10000); const {source} = this.props;
this.drawDurationGraph(source);
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
window.clearInterval(Duration.intervalDuration);
} }
render() { render() {
...@@ -136,7 +119,7 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -136,7 +119,7 @@ class Duration extends React.Component<{}, DurationState> {
<div> <div>
<ReactEcharts <ReactEcharts
option={durationSource} option={durationSource}
style={{ width: '100%', height: 412, margin: '0 auto' }} style={{ width: '95%', height: 412, margin: '0 auto' }}
theme="my_theme" theme="my_theme"
/> />
</div> </div>
......
import * as React from 'react';
import { Row, Col, Button, Switch } from 'antd';
import { TooltipForIntermediate, TableObj } from '../../static/interface';
import ReactEcharts from 'echarts-for-react';
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
}
interface IntermediateState {
interSource: object;
filterSource: Array<TableObj>;
eachIntermediateNum: number; // trial's intermediate number count
isLoadconfirmBtn: boolean;
isFilter: boolean;
}
interface IntermediateProps {
source: Array<TableObj>;
}
class Intermediate extends React.Component<IntermediateProps, IntermediateState> {
static intervalMediate = 1;
public _isMounted = false;
public pointInput: HTMLInputElement | null;
public minValInput: HTMLInputElement | null;
public maxValInput: HTMLInputElement | null;
constructor(props: IntermediateProps) {
super(props);
this.state = {
interSource: {},
filterSource: [],
eachIntermediateNum: 1,
isLoadconfirmBtn: false,
isFilter: false
};
}
initMediate = () => {
const option = {
grid: {
left: '5%',
top: 40,
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
},
yAxis: {
type: 'value',
name: 'Scape'
}
};
if (this._isMounted) {
this.setState(() => ({
interSource: option
}));
}
}
drawIntermediate = (source: Array<TableObj>) => {
if (source.length > 0) {
const trialIntermediate: Array<Intermedia> = [];
Object.keys(source).map(item => {
const temp = source[item];
trialIntermediate.push({
name: temp.id,
data: temp.description.intermediate,
type: 'line',
hyperPara: temp.description.parameters
});
});
// find max intermediate number
trialIntermediate.sort((a, b) => { return (b.data.length - a.data.length); });
const legend: Array<string> = [];
// max length
const length = trialIntermediate[0].data.length;
const xAxis: Array<number> = [];
Object.keys(trialIntermediate).map(item => {
const temp = trialIntermediate[item];
legend.push(temp.name);
});
for (let i = 1; i <= length; i++) {
xAxis.push(i);
}
const option = {
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForIntermediate) {
if (data.dataIndex < length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForIntermediate) {
const trialId = data.seriesName;
let obj = {};
const temp = trialIntermediate.find(key => key.name === trialId);
if (temp !== undefined) {
obj = temp.hyperPara;
}
return '<div class="tooldetailAccuracy">' +
'<div>Trial Id: ' + trialId + '</div>' +
'<div>Intermediate: ' + data.data + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(obj, null, 4) + '</pre>' +
'</div>' +
'</div>';
}
},
grid: {
left: '5%',
top: 40,
containLabel: true
},
xAxis: {
type: 'category',
name: 'Scape',
boundaryGap: false,
data: xAxis
},
yAxis: {
type: 'value',
name: 'Intermediate'
},
series: trialIntermediate
};
if (this._isMounted) {
this.setState(() => ({
interSource: option
}));
}
} else {
this.initMediate();
}
}
// confirm btn function [filter data]
filterLines = () => {
if (this._isMounted) {
const filterSource: Array<TableObj> = [];
this.setState({ isLoadconfirmBtn: true }, () => {
const { source } = this.props;
// get input value
const pointVal = this.pointInput !== null ? this.pointInput.value : '';
const minVal = this.minValInput !== null ? this.minValInput.value : '';
const maxVal = this.maxValInput !== null ? this.maxValInput.value : '';
// user not input message
if (pointVal === '' || minVal === '') {
alert('Please input filter message');
} else {
// user not input max value
const position = JSON.parse(pointVal);
const min = JSON.parse(minVal);
if (maxVal === '') {
Object.keys(source).map(item => {
const temp = source[item];
const val = temp.description.intermediate[position - 1];
if (val >= min) {
filterSource.push(temp);
}
});
} else {
const max = JSON.parse(maxVal);
Object.keys(source).map(item => {
const temp = source[item];
const val = temp.description.intermediate[position - 1];
if (val >= min && val <= max) {
filterSource.push(temp);
}
});
}
if (this._isMounted) {
this.setState({ filterSource: filterSource });
}
this.drawIntermediate(filterSource);
}
this.setState({ isLoadconfirmBtn: false });
});
}
}
switchTurn = (checked: boolean) => {
if (this._isMounted) {
this.setState({ isFilter: checked });
}
if (checked === false) {
this.drawIntermediate(this.props.source);
}
}
componentDidMount() {
this._isMounted = true;
const { source } = this.props;
this.drawIntermediate(source);
}
componentWillReceiveProps(nextProps: IntermediateProps) {
const { isFilter, filterSource } = this.state;
if (isFilter === true) {
const pointVal = this.pointInput !== null ? this.pointInput.value : '';
const minVal = this.minValInput !== null ? this.minValInput.value : '';
if (pointVal === '' && minVal === '') {
this.drawIntermediate(nextProps.source);
} else {
this.drawIntermediate(filterSource);
}
} else {
this.drawIntermediate(nextProps.source);
}
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const { interSource, isLoadconfirmBtn, isFilter } = this.state;
return (
<div>
{/* style in para.scss */}
<Row className="meline intermediate">
<Col span={8} />
<Col span={3} style={{ height: 34 }}>
{/* filter message */}
<span>filter</span>
<Switch
defaultChecked={false}
onChange={this.switchTurn}
/>
</Col>
{
isFilter
?
<div>
<Col span={3}>
<span>Scape</span>
<input
placeholder="point"
ref={input => this.pointInput = input}
className="strange"
/>
</Col>
<Col className="range" span={10}>
<span>Intermediate Result</span>
<input
placeholder="number"
ref={input => this.minValInput = input}
/>
<span className="heng">-</span>
<input
placeholder="number"
ref={input => this.maxValInput = input}
/>
<Button
type="primary"
className="changeBtu tableButton"
onClick={this.filterLines}
disabled={isLoadconfirmBtn}
>
Confirm
</Button>
</Col>
</div>
:
<Col />
}
</Row>
<Row>
<ReactEcharts
option={interSource}
style={{ width: '100%', height: 418, margin: '0 auto' }}
notMerge={true} // update now
/>
</Row>
</div>
);
}
}
export default Intermediate;
\ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
import { Row, Col, Select, Button, message } from 'antd'; import { Row, Col, Select, Button, message } from 'antd';
import { ParaObj, VisualMapValue, Dimobj } from '../../static/interface'; import { ParaObj, Dimobj, TableObj, SearchSpace } from '../../static/interface';
import { getFinalResult } from '../../static/function';
const Option = Select.Option; const Option = Select.Option;
require('echarts/lib/chart/parallel'); require('echarts/lib/chart/parallel');
require('echarts/lib/component/tooltip'); require('echarts/lib/component/tooltip');
...@@ -20,12 +17,14 @@ interface ParaState { ...@@ -20,12 +17,14 @@ interface ParaState {
swapAxisArr: Array<string>; swapAxisArr: Array<string>;
percent: number; percent: number;
paraNodata: string; paraNodata: string;
visualValue: VisualMapValue; barColorMax: number;
barColorMin: number;
} }
interface SearchSpace { interface ParaProps {
_value: Array<number | string>; dataSource: Array<TableObj>;
_type: string; expSearchSpace: string;
defaultMetric: Array<number> | undefined;
} }
message.config({ message.config({
...@@ -33,12 +32,18 @@ message.config({ ...@@ -33,12 +32,18 @@ message.config({
duration: 2, duration: 2,
}); });
class Para extends React.Component<{}, ParaState> { class Para extends React.Component<ParaProps, ParaState> {
static intervalIDPara = 4;
public _isMounted = false; public _isMounted = false;
constructor(props: {}) { private chartMulineStyle = {
width: '100%',
height: 392,
margin: '0 auto',
padding: '0 15 10 15'
};
constructor(props: ParaProps) {
super(props); super(props);
this.state = { this.state = {
option: {}, option: {},
...@@ -53,28 +58,37 @@ class Para extends React.Component<{}, ParaState> { ...@@ -53,28 +58,37 @@ class Para extends React.Component<{}, ParaState> {
swapAxisArr: [], swapAxisArr: [],
percent: 0, percent: 0,
paraNodata: '', paraNodata: '',
visualValue: { barColorMax: this.props.defaultMetric !== undefined
minAccuracy: 0, ?
maxAccuracy: 1 this.props.defaultMetric[1]
} :
1,
barColorMin: this.props.defaultMetric !== undefined
?
this.props.defaultMetric[0]
:
1
}; };
} }
componentDidMount() {
this._isMounted = true;
this.reInit();
}
getParallelAxis = getParallelAxis =
( (
dimName: Array<string>, searchRange: SearchSpace, dimName: Array<string>, searchRange: SearchSpace,
parallelAxis: Array<Dimobj>, accPara: Array<number>, accPara: Array<number>,
eachTrialParams: Array<string>, paraYdata: number[][] eachTrialParams: Array<string>, paraYdata: number[][]
) => { ) => {
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState(() => ({
dimName: dimName, dimName: dimName
visualValue: {
minAccuracy: accPara.length !== 0 ? Math.min(...accPara) : 0,
maxAccuracy: accPara.length !== 0 ? Math.max(...accPara) : 1
}
})); }));
} }
const parallelAxis: Array<Dimobj> = [];
// search space range and specific value [only number] // search space range and specific value [only number]
for (let i = 0; i < dimName.length; i++) { for (let i = 0; i < dimName.length; i++) {
const searchKey = searchRange[dimName[i]]; const searchKey = searchRange[dimName[i]];
...@@ -107,7 +121,24 @@ class Para extends React.Component<{}, ParaState> { ...@@ -107,7 +121,24 @@ class Para extends React.Component<{}, ParaState> {
dim: i, dim: i,
name: dimName[i], name: dimName[i],
type: 'category', type: 'category',
data: data data: data,
boundaryGap: true,
axisLine: {
lineStyle: {
type: 'dotted', // axis type,solid,dashed,dotted
width: 1
}
},
axisTick: {
show: true,
interval: 0,
alignWithLabel: true,
},
axisLabel: {
show: true,
interval: 0,
// rotate: 30
},
}); });
break; break;
// support log distribute // support log distribute
...@@ -143,100 +174,70 @@ class Para extends React.Component<{}, ParaState> { ...@@ -143,100 +174,70 @@ class Para extends React.Component<{}, ParaState> {
} }
paraYdata.push(temp); paraYdata.push(temp);
}); });
}
hyperParaPic = () => {
axios
.all([
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/experiment`)
])
.then(axios.spread((res, res1) => {
if (res.status === 200 && res1.status === 200) {
if (res.data.length !== 0) {
const accParaData = res.data;
const accPara: Array<number> = [];
// specific value array
const eachTrialParams: Array<string> = [];
const parallelAxis: Array<Dimobj> = [];
const paraYdata: number[][] = [];
// experiment interface search space obj
const searchRange = JSON.parse(res1.data.params.searchSpace);
const reallySearchKeys = Object.keys(searchRange);
// trial-jobs interface list
Object.keys(accParaData).map(item => {
if (accParaData[item].status === 'SUCCEEDED') {
const finalData = accParaData[item].finalMetricData;
if (finalData && accParaData[item].hyperParameters) {
const result = getFinalResult(finalData);
accPara.push(result);
// get dim and every line specific number
const temp = JSON.parse(accParaData[item].hyperParameters).parameters;
eachTrialParams.push(temp);
}
}
});
const dimName = reallySearchKeys;
this.getParallelAxis(dimName, searchRange, parallelAxis, accPara, eachTrialParams, paraYdata);
// add acc // add acc
Object.keys(paraYdata).map(item => { Object.keys(paraYdata).map(item => {
paraYdata[item].push(accPara[item]); paraYdata[item].push(accPara[item]);
}); });
// according acc to sort ydata // according acc to sort ydata
if (paraYdata.length !== 0) { if (paraYdata.length !== 0) {
const len = paraYdata[0].length - 1; const len = paraYdata[0].length - 1;
paraYdata.sort((a, b) => b[len] - a[len]); paraYdata.sort((a, b) => b[len] - a[len]);
} }
if (this._isMounted) { const paraData = {
this.setState(() => ({
paraBack: {
parallelAxis: parallelAxis, parallelAxis: parallelAxis,
data: paraYdata data: paraYdata
} };
})); const { percent, swapAxisArr } = this.state;
}
const { percent, swapAxisArr, paraBack } = this.state;
// need to cut down the data // need to cut down the data
if (percent !== 0) { if (percent !== 0) {
const linesNum = paraBack.data.length; const linesNum = paraData.data.length;
const len = Math.floor(linesNum * percent); const len = Math.floor(linesNum * percent);
paraBack.data.length = len; paraData.data.length = len;
} }
// need to swap the yAxis // need to swap the yAxis
if (swapAxisArr.length >= 2) { if (swapAxisArr.length >= 2) {
this.swapGraph(paraBack, swapAxisArr); this.swapGraph(paraData, swapAxisArr);
} }
this.getOption(paraBack); this.getOption(paraData);
} }
hyperParaPic = (dataSource: Array<TableObj>, searchSpace: string) => {
const accPara: Array<number> = [];
// specific value array
const eachTrialParams: Array<string> = [];
const paraYdata: number[][] = [];
// experiment interface search space obj
const searchRange = JSON.parse(searchSpace);
const dimName = Object.keys(searchRange);
// trial-jobs interface list
Object.keys(dataSource).map(item => {
const temp = dataSource[item];
if (temp.status === 'SUCCEEDED') {
accPara.push(temp.acc.default);
eachTrialParams.push(temp.description.parameters);
} }
})); });
this.getParallelAxis(dimName, searchRange, accPara, eachTrialParams, paraYdata);
} }
// get percent value number // get percent value number
percentNum = (value: string) => { percentNum = (value: string) => {
window.clearInterval(Para.intervalIDPara);
let vals = parseFloat(value); let vals = parseFloat(value);
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState({ percent: vals }, () => {
percent: vals this.reInit();
})); });
} }
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
// deal with response data into pic data // deal with response data into pic data
getOption = (dataObj: ParaObj) => { getOption = (dataObj: ParaObj) => {
const { visualValue } = this.state; const {barColorMax, barColorMin} = this.state;
let parallelAxis = dataObj.parallelAxis; let parallelAxis = dataObj.parallelAxis;
let paralleData = dataObj.data; let paralleData = dataObj.data;
const maxAccuracy = visualValue.maxAccuracy;
const minAccuracy = visualValue.minAccuracy;
let visualMapObj = {}; let visualMapObj = {};
if (maxAccuracy === minAccuracy) { if (barColorMax === barColorMin) {
visualMapObj = { visualMapObj = {
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
...@@ -247,10 +248,9 @@ class Para extends React.Component<{}, ParaState> { ...@@ -247,10 +248,9 @@ class Para extends React.Component<{}, ParaState> {
bottom: '20px', bottom: '20px',
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
min: visualValue.minAccuracy, min: barColorMin,
max: visualValue.maxAccuracy, max: barColorMax,
color: ['#CA0000', '#FFC400', '#90EE90'], color: ['#CA0000', '#FFC400', '#90EE90']
calculable: true
}; };
} }
let optionown = { let optionown = {
...@@ -317,11 +317,9 @@ class Para extends React.Component<{}, ParaState> { ...@@ -317,11 +317,9 @@ class Para extends React.Component<{}, ParaState> {
} }
} }
swapBtn = () => { reInit = () => {
const { dataSource, expSearchSpace } = this.props;
window.clearInterval(Para.intervalIDPara); this.hyperParaPic(dataSource, expSearchSpace);
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
sortDimY = (a: Dimobj, b: Dimobj) => { sortDimY = (a: Dimobj, b: Dimobj) => {
...@@ -330,8 +328,6 @@ class Para extends React.Component<{}, ParaState> { ...@@ -330,8 +328,6 @@ class Para extends React.Component<{}, ParaState> {
// deal with after swap data into pic // deal with after swap data into pic
swapGraph = (paraBack: ParaObj, swapAxisArr: string[]) => { swapGraph = (paraBack: ParaObj, swapAxisArr: string[]) => {
if (swapAxisArr.length >= 2) {
const paralDim = paraBack.parallelAxis; const paralDim = paraBack.parallelAxis;
const paraData = paraBack.data; const paraData = paraBack.data;
let temp: number; let temp: number;
...@@ -362,10 +358,10 @@ class Para extends React.Component<{}, ParaState> { ...@@ -362,10 +358,10 @@ class Para extends React.Component<{}, ParaState> {
// swap dim's number // swap dim's number
Object.keys(paralDim).map(item => { Object.keys(paralDim).map(item => {
if (bool3) { if (bool3) {
if (paralDim[item].name === this.state.swapAxisArr[0]) { if (paralDim[item].name === swapAxisArr[0]) {
paralDim[item].dim = dim2; paralDim[item].dim = dim2;
} }
if (paralDim[item].name === this.state.swapAxisArr[1]) { if (paralDim[item].name === swapAxisArr[1]) {
paralDim[item].dim = dim1; paralDim[item].dim = dim1;
} }
} }
...@@ -379,30 +375,26 @@ class Para extends React.Component<{}, ParaState> { ...@@ -379,30 +375,26 @@ class Para extends React.Component<{}, ParaState> {
paraData[paraItem][dim2] = temp; paraData[paraItem][dim2] = temp;
}); });
} }
}
componentDidMount() { componentWillReceiveProps(nextProps: ParaProps) {
const dataSource = nextProps.dataSource;
const expSearchSpace = nextProps.expSearchSpace;
const metricMax = nextProps.defaultMetric !== undefined
?
nextProps.defaultMetric[1]
:
1;
this.setState({ barColorMax: metricMax });
this.hyperParaPic(dataSource, expSearchSpace);
this._isMounted = true;
// default draw all data pic
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
window.clearInterval(Para.intervalIDPara);
} }
render() { render() {
const { option, paraNodata, dimName } = this.state; const { option, paraNodata, dimName } = this.state;
const chartMulineStyle = {
width: '100%',
height: 392,
margin: '0 auto',
padding: '0 15 10 15'
};
return ( return (
<Row className="parameter"> <Row className="parameter">
<Row> <Row>
...@@ -439,7 +431,7 @@ class Para extends React.Component<{}, ParaState> { ...@@ -439,7 +431,7 @@ class Para extends React.Component<{}, ParaState> {
<Button <Button
type="primary" type="primary"
className="changeBtu tableButton" className="changeBtu tableButton"
onClick={this.swapBtn} onClick={this.reInit}
> >
Confirm Confirm
</Button> </Button>
...@@ -449,8 +441,8 @@ class Para extends React.Component<{}, ParaState> { ...@@ -449,8 +441,8 @@ class Para extends React.Component<{}, ParaState> {
<Row className="searcHyper"> <Row className="searcHyper">
<ReactEcharts <ReactEcharts
option={option} option={option}
style={chartMulineStyle} style={this.chartMulineStyle}
// lazyUpdate={true} lazyUpdate={true}
notMerge={true} // update now notMerge={true} // update now
/> />
<div className="noneData">{paraNodata}</div> <div className="noneData">{paraNodata}</div>
......
...@@ -2,9 +2,8 @@ import * as React from 'react'; ...@@ -2,9 +2,8 @@ import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
import { import {
Row, Input, Table, Button, Popconfirm, Modal, Checkbox Row, Table, Button, Popconfirm, Modal, Checkbox
} from 'antd'; } from 'antd';
const { TextArea } = Input;
const CheckboxGroup = Checkbox.Group; const CheckboxGroup = Checkbox.Group;
import { MANAGER_IP, DOWNLOAD_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/const'; import { MANAGER_IP, DOWNLOAD_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/const';
import { convertDuration, intermediateGraphOption, killJob } from '../../static/function'; import { convertDuration, intermediateGraphOption, killJob } from '../../static/function';
...@@ -29,9 +28,7 @@ echarts.registerTheme('my_theme', { ...@@ -29,9 +28,7 @@ echarts.registerTheme('my_theme', {
interface TableListProps { interface TableListProps {
entries: number; entries: number;
tableSource: Array<TableObj>; tableSource: Array<TableObj>;
searchResult: Array<TableObj>;
updateList: Function; updateList: Function;
isHasSearch: boolean;
platform: string; platform: string;
} }
...@@ -78,6 +75,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -78,6 +75,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
const intermediateArr: number[] = []; const intermediateArr: number[] = [];
// support intermediate result is dict
Object.keys(res.data).map(item => { Object.keys(res.data).map(item => {
const temp = JSON.parse(res.data[item].data); const temp = JSON.parse(res.data[item].data);
if (typeof temp === 'object') { if (typeof temp === 'object') {
...@@ -244,10 +242,8 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -244,10 +242,8 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() { render() {
const { entries, tableSource, searchResult, isHasSearch, updateList } = this.props; const { entries, tableSource, updateList } = this.props;
const { intermediateOption, modalVisible, isShowColumn, columnSelected, const { intermediateOption, modalVisible, isShowColumn, columnSelected} = this.state;
logMessage, logModal
} = this.state;
let showTitle = COLUMN; let showTitle = COLUMN;
let bgColor = ''; let bgColor = '';
const trialJob: Array<TrialJob> = []; const trialJob: Array<TrialJob> = [];
...@@ -340,7 +336,10 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -340,7 +336,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
); );
}, },
filters: trialJob, filters: trialJob,
onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0, onFilter: (value: string, record: TableObj) => {
return record.status.indexOf(value) === 0;
},
// onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0,
sorter: (a: TableObj, b: TableObj): number => a.status.localeCompare(b.status) sorter: (a: TableObj, b: TableObj): number => a.status.localeCompare(b.status)
}); });
break; break;
...@@ -453,7 +452,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -453,7 +452,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
<Table <Table
columns={showColumn} columns={showColumn}
expandedRowRender={this.openRow} expandedRowRender={this.openRow}
dataSource={isHasSearch ? searchResult : tableSource} dataSource={tableSource}
className="commonTableStyle" className="commonTableStyle"
pagination={{ pageSize: entries }} pagination={{ pageSize: entries }}
/> />
...@@ -475,24 +474,6 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -475,24 +474,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
theme="my_theme" theme="my_theme"
/> />
</Modal> </Modal>
{/* trial log modal */}
<Modal
title="trial log"
visible={logModal}
onCancel={this.hideLogModal}
footer={null}
destroyOnClose={true}
width="80%"
>
<div id="trialLogContent" style={{ height: window.innerHeight * 0.6 }}>
<TextArea
value={logMessage}
disabled={true}
className="logcontent"
/>
</div>
</Modal>
</div> </div>
{/* Add Column Modal */} {/* Add Column Modal */}
<Modal <Modal
......
...@@ -10,6 +10,11 @@ interface TableObj { ...@@ -10,6 +10,11 @@ interface TableObj {
color?: string; color?: string;
} }
interface SearchSpace {
_value: Array<number | string>;
_type: string;
}
interface FinalType { interface FinalType {
default: string; default: string;
} }
...@@ -21,6 +26,7 @@ interface ErrorParameter { ...@@ -21,6 +26,7 @@ interface ErrorParameter {
interface Parameters { interface Parameters {
parameters: ErrorParameter; parameters: ErrorParameter;
logPath?: string; logPath?: string;
intermediate?: Array<number>;
} }
interface Experiment { interface Experiment {
...@@ -54,6 +60,12 @@ interface DetailAccurPoint { ...@@ -54,6 +60,12 @@ interface DetailAccurPoint {
searchSpace: string; searchSpace: string;
} }
interface TooltipForIntermediate {
data: string;
seriesName: string;
dataIndex: number;
}
interface TooltipForAccuracy { interface TooltipForAccuracy {
data: Array<number | object>; data: Array<number | object>;
} }
...@@ -80,6 +92,10 @@ interface Dimobj { ...@@ -80,6 +92,10 @@ interface Dimobj {
min?: number; min?: number;
type?: string; type?: string;
data?: string[]; data?: string[];
boundaryGap?: boolean;
axisTick?: object;
axisLabel?: object;
axisLine?: object;
} }
interface ParaObj { interface ParaObj {
...@@ -87,11 +103,6 @@ interface ParaObj { ...@@ -87,11 +103,6 @@ interface ParaObj {
parallelAxis: Array<Dimobj>; parallelAxis: Array<Dimobj>;
} }
interface VisualMapValue {
maxAccuracy: number;
minAccuracy: number;
}
interface FinalResult { interface FinalResult {
data: string; data: string;
} }
...@@ -100,5 +111,6 @@ export { ...@@ -100,5 +111,6 @@ export {
TableObj, Parameters, Experiment, TableObj, Parameters, Experiment,
AccurPoint, TrialNumber, TrialJob, AccurPoint, TrialNumber, TrialJob,
DetailAccurPoint, TooltipForAccuracy, DetailAccurPoint, TooltipForAccuracy,
ParaObj, VisualMapValue, Dimobj, FinalResult, FinalType ParaObj, Dimobj, FinalResult, FinalType,
TooltipForIntermediate, SearchSpace
}; };
...@@ -13,7 +13,6 @@ $titleBgcolor: #b3b3b3; ...@@ -13,7 +13,6 @@ $titleBgcolor: #b3b3b3;
height: 22px; height: 22px;
margin-top: -8px; margin-top: -8px;
padding-left: 14px; padding-left: 14px;
padding-right: 14px;
} }
span{ span{
...@@ -22,9 +21,22 @@ $titleBgcolor: #b3b3b3; ...@@ -22,9 +21,22 @@ $titleBgcolor: #b3b3b3;
font-family: 'Segoe'; font-family: 'Segoe';
color: #333; color: #333;
line-height: 38px; line-height: 38px;
margin-left: 14px;
}
i{
font-size: 24px;
margin-left: 14px;
color: #545454;
position: relative;
top: 2px;
} }
} }
/* antd icon margin intermediate result style*/
#tabsty .anticon{
margin-right: 0;
}
.top10bg{ .top10bg{
background-color: $titleBgcolor; background-color: $titleBgcolor;
......
.parameter{ .parameter{
height: 100%; height: 100%;
}
.meline{ .meline{
margin-top: 15px; margin-top: 15px;
span{ span{
font-size: 14px; font-size: 14px;
margin-right: 6px; margin-right: 6px;
} }
}
} }
.searcHyper{ .searcHyper{
...@@ -25,3 +24,22 @@ ...@@ -25,3 +24,22 @@
color: #999; color: #999;
} }
} }
/* Intermediate Result Style */
.intermediate{
/* border: 1px solid blue; */
input{
width: 80px;
height: 32px;
padding-left: 8px;
}
.strange{
margin-top: 2px;
}
.range{
.heng{
margin-left: 6px;
margin-right: 6px;
}
}
}
...@@ -76,8 +76,8 @@ def run(dispatch_type): ...@@ -76,8 +76,8 @@ def run(dispatch_type):
dipsatcher_list = TUNER_LIST if dispatch_type == 'Tuner' else ASSESSOR_LIST dipsatcher_list = TUNER_LIST if dispatch_type == 'Tuner' else ASSESSOR_LIST
for dispatcher_name in dipsatcher_list: for dispatcher_name in dipsatcher_list:
try: try:
# sleep 5 seconds here, to make sure previous stopped exp has enough time to exit to avoid port conflict # Sleep here to make sure previous stopped exp has enough time to exit to avoid port conflict
time.sleep(5) time.sleep(6)
test_builtin_dispatcher(dispatch_type, dispatcher_name) test_builtin_dispatcher(dispatch_type, dispatcher_name)
print(GREEN + 'Test %s %s: TEST PASS' % (dispatcher_name, dispatch_type) + CLEAR) print(GREEN + 'Test %s %s: TEST PASS' % (dispatcher_name, dispatch_type) + CLEAR)
except Exception as error: except Exception as error:
......
...@@ -36,6 +36,7 @@ Optional('nniManagerIp'): str, ...@@ -36,6 +36,7 @@ Optional('nniManagerIp'): str,
Optional('logDir'): os.path.isdir, Optional('logDir'): os.path.isdir,
Optional('debug'): bool, Optional('debug'): bool,
Optional('logLevel'): Or('trace', 'debug', 'info', 'warning', 'error', 'fatal'), Optional('logLevel'): Or('trace', 'debug', 'info', 'warning', 'error', 'fatal'),
Optional('logCollection'): Or('http', 'none'),
'useAnnotation': bool, 'useAnnotation': bool,
Optional('advisor'): Or({ Optional('advisor'): Or({
'builtinAdvisorName': Or('Hyperband'), 'builtinAdvisorName': Or('Hyperband'),
...@@ -57,6 +58,7 @@ Optional('tuner'): Or({ ...@@ -57,6 +58,7 @@ Optional('tuner'): Or({
Optional('classArgs'): { Optional('classArgs'): {
'optimize_mode': Or('maximize', 'minimize') 'optimize_mode': Or('maximize', 'minimize')
}, },
Optional('includeIntermediateResults'): bool,
Optional('gpuNum'): And(int, lambda x: 0 <= x <= 99999), Optional('gpuNum'): And(int, lambda x: 0 <= x <= 99999),
},{ },{
'builtinTunerName': Or('BatchTuner', 'GridSearch'), 'builtinTunerName': Or('BatchTuner', 'GridSearch'),
......
...@@ -274,6 +274,8 @@ def set_experiment(experiment_config, mode, port, config_file_name): ...@@ -274,6 +274,8 @@ def set_experiment(experiment_config, mode, port, config_file_name):
#debug mode should disable version check #debug mode should disable version check
if experiment_config.get('debug') is not None: if experiment_config.get('debug') is not None:
request_data['versionCheck'] = not experiment_config.get('debug') request_data['versionCheck'] = not experiment_config.get('debug')
if experiment_config.get('logCollection'):
request_data['logCollection'] = experiment_config.get('logCollection')
request_data['clusterMetaData'] = [] request_data['clusterMetaData'] = []
if experiment_config['trainingServicePlatform'] == 'local': if experiment_config['trainingServicePlatform'] == 'local':
......
...@@ -25,6 +25,7 @@ import logging ...@@ -25,6 +25,7 @@ import logging
import logging.handlers import logging.handlers
import time import time
import threading import threading
import re
from datetime import datetime from datetime import datetime
from enum import Enum, unique from enum import Enum, unique
...@@ -81,7 +82,7 @@ class RemoteLogger(object): ...@@ -81,7 +82,7 @@ class RemoteLogger(object):
""" """
NNI remote logger NNI remote logger
""" """
def __init__(self, syslog_host, syslog_port, tag, std_output_type, log_level=logging.INFO): def __init__(self, syslog_host, syslog_port, tag, std_output_type, log_collection, log_level=logging.INFO):
''' '''
constructor constructor
''' '''
...@@ -94,12 +95,13 @@ class RemoteLogger(object): ...@@ -94,12 +95,13 @@ class RemoteLogger(object):
self.orig_stdout = sys.__stdout__ self.orig_stdout = sys.__stdout__
else: else:
self.orig_stdout = sys.__stderr__ self.orig_stdout = sys.__stderr__
self.log_collection = log_collection
def get_pipelog_reader(self): def get_pipelog_reader(self):
''' '''
Get pipe for remote logger Get pipe for remote logger
''' '''
return PipeLogReader(self.logger, logging.INFO) return PipeLogReader(self.logger, self.log_collection, logging.INFO)
def write(self, buf): def write(self, buf):
''' '''
...@@ -117,7 +119,7 @@ class PipeLogReader(threading.Thread): ...@@ -117,7 +119,7 @@ class PipeLogReader(threading.Thread):
""" """
The reader thread reads log data from pipe The reader thread reads log data from pipe
""" """
def __init__(self, logger, log_level=logging.INFO): def __init__(self, logger, log_collection, log_level=logging.INFO):
"""Setup the object with a logger and a loglevel """Setup the object with a logger and a loglevel
and start the thread and start the thread
""" """
...@@ -131,6 +133,8 @@ class PipeLogReader(threading.Thread): ...@@ -131,6 +133,8 @@ class PipeLogReader(threading.Thread):
self.orig_stdout = sys.__stdout__ self.orig_stdout = sys.__stdout__
self._is_read_completed = False self._is_read_completed = False
self.process_exit = False self.process_exit = False
self.log_collection = log_collection
self.log_pattern = re.compile(r'^NNISDK_MEb\'.*\'$')
def _populateQueue(stream, queue): def _populateQueue(stream, queue):
''' '''
...@@ -143,8 +147,6 @@ class PipeLogReader(threading.Thread): ...@@ -143,8 +147,6 @@ class PipeLogReader(threading.Thread):
line = self.queue.get(True, 5) line = self.queue.get(True, 5)
try: try:
self.logger.log(self.log_level, line.rstrip()) self.logger.log(self.log_level, line.rstrip())
self.orig_stdout.write(line.rstrip() + '\n')
self.orig_stdout.flush()
except Exception as e: except Exception as e:
pass pass
except Exception as e: except Exception as e:
...@@ -165,9 +167,17 @@ class PipeLogReader(threading.Thread): ...@@ -165,9 +167,17 @@ class PipeLogReader(threading.Thread):
def run(self): def run(self):
"""Run the thread, logging everything. """Run the thread, logging everything.
If the log_collection is 'none', the log content will not be enqueued
""" """
for line in iter(self.pipeReader.readline, ''): for line in iter(self.pipeReader.readline, ''):
self.orig_stdout.write(line.rstrip() + '\n')
self.orig_stdout.flush()
if self.log_collection == 'none':
# If not match metrics, do not put the line into queue
if not self.log_pattern.match(line):
continue
self.queue.put(line) self.queue.put(line)
self.pipeReader.close() self.pipeReader.close()
def close(self): def close(self):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment