feat:时间选择&定时刷新抽取为组件
This commit is contained in:
@@ -254,6 +254,10 @@ li{
|
|||||||
.nz-btn:focus {
|
.nz-btn:focus {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
.nz-btn .nz-btn-text{
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.nz-btn.nz-btn-disabled {
|
.nz-btn.nz-btn-disabled {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
color: #e5e5e5;
|
color: #e5e5e5;
|
||||||
|
|||||||
227
nezha-fronted/src/components/common/intervalRefresh.vue
Normal file
227
nezha-fronted/src/components/common/intervalRefresh.vue
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<template>
|
||||||
|
<div class="interval-refresh">
|
||||||
|
<el-date-picker size="mini" ref="calendar"
|
||||||
|
format="yyyy/MM/dd HH:mm:ss"
|
||||||
|
@change="dateChange"
|
||||||
|
v-model="searchTime"
|
||||||
|
type="datetimerange"
|
||||||
|
:picker-options="pickerOptions"
|
||||||
|
:range-separator="$t('dashboard.panel.to')"
|
||||||
|
:start-placeholder="$t('dashboard.panel.startTime')"
|
||||||
|
:end-placeholder="$t('dashboard.panel.endTime')"
|
||||||
|
style="margin-right: 20px"
|
||||||
|
align="right">
|
||||||
|
</el-date-picker>
|
||||||
|
<div class="nz-btn-group nz-btn-group-size-normal nz-btn-group-light margin-r-20">
|
||||||
|
<button style="border-right: 1px solid rgba(162,162,162,0.50);height: 100%" type="button" class="nz-btn nz-btn-size-normal nz-btn-style-light" @click="refreshDataFunc">
|
||||||
|
<i style="font-size: 12px" class="global-active-color nz-icon nz-icon-refresh"></i>
|
||||||
|
<span class="nz-btn nz-btn-text" ><slot name="added-text"></slot></span>
|
||||||
|
</button>
|
||||||
|
<el-popover v-model="visible" placement="bottom-start" :width="50" trigger="click" popper-class="interval-refresh-popover">
|
||||||
|
<ul class="popover_ul">
|
||||||
|
<li v-for="i in intervalList" :style="{color:interval==i.value?'#31749C':''}" :key="i.value+i.name" @click="selectInterval(i)">
|
||||||
|
{{i.name}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button type="button" style="border-radius: 0 4px 4px 0;height: 100%" class="nz-btn nz-btn-size-normal nz-btn-style-light" slot="reference">
|
||||||
|
<span class="nz-btn nz-btn-text">{{interval.value != -1?interval.name:''}} </span><i style="font-size: 12px" class="nz-icon nz-icon-arrow-down"></i>
|
||||||
|
</button>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import bus from "../../libs/bus";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "intervalRefresh",
|
||||||
|
model:{
|
||||||
|
event:'change',
|
||||||
|
prop:'timeRange'
|
||||||
|
},
|
||||||
|
props:{
|
||||||
|
refreshDataFunc:{
|
||||||
|
required:true,
|
||||||
|
type:Function
|
||||||
|
},
|
||||||
|
timeRange:{
|
||||||
|
type:Array,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return{
|
||||||
|
searchTime:[],
|
||||||
|
pickerOptions: {
|
||||||
|
shortcuts: [
|
||||||
|
{
|
||||||
|
text: this.$t("dashboard.panel.recOne"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setHours(start.getHours() - 1);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.recFour"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setHours(start.getHours() - 4);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.recOneDay"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setDate(start.getDate() - 1);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.yesterday"),
|
||||||
|
onClick(picker) {
|
||||||
|
const start = new Date();
|
||||||
|
const end = new Date();
|
||||||
|
start.setDate(start.getDate() - 1);
|
||||||
|
start.setHours(0);
|
||||||
|
start.setMinutes(0);
|
||||||
|
start.setSeconds(0);
|
||||||
|
end.setDate(end.getDate() - 1);
|
||||||
|
end.setHours(23);
|
||||||
|
end.setMinutes(59);
|
||||||
|
end.setSeconds(59);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.recSevenDay"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setDate(start.getDate() - 7);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.recOneMonth"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setDate(start.getDate() - 30);
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.curMonth"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setDate(1);
|
||||||
|
start.setHours(0);
|
||||||
|
start.setMinutes(0);
|
||||||
|
start.setSeconds(0)
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: this.$t("dashboard.panel.lastMonth"),
|
||||||
|
onClick(picker) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date();
|
||||||
|
start.setDate(1);
|
||||||
|
start.setMonth(start.getMonth() - 1);
|
||||||
|
end.setDate(0);
|
||||||
|
start.setStart();
|
||||||
|
end.setEnd();
|
||||||
|
picker.$emit('pick', [start, end]);
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
visible: false,
|
||||||
|
intervalTimer: null,
|
||||||
|
intervalList: [{
|
||||||
|
value: -1,
|
||||||
|
name: this.$t("dashboard.panel.refreshInterval.never"),
|
||||||
|
}, {
|
||||||
|
value: 30,
|
||||||
|
name: '30s',
|
||||||
|
}, {
|
||||||
|
value: 60,
|
||||||
|
name: '1m',
|
||||||
|
}, {
|
||||||
|
value: 300,
|
||||||
|
name: '5m',
|
||||||
|
}, {
|
||||||
|
value: 900,
|
||||||
|
name: '15m',
|
||||||
|
}, {
|
||||||
|
value: 1800,
|
||||||
|
name: '30m',
|
||||||
|
}],
|
||||||
|
interval: -1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
this.searchTime=this.timeFormate(this.timeRange)
|
||||||
|
this.$emit('change',this.searchTime)
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
selectInterval(val) {
|
||||||
|
this.visible = false;
|
||||||
|
clearInterval(this.intervalTimer);
|
||||||
|
if (val) {
|
||||||
|
this.interval = val;
|
||||||
|
const start = new Date(this.searchTime[1]);
|
||||||
|
const now = new Date();
|
||||||
|
const interval = Math.floor((now.getTime() - start.getTime()) / 1000); //计算当前结束时间到现在的间隔(秒)
|
||||||
|
if (interval >= 60) { //如果结束时间到现在超过1分钟,则
|
||||||
|
this.getIntervalData(interval);
|
||||||
|
}
|
||||||
|
this.intervalTimer = setInterval(() => {
|
||||||
|
this.getIntervalData(this.interval.value);
|
||||||
|
}, val.value * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getIntervalData(interval) { //interval:结束时间到现在的秒数
|
||||||
|
const start = new Date(this.searchTime[0]);
|
||||||
|
const end = new Date(this.searchTime[1]);
|
||||||
|
start.setSeconds(start.getSeconds() + interval);
|
||||||
|
end.setSeconds(end.getSeconds() + interval);
|
||||||
|
|
||||||
|
this.searchTime = this.timeFormate([start,end])
|
||||||
|
//刷新数据
|
||||||
|
this.refreshDataFunc();
|
||||||
|
},
|
||||||
|
timeFormate(timeRange){
|
||||||
|
const startTime = bus.timeFormate(timeRange[0], 'yyyy-MM-dd hh:mm:ss');
|
||||||
|
const endTime = bus.timeFormate(timeRange[1], 'yyyy-MM-dd hh:mm:ss');
|
||||||
|
return [startTime, endTime];
|
||||||
|
},
|
||||||
|
dateChange(time) {
|
||||||
|
let timeRange=this.timeFormate(time);
|
||||||
|
this.$emit('change',timeRange)
|
||||||
|
this.refreshDataFunc();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.interval-refresh{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.popover_ul{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.popover_ul li {
|
||||||
|
padding: 10px 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.popover_ul li:hover {
|
||||||
|
background: $dropdown-hover-background-color !important;
|
||||||
|
color: $global-text-color-active !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.interval-refresh-popover{
|
||||||
|
min-width: unset !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -168,7 +168,7 @@ const cn = {
|
|||||||
lastSevenDay: "最近7天",
|
lastSevenDay: "最近7天",
|
||||||
lastThirtyDay: "最近30天",
|
lastThirtyDay: "最近30天",
|
||||||
refreshInterval: {
|
refreshInterval: {
|
||||||
never: "从不",
|
never: "关闭",
|
||||||
oneMinute: "1分钟",
|
oneMinute: "1分钟",
|
||||||
threeMinutes: "3分钟",
|
threeMinutes: "3分钟",
|
||||||
fiveMinutes: "5分钟",
|
fiveMinutes: "5分钟",
|
||||||
@@ -196,7 +196,9 @@ const cn = {
|
|||||||
saveChartToPanel: "保存图表到看板"
|
saveChartToPanel: "保存图表到看板"
|
||||||
},
|
},
|
||||||
metricPreview: {
|
metricPreview: {
|
||||||
title: "探索"
|
title: "探索",
|
||||||
|
inputTip:'输入PromQL查询语句',
|
||||||
|
runQuery:'查询',
|
||||||
},
|
},
|
||||||
refresh: "刷新",
|
refresh: "刷新",
|
||||||
edit: "编辑",
|
edit: "编辑",
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ const en = {
|
|||||||
lastSevenDay:'Last 7 days',
|
lastSevenDay:'Last 7 days',
|
||||||
lastThirtyDay:'Last 30 days',
|
lastThirtyDay:'Last 30 days',
|
||||||
refreshInterval:{
|
refreshInterval:{
|
||||||
never:'Never', //'从不'
|
never:'OFF', //'从不'
|
||||||
oneMinute:'1 minute', // 1 minute
|
oneMinute:'1 minute', // 1 minute
|
||||||
threeMinutes:'3 minutes', //'3分钟'
|
threeMinutes:'3 minutes', //'3分钟'
|
||||||
fiveMinutes:'5 minutes', //'5分钟'
|
fiveMinutes:'5 minutes', //'5分钟'
|
||||||
@@ -202,7 +202,8 @@ const en = {
|
|||||||
},
|
},
|
||||||
metricPreview:{
|
metricPreview:{
|
||||||
title:'Explore',
|
title:'Explore',
|
||||||
inputTip:'Enter a PromQL query'
|
inputTip:'Enter a PromQL query',
|
||||||
|
runQuery:'Run query',
|
||||||
},
|
},
|
||||||
refresh:'Refresh',//'刷新'
|
refresh:'Refresh',//'刷新'
|
||||||
edit:'Edit',//'编辑'
|
edit:'Edit',//'编辑'
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div slot="content-right" class="slot-content">
|
<div slot="content-right" class="slot-content">
|
||||||
<div class="main-list main-and-sub-transition">
|
<div class="main-list main-and-sub-transition">
|
||||||
<el-scrollbar style="height: 100%">
|
|
||||||
<!-- 顶部工具栏 -->
|
<!-- 顶部工具栏 -->
|
||||||
<div class="top-tools" style="z-index: 1">
|
<div class="top-tools" style="z-index: 1">
|
||||||
<button :disabled="saveDisabled" type="button" @click="saveChart"
|
<button :disabled="saveDisabled" type="button" @click="saveChart"
|
||||||
@@ -19,188 +18,163 @@
|
|||||||
:class="{'nz-btn-disabled btn-disabled-cursor-not-allowed' : saveDisabled}">
|
:class="{'nz-btn-disabled btn-disabled-cursor-not-allowed' : saveDisabled}">
|
||||||
{{$t('dashboard.metric.saveChart')}}
|
{{$t('dashboard.metric.saveChart')}}
|
||||||
</button>
|
</button>
|
||||||
<div class="nz-btn-group nz-btn-group-size-normal nz-btn-group-light margin-r-20">
|
<interval-refresh :refresh-data-func="expressionChange" v-model="filterTime">
|
||||||
<button style="border-right: 1px solid rgba(162,162,162,0.50);" type="button"
|
<template slot="added-text">{{$t('dashboard.metricPreview.runQuery')}}</template>
|
||||||
class="nz-btn nz-btn-size-normal nz-btn-style-light" @click="expressionChange">
|
</interval-refresh>
|
||||||
<i style="font-size: 12px" class="global-active-color nz-icon nz-icon-refresh"></i>
|
</div>
|
||||||
</button>
|
<div style="height: 100%;width: 100%;" >
|
||||||
<el-popover
|
<el-scrollbar style="height: 100%" class="el-scrollbar-large">
|
||||||
v-model="visible" placement="bottom-start" width="200" trigger="click">
|
<div class="expression-room right-margin" style="padding-top: 5px">
|
||||||
<ul class="popover_ul">
|
<!--坑,这个index居然是从1开始-->
|
||||||
<li v-for="i in intervalList" :style="{color:interval==i.value?'#31749C':''}" :key="i.value+i.name"
|
<promql-input
|
||||||
@click="selectInterval(i.value)">
|
v-for="index of promqlKeys.length"
|
||||||
{{i.name}}
|
:id="promqlKeys[index-1]"
|
||||||
</li>
|
:key="promqlKeys[index-1]"
|
||||||
</ul>
|
:expression-list="expressions"
|
||||||
<button type="button" style="border-radius: 0 4px 4px 0"
|
:index="index-1"
|
||||||
class="nz-btn nz-btn-size-normal nz-btn-style-light" slot="reference">
|
@change="expressionChange"
|
||||||
<i style="font-size: 12px" class="nz-icon nz-icon-arrow-down"></i>
|
@addExpression="addExpression"
|
||||||
</button>
|
@removeExpression="removeExpression"
|
||||||
</el-popover>
|
></promql-input>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="chart-view right-margin" v-show="!showIntroduce"
|
||||||
<el-date-picker size="mini" ref="calendar"
|
:class="{'shrink-view':!chartVisible || !defaultChartVisible}">
|
||||||
format="yyyy/MM/dd HH:mm"
|
<div class="view-title" @click="changeChartVisible"><i class="el-icon-caret-top"></i> graph</div>
|
||||||
@change="dateChange"
|
<div class="chart-room">
|
||||||
v-model="searchTime"
|
<chart ref="exploreChart"></chart>
|
||||||
type="datetimerange"
|
</div>
|
||||||
:picker-options="pickerOptions"
|
|
||||||
:range-separator="$t('dashboard.panel.to')"
|
|
||||||
:start-placeholder="$t('dashboard.panel.startTime')"
|
|
||||||
:end-placeholder="$t('dashboard.panel.endTime')"
|
|
||||||
style="margin-right: 20px"
|
|
||||||
align="right">
|
|
||||||
</el-date-picker>
|
|
||||||
</div>
|
|
||||||
<div class="expression-room">
|
|
||||||
<!--坑,这个index居然是从1开始-->
|
|
||||||
<promql-input
|
|
||||||
v-for="index of promqlKeys.length"
|
|
||||||
:id="promqlKeys[index-1]"
|
|
||||||
:key="promqlKeys[index-1]"
|
|
||||||
:expression-list="expressions"
|
|
||||||
:index="index"
|
|
||||||
@change="expressionChange"
|
|
||||||
@addExpression="addExpression"
|
|
||||||
@removeExpression="removeExpression"
|
|
||||||
></promql-input>
|
|
||||||
</div>
|
|
||||||
<div class="chart-view " v-show="!showIntroduce"
|
|
||||||
:class="{'shrink-view':!chartVisible || !defaultChartVisible}">
|
|
||||||
<div class="view-title" @click="changeChartVisible"><i class="el-icon-caret-top"></i> graph</div>
|
|
||||||
<div class="chart-room">
|
|
||||||
<chart ref="exploreChart"></chart>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="table-view right-margin" v-show="!showIntroduce"
|
||||||
<div class="table-view " v-show="!showIntroduce"
|
:class="{'shrink-view':!tableVisible || !defaultTableVisible}">
|
||||||
:class="{'shrink-view':!tableVisible || !defaultTableVisible}">
|
<div class="view-title" @click="changeTableVisible"><i class="el-icon-caret-top"></i> table</div>
|
||||||
<div class="view-title" @click="changeTableVisible"><i class="el-icon-caret-top"></i> table</div>
|
<div class="table-room">
|
||||||
<div class="table-room">
|
<el-table class="nz-table explore-table"
|
||||||
<el-table class="nz-table explore-table"
|
:data="tableData"
|
||||||
:data="tableData"
|
border
|
||||||
border
|
ref="exploreTable"
|
||||||
ref="exploreTable"
|
tooltip-effect="light"
|
||||||
tooltip-effect="light"
|
v-scrollBar:el-table="'large'"
|
||||||
v-scrollBar:el-table="'large'"
|
v-loading="tableLoading"
|
||||||
v-loading="tableLoading"
|
style="width: 100%;">
|
||||||
style="width: 100%;">
|
<el-table-column
|
||||||
<el-table-column
|
:resizable="false"
|
||||||
:resizable="false"
|
v-for="(item, index) in showTableLabels"
|
||||||
v-for="(item, index) in showTableLabels"
|
v-if="item.show"
|
||||||
v-if="item.show"
|
:key="`col-${index}`"
|
||||||
:key="`col-${index}`"
|
:label="item.label"
|
||||||
:label="item.label"
|
:prop="item.prop"
|
||||||
:prop="item.prop"
|
show-overflow-tooltip
|
||||||
show-overflow-tooltip
|
min-width="110px"
|
||||||
min-width="110px"
|
></el-table-column>
|
||||||
></el-table-column>
|
<el-table-column width="28" v-if="showTableLabels.length>0">
|
||||||
<el-table-column width="28">
|
<template slot="header" slot-scope="scope" :resizable="false">
|
||||||
<template slot="header" slot-scope="scope" :resizable="false">
|
|
||||||
<span @click.stop="elementsetShow('shezhi',$event)" class="nz-table-gear">
|
<span @click.stop="elementsetShow('shezhi',$event)" class="nz-table-gear">
|
||||||
<i class="nz-icon nz-icon-gear"></i>
|
<i class="nz-icon nz-icon-gear"></i>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination :page-obj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"
|
<pagination :page-obj="pageObj" @pageNo='pageNo' @pageSize='pageSize' ref="Pagination"
|
||||||
:append-to-body="false"></pagination>
|
:append-to-body="false"></pagination>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="introduce-view right-margin" v-show="showIntroduce">
|
||||||
<div class="introduce-view" v-show="showIntroduce">
|
<div class="info-room">
|
||||||
<div class="info-room">
|
<div class="col-md-9 doc-content">
|
||||||
<div class="col-md-9 doc-content">
|
<h2 >
|
||||||
<h2 >
|
Simple time series selection
|
||||||
Simple time series selection
|
</h2>
|
||||||
</h2>
|
|
||||||
|
|
||||||
<p>Return all time series with the metric <code>http_requests_total</code>:</p>
|
<p>Return all time series with the metric <code>http_requests_total</code>:</p>
|
||||||
|
|
||||||
<pre><code>http_requests_total</code></pre>
|
<pre><code>http_requests_total</code></pre>
|
||||||
|
|
||||||
<p>Return all time series with the metric <code>http_requests_total</code> and the given<code>job</code> and <code>handler</code> labels:</p>
|
<p>Return all time series with the metric <code>http_requests_total</code> and the given<code>job</code> and <code>handler</code> labels:</p>
|
||||||
|
|
||||||
<pre><code>http_requests_total{job="apiserver", handler="/api/comments"}</code></pre>
|
<pre><code>http_requests_total{job="apiserver", handler="/api/comments"}</code></pre>
|
||||||
|
|
||||||
<p>Return a whole range of time (in this case 5 minutes) for the same vector,
|
<p>Return a whole range of time (in this case 5 minutes) for the same vector,
|
||||||
making it a range vector:</p>
|
making it a range vector:</p>
|
||||||
|
|
||||||
<pre><code>http_requests_total{job="apiserver", handler="/api/comments"}[5m]</code></pre>
|
<pre><code>http_requests_total{job="apiserver", handler="/api/comments"}[5m]</code></pre>
|
||||||
|
|
||||||
<p>Note that an expression resulting in a range vector cannot be graphed directly,
|
<p>Note that an expression resulting in a range vector cannot be graphed directly,
|
||||||
but viewed in the tabular ("Console") view of the expression browser.</p>
|
but viewed in the tabular ("Console") view of the expression browser.</p>
|
||||||
|
|
||||||
<p>Using regular expressions, you could select time series only for jobs whose
|
<p>Using regular expressions, you could select time series only for jobs whose
|
||||||
name match a certain pattern, in this case, all jobs that end with <code>server</code>:</p>
|
name match a certain pattern, in this case, all jobs that end with <code>server</code>:</p>
|
||||||
|
|
||||||
<pre><code>http_requests_total{job=~".*server"}</code></pre>
|
<pre><code>http_requests_total{job=~".*server"}</code></pre>
|
||||||
|
|
||||||
<p>All regular expressions in Prometheus use RE2 syntax.</p>
|
<p>All regular expressions in Prometheus use RE2 syntax.</p>
|
||||||
|
|
||||||
<p>To select all HTTP status codes except 4xx ones, you could run:</p>
|
<p>To select all HTTP status codes except 4xx ones, you could run:</p>
|
||||||
|
|
||||||
<pre><code>http_requests_total{status!~"4.."}</code></pre>
|
<pre><code>http_requests_total{status!~"4.."}</code></pre>
|
||||||
|
|
||||||
<h2 >
|
<h2 >
|
||||||
Subquery
|
Subquery
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p>Return the 5-minute rate of the <code>http_requests_total</code> metric for the past 30 minutes, with a resolution of 1 minute.</p>
|
<p>Return the 5-minute rate of the <code>http_requests_total</code> metric for the past 30 minutes, with a resolution of 1 minute.</p>
|
||||||
|
|
||||||
<pre><code>rate(http_requests_total[5m])[30m:1m]</code></pre>
|
<pre><code>rate(http_requests_total[5m])[30m:1m]</code></pre>
|
||||||
|
|
||||||
<p>This is an example of a nested subquery. The subquery for the <code>deriv</code> function uses the default resolution. Note that using subqueries unnecessarily is unwise.</p>
|
<p>This is an example of a nested subquery. The subquery for the <code>deriv</code> function uses the default resolution. Note that using subqueries unnecessarily is unwise.</p>
|
||||||
|
|
||||||
<pre><code>max_over_time(deriv(rate(distance_covered_total[5s])[30s:5s])[10m:])</code></pre>
|
<pre><code>max_over_time(deriv(rate(distance_covered_total[5s])[30s:5s])[10m:])</code></pre>
|
||||||
|
|
||||||
<h2 >
|
<h2 >
|
||||||
Using functions, operators, etc.
|
Using functions, operators, etc.
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p>Return the per-second rate for all time series with the <code>http_requests_total</code>
|
<p>Return the per-second rate for all time series with the <code>http_requests_total</code>
|
||||||
metric name, as measured over the last 5 minutes:</p>
|
metric name, as measured over the last 5 minutes:</p>
|
||||||
|
|
||||||
<pre><code>rate(http_requests_total[5m])</code></pre>
|
<pre><code>rate(http_requests_total[5m])</code></pre>
|
||||||
|
|
||||||
<p>Assuming that the <code>http_requests_total</code> time series all have the labels <code>job</code>
|
<p>Assuming that the <code>http_requests_total</code> time series all have the labels <code>job</code>
|
||||||
(fanout by job name) and <code>instance</code> (fanout by instance of the job), we might
|
(fanout by job name) and <code>instance</code> (fanout by instance of the job), we might
|
||||||
want to sum over the rate of all instances, so we get fewer output time series,
|
want to sum over the rate of all instances, so we get fewer output time series,
|
||||||
but still preserve the <code>job</code> dimension:</p>
|
but still preserve the <code>job</code> dimension:</p>
|
||||||
|
|
||||||
<pre><code>sum by (job) (rate(http_requests_total[5m]))</code></pre>
|
<pre><code>sum by (job) (rate(http_requests_total[5m]))</code></pre>
|
||||||
|
|
||||||
<p>If we have two different metrics with the same dimensional labels, we can apply
|
<p>If we have two different metrics with the same dimensional labels, we can apply
|
||||||
binary operators to them and elements on both sides with the same label set
|
binary operators to them and elements on both sides with the same label set
|
||||||
will get matched and propagated to the output. For example, this expression
|
will get matched and propagated to the output. For example, this expression
|
||||||
returns the unused memory in MiB for every instance (on a fictional cluster
|
returns the unused memory in MiB for every instance (on a fictional cluster
|
||||||
scheduler exposing these metrics about the instances it runs):</p>
|
scheduler exposing these metrics about the instances it runs):</p>
|
||||||
|
|
||||||
<pre><code>(instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024</code></pre>
|
<pre><code>(instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024</code></pre>
|
||||||
|
|
||||||
<p>The same expression, but summed by application, could be written like this:</p>
|
<p>The same expression, but summed by application, could be written like this:</p>
|
||||||
|
|
||||||
<pre><code>sum by (app, proc) (instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024</code></pre>
|
<pre><code>sum by (app, proc) (instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024</code></pre>
|
||||||
|
|
||||||
<p>If the same fictional cluster scheduler exposed CPU usage metrics like the following for every instance:</p>
|
<p>If the same fictional cluster scheduler exposed CPU usage metrics like the following for every instance:</p>
|
||||||
|
|
||||||
<pre><code>instance_cpu_time_ns{app="lion", proc="web", rev="34d0f99", env="prod", job="cluster-manager"}
|
<pre><code>instance_cpu_time_ns{app="lion", proc="web", rev="34d0f99", env="prod", job="cluster-manager"}
|
||||||
instance_cpu_time_ns{app="elephant", proc="worker", rev="34d0f99", env="prod", job="cluster-manager"}
|
instance_cpu_time_ns{app="elephant", proc="worker", rev="34d0f99", env="prod", job="cluster-manager"}
|
||||||
instance_cpu_time_ns{app="turtle", proc="api", rev="4d3a513", env="prod", job="cluster-manager"}
|
instance_cpu_time_ns{app="turtle", proc="api", rev="4d3a513", env="prod", job="cluster-manager"}
|
||||||
instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="cluster-manager"}
|
instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="cluster-manager"}
|
||||||
...
|
...
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
<p>...we could get the top 3 CPU users grouped by application (<code>app</code>) and process type (<code>proc</code>) like this:</p>
|
<p>...we could get the top 3 CPU users grouped by application (<code>app</code>) and process type (<code>proc</code>) like this:</p>
|
||||||
|
|
||||||
<pre><code>topk(3, sum by (app, proc) (rate(instance_cpu_time_ns[5m])))</code></pre>
|
<pre><code>topk(3, sum by (app, proc) (rate(instance_cpu_time_ns[5m])))</code></pre>
|
||||||
|
|
||||||
<p>Assuming this metric contains one time series per running instance, you could count the number of running instances per application like this:</p>
|
<p>Assuming this metric contains one time series per running instance, you could count the number of running instances per application like this:</p>
|
||||||
|
|
||||||
<pre><code>count by (app) (instance_cpu_time_ns)</code></pre>
|
<pre><code>count by (app) (instance_cpu_time_ns)</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<chart-box ref="addChartModal" :panel-data="panelData" @on-create-success="createSuccess"></chart-box>
|
<chart-box ref="addChartModal" :panel-data="panelData" @on-create-success="createSuccess"></chart-box>
|
||||||
<element-set
|
<element-set
|
||||||
@@ -235,9 +209,7 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
promqlCount: 1,
|
promqlCount: 1,
|
||||||
promqlKeys: [],
|
promqlKeys: [],
|
||||||
expressions: [''],
|
expressions: [''],
|
||||||
searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
|
filterTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
|
||||||
filterTime: {},
|
|
||||||
visible: false,
|
|
||||||
showIntroduce: true,
|
showIntroduce: true,
|
||||||
defaultChartVisible: true,
|
defaultChartVisible: true,
|
||||||
defaultTableVisible: true,
|
defaultTableVisible: true,
|
||||||
@@ -253,112 +225,11 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
tableLabels: [],
|
tableLabels: [],
|
||||||
showTableLabels: [],
|
showTableLabels: [],
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
intervalTimer: null,
|
|
||||||
intervalList: [{
|
|
||||||
value: 0,
|
|
||||||
name: this.$t("dashboard.panel.refreshInterval.never"),
|
|
||||||
}, {
|
|
||||||
value: 60,
|
|
||||||
name: this.$t("dashboard.panel.refreshInterval.oneMinute"),
|
|
||||||
}, {
|
|
||||||
value: 180,
|
|
||||||
name: this.$t("dashboard.panel.refreshInterval.threeMinutes"),
|
|
||||||
}, {
|
|
||||||
value: 300,
|
|
||||||
name: this.$t("dashboard.panel.refreshInterval.fiveMinutes"),
|
|
||||||
}, {
|
|
||||||
value: 600,
|
|
||||||
name: this.$t("dashboard.panel.refreshInterval.tenMinutes"),
|
|
||||||
}],
|
|
||||||
interval: 0,
|
|
||||||
saveDisabled: true,
|
saveDisabled: true,
|
||||||
panelData: [],
|
panelData: [],
|
||||||
pickerOptions: {
|
|
||||||
shortcuts: [
|
|
||||||
{
|
|
||||||
text: this.$t("dashboard.panel.recOne"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setHours(start.getHours() - 1);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.recFour"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setHours(start.getHours() - 4);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.recOneDay"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setDate(start.getDate() - 1);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.yesterday"),
|
|
||||||
onClick(picker) {
|
|
||||||
const start = new Date();
|
|
||||||
const end = new Date();
|
|
||||||
start.setDate(start.getDate() - 1);
|
|
||||||
start.setHours(0);
|
|
||||||
start.setMinutes(0);
|
|
||||||
start.setSeconds(0);
|
|
||||||
end.setDate(end.getDate() - 1);
|
|
||||||
end.setHours(23);
|
|
||||||
end.setMinutes(59);
|
|
||||||
end.setSeconds(59);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.recSevenDay"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setDate(start.getDate() - 7);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.recOneMonth"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setDate(start.getDate() - 30);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.curMonth"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setDate(1);
|
|
||||||
start.setHours(0);
|
|
||||||
start.setMinutes(0);
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
text: this.$t("dashboard.panel.lastMonth"),
|
|
||||||
onClick(picker) {
|
|
||||||
const end = new Date();
|
|
||||||
const start = new Date();
|
|
||||||
start.setDate(1);
|
|
||||||
start.setMonth(start.getMonth() - 1);
|
|
||||||
end.setDate(0);
|
|
||||||
start.setStart();
|
|
||||||
end.setEnd();
|
|
||||||
picker.$emit('pick', [start, end]);
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.filterTime.startTime = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss');
|
|
||||||
this.filterTime.endTime = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss');
|
|
||||||
this.getPanelData();
|
this.getPanelData();
|
||||||
this.promqlKeys.push(this.guid());
|
this.promqlKeys.push(this.guid());
|
||||||
},
|
},
|
||||||
@@ -381,7 +252,8 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
let requestArr = [];
|
let requestArr = [];
|
||||||
this.expressions.forEach((item, index) => {
|
this.expressions.forEach((item, index) => {
|
||||||
if (item != '') {
|
if (item != '') {
|
||||||
requestArr.push(axios.get('/prom/api/v1/query_range?query=' + item + '&start=' + this.filterTime.startTime + '&end=' + this.filterTime.endTime + '&step=15'))
|
let step=bus.getStep(this.filterTime[0],this.filterTime[1]);
|
||||||
|
requestArr.push(axios.get('/prom/api/v1/query_range?query=' + item + '&start=' + this.filterTime[0] + '&end=' + this.filterTime[1] + '&step='+step))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (requestArr.length > 0) {
|
if (requestArr.length > 0) {
|
||||||
@@ -500,47 +372,15 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
this.promqlCount++;
|
this.promqlCount++;
|
||||||
},
|
},
|
||||||
removeExpression: function (index) {
|
removeExpression: function (index) {
|
||||||
|
console.log(this.expressions)
|
||||||
|
console.log(this.promqlKeys)
|
||||||
|
console.log(this.promqlCount)
|
||||||
if (this.promqlCount > 1) {
|
if (this.promqlCount > 1) {
|
||||||
this.expressions.splice(index, 1);
|
this.expressions.splice(index, 1);
|
||||||
this.promqlKeys.splice(index, 1);
|
this.promqlKeys.splice(index, 1);
|
||||||
this.promqlCount--;
|
this.promqlCount--;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dateChange(time) {
|
|
||||||
this.filterTime.startTime = bus.timeFormate(time[0], 'yyyy-MM-dd hh:mm:ss');
|
|
||||||
this.filterTime.endTime = bus.timeFormate(time[1], 'yyyy-MM-dd hh:mm:ss');
|
|
||||||
this.expressionChange();
|
|
||||||
},
|
|
||||||
//定期刷新
|
|
||||||
selectInterval(val) {
|
|
||||||
this.visible = false;
|
|
||||||
clearInterval(this.intervalTimer);
|
|
||||||
if (val) {
|
|
||||||
this.interval = val;
|
|
||||||
const start = new Date(this.searchTime[1]);
|
|
||||||
const now = new Date();
|
|
||||||
const interval = Math.floor((now.getTime() - start.getTime()) / 1000); //计算当前结束时间到现在的间隔(秒)
|
|
||||||
if (interval >= 60) { //如果结束时间到现在超过1分钟,则
|
|
||||||
this.getIntervalData(interval);
|
|
||||||
}
|
|
||||||
this.intervalTimer = setInterval(() => {
|
|
||||||
this.getIntervalData(this.interval);
|
|
||||||
}, val * 1000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getIntervalData(interval) { //interval:结束时间到现在的秒数
|
|
||||||
const start = new Date(this.searchTime[0]);
|
|
||||||
const end = new Date(this.searchTime[1]);
|
|
||||||
start.setSeconds(start.getSeconds() + interval);
|
|
||||||
end.setSeconds(end.getSeconds() + interval);
|
|
||||||
const startTime = bus.timeFormate(start, 'yyyy-MM-dd hh:mm');
|
|
||||||
const endTime = bus.timeFormate(end, 'yyyy-MM-dd hh:mm');
|
|
||||||
this.searchTime = [startTime, endTime];
|
|
||||||
this.filterTime.startTime = startTime;
|
|
||||||
this.filterTime.endTime = endTime;
|
|
||||||
//刷新数据
|
|
||||||
this.expressionChange();
|
|
||||||
},
|
|
||||||
changeChartVisible: function () {
|
changeChartVisible: function () {
|
||||||
this.chartVisible = !this.chartVisible;
|
this.chartVisible = !this.chartVisible;
|
||||||
},
|
},
|
||||||
@@ -708,7 +548,6 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
background-color: #e9edf2;
|
background-color: #e9edf2;
|
||||||
border-top: 3px solid #3274d9;
|
border-top: 3px solid #3274d9;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
margin-right: 4px;
|
|
||||||
-webkit-box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1);
|
-webkit-box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1);
|
||||||
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1);
|
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1);
|
||||||
-webkit-box-flex: 1;
|
-webkit-box-flex: 1;
|
||||||
@@ -733,17 +572,9 @@ instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="c
|
|||||||
border: 1px solid #c7d0d9;
|
border: 1px solid #c7d0d9;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
.right-margin{
|
||||||
.popover_ul li {
|
margin-right: 15px;
|
||||||
padding: 10px 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover_ul li:hover {
|
|
||||||
background: $dropdown-hover-background-color !important;
|
|
||||||
color: $global-text-color-active !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*外部引用 样式start*/
|
/*外部引用 样式start*/
|
||||||
.doc-content {
|
.doc-content {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|||||||
@@ -457,15 +457,18 @@
|
|||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
detailProjectInfo:function(event,project){
|
detailProjectInfo:function(event,project){
|
||||||
|
console.log(event)
|
||||||
if(event){
|
if(event){
|
||||||
this.pageType='project'
|
this.pageType='project'
|
||||||
if(project){
|
if(project){
|
||||||
this.currentProject=project;
|
this.currentProject=project;
|
||||||
this.$store.commit('setProject',this.currentProject)
|
// this.$store.commit('setProject',this.currentProject)
|
||||||
}
|
}
|
||||||
this.currentModule={};
|
this.currentModule={};
|
||||||
this.currentProjectTitle=this.currentProject.name+"-"+this.currentProject.id
|
|
||||||
// this.$refs.projectLeft.setActiveNames([]);
|
// this.$refs.projectLeft.setActiveNames([]);
|
||||||
|
}else{
|
||||||
|
this.currentProjectTitle=this.currentProject.name+"-"+this.currentProject.id
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getAllModuleList:function(){
|
getAllModuleList:function(){
|
||||||
@@ -744,7 +747,7 @@
|
|||||||
if (pageSize) {
|
if (pageSize) {
|
||||||
this.endpointPageObj.pageSize = pageSize
|
this.endpointPageObj.pageSize = pageSize
|
||||||
}
|
}
|
||||||
this.detailProjectInfo({});
|
this.detailProjectInfo();
|
||||||
// setTimeout(()=>{
|
// setTimeout(()=>{
|
||||||
// this.getEndpointTableData();
|
// this.getEndpointTableData();
|
||||||
// }, 200);
|
// }, 200);
|
||||||
@@ -794,7 +797,7 @@
|
|||||||
currentProjectChange:{
|
currentProjectChange:{
|
||||||
handler(n, o) {
|
handler(n, o) {
|
||||||
this.currentProject = Object.assign({}, n);
|
this.currentProject = Object.assign({}, n);
|
||||||
this.detailProjectInfo({});
|
this.detailProjectInfo();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
currentProject(n, o) {
|
currentProject(n, o) {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import "perfect-scrollbar/css/perfect-scrollbar.css";
|
|||||||
import loading from "./components/common/loading";
|
import loading from "./components/common/loading";
|
||||||
import mibBox from "./components/common/rightBox/mibBox";
|
import mibBox from "./components/common/rightBox/mibBox";
|
||||||
import leftMenu from "./components/common/leftMenu";
|
import leftMenu from "./components/common/leftMenu";
|
||||||
|
import intervalRefresh from "./components/common/intervalRefresh";
|
||||||
|
|
||||||
Vue.component("Pagination", Pagination);
|
Vue.component("Pagination", Pagination);
|
||||||
Vue.component("searchInput", searchInput);
|
Vue.component("searchInput", searchInput);
|
||||||
@@ -69,6 +70,7 @@ Vue.component('loading',loading);
|
|||||||
Vue.component('bottom-box', bottomBox);
|
Vue.component('bottom-box', bottomBox);
|
||||||
Vue.component('mib-box',mibBox);
|
Vue.component('mib-box',mibBox);
|
||||||
Vue.component('left-menu',leftMenu);
|
Vue.component('left-menu',leftMenu);
|
||||||
|
Vue.component('interval-refresh',intervalRefresh);
|
||||||
|
|
||||||
Vue.prototype.$axios = axios;
|
Vue.prototype.$axios = axios;
|
||||||
Vue.prototype.$post = post;
|
Vue.prototype.$post = post;
|
||||||
|
|||||||
Reference in New Issue
Block a user