release v5.0.0-rc1 (#708)

* release v5.0.0-rc1
This commit is contained in:
qinyening 2021-06-28 00:42:39 +08:00 committed by GitHub
parent 2ef9a77325
commit 4e6e70c14d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5468 changed files with 13791 additions and 1409102 deletions

View File

@ -23,4 +23,4 @@ jobs:
uses: actions/checkout@v2
- name: Build
run: ./control build
run: ./build.sh

13
.gitignore vendored
View File

@ -26,27 +26,24 @@ _test
/log*
/bin
/out
/meta
/pub
/build
/dist
/etc/*.local.yml
/etc/plugins/*.local.yml
/etc/log/log.test.json
/data*
/tarball
/run
/vendor
/tmp
/pub
.alerts
.idea
.index
.vscode
.DS_Store
.cache-loader
queries.active
/n9e-*
tmp/
main
Makefile
src/modules/monapi/plugins/snmp/
src/modules/monapi/plugins/oracle/

View File

@ -1,6 +1,5 @@
- 官网:[n9e.didiyun.com](https://n9e.didiyun.com/) 右上角切换版本当下是v46月底7月初发布v5没有上生产的用户建议等v5
- 官网:[n9e.didiyun.com](https://n9e.didiyun.com/) 右上角切换版本
- 招聘前后端都要base北京薪资open可将简历发至邮箱 `echo cWlueWVuaW5nQGRpZGlnbG9iYWwuY29t | base64 -d` 一起来做开源
- 加群加入网友互助交流群和IT同仁一起交流运维监控扫描如下二维码加小助手微信备注“夜莺加群”小助手会拉你入群
<img src="https://s3-gz01.didistatic.com/n9e-pub/image/n9e-invite.png" width="250" alt="Nightingale"/>
<img src="https://s3-gz01.didistatic.com/n9e-pub/image/n9e-invite.png" width="250" alt="Nightingale"/>

7
alert/alert.go Normal file
View File

@ -0,0 +1,7 @@
package alert
import "context"
func Start(ctx context.Context) {
go popEvent()
}

293
alert/consume.go Normal file
View File

@ -0,0 +1,293 @@
package alert
import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"sort"
"strconv"
"strings"
"time"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/judge"
"github.com/didi/nightingale/v5/models"
"github.com/toolkits/pkg/concurrent/semaphore"
"github.com/toolkits/pkg/logger"
"github.com/toolkits/pkg/net/httplib"
"github.com/toolkits/pkg/sys"
)
func popEvent() {
sema := semaphore.NewSemaphore(config.Config.Alert.NotifyConcurrency)
duration := time.Duration(100) * time.Millisecond
for {
events := judge.EventQueue.PopBackBy(200)
if len(events) < 1 {
time.Sleep(duration)
continue
}
consume(events, sema)
}
}
func consume(events []interface{}, sema *semaphore.Semaphore) {
for i := range events {
if events[i] == nil {
continue
}
event := events[i].(*models.AlertEvent)
alertRule, exists := cache.AlertRules.Get(event.RuleId)
if !exists {
logger.Errorf("event_consume: alert rule not found, event:%+v", event)
continue
}
logger.Debugf("[event_consume_success][type:%v][event:%+v]", event.IsPromePull, event)
if isNoneffective(event, alertRule) {
// 告警规则非生效时段
continue
}
event.RuleName = alertRule.Name
event.RuleNote = alertRule.Note
event.NotifyChannels = alertRule.NotifyChannels
classpaths := cache.ResClasspath.GetValues(event.ResIdent)
event.ResClasspaths = strings.Join(classpaths, " ")
enrichTag(event, alertRule)
if isEventMute(event) {
// 被屏蔽的事件
event.MarkMuted()
if config.Config.Alert.MutedAlertPersist {
err := event.Add()
if err != nil {
logger.Warningf("event_consume: insert muted event err:%v, event:%+v", err, event)
}
}
continue
}
// 操作数据库
persist(event)
// 不管是告警还是恢复,都触发回调,接收端自己处理
if alertRule.Callbacks != "" {
go callback(event, alertRule)
}
uids := genNotifyUserIDs(alertRule)
if len(uids) == 0 {
logger.Warningf("event_consume: notify users not found, event:%+v", event)
continue
}
users := cache.UserCache.GetByIds(uids)
if len(users) == 0 {
logger.Warningf("event_consume: notify users not found, event:%+v", event)
continue
}
alertMsg := AlertMsg{
Event: event,
Rule: alertRule,
Users: users,
}
logger.Infof("event_consume: notify alert:%+v", alertMsg)
sema.Acquire()
go func(alertMsg AlertMsg) {
defer sema.Release()
notify(alertMsg)
}(alertMsg)
}
}
func genNotifyUserIDs(alertRule *models.AlertRule) []int64 {
uidMap := make(map[int64]struct{})
groupIds := strings.Fields(alertRule.NotifyGroups)
for _, groupId := range groupIds {
gid, err := strconv.ParseInt(groupId, 10, 64)
if err != nil {
logger.Warningf("event_consume: strconv groupid(%s) fail: %v", groupId, err)
continue
}
um, exists := cache.UserGroupMember.Get(gid)
if !exists {
continue
}
for uid := range um {
uidMap[uid] = struct{}{}
}
}
userIds := strings.Fields(alertRule.NotifyUsers)
for _, userId := range userIds {
uid, err := strconv.ParseInt(userId, 10, 64)
if err != nil {
logger.Warningf("event_consume: strconv userid(%s) fail: %v", userId, err)
continue
}
uidMap[uid] = struct{}{}
}
uids := make([]int64, 0, len(uidMap))
for uid := range uidMap {
uids = append(uids, uid)
}
return uids
}
// 如果是告警,就存库,如果是恢复,就从未恢复的告警表里删除
func persist(event *models.AlertEvent) {
if event.IsRecov() {
err := event.DelByHashId()
if err != nil {
logger.Warningf("event_consume: delete recovery event err:%v, event:%+v", err, event)
}
} else {
err := event.Add()
if err != nil {
logger.Warningf("event_consume: insert alert event err:%v, event:%+v", err, event)
}
}
}
type AlertMsg struct {
Event *models.AlertEvent `json:"event"`
Rule *models.AlertRule `json:"rule"`
Users []*models.User `json:"users"`
}
func notify(alertMsg AlertMsg) {
//增加并发控制
bs, err := json.Marshal(alertMsg)
if err != nil {
logger.Errorf("notify: marshal alert %+v err:%v", alertMsg, err)
}
fpath := config.Config.Alert.NotifyScriptPath
cmd := exec.Command(fpath)
cmd.Stdin = bytes.NewReader(bs)
// combine stdout and stderr
var buf bytes.Buffer
cmd.Stdout = &buf
cmd.Stderr = &buf
err = cmd.Start()
if err != nil {
logger.Errorf("notify: run cmd err:%v", err)
return
}
err, isTimeout := sys.WrapTimeout(cmd, time.Duration(10)*time.Second)
if isTimeout {
if err == nil {
logger.Errorf("notify: timeout and killed process %s", fpath)
}
if err != nil {
logger.Errorf("notify: kill process %s occur error %v", fpath, err)
}
return
}
if err != nil {
logger.Errorf("notify: exec script %s occur error: %v", fpath, err)
return
}
logger.Infof("notify: exec %s output: %s", fpath, buf.String())
}
func callback(event *models.AlertEvent, alertRule *models.AlertRule) {
urls := strings.Fields(alertRule.Callbacks)
for _, url := range urls {
if url == "" {
continue
}
if !(strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://")) {
url = "http://" + url
}
resp, code, err := httplib.PostJSON(url, 5*time.Second, event, map[string]string{})
if err != nil {
logger.Errorf("callback[%s] fail, callback content: %+v, resp: %s, err: %v, code:%d", url, event, string(resp), err, code)
} else {
logger.Infof("callback[%s] succ, callback content: %+v, resp: %s, code:%d", url, event, string(resp), code)
}
}
}
func isNoneffective(event *models.AlertEvent, alertRule *models.AlertRule) bool {
// 生效时间过滤
if alertRule.Status == models.ALERT_RULE_DISABLED {
logger.Debugf("event:%+v alert rule:%+v disable", event, alertRule)
return true
}
tm := time.Unix(event.TriggerTime, 0)
triggerTime := tm.Format("15:04")
triggerWeek := strconv.Itoa(int(tm.Weekday()))
if alertRule.EnableStime <= alertRule.EnableEtime {
if triggerTime < alertRule.EnableStime || triggerTime > alertRule.EnableEtime {
logger.Debugf("event:%+v alert rule:%+v triggerTime Noneffective", event, alertRule)
return true
}
} else {
if triggerTime < alertRule.EnableStime && triggerTime > alertRule.EnableEtime {
logger.Debugf("event:%+v alert rule:%+v triggerTime Noneffective", event, alertRule)
return true
}
}
if !strings.Contains(alertRule.EnableDaysOfWeek, triggerWeek) {
logger.Debugf("event:%+v alert rule:%+v triggerWeek Noneffective", event, alertRule)
return true
}
return false
}
// 事件的tags有多种tags组成ident作为一个tag数据本身的tags(前期已经把res的tags也附到数据tags里了)、规则的tags
func enrichTag(event *models.AlertEvent, alertRule *models.AlertRule) {
if event.ResIdent != "" {
event.TagMap["ident"] = event.ResIdent
}
if alertRule.AppendTags != "" {
appendTags := strings.Fields(alertRule.AppendTags)
for _, tag := range appendTags {
arr := strings.Split(tag, "=")
if len(arr) != 2 {
logger.Warningf("alertRule AppendTags:%+v illagel", alertRule.AppendTags)
continue
}
event.TagMap[arr[0]] = arr[1]
}
}
var tagList []string
for key, value := range event.TagMap {
tagList = append(tagList, fmt.Sprintf("%s=%s", key, value))
}
sort.Strings(tagList)
event.Tags = strings.Join(tagList, " ")
}

79
alert/mute.go Normal file
View File

@ -0,0 +1,79 @@
package alert
import (
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
"github.com/toolkits/pkg/logger"
)
func isEventMute(event *models.AlertEvent) bool {
historyPoints, err := event.GetHistoryPoints()
if err != nil {
logger.Errorf("get event HistoryPoints:%+v failed, err: %v", event.HistoryPoints, err)
return false
}
// 先去匹配一下metric为空的mute
if matchMute("", event.ResIdent, event.TagMap) {
return true
}
// 如果是与条件就会有多个metric任一个匹配了屏蔽规则都算被屏蔽
for i := 0; i < len(historyPoints); i++ {
if matchMute(historyPoints[i].Metric, event.ResIdent, event.TagMap) {
return true
}
}
resAndTags, exists := cache.ResTags.Get(event.ResIdent)
if exists {
if event.TriggerTime > resAndTags.Resource.MuteBtime && event.TriggerTime < resAndTags.Resource.MuteEtime {
return true
}
}
return false
}
func matchMute(metric, ident string, tags map[string]string) bool {
filters, exists := cache.AlertMute.GetByKey(metric)
if !exists {
// 没有屏蔽规则跟这个事件相关
return false
}
// 只要有一个屏蔽规则命中,那这个事件就是被屏蔽了
for _, filter := range filters {
if matchMuteOnce(filter, ident, tags) {
return true
}
}
return false
}
func matchMuteOnce(filter cache.Filter, ident string, tags map[string]string) bool {
if filter.ResReg != nil && !filter.ResReg.MatchString(ident) {
// 比如屏蔽规则配置的是c3-ceph.*
// 当前事件的资源标识是c4-ceph01.bj
// 只要有任一点不满足,那这个屏蔽规则也没有继续验证下去的必要
return false
}
// 每个mute中的tags都得出现在event.tags否则就是不匹配
return mapContains(tags, filter.TagsMap)
}
func mapContains(big, small map[string]string) bool {
for tagk, tagv := range small {
val, exists := big[tagk]
if !exists {
return false
}
if val != tagv {
return false
}
}
return true
}

88
backend/datasource.go Normal file
View File

@ -0,0 +1,88 @@
package backend
import (
"fmt"
"github.com/prometheus/prometheus/promql"
"github.com/didi/nightingale/v5/vos"
"github.com/toolkits/pkg/container/list"
pp "github.com/didi/nightingale/v5/backend/prome"
)
type BackendSection struct {
DataSource string `yaml:"datasource"`
Prometheus pp.PromeSection `yaml:"prometheus"`
}
type DataSource interface {
PushEndpoint
QueryData(inputs vos.DataQueryParam) []*vos.DataQueryResp // 查询一段时间
QueryTagKeys(recv vos.CommonTagQueryParam) *vos.TagKeyQueryResp // 获取标签的names
QueryTagValues(recv vos.CommonTagQueryParam) *vos.TagValueQueryResp // 根据一个label_name获取 values
QueryTagPairs(recv vos.CommonTagQueryParam) *vos.TagPairQueryResp // 根据匹配拿到所有 series 上面三个使用统一的结构体
QueryMetrics(recv vos.MetricQueryParam) *vos.MetricQueryResp // 根据标签查 metric_names
QueryVector(ql string) promql.Vector // prometheus pull alert 所用,其他数据源留空即可
CleanUp() // 数据源退出时需要做的清理工作
}
type PushEndpoint interface {
Push2Queue(items []*vos.MetricPoint)
}
var (
defaultDataSource string
registryDataSources = make(map[string]DataSource)
registryPushEndpoints = make(map[string]PushEndpoint)
)
func Init(cfg BackendSection) {
defaultDataSource = cfg.DataSource
// init prometheus
if cfg.Prometheus.Enable {
promeDs := &pp.PromeDataSource{
Section: cfg.Prometheus,
PushQueue: list.NewSafeListLimited(10240000),
}
promeDs.Init()
RegisterDataSource(cfg.Prometheus.Name, promeDs)
}
}
// get backend datasource
// (pluginId == "" for default datasource)
func GetDataSourceFor(pluginId string) (DataSource, error) {
if pluginId == "" {
pluginId = defaultDataSource
}
if source, exists := registryDataSources[pluginId]; exists {
return source, nil
}
return nil, fmt.Errorf("could not find datasource for plugin: %s", pluginId)
}
func DatasourceCleanUp() {
for _, ds := range registryDataSources {
ds.CleanUp()
}
}
// get all push endpoints
func GetPushEndpoints() ([]PushEndpoint, error) {
if len(registryPushEndpoints) > 0 {
items := make([]PushEndpoint, 0, len(registryPushEndpoints))
for _, value := range registryPushEndpoints {
items = append(items, value)
}
return items, nil
}
return nil, fmt.Errorf("could not find any pushendpoint")
}
func RegisterDataSource(pluginId string, datasource DataSource) {
registryDataSources[pluginId] = datasource
registryPushEndpoints[pluginId] = datasource
}

162
backend/prome/convert.go Normal file
View File

@ -0,0 +1,162 @@
package backend
import (
"bufio"
"bytes"
"context"
"io"
"io/ioutil"
"net/http"
"regexp"
"time"
"github.com/gogo/protobuf/proto"
"github.com/golang/snappy"
"github.com/opentracing-contrib/go-stdlib/nethttp"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/prompb"
"github.com/didi/nightingale/v5/vos"
)
var MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`)
type sample struct {
labels labels.Labels
t int64
v float64
}
func labelsToLabelsProto(labels labels.Labels, buf []prompb.Label) []prompb.Label {
result := buf[:0]
if cap(buf) < len(labels) {
result = make([]prompb.Label, 0, len(labels))
}
for _, l := range labels {
result = append(result, prompb.Label{
Name: l.Name,
Value: l.Value,
})
}
return result
}
func (pd *PromeDataSource) convertOne(item *vos.MetricPoint) (prompb.TimeSeries, error) {
pt := prompb.TimeSeries{}
pt.Samples = []prompb.Sample{{}}
s := sample{}
s.t = item.Time
s.v = item.Value
// name
if !MetricNameRE.MatchString(item.Metric) {
return pt, errors.New("invalid metrics name")
}
nameLs := labels.Label{
Name: LABEL_NAME,
Value: item.Metric,
}
s.labels = append(s.labels, nameLs)
if item.Ident != "" {
identLs := labels.Label{
Name: LABEL_IDENT,
Value: item.Ident,
}
s.labels = append(s.labels, identLs)
}
for k, v := range item.TagsMap {
if model.LabelNameRE.MatchString(k) {
ls := labels.Label{
Name: k,
Value: v,
}
s.labels = append(s.labels, ls)
}
}
pt.Labels = labelsToLabelsProto(s.labels, pt.Labels)
// 时间赋值问题,使用毫秒时间戳
tsMs := time.Unix(s.t, 0).UnixNano() / 1e6
pt.Samples[0].Timestamp = tsMs
pt.Samples[0].Value = s.v
return pt, nil
}
type RecoverableError struct {
error
}
func remoteWritePost(c *HttpClient, req []byte) error {
httpReq, err := http.NewRequest("POST", c.url.String(), bytes.NewReader(req))
if err != nil {
// Errors from NewRequest are from unparsable URLs, so are not
// recoverable.
return err
}
httpReq.Header.Add("Content-Encoding", "snappy")
httpReq.Header.Set("Content-Type", "application/x-protobuf")
httpReq.Header.Set("User-Agent", "n9e-v5")
httpReq.Header.Set("X-Prometheus-Remote-Write-Version", "0.1.0")
ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
defer cancel()
httpReq = httpReq.WithContext(ctx)
if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil {
var ht *nethttp.Tracer
httpReq, ht = nethttp.TraceRequest(
parentSpan.Tracer(),
httpReq,
nethttp.OperationName("Remote Store"),
nethttp.ClientTrace(false),
)
defer ht.Finish()
}
httpResp, err := c.Client.Do(httpReq)
if err != nil {
// Errors from Client.Do are from (for example) network errors, so are
// recoverable.
return RecoverableError{err}
}
defer func() {
io.Copy(ioutil.Discard, httpResp.Body)
httpResp.Body.Close()
}()
if httpResp.StatusCode/100 != 2 {
scanner := bufio.NewScanner(io.LimitReader(httpResp.Body, 512))
line := ""
if scanner.Scan() {
line = scanner.Text()
}
err = errors.Errorf("server returned HTTP status %s: %s", httpResp.Status, line)
}
if httpResp.StatusCode/100 == 5 {
return RecoverableError{err}
}
return err
}
func (pd *PromeDataSource) buildWriteRequest(samples []prompb.TimeSeries) ([]byte, error) {
req := &prompb.WriteRequest{
Timeseries: samples,
Metadata: nil,
}
data, err := proto.Marshal(req)
if err != nil {
return nil, err
}
compressed := snappy.Encode(nil, data)
return compressed, nil
}

253
backend/prome/prome.go Normal file
View File

@ -0,0 +1,253 @@
package backend
import (
"io/ioutil"
"net/http"
"net/url"
"os"
"time"
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
config_util "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/common/promlog"
pc "github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/storage/remote"
"github.com/toolkits/pkg/container/list"
"github.com/toolkits/pkg/logger"
"go.uber.org/atomic"
"github.com/didi/nightingale/v5/vos"
)
const (
DefaultPopNum = 1000
)
type PromeSection struct {
Enable bool `yaml:"enable"`
Name string `yaml:"name"`
Batch int `yaml:"batch"`
MaxRetry int `yaml:"maxRetry"`
LookbackDeltaMinute int `yaml:"lookbackDeltaMinute"`
MaxConcurrentQuery int `yaml:"maxConcurrentQuery"`
MaxSamples int `yaml:"maxSamples"`
MaxFetchAllSeriesLimitMinute int64 `yaml:"maxFetchAllSeriesLimitMinute"`
RemoteWrite []RemoteConfig `yaml:"remoteWrite"`
RemoteRead []RemoteConfig `yaml:"remoteRead"`
}
type RemoteConfig struct {
Name string `yaml:"name"`
Url string `yaml:"url"`
RemoteTimeoutSecond int `yaml:"remoteTimeoutSecond"`
}
type PromeDataSource struct {
Section PromeSection
LocalTmpDir string
// 除了promql的查询需要后端存储
Queryable storage.SampleAndChunkQueryable
// promql相关查询
QueryEngine *promql.Engine
PushQueue *list.SafeListLimited
WriteTargets []*HttpClient
}
type safePromQLNoStepSubqueryInterval struct {
value atomic.Int64
}
type HttpClient struct {
remoteName string // Used to differentiate clients in metrics.
url *url.URL
Client *http.Client
timeout time.Duration
}
func durationToInt64Millis(d time.Duration) int64 {
return int64(d / time.Millisecond)
}
func (i *safePromQLNoStepSubqueryInterval) Set(ev model.Duration) {
i.value.Store(durationToInt64Millis(time.Duration(ev)))
}
func (i *safePromQLNoStepSubqueryInterval) Get(int64) int64 {
return i.value.Load()
}
func (pd *PromeDataSource) CleanUp() {
err := os.RemoveAll(pd.LocalTmpDir)
logger.Infof("[remove_prome_tmp_dir_err][dir:%+v][err: %v]", pd.LocalTmpDir, err)
}
func (pd *PromeDataSource) Init() {
// 模拟创建本地存储目录
dbDir, err := ioutil.TempDir("", "tsdb-api-ready")
if err != nil {
logger.Errorf("[error_create_local_tsdb_dir][err: %v]", err)
return
}
pd.LocalTmpDir = dbDir
promlogConfig := promlog.Config{}
// 使用本地目录创建remote-storage
remoteS := remote.NewStorage(promlog.New(&promlogConfig), prometheus.DefaultRegisterer, func() (int64, error) {
return 0, nil
}, dbDir, 1*time.Minute, nil)
// ApplyConfig 加载queryables
remoteReadC := make([]*pc.RemoteReadConfig, 0)
for _, u := range pd.Section.RemoteRead {
ur, err := url.Parse(u.Url)
if err != nil {
logger.Errorf("[prome_ds_init_error][parse_url_error][url:%+v][err:%+v]", u.Url, err)
continue
}
remoteReadC = append(remoteReadC,
&pc.RemoteReadConfig{
URL: &config_util.URL{URL: ur},
RemoteTimeout: model.Duration(time.Duration(u.RemoteTimeoutSecond) * time.Second),
ReadRecent: true,
},
)
}
if len(remoteReadC) == 0 {
logger.Errorf("[prome_ds_error_got_zero_remote_read_storage]")
return
}
err = remoteS.ApplyConfig(&pc.Config{RemoteReadConfigs: remoteReadC})
if err != nil {
logger.Errorf("[error_load_remote_read_config][err: %v]", err)
return
}
pLogger := log.NewNopLogger()
noStepSubqueryInterval := &safePromQLNoStepSubqueryInterval{}
queryQueueDir, err := ioutil.TempDir(dbDir, "prom_query_concurrency")
opts := promql.EngineOpts{
Logger: log.With(pLogger, "component", "query engine"),
Reg: prometheus.DefaultRegisterer,
MaxSamples: pd.Section.MaxSamples,
Timeout: 30 * time.Second,
ActiveQueryTracker: promql.NewActiveQueryTracker(queryQueueDir, pd.Section.MaxConcurrentQuery, log.With(pLogger, "component", "activeQueryTracker")),
LookbackDelta: time.Duration(pd.Section.LookbackDeltaMinute) * time.Minute,
NoStepSubqueryIntervalFn: noStepSubqueryInterval.Get,
EnableAtModifier: true,
}
queryEngine := promql.NewEngine(opts)
pd.QueryEngine = queryEngine
pd.Queryable = remoteS
// 初始化writeClients
if len(pd.Section.RemoteWrite) == 0 {
logger.Warningf("[prome_ds_init_with_zero_RemoteWrite_target]")
logger.Infof("[successfully_init_prometheus_datasource][remote_read_num:%+v][remote_write_num:%+v]",
len(pd.Section.RemoteRead),
len(pd.Section.RemoteWrite),
)
return
}
writeTs := make([]*HttpClient, 0)
for _, u := range pd.Section.RemoteWrite {
ur, err := url.Parse(u.Url)
if err != nil {
logger.Errorf("[prome_ds_init_error][parse_url_error][url:%+v][err:%+v]", u.Url, err)
continue
}
writeTs = append(writeTs,
&HttpClient{
remoteName: u.Name,
url: ur,
Client: &http.Client{},
timeout: time.Duration(u.RemoteTimeoutSecond) * time.Second,
})
}
pd.WriteTargets = writeTs
// 开启prometheus 队列消费协程
go pd.remoteWrite()
logger.Infof("[successfully_init_prometheus_datasource][remote_read_num:%+v][remote_write_num:%+v]",
len(remoteReadC),
len(writeTs),
)
}
func (pd *PromeDataSource) Push2Queue(points []*vos.MetricPoint) {
for _, point := range points {
pt, err := pd.convertOne(point)
if err != nil {
logger.Errorf("[prome_convertOne_error][point: %+v][err:%s]", point, err)
continue
}
ok := pd.PushQueue.PushFront(pt)
if !ok {
logger.Errorf("[prome_push_queue_error][point: %+v] ", point)
}
}
}
func (pd *PromeDataSource) remoteWrite() {
batch := pd.Section.Batch // 一次发送,最多batch条数据
if batch <= 0 {
batch = DefaultPopNum
}
for {
items := pd.PushQueue.PopBackBy(batch)
count := len(items)
if count == 0 {
time.Sleep(time.Millisecond * 100)
continue
}
pbItems := make([]prompb.TimeSeries, count)
for i := 0; i < count; i++ {
pbItems[i] = items[i].(prompb.TimeSeries)
}
payload, err := pd.buildWriteRequest(pbItems)
if err != nil {
logger.Errorf("[prome_remote_write_error][pb_marshal_error][items: %+v][pb.err: %v]: ", items, err)
continue
}
pd.processWrite(payload)
}
}
func (pd *PromeDataSource) processWrite(payload []byte) {
retry := pd.Section.MaxRetry
for _, c := range pd.WriteTargets {
newC := c
go func(cc *HttpClient, payload []byte) {
sendOk := false
var err error
for i := 0; i < retry; i++ {
err := remoteWritePost(cc, payload)
if err == nil {
sendOk = true
break
}
err, ok := err.(RecoverableError)
if !ok {
break
}
logger.Warningf("send prome fail: %v", err)
time.Sleep(time.Millisecond * 100)
}
if !sendOk {
logger.Warningf("send prome finally fail: %v", err)
} else {
logger.Infof("send to prome %s ok", cc.url.String())
}
}(newC, payload)
}
}

642
backend/prome/query.go Normal file
View File

@ -0,0 +1,642 @@
package backend
import (
"context"
"errors"
"fmt"
"math"
"sort"
"strings"
"time"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/storage"
"github.com/toolkits/pkg/logger"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
"github.com/didi/nightingale/v5/vos"
)
const (
LABEL_IDENT = "ident"
LABEL_NAME = "__name__"
DEFAULT_QL = `{__name__=~".*a.*|.*e.*"}`
DEFAULT_STEP = 14
)
type commonQueryObj struct {
Idents []string
TagPairs []*vos.TagPair
Metric string
Start int64
End int64
MetricNameExact bool // metric_name精确匹配在查询看图的时候为true
From string // 调用的来源
}
// 为查询索引或标签相关的转换,大部分都是正则匹配
func convertToPromql(recv *commonQueryObj) string {
qlStr := ""
qlStrFinal := ""
metricName := ""
labelIdent := ""
labelStrSlice := make([]string, 0)
// 匹配metric_name __name__=~"xx.*"
if recv.Metric != "" {
if recv.MetricNameExact {
metricName = fmt.Sprintf(`__name__="%s"`, recv.Metric)
} else {
metricName = fmt.Sprintf(`__name__=~".*%s.*"`, recv.Metric)
}
labelStrSlice = append(labelStrSlice, metricName)
}
// 匹配ident=~"k1.*|k2.*"
for _, i := range recv.Idents {
if i != "" {
labelIdent += fmt.Sprintf(`.*%s.*|`, i)
}
}
labelIdent = strings.TrimRight(labelIdent, "|")
if labelIdent != "" {
labelStrSlice = append(labelStrSlice, fmt.Sprintf(`ident=~"%s"`, labelIdent))
}
// 匹配标签
labelM := make(map[string]string)
for _, i := range recv.TagPairs {
if i.Key == "" {
continue
}
lastStr, _ := labelM[i.Key]
lastStr += fmt.Sprintf(`.*%s.*|`, i.Value)
labelM[i.Key] = lastStr
}
for k, v := range labelM {
thisLabel := strings.TrimRight(v, "|")
labelStrSlice = append(labelStrSlice, fmt.Sprintf(`%s=~"%s"`, k, thisLabel))
}
for _, s := range labelStrSlice {
qlStr += fmt.Sprintf(`%s,`, s)
}
qlStr = strings.TrimRight(qlStr, ",")
qlStrFinal = fmt.Sprintf(`{%s}`, qlStr)
logger.Debugf("[convertToPromql][type=queryLabel][recv:%+v][qlStrFinal:%s]", recv, qlStrFinal)
return qlStrFinal
}
// 查询数据的转换metrics_name和标签都是精确匹配
func convertToPromqlForQueryData(recv *commonQueryObj) string {
qlStr := ""
qlStrFinal := ""
metricName := ""
labelIdent := ""
labelStrSlice := make([]string, 0)
// 匹配metric_name __name__=~"xx.*"
if recv.Metric != "" {
metricName = fmt.Sprintf(`__name__="%s"`, recv.Metric)
labelStrSlice = append(labelStrSlice, metricName)
}
// 匹配ident=~"k1.*|k2.*"
for _, i := range recv.Idents {
if i != "" {
labelIdent += fmt.Sprintf(`%s|`, i)
}
}
labelIdent = strings.TrimRight(labelIdent, "|")
if labelIdent != "" {
labelStrSlice = append(labelStrSlice, fmt.Sprintf(`ident=~"%s"`, labelIdent))
}
// 匹配标签
labelM := make(map[string]string)
for _, i := range recv.TagPairs {
if i.Key == "" {
continue
}
lastStr, _ := labelM[i.Key]
lastStr += fmt.Sprintf(`%s|`, i.Value)
labelM[i.Key] = lastStr
}
for k, v := range labelM {
thisLabel := strings.TrimRight(v, "|")
labelStrSlice = append(labelStrSlice, fmt.Sprintf(`%s=~"%s"`, k, thisLabel))
}
for _, s := range labelStrSlice {
qlStr += fmt.Sprintf(`%s,`, s)
}
qlStr = strings.TrimRight(qlStr, ",")
qlStrFinal = fmt.Sprintf(`{%s}`, qlStr)
logger.Debugf("[convertToPromql][type=queryData][recv:%+v][qlStrFinal:%s]", recv, qlStrFinal)
return qlStrFinal
}
func parseMatchersParam(matchers []string) ([][]*labels.Matcher, error) {
var matcherSets [][]*labels.Matcher
for _, s := range matchers {
matchers, err := parser.ParseMetricSelector(s)
if err != nil {
return nil, err
}
matcherSets = append(matcherSets, matchers)
}
OUTER:
for _, ms := range matcherSets {
for _, lm := range ms {
if lm != nil && !lm.Matches("") {
continue OUTER
}
}
return nil, errors.New("match[] must contain at least one non-empty matcher")
}
return matcherSets, nil
}
func (pd *PromeDataSource) QueryData(inputs vos.DataQueryParam) []*vos.DataQueryResp {
respD := make([]*vos.DataQueryResp, 0)
for _, input := range inputs.Params {
var qlStrFinal string
if input.PromeQl != "" {
qlStrFinal = input.PromeQl
} else {
if len(input.Idents) == 0 {
for i := range input.TagPairs {
if input.TagPairs[i].Key == "ident" {
input.Idents = append(input.Idents, input.TagPairs[i].Value)
}
}
}
if len(input.Idents) == 0 && input.ClasspathId != 0 {
if input.ClasspathPrefix == 0 {
classpathAndRes, exists := cache.ClasspathRes.Get(input.ClasspathId)
if exists {
input.Idents = classpathAndRes.Res
}
} else {
classpath, err := models.ClasspathGet("id=?", input.ClasspathId)
if err != nil {
continue
}
cps, _ := models.ClasspathGetsByPrefix(classpath.Path)
for _, classpath := range cps {
classpathAndRes, exists := cache.ClasspathRes.Get(classpath.Id)
if exists {
idents := classpathAndRes.Res
input.Idents = append(input.Idents, idents...)
}
}
}
}
cj := &commonQueryObj{
Idents: input.Idents,
TagPairs: input.TagPairs,
Metric: input.Metric,
Start: inputs.Start,
End: inputs.End,
MetricNameExact: true,
}
qlStrFinal = convertToPromqlForQueryData(cj)
}
logger.Debugf("[input:%+v][qlStrFinal:%s]\n", input, qlStrFinal)
// 转化为utc时间
startT := tsToUtcTs(inputs.Start)
endT := tsToUtcTs(inputs.End)
// TODO 前端传入分辨率还是后端计算grafana和prometheus ui都是前端传入
delta := (inputs.End - inputs.Start) / 3600
if delta <= 0 {
delta = 1
}
resolution := time.Second * time.Duration(delta*DEFAULT_STEP)
q, err := pd.QueryEngine.NewRangeQuery(pd.Queryable, qlStrFinal, startT, endT, resolution)
if err != nil {
logger.Errorf("[prome_query_error][QueryData_error_may_be_parse_ql_error][args:%+v][err:%+v]", input, err)
continue
}
ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
res := q.Exec(ctx)
// TODO 将err返回给前端
if res.Err != nil {
logger.Errorf("[prome_query_error][rangeQuery_exec_error][args:%+v][err:%+v]", input, res.Err)
q.Close()
continue
}
mat, ok := res.Value.(promql.Matrix)
if !ok {
logger.Errorf("[promql.Engine.exec: invalid expression type %q]", res.Value.Type())
q.Close()
continue
}
if res.Err != nil {
logger.Errorf("[prome_query_error][res.Matrix_error][args:%+v][err:%+v]", input, res.Err)
q.Close()
continue
}
for index, m := range mat {
if inputs.Limit > 0 && index+1 > inputs.Limit {
continue
}
tagStr := ""
oneResp := &vos.DataQueryResp{}
ident := m.Metric.Get(LABEL_IDENT)
name := m.Metric.Get(LABEL_NAME)
oneResp.Metric = name
oneResp.Ident = ident
// TODO 去掉point num
pNum := len(m.Points)
for _, p := range m.Points {
tmpP := &vos.Point{
Timestamp: p.T,
Value: vos.JsonFloat(p.V),
}
oneResp.Values = append(oneResp.Values, tmpP)
}
for _, x := range m.Metric {
if x.Name == LABEL_NAME {
continue
}
tagStr += fmt.Sprintf("%s=%s,", x.Name, x.Value)
}
tagStr = strings.TrimRight(tagStr, ",")
oneResp.Tags = tagStr
oneResp.Resolution = delta * DEFAULT_STEP
oneResp.PNum = pNum
respD = append(respD, oneResp)
}
q.Close()
}
return respD
}
func tsToUtcTs(s int64) time.Time {
return time.Unix(s, 0).UTC()
}
func timeParse(ts int64) time.Time {
t := float64(ts)
s, ns := math.Modf(t)
ns = math.Round(ns*1000) / 1000
return time.Unix(int64(s), int64(ns*float64(time.Second))).UTC()
}
func millisecondTs(t time.Time) int64 {
return t.Unix()*1000 + int64(t.Nanosecond())/int64(time.Millisecond)
}
func tsToStr(timestamp int64) string {
timeNow := time.Unix(timestamp, 0)
return timeNow.Format("2006-01-02 15:04:05")
}
func (pd *PromeDataSource) CommonQuerySeries(cj *commonQueryObj) storage.SeriesSet {
qlStrFinal := convertToPromql(cj)
if qlStrFinal == "{}" {
qlStrFinal = DEFAULT_QL
reqMinute := (cj.End - cj.Start) / 60
// 如果前端啥都没传要限制下查询series的时间范围防止高基础查询
if reqMinute > pd.Section.MaxFetchAllSeriesLimitMinute {
// 时间超长,用配置文件中的限制一下
now := time.Now().Unix()
cj.End = now
cj.Start = now - pd.Section.MaxFetchAllSeriesLimitMinute*60
logger.Debugf("[CommonQuerySeries.FetchAllSeries.LimitQueryTimeRange][start:%v][end:%v]", cj.Start, cj.End)
}
}
matcherSets, err := parseMatchersParam([]string{qlStrFinal})
if err != nil {
logger.Errorf("[prome_query_error][parse_label_match_error][err:%+v]", err)
return nil
}
now := time.Now().Unix()
if cj.Start == 0 {
cj.Start = now - 60*pd.Section.MaxFetchAllSeriesLimitMinute
}
if cj.End == 0 {
cj.End = now
}
startT := millisecondTs(timeParse(cj.Start))
endT := millisecondTs(timeParse(cj.End))
ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
q, err := pd.Queryable.Querier(ctx, startT, endT)
if err != nil {
logger.Errorf("[prome_query_error][get_querier_errro]")
return nil
}
logger.Debugf("[CommonQuerySeries.Result][from:%s][cj.start_ts:%+v cj.start_str:%+v SelectHints.startT:%+v][cj.end_ts:%+v cj.end_str:%+v SelectHints.endT:%+v][qlStrFinal:%s][cj:%+v]",
cj.From,
cj.Start,
tsToStr(cj.Start),
startT,
cj.End,
tsToStr(cj.End),
endT,
qlStrFinal,
cj,
)
defer q.Close()
hints := &storage.SelectHints{
Start: startT,
End: endT,
Func: "series", // There is no series function, this token is used for lookups that don't need samples.
}
// Get all series which match matchers.
s := q.Select(true, hints, matcherSets[0]...)
return s
}
// 全部转化为 {__name__="a",label_a!="b",label_b=~"d|c",label_c!~"d"}
// 对应prometheus 中的 /api/v1/labels
// TODO 等待prometheus官方对 remote_read label_values 的支持
// Implement: https://github.com/prometheus/prometheus/issues/3351
func (pd *PromeDataSource) QueryTagKeys(recv vos.CommonTagQueryParam) *vos.TagKeyQueryResp {
// TODO 完成标签匹配模式
respD := &vos.TagKeyQueryResp{
Keys: make([]string, 0),
}
labelNamesSet := make(map[string]struct{})
for _, x := range recv.Params {
cj := &commonQueryObj{
Idents: x.Idents,
TagPairs: recv.TagPairs,
Metric: x.Metric,
Start: recv.Start,
End: recv.End,
From: "QueryTagKeys",
}
s := pd.CommonQuerySeries(cj)
if s.Warnings() != nil {
logger.Warningf("[prome_query_error][series_set_iter_error][warning:%+v]", s.Warnings())
}
if err := s.Err(); err != nil {
logger.Errorf("[prome_query_error][series_set_iter_error][err:%+v]", err)
continue
}
for s.Next() {
series := s.At()
for _, lb := range series.Labels() {
if lb.Name == LABEL_NAME {
continue
}
if recv.TagKey != "" {
if !strings.Contains(lb.Name, recv.TagKey) {
continue
}
}
labelNamesSet[lb.Name] = struct{}{}
}
}
}
names := make([]string, 0)
for key := range labelNamesSet {
names = append(names, key)
}
sort.Strings(names)
// 因为map中的key是无序的必须这样才能稳定输出
if recv.Limit > 0 && len(names) > recv.Limit {
names = names[:recv.Limit]
}
respD.Keys = names
return respD
}
// 对应prometheus 中的 /api/v1/label/<label_name>/values
func (pd *PromeDataSource) QueryTagValues(recv vos.CommonTagQueryParam) *vos.TagValueQueryResp {
labelValuesSet := make(map[string]struct{})
for _, x := range recv.Params {
cj := &commonQueryObj{
Idents: x.Idents,
Metric: x.Metric,
TagPairs: recv.TagPairs,
Start: recv.Start,
End: recv.End,
From: "QueryTagValues",
}
s := pd.CommonQuerySeries(cj)
if s.Warnings() != nil {
logger.Warningf("[prome_query_error][series_set_iter_error][warning:%+v]", s.Warnings())
}
if err := s.Err(); err != nil {
logger.Errorf("[prome_query_error][series_set_iter_error][err:%+v]", err)
continue
}
for s.Next() {
series := s.At()
for _, lb := range series.Labels() {
if lb.Name == recv.TagKey {
if recv.TagValue != "" {
if !strings.Contains(lb.Value, recv.TagValue) {
continue
}
}
labelValuesSet[lb.Value] = struct{}{}
}
}
}
}
vals := make([]string, 0)
for val := range labelValuesSet {
vals = append(vals, val)
}
sort.Strings(vals)
if recv.Limit > 0 && len(vals) > recv.Limit {
vals = vals[:recv.Limit]
}
respD := &vos.TagValueQueryResp{}
respD.Values = vals
return respD
}
// 对应prometheus 中的 /api/v1/label/<label_name>/values label_name == __name__
func (pd *PromeDataSource) QueryMetrics(recv vos.MetricQueryParam) *vos.MetricQueryResp {
cj := &commonQueryObj{
Idents: recv.Idents,
Metric: recv.Metric,
TagPairs: recv.TagPairs,
Start: recv.Start,
End: recv.End,
From: "QueryMetrics",
}
respD := &vos.MetricQueryResp{}
respD.Metrics = make([]string, 0)
s := pd.CommonQuerySeries(cj)
for _, x := range s.Warnings() {
logger.Warningf("[prome_query_error][series_set_iter_error][warning:%+v]\n", x.Error())
}
if err := s.Err(); err != nil {
logger.Errorf("[prome_query_error][series_set_iter_error][err:%+v]", err)
return respD
}
var sets []storage.SeriesSet
sets = append(sets, s)
set := storage.NewMergeSeriesSet(sets, storage.ChainedSeriesMerge)
labelValuesSet := make(map[string]struct{})
//for s.Next() {
for set.Next() {
series := set.At()
for _, lb := range series.Labels() {
if lb.Name == LABEL_NAME {
labelValuesSet[lb.Value] = struct{}{}
}
}
}
vals := make([]string, 0)
for val := range labelValuesSet {
vals = append(vals, val)
}
sort.Strings(vals)
if recv.Limit > 0 && len(vals) > recv.Limit {
vals = vals[:recv.Limit]
}
respD.Metrics = vals
return respD
}
// 对应prometheus 中的 /api/v1/series
func (pd *PromeDataSource) QueryTagPairs(recv vos.CommonTagQueryParam) *vos.TagPairQueryResp {
respD := &vos.TagPairQueryResp{
TagPairs: make([]string, 0),
Idents: make([]string, 0),
}
tps := make(map[string]struct{})
for _, x := range recv.Params {
cj := &commonQueryObj{
Idents: x.Idents,
TagPairs: recv.TagPairs,
Metric: x.Metric,
Start: recv.Start,
End: recv.End,
From: "QueryTagPairs",
}
s := pd.CommonQuerySeries(cj)
if s.Warnings() != nil {
logger.Warningf("[prome_query_error][series_set_iter_error][warning:%+v]", s.Warnings())
}
if err := s.Err(); err != nil {
logger.Errorf("[prome_query_error][series_set_iter_error][err:%+v]", err)
continue
}
var sets []storage.SeriesSet
sets = append(sets, s)
set := storage.NewMergeSeriesSet(sets, storage.ChainedSeriesMerge)
labelIdents := make([]string, 0)
for set.Next() {
series := s.At()
labelsS := series.Labels()
for _, i := range labelsS {
if i.Name == LABEL_NAME {
continue
}
if i.Name == LABEL_IDENT {
labelIdents = append(labelIdents, i.Value)
}
tps[fmt.Sprintf("%s=%s", i.Name, i.Value)] = struct{}{}
}
}
}
newTags := make([]string, 0)
for k := range tps {
newTags = append(newTags, k)
}
sort.Strings(newTags)
if recv.Limit > 0 && len(newTags) > recv.Limit {
newTags = newTags[:recv.Limit]
}
respD.TagPairs = newTags
return respD
}
func (pd *PromeDataSource) QueryVector(ql string) promql.Vector {
t := time.Now()
q, err := pd.QueryEngine.NewInstantQuery(pd.Queryable, ql, t)
if err != nil {
logger.Errorf("[prome_query_error][new_insQuery_error][err:%+v][ql:%+v]", err, ql)
return nil
}
ctx := context.Background()
res := q.Exec(ctx)
if res.Err != nil {
logger.Errorf("[prome_query_error][insQuery_exec_error][err:%+v][ql:%+v]", err, ql)
return nil
}
defer q.Close()
switch v := res.Value.(type) {
case promql.Vector:
return v
case promql.Scalar:
return promql.Vector{promql.Sample{
Point: promql.Point(v),
Metric: labels.Labels{},
}}
default:
logger.Errorf("[prome_query_error][insQuery_res_error rule result is not a vector or scalar][err:%+v][ql:%+v]", err, ql)
return nil
}
}

8
build.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
# release version
version=5.0.0-rc1
export GO111MODULE=on
go build -ldflags "-X main.version=${version}" -o n9e-server main.go

32
cache/alert_mute.go vendored Normal file
View File

@ -0,0 +1,32 @@
package cache
import (
"regexp"
"sync"
)
type AlertMuteMap struct {
sync.RWMutex
Data map[string][]Filter
}
type Filter struct {
ResReg *regexp.Regexp
TagsMap map[string]string
}
var AlertMute = &AlertMuteMap{Data: make(map[string][]Filter)}
func (a *AlertMuteMap) SetAll(m map[string][]Filter) {
a.Lock()
defer a.Unlock()
a.Data = m
}
func (a *AlertMuteMap) GetByKey(key string) ([]Filter, bool) {
a.RLock()
defer a.RUnlock()
value, exists := a.Data[key]
return value, exists
}

75
cache/alert_rule.go vendored Normal file
View File

@ -0,0 +1,75 @@
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
type AlertRulesByMetricCache struct {
sync.RWMutex
Data map[string][]*models.AlertRule // key是metric便于后续检索
MaxUpdateTs int64 // 从数据库拿到的最大update_at
RuleNum int64 // 从数据库中统计到的行数
LastSync int64 // 保存上次全量同步时间
}
var (
AlertRulesByMetric = &AlertRulesByMetricCache{Data: make(map[string][]*models.AlertRule)}
)
func (a *AlertRulesByMetricCache) GetBy(instance string) []*models.AlertRule {
a.RLock()
defer a.RUnlock()
return a.Data[instance]
}
func (a *AlertRulesByMetricCache) SetAll(alertRulesMap map[string][]*models.AlertRule, lastUpdateTs, ruleNum, lastSync int64) {
a.Lock()
defer a.Unlock()
a.Data = alertRulesMap
a.MaxUpdateTs = lastUpdateTs
a.RuleNum = ruleNum
a.LastSync = lastSync
}
type AlertRulesTotalCache struct {
sync.RWMutex
Data map[int64]*models.AlertRule
}
var AlertRules = &AlertRulesTotalCache{Data: make(map[int64]*models.AlertRule)}
func (a *AlertRulesTotalCache) Get(id int64) (*models.AlertRule, bool) {
a.RLock()
defer a.RUnlock()
alertRule, exists := a.Data[id]
return alertRule, exists
}
func (a *AlertRulesTotalCache) SetAll(alertRulesMap map[int64]*models.AlertRule) {
a.Lock()
defer a.Unlock()
a.Data = alertRulesMap
}
// 获取所有PULL型规则的列表
func (a *AlertRulesTotalCache) Pulls() []*models.AlertRule {
a.RLock()
defer a.RUnlock()
cnt := len(a.Data)
ret := make([]*models.AlertRule, 0, cnt)
for _, rule := range a.Data {
if rule.Type == models.PULL {
ret = append(ret, rule)
}
}
return ret
}

7
cache/cache.go vendored Normal file
View File

@ -0,0 +1,7 @@
package cache
import (
cmap "github.com/orcaman/concurrent-map"
)
var MetricDescMapper = cmap.New()

27
cache/classpath_prefix.go vendored Normal file
View File

@ -0,0 +1,27 @@
package cache
import (
"sync"
)
type ClasspathPrefixMap struct {
sync.RWMutex
Data map[int64][]int64
}
var ClasspathPrefix = &ClasspathPrefixMap{Data: make(map[int64][]int64)}
func (c *ClasspathPrefixMap) Get(id int64) ([]int64, bool) {
c.RLock()
defer c.RUnlock()
ids, exists := c.Data[id]
return ids, exists
}
func (c *ClasspathPrefixMap) SetAll(data map[int64][]int64) {
c.Lock()
defer c.Unlock()
c.Data = data
return
}

33
cache/classpath_res.go vendored Normal file
View File

@ -0,0 +1,33 @@
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
type ClasspathResMap struct {
sync.RWMutex
Data map[int64]*ClasspathAndRes
}
type ClasspathAndRes struct {
Res []string
Classpath *models.Classpath
}
// classpath_id -> classpath & res_idents
var ClasspathRes = &ClasspathResMap{Data: make(map[int64]*ClasspathAndRes)}
func (c *ClasspathResMap) Get(id int64) (*ClasspathAndRes, bool) {
c.RLock()
defer c.RUnlock()
resources, exists := c.Data[id]
return resources, exists
}
func (c *ClasspathResMap) SetAll(collectRulesMap map[int64]*ClasspathAndRes) {
c.Lock()
defer c.Unlock()
c.Data = collectRulesMap
}

32
cache/collect_rule.go vendored Normal file
View File

@ -0,0 +1,32 @@
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
type CollectRuleOfIdentMap struct {
sync.RWMutex
Data map[string][]*models.CollectRule
}
var CollectRulesOfIdent = &CollectRuleOfIdentMap{Data: make(map[string][]*models.CollectRule)}
func (c *CollectRuleOfIdentMap) GetBy(ident string) []*models.CollectRule {
c.RLock()
defer c.RUnlock()
return c.Data[ident]
}
func (c *CollectRuleOfIdentMap) Set(node string, collectRules []*models.CollectRule) {
c.Lock()
defer c.Unlock()
c.Data[node] = collectRules
}
func (c *CollectRuleOfIdentMap) SetAll(collectRulesMap map[string][]*models.CollectRule) {
c.Lock()
defer c.Unlock()
c.Data = collectRulesMap
}

76
cache/res_classpath.go vendored Normal file
View File

@ -0,0 +1,76 @@
package cache
import (
"sync"
)
type SafeDoubleMap struct {
sync.RWMutex
M map[string]map[string]struct{}
}
// res_ident -> classpath_path -> struct{}{}
var ResClasspath = &SafeDoubleMap{M: make(map[string]map[string]struct{})}
func (s *SafeDoubleMap) GetKeys() []string {
s.RLock()
defer s.RUnlock()
keys := make([]string, 0, len(s.M))
for key := range s.M {
keys = append(keys, key)
}
return keys
}
func (s *SafeDoubleMap) GetValues(key string) []string {
s.RLock()
defer s.RUnlock()
valueMap, exists := s.M[key]
if !exists {
return []string{}
}
values := make([]string, 0, len(valueMap))
for value := range valueMap {
values = append(values, value)
}
return values
}
func (s *SafeDoubleMap) Exists(key string, value string) bool {
s.RLock()
defer s.RUnlock()
if _, exists := s.M[key]; !exists {
return false
}
if _, exists := s.M[key][value]; !exists {
return false
}
return true
}
func (s *SafeDoubleMap) Set(key string, value string) {
s.Lock()
defer s.Unlock()
if _, exists := s.M[key]; !exists {
s.M[key] = make(map[string]struct{})
}
s.M[key][value] = struct{}{}
}
func (s *SafeDoubleMap) SetAll(data map[string]map[string]struct{}) {
s.Lock()
defer s.Unlock()
s.M = data
}

36
cache/res_tags.go vendored Normal file
View File

@ -0,0 +1,36 @@
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
// resource_ident -> tags_map
// 监控数据上报的时候要把资源的tags附到指标数据上
type ResTagsMap struct {
sync.RWMutex
Data map[string]ResourceAndTags
}
type ResourceAndTags struct {
Tags map[string]string
Resource models.Resource
}
var ResTags = &ResTagsMap{Data: make(map[string]ResourceAndTags)}
func (r *ResTagsMap) SetAll(m map[string]ResourceAndTags) {
r.Lock()
defer r.Unlock()
r.Data = m
}
func (r *ResTagsMap) Get(key string) (ResourceAndTags, bool) {
r.RLock()
defer r.RUnlock()
value, exists := r.Data[key]
return value, exists
}

41
cache/user.go vendored Normal file
View File

@ -0,0 +1,41 @@
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
type UserMap struct {
sync.RWMutex
Data map[int64]*models.User
}
var UserCache = &UserMap{Data: make(map[int64]*models.User)}
func (s *UserMap) GetBy(id int64) *models.User {
s.RLock()
defer s.RUnlock()
return s.Data[id]
}
func (s *UserMap) GetByIds(ids []int64) []*models.User {
s.RLock()
defer s.RUnlock()
var users []*models.User
for _, id := range ids {
if s.Data[id] == nil {
continue
}
users = append(users, s.Data[id])
}
return users
}
func (s *UserMap) SetAll(users map[int64]*models.User) {
s.Lock()
defer s.Unlock()
s.Data = users
}

38
cache/user_group_member.go vendored Normal file
View File

@ -0,0 +1,38 @@
package cache
import (
"sync"
)
type UserGroupMemberMap struct {
sync.RWMutex
Data map[int64]map[int64]struct{}
}
// groupid -> userid
var UserGroupMember = &UserGroupMemberMap{Data: make(map[int64]map[int64]struct{})}
func (m *UserGroupMemberMap) Get(id int64) (map[int64]struct{}, bool) {
m.RLock()
defer m.RUnlock()
ids, exists := m.Data[id]
return ids, exists
}
func (m *UserGroupMemberMap) Exists(gid, uid int64) bool {
m.RLock()
defer m.RUnlock()
uidMap, exists := m.Data[gid]
if !exists {
return false
}
_, exists = uidMap[uid]
return exists
}
func (m *UserGroupMemberMap) SetAll(data map[int64]map[int64]struct{}) {
m.Lock()
defer m.Unlock()
m.Data = data
}

View File

@ -132,7 +132,7 @@
- 服务端模块合并为一个模块
- agentd和server的调用全部走rpc
重新安装:见 https://n9e.didiyun.com/docs/install/binary/
重新安装:见 https://n9e.didiyun.com/v4/docs/install/
升级方法:
- 使用新的etc替换掉原来的etc
@ -145,7 +145,7 @@
升级内容:
- 修复消息通知的问题
重新安装:见 https://n9e.didiyun.com/docs/install/binary/
重新安装:见 https://n9e.didiyun.com/v4/docs/install/
升级方法:
- 将 *.tpl 文件放到 etc/tpl 下
@ -157,7 +157,7 @@
- 优化告警接收人补全逻辑
- 增加pospostgresql监控插件
重新安装:见 https://n9e.didiyun.com/docs/install/binary/
重新安装:见 https://n9e.didiyun.com/v4/docs/install/
升级方法:
- 替换n9e-server n9e-prober
@ -167,4 +167,11 @@
- 修复nodata恢复告警重复问题
升级方法:
- 替换n9e-server
- 替换n9e-server
5.0.0-rc1
升级内容:
- 发布v5预览版
部署方式:
- 见文档 https://n9e.didiyun.com/docs/install/

163
config/config.go Normal file
View File

@ -0,0 +1,163 @@
package config
import (
"bytes"
"fmt"
"net"
"os"
"strings"
"github.com/spf13/viper"
"github.com/toolkits/pkg/file"
"github.com/didi/nightingale/v5/backend"
"github.com/didi/nightingale/v5/models"
"github.com/didi/nightingale/v5/pkg/i18n"
"github.com/didi/nightingale/v5/pkg/iconf"
"github.com/didi/nightingale/v5/pkg/ilog"
)
type ConfigStruct struct {
Logger ilog.Config `yaml:"logger"`
HTTP httpSection `yaml:"http"`
RPC rpcSection `yaml:"rpc"`
LDAP models.LdapSection `yaml:"ldap"`
MySQL models.MysqlSection `yaml:"mysql"`
Heartbeat heartbeatSection `yaml:"heartbeat"`
I18N i18n.Config `yaml:"i18n"`
Judge judgeSection `yaml:"judge"`
Alert alertSection `yaml:"alert"`
Trans transSection `yaml:"trans"`
ContactKeys []contactKey `yaml:"contactKeys"`
NotifyChannels []string `yaml:"notifyChannels"`
}
type alertSection struct {
NotifyScriptPath string `yaml:"notifyScriptPath"`
NotifyConcurrency int `yaml:"notifyConcurrency"`
MutedAlertPersist bool `yaml:"mutedAlertPersist"`
}
type transSection struct {
Enable bool `yaml:"enable"`
Backend backend.BackendSection `yaml:"backend"`
}
type judgeSection struct {
ReadBatch int `yaml:"readBatch"`
ConnTimeout int `yaml:"connTimeout"`
CallTimeout int `yaml:"callTimeout"`
WriterNum int `yaml:"writerNum"`
ConnMax int `yaml:"connMax"`
ConnIdle int `yaml:"connIdle"`
}
type heartbeatSection struct {
IP string `yaml:"ip"`
LocalAddr string `yaml:"-"`
Interval int64 `yaml:"interval"`
}
type httpSection struct {
Mode string `yaml:"mode"`
Access bool `yaml:"access"`
Listen string `yaml:"listen"`
Pprof bool `yaml:"pprof"`
CookieName string `yaml:"cookieName"`
CookieDomain string `yaml:"cookieDomain"`
CookieSecure bool `yaml:"cookieSecure"`
CookieHttpOnly bool `yaml:"cookieHttpOnly"`
CookieMaxAge int `yaml:"cookieMaxAge"`
CookieSecret string `yaml:"cookieSecret"`
CsrfSecret string `yaml:"csrfSecret"`
}
type rpcSection struct {
Listen string `yaml:"listen"`
}
type contactKey struct {
Label string `yaml:"label" json:"label"`
Key string `yaml:"key" json:"key"`
}
var Config *ConfigStruct
func Parse() error {
ymlFile := iconf.GetYmlFile("server")
if ymlFile == "" {
return fmt.Errorf("configuration file of server not found")
}
bs, err := file.ReadBytes(ymlFile)
if err != nil {
return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err)
}
viper.SetConfigType("yaml")
err = viper.ReadConfig(bytes.NewBuffer(bs))
if err != nil {
return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err)
}
// default value settings
viper.SetDefault("i18n.lang", "zh")
viper.SetDefault("heartbeat.interval", 1000)
viper.SetDefault("judge.readBatch", 2000)
viper.SetDefault("judge.connTimeout", 2000)
viper.SetDefault("judge.callTimeout", 5000)
viper.SetDefault("judge.writerNum", 256)
viper.SetDefault("judge.connMax", 2560)
viper.SetDefault("judge.connIdle", 256)
viper.SetDefault("alert.notifyScriptPath", "./etc/script/notify.py")
viper.SetDefault("alert.notifyScriptConcurrency", 200)
viper.SetDefault("alert.mutedAlertPersist", true)
viper.SetDefault("trans.backend.prometheus.lookbackDeltaMinute", 2)
viper.SetDefault("trans.backend.prometheus.maxConcurrentQuery", 30)
viper.SetDefault("trans.backend.prometheus.maxSamples", 50000000)
viper.SetDefault("trans.backend.prometheus.maxFetchAllSeriesLimitMinute", 5)
err = viper.Unmarshal(&Config)
if err != nil {
return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err)
}
fmt.Println("config.file:", ymlFile)
if Config.Heartbeat.IP == "" {
// auto detect
Config.Heartbeat.IP = fmt.Sprint(GetOutboundIP())
if Config.Heartbeat.IP == "" {
fmt.Println("heartbeat ip auto got is blank")
os.Exit(1)
}
port := strings.Split(Config.RPC.Listen, ":")[1]
endpoint := Config.Heartbeat.IP + ":" + port
Config.Heartbeat.LocalAddr = endpoint
}
// 正常情况肯定不是127.0.0.1,但是,如果就是单机部署,并且这个机器没有网络,比如本地调试并且本机没网的时候
// if Config.Heartbeat.IP == "127.0.0.1" {
// fmt.Println("heartbeat ip is 127.0.0.1 and it is useless, so, exit")
// os.Exit(1)
// }
fmt.Println("heartbeat.ip:", Config.Heartbeat.IP)
fmt.Printf("heartbeat.interval: %dms\n", Config.Heartbeat.Interval)
return nil
}
// Get preferred outbound ip of this machine
func GetOutboundIP() net.IP {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
fmt.Println("auto get outbound ip fail:", err)
os.Exit(1)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP
}

4
config/const.go Normal file
View File

@ -0,0 +1,4 @@
package config
// Server周期性去数据库心跳给自己起的名字
const EndpointName = "server_rpc"

65
config/i18n.go Normal file
View File

@ -0,0 +1,65 @@
package config
import "github.com/didi/nightingale/v5/pkg/i18n"
var (
dict = map[string]string{
"Login fail, check your username and password": "登录失败,请检查您的用户名和密码",
"Internal server error, try again later please": "系统内部错误,请稍后再试",
"Each user has at most two tokens": "每个用户至多创建两个密钥",
"No such token": "密钥不存在",
"Username is blank": "用户名不能为空",
"Username has invalid characters": "用户名含有非法字符",
"Nickname has invalid characters": "用户昵称含有非法字符",
"Phone invalid": "手机号格式有误",
"Email invalid": "邮箱格式有误",
"Incorrect old password": "旧密码错误",
"Username %s already exists": "用户名(%s)已存在",
"No such user": "用户不存在",
"UserGroup %s already exists": "用户组(%s)已存在",
"Group name has invalid characters": "分组名称含有非法字符",
"Group note has invalid characters": "分组备注含有非法字符",
"No such user group": "用户组不存在",
"Classpath path has invalid characters": "机器分组路径含有非法字符",
"Classpath note has invalid characters": "机器分组路径备注含有非法字符",
"There are still resources under the classpath": "机器分组路径下仍然挂有资源",
"There are still collect rules under the classpath": "机器分组路径下仍然存在采集策略",
"No such classpath": "机器分组路径不存在",
"Classpath %s already exists": "机器分组路径(%s)已存在",
"Preset classpath %s cannot delete": "内置机器分组(%s)不允许删除",
"No such mute config": "此屏蔽配置不存在",
"DashboardGroup name has invalid characters": "大盘分组名称含有非法字符",
"DashboardGroup name is blank": "大盘分组名称为空",
"DashboardGroup %s already exists": "大盘分组(%s)已存在",
"No such dashboard group": "大盘分组不存在",
"Dashboard name has invalid characters": "大盘名称含有非法字符",
"Dashboard %s already exists": "监控大盘(%s)已存在",
"ChartGroup name has invalid characters": "图表分组名称含有非法字符",
"No such dashboard": "监控大盘不存在",
"No such chart group": "图表分组不存在",
"No such chart": "图表不存在",
"There are still dashboards under the group": "分组下面仍然存在监控大盘,请先从组内移出",
"AlertRuleGroup name has invalid characters": "告警规则分组含有非法字符",
"AlertRuleGroup %s already exists": "告警规则分组(%s)已存在",
"There are still alert rules under the group": "分组下面仍然存在告警规则",
"AlertRule name has invalid characters": "告警规则含有非法字符",
"No such alert rule": "告警规则不存在",
"No such alert rule group": "告警规则分组不存在",
"No such alert event": "告警事件不存在",
"No such collect rule": "采集规则不存在",
"Decoded metric description empty": "导入的指标释义列表为空",
"User disabled": "用户已被禁用",
"Tags(%s) invalid": "标签(%s)格式不合法",
"Resource filter(Func:%s)'s param invalid": "资源过滤条件(函数:%s)参数不合法(为空或包含空格都不合法)",
"Tags filter(Func:%s)'s param invalid": "标签过滤条件(函数:%s)参数不合法(为空或包含空格都不合法)",
"Regexp: %s cannot be compiled": "正则表达式(%s)不合法,无法编译",
"AppendTags(%s) invalid": "附件标签(%s)格式不合法",
}
langDict = map[string]map[string]string{
"zh": dict,
}
)
func init() {
i18n.DictRegister(langDict)
}

251
control
View File

@ -1,251 +0,0 @@
#!/bin/bash
# release version
version=4.0.3
CWD=$(cd $(dirname $0)/; pwd)
cd $CWD
usage()
{
echo $"Usage: $0 {start|stop|restart|status|build|build_local|pack} <module>"
exit 0
}
start_all()
{
test -x n9e-server && start server
test -x n9e-agentd && start agentd
test -x n9e-prober && start prober
}
start()
{
mod=$1
if [ "x${mod}" = "x" ]; then
usage
return
fi
if [ "x${mod}" = "xall" ]; then
start_all
return
fi
binfile=n9e-${mod}
if [ ! -f $binfile ]; then
echo "file[$binfile] not found"
exit 1
fi
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -gt 0 ]; then
echo "${mod} already started"
return
fi
mkdir -p logs/$mod
nohup $CWD/$binfile &> logs/${mod}/stdout.log &
for((i=1;i<=15;i++)); do
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -gt 0 ]; then
echo "${mod} started"
return
fi
sleep 0.2
done
echo "cannot start ${mod}"
exit 1
}
stop_all()
{
test -x n9e-server && stop server
test -x n9e-prober && stop prober
test -x n9e-agentd && stop agentd
}
stop()
{
mod=$1
if [ "x${mod}" = "x" ]; then
usage
return
fi
if [ "x${mod}" = "xall" ]; then
stop_all
return
fi
binfile=n9e-${mod}
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -eq 0 ]; then
echo "${mod} already stopped"
return
fi
ps aux|grep -v grep|grep -v control|grep "$binfile"|awk '{print $2}'|xargs kill
for((i=1;i<=15;i++)); do
if [ $(ps aux|grep -v grep|grep -v control|grep "$binfile" -c) -eq 0 ]; then
echo "${mod} stopped"
return
fi
sleep 0.2
done
echo "cannot stop $mod"
exit 1
}
restart()
{
mod=$1
if [ "x${mod}" = "x" ]; then
usage
return
fi
if [ "x${mod}" = "xall" ]; then
stop_all
start_all
return
fi
stop $mod
start $mod
status
}
status()
{
ps aux|grep -v grep|grep "n9e"
}
build_one()
{
mod=$1
echo -n "building ${mod} ... "
go build -ldflags "-X main.version=${version}" -o n9e-${mod} src/modules/${mod}/${mod}.go
echo "done"
}
build_local_one()
{
mod=$1
echo -n "building ${mod} ... "
go build -mod=vendor -ldflags "-X main.version=${version}" -o n9e-${mod} src/modules/${mod}/${mod}.go
echo "done"
}
build()
{
export GO111MODULE=on
mod=$1
if [ "x${mod}" = "x" ]; then
build_one server
build_one agentd
build_one prober
return
fi
build_one $mod
}
build_local()
{
export GO111MODULE=on
mod=$1
if [ "x${mod}" = "x" ]; then
build_local_one server
build_local_one agentd
build_local_one prober
return
fi
build_local_one $mod
}
reload()
{
mod=$1
if [ "x${mod}" = "x" ]; then
echo "arg: <mod> is necessary"
return
fi
build_one $mod
restart $mod
}
pack()
{
clock=$(date +%s)
mkdir -p ~/n9e.bak.$clock
if ls etc/*.local.yml &>/dev/null; then
mv etc/*.local.yml ~/n9e.bak.$clock
fi
tar zcvf n9e-${version}.tar.gz script control sql etc n9e-*
if ls ~/n9e.bak.$clock/*.local.yml &>/dev/null; then
mv ~/n9e.bak.$clock/*.local.yml etc/
fi
rm -rf ~/n9e.bak.$clock
}
exec()
{
params=${@:2}
if [ ${#2} -gt 0 ]; then
for mod in $params
do
mod=${mod#n9e-}
$1 $mod
if [ "x${mod}" = "xall" ]; then
break
fi
done
else
echo "todo $1 at "$(date "+%Y-%m-%d %H:%M:%S")
$1
echo "done $1 at "$(date "+%Y-%m-%d %H:%M:%S")
fi
}
case "$1" in
start)
exec start ${@:2}
;;
stop)
exec stop ${@:2}
;;
restart)
exec restart ${@:2}
;;
status)
status
;;
build)
exec build ${@:2}
;;
build_local)
exec build_local ${@:2}
;;
reload)
exec reload ${@:2}
;;
pack)
exec pack ${@:2}
;;
*)
usage
esac

View File

@ -1,59 +0,0 @@
version: '3.6'
services:
web:
build:
dockerfile: Dockerfile
context: nginx
container_name: nginx-n9e
hostname: nginx-n9e
ports:
- 80:80
restart: unless-stopped
links:
- n9e:n9e
mysql:
image: mysql:5
container_name: mysql
hostname: mysql
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: 1234
# volumes:
# - /usr/local/docker/mysql/data:/var/lib/mysql
redis:
image: redis
container_name: redis
hostname: redis
ports:
- 6379:6379
n9e:
build:
dockerfile: Dockerfile
context: n9e
container_name: n9e
hostname: n9e
ports:
- 8000:8000
- 8002:8002
- 8004:8004
- 8005:8005
- 8006:8006
- 8008:8008
- 8009:8009
- 8010:8010
- 8011:8011
- 8012:8012
- 8013:8013
- 8014:8014
- 8015:8015
- 2080:2080
links:
- mysql:mysql
- redis:redis
depends_on:
- mysql
- redis

View File

@ -1,17 +0,0 @@
FROM centos:7
WORKDIR /home/n9e
RUN set -ex \
&& yum install mysql net-tools wget -y \
&& yum clean all \
&& rm -rf /var/cache/yum
ADD http://116.85.64.82/n9e-3.8.0.tar.gz .
RUN tar xvf n9e-3.8.0.tar.gz \
&& sed -i "s/127.0.0.1:6379/redis:6379/g" `grep -rl "127.0.0.1:6379" ./etc/` \
&& sed -i 's/127.0.0.1/mysql/g' etc/mysql.yml
COPY entrpoint.sh .
ENTRYPOINT ./entrpoint.sh

View File

@ -1,17 +0,0 @@
#!/bin/bash
mysqlRootPassword=1234
until mysql -hmysql -u root -p$mysqlRootPassword -e ";" ; do
echo "Can't connect mysql, retry"
sleep 5
done
mysql -hmysql -uroot -p$mysqlRootPassword < sql/n9e_ams.sql
mysql -hmysql -uroot -p$mysqlRootPassword < sql/n9e_hbs.sql
mysql -hmysql -uroot -p$mysqlRootPassword < sql/n9e_job.sql
mysql -hmysql -uroot -p$mysqlRootPassword < sql/n9e_mon.sql
mysql -hmysql -uroot -p$mysqlRootPassword < sql/n9e_rdb.sql
./control start all
sleep infinity

View File

@ -1,5 +0,0 @@
FROM nginx
WORKDIR /home/n9e
COPY nginx.conf /etc/nginx
ADD http://116.85.64.82/pub.tar.gz .
RUN tar xvf pub.tar.gz

View File

@ -1,139 +0,0 @@
user root;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 204800;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
use epoll;
worker_connections 204800;
}
http {
log_format main '$server_addr $host $remote_addr [$time_local] $scheme "$request" '
'$status $upstream_status $body_bytes_sent $request_time $upstream_addr $upstream_response_time "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
proxy_connect_timeout 500ms;
proxy_send_timeout 1000ms;
proxy_read_timeout 3000ms;
proxy_buffers 64 8k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 64k;
proxy_redirect off;
proxy_next_upstream error invalid_header timeout http_502 http_504;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
client_body_buffer_size 512k;
client_body_timeout 180;
client_header_timeout 10;
send_timeout 240;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types application/javascript application/x-javascript text/css text/javascript image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
upstream n9e.rdb {
server n9e:8000;
keepalive 60;
}
upstream n9e.ams {
server n9e:8002;
keepalive 60;
}
upstream n9e.job {
server n9e:8004;
keepalive 60;
}
upstream n9e.monapi {
server n9e:8006;
keepalive 60;
}
upstream n9e.transfer {
server n9e:8008;
keepalive 60;
}
upstream n9e.index {
server n9e:8012;
keepalive 60;
}
server {
listen 80 default_server;
server_name n9e.example.com;
root /home/n9e/pub;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location =/ {
rewrite / /mon;
}
location / {
try_files $uri /layout/index.html;
}
location ~ .*(.htm|.html|manifest.json)$ {
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}
location /api/rdb {
proxy_pass http://n9e.rdb;
}
location /api/ams {
proxy_pass http://n9e.ams;
}
location /api/job {
proxy_pass http://n9e.job;
}
location /api/mon {
proxy_pass http://n9e.monapi;
}
location /api/index {
proxy_pass http://n9e.index;
}
location /api/transfer {
proxy_pass http://n9e.transfer;
}
}
}

View File

@ -1,16 +0,0 @@
## 登陆相关
#### 来源地址限制
IP地址的获取顺序
- http header "X-Forwarded-For"
- http header "X-Real-Ip"
- http request RemoteAddr
nginx 代理配置客户端地址
```
# https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
```

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Nightingale</title>
</head>
<body>
<h1>Hello, Nightingale</h1>
</body>
</html>

View File

@ -1,50 +0,0 @@
# 安装 M3dbETCD
下载安装包 [m3db-install.tar.gz](https://s3-gz01.didistatic.com/n9e-pub/tarball/m3db-install.tar.gz) 
## 配置
#### etcd证书
```shell
# 修改 ./etcd/certs/config/hosts-etcd
# 填写etcd的机器列表
# 生成证书
cd etcd/certs
./reinit-root-ca.sh
./update-etcd-client-certs.sh
./update-etcd-server-certs.sh
```
#### m3db 配置
```shell
# 修改 ./m3db/etc/m3dbnode.yml
db:
config:
service:
etcdClusters:
- zone: embedded
endpoints:
- 10.255.0.146:2379 # 这里需要修改 etcd 节点信息
- 10.255.0.129:2379
```
## 安装部署
```shell
. ./functions.sh
# 设置安装的机器节点,
hosts="{node1} {node2} {node3}"
# 设置好ssh Public key认证后设置 publick key 用户名
user="dc2-user"
# 同步文件
sync
# 安装
install
# 检查
status
```

View File

@ -1,12 +0,0 @@
---
server:
http: 0.0.0.0:8000
rpc: 0.0.0.0:8001
addresses:
- 127.0.0.1
prober:
http: 0.0.0.0:8023
agentd:
http: 0.0.0.0:2080

View File

@ -1,90 +0,0 @@
logger:
dir: logs/agentd
level: INFO
keepHours: 24
enable:
mon: true
job: true
report: true
metrics: true
defaultTags:
enable: false
tags:
key1: value1
key2: value2
udp:
enable: false
listen: :788
metrics:
maxProcs: 1
reportIntervalMs: 10
reportTimeoutMs: 2000
reportPacketSize: 100
sendToInfoFile: false
job:
metadir: ./meta
interval: 2
report:
# 调用ams的接口上报数据需要ams的token
token: ams-builtin-token
# 上报周期,单位是秒
interval: 10
# physical物理机virtual虚拟机container容器switch交换机
cate: physical
# 使用哪个字段作为唯一KEY即作为where条件更新对应记录一般使用sn或ip
uniqkey: ip
# 如果是虚拟机应该是获取uuid
# curl -s http://169.254.169.254/a/meta-data/instance-id
sn: dmidecode -s system-serial-number | tail -n 1
fields:
cpu: cat /proc/cpuinfo | grep processor | wc -l
mem: cat /proc/meminfo | grep MemTotal | awk '{printf "%.1fGi", $2/1024/1024}'
disk: df -m | grep '/dev/' | grep -v '/var/lib' | grep -v tmpfs | awk '{sum += $2};END{printf "%.1fGi", sum/1024}'
sys:
# timeout in ms
# interval in second
timeout: 5000
interval: 30
ifacePrefix:
- eth
- em
- ens
# 磁盘采集
mountCollect:
# 正则匹配需要采集的挂载卷类型
typePrefix: "^(btrfs|ext2|ext3|ext4|jfs|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|ntfs|fat32|zfs|nfs)$"
# 忽略采集以下面开头的挂载目录
ignorePrefix:
- /var/lib
- /run
- /boot
# 仍然采集ignorePrefix中的例外的挂载目录(填写全路径)
exclude: []
ignoreMetrics:
- cpu.core.idle
- cpu.core.util
- cpu.core.sys
- cpu.core.user
- cpu.core.nice
- cpu.core.guest
- cpu.core.irq
- cpu.core.softirq
- cpu.core.iowait
- cpu.core.steal
#ntpServers:
# - ntp1.aliyun.com

View File

@ -1,752 +0,0 @@
[
{
"name": "timewait状态tcp连接超过2万",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 3,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "net.sockets.tcp.timewait",
"params": [],
"threshold": 20000
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": [],
"notify_user": [],
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "内存利用率大于75%",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "mem.bytes.used.percent",
"params": [],
"threshold": 75
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "机器loadavg大于16",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "cpu.loadavg.1",
"params": [],
"threshold": 16
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "某磁盘无法正常读写",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 1,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "disk.rw.error",
"params": [],
"threshold": 0
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "监控agent失联",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 1,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": "=",
"func": "nodata",
"metric": "proc.agent.alive",
"params": [],
"threshold": 0
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "磁盘利用率达到85%",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 3,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "disk.bytes.used.percent",
"params": [],
"threshold": 85
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "磁盘利用率达到88%",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "disk.bytes.used.percent",
"params": [],
"threshold": 88
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "磁盘利用率达到92%",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 1,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "disk.bytes.used.percent",
"params": [],
"threshold": 92
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "端口挂了",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": "!=",
"func": "all",
"metric": "proc.port.listen",
"params": [],
"threshold": 1
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "网卡入方向丢包",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "net.in.dropped",
"params": [],
"threshold": 3
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "网卡入方向错包",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "net.in.errs",
"params": [],
"threshold": 3
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "网卡出方向丢包",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "net.out.dropped",
"params": [],
"threshold": 3
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "网卡出方向错包",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "net.out.errs",
"params": [],
"threshold": 3
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "进程总数超过3000",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 1,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": ">",
"func": "all",
"metric": "sys.ps.process.total",
"params": [],
"threshold": 3000
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
},
{
"name": "进程挂了",
"category": 1,
"alert_dur": 60,
"recovery_dur": 0,
"recovery_notify": 1,
"enable_stime": "00:00",
"enable_etime": "23:59",
"priority": 2,
"callback": "",
"need_upgrade": 0,
"runbook": "",
"excl_nid": null,
"nids": null,
"exprs": [
{
"eopt": "<",
"func": "all",
"metric": "proc.num",
"params": [],
"threshold": 1
}
],
"tags": [],
"enable_days_of_week": [
0,
1,
2,
3,
4,
5,
6
],
"converge": [
36000,
1
],
"notify_group": null,
"notify_user": null,
"leaf_nids": null,
"endpoints": null,
"alert_upgrade": {
"users": [],
"groups": [],
"duration": 60,
"level": 1
},
"judge_instance": "",
"work_groups": null
}
]

View File

@ -1,20 +0,0 @@
- system: 资产管理系统
groups:
- title: 主机设备
ops:
- en: ams_host_mgr_menu
cn: 主机设备管理菜单展示
- en: ams_host_delete
cn: 主机设备删除
- en: ams_host_modify
cn: 主机设备信息修改
- en: ams_host_field_mgr_menu
cn: 主机设备扩展字段菜单展示
- en: ams_host_field_mgr
cn: 主机设备扩展字段管理
# - title: 网络设备
# ops:
# - en: ams_netware_mgr_menu
# cn: 网络设备管理菜单
# - en: ams_netware_modify
# cn: 网络设备信息修改

View File

@ -1,9 +0,0 @@
# for heartbeat, connected by other modules
ip:
specify: ""
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1|awk -F':' '{print $NF}'
# as identity. equals to endpoint. used by agentd, prober, server
ident:
specify: ""
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1|awk -F':' '{print $NF}'

View File

@ -1,86 +0,0 @@
- system: 用户资源库
groups:
- title: 人员授权
ops:
- en: rdb_perm_grant
cn: 权限分配
- title: 节点类操作
ops:
- en: rdb_node_create
cn: 创建节点
- en: rdb_node_modify
cn: 修改节点
- en: rdb_node_delete
cn: 删除节点
- title: 资源类操作
ops:
- en: rdb_resource_view
cn: 资源信息查看
- en: rdb_resource_bind
cn: 资源挂载节点
- en: rdb_resource_unbind
cn: 资源解挂节点
- en: rdb_resource_modify
cn: 资源信息修改
- system: 任务执行中心
groups:
- title: 任务模板相关
ops:
- en: job_tpl_view
cn: 查看任务模板
- en: job_tpl_create
cn: 创建任务模板
- en: job_tpl_modify
cn: 修改任务模板
- en: job_tpl_delete
cn: 删除任务模板
- title: 任务执行相关
ops:
- en: task_run_use_root_account
cn: 使用root账号运行脚本
- en: task_run_use_gene_account
cn: 使用普通账号运行脚本
- system: 监控告警系统
groups:
- title: 告警策略
ops:
- en: mon_stra_create
cn: 创建告警策略
- en: mon_stra_modify
cn: 修改告警策略
- en: mon_stra_delete
cn: 删除告警策略
- title: 告警屏蔽
ops:
- en: mon_maskconf_create
cn: 创建告警屏蔽
- en: mon_maskconf_modify
cn: 修改告警屏蔽
- en: mon_maskconf_delete
cn: 删除告警屏蔽
- title: 采集策略
ops:
- en: mon_collect_create
cn: 创建采集策略
- en: mon_collect_modify
cn: 修改采集策略
- en: mon_collect_delete
cn: 删除采集策略
- title: 大盘操作
ops:
- en: mon_screen_create
cn: 创建监控大盘
- en: mon_screen_modify
cn: 修改监控大盘
- en: mon_screen_delete
cn: 删除监控大盘
- en: mon_screen_view
cn: 查看监控大盘
# - title: 指标计算
# ops:
# - en: mon_aggr_write
# cn: 指标计算配置权限
- title: 告警历史
ops:
- en: mon_event_write
cn: 告警历史认领、忽略

View File

@ -1,26 +0,0 @@
---
rdb:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_rdb?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false
ams:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_ams?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false
job:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_job?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false
mon:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_mon?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false
hbs:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_hbs?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false

View File

@ -1,119 +0,0 @@
user root;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 204800;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
use epoll;
worker_connections 204800;
}
http {
log_format main '$server_addr $host $remote_addr [$time_local] $scheme "$request" '
'$status $upstream_status $body_bytes_sent $request_time $upstream_addr $upstream_response_time "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
proxy_connect_timeout 500ms;
proxy_send_timeout 1000ms;
proxy_read_timeout 3000ms;
proxy_buffers 64 8k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 64k;
proxy_redirect off;
proxy_next_upstream error invalid_header timeout http_502 http_504;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
client_body_buffer_size 512k;
client_body_timeout 180;
client_header_timeout 10;
send_timeout 240;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types application/javascript application/x-javascript text/css text/javascript image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
upstream n9e.server {
server 127.0.0.1:8000;
keepalive 60;
}
upstream n9e.index {
server 127.0.0.1:8012;
keepalive 60;
}
server {
listen 80 default_server;
server_name localhost;
root /home/n9e/pub;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location =/ {
rewrite / /mon;
}
location / {
try_files $uri /layout/index.html;
}
location ~ .*(.htm|.html|.json)$ {
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}
location /api/rdb {
proxy_pass http://n9e.server;
}
location /api/ams {
proxy_pass http://n9e.server;
}
location /api/job {
proxy_pass http://n9e.server;
}
location /api/mon {
proxy_pass http://n9e.server;
}
location /api/index {
proxy_pass http://n9e.server;
}
location /api/transfer {
proxy_pass http://n9e.server;
}
}
}

View File

@ -1,5 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: dns_query_query_time_ms
- name: dns_query_result_code
- name: dns_query_rcode_value

View File

@ -1 +0,0 @@
mode: all # whitelist(default),all

View File

@ -1,9 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: github_repository_forks
- name: github_repository_networks
- name: github_repository_open_issues
- name: github_repository_size
- name: github_repository_stars
- name: github_repository_subscribers
- name: github_repository_watchers

View File

@ -1,8 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: http_response_http_response_code
- name: http_response_content_length
- name: http_response_response_string_match
- name: http_response_response_status_code_match
- name: http_response_result_code
- name: http_response_response_time

View File

@ -1,183 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: mongodb_assert_msg
type: COUNTER
- name: mongodb_assert_regular
type: COUNTER
- name: mongodb_assert_rollovers
type: COUNTER
- name: mongodb_assert_user
type: COUNTER
- name: mongodb_assert_warning
type: COUNTER
- name: mongodb_commands
type: COUNTER
- name: mongodb_count_command_failed
type: COUNTER
- name: mongodb_count_command_total
type: COUNTER
- name: mongodb_connections_available
- name: mongodb_connections_current
- name: mongodb_connections_total_created
type: COUNTER
trash:
- name: mongodb_active_reads
type: COUNTER
- name: mongodb_active_writes
type: COUNTER
- name: mongodb_aggregate_command_failed
type: COUNTER
- name: mongodb_aggregate_command_total
type: COUNTER
- name: mongodb_available_reads
- name: mongodb_available_writes
- name: mongodb_col_stats_avg_obj_size
- name: mongodb_col_stats_count
- name: mongodb_col_stats_ok
- name: mongodb_col_stats_size
- name: mongodb_col_stats_storage_size
- name: mongodb_col_stats_total_index_size
- name: mongodb_commands_per_sec
- name: mongodb_cursor_no_timeout
- name: mongodb_cursor_no_timeout_count
- name: mongodb_cursor_pinned
- name: mongodb_cursor_pinned_count
- name: mongodb_cursor_timed_out
- name: mongodb_cursor_timed_out_count
- name: mongodb_cursor_total
- name: mongodb_cursor_total_count
- name: mongodb_db_stats_avg_obj_size
- name: mongodb_db_stats_collections
- name: mongodb_db_stats_data_size
- name: mongodb_db_stats_index_size
- name: mongodb_db_stats_indexes
- name: mongodb_db_stats_num_extents
- name: mongodb_db_stats_objects
- name: mongodb_db_stats_ok
- name: mongodb_db_stats_storage_size
- name: mongodb_delete_command_failed
type: COUNTER
- name: mongodb_delete_command_total
type: COUNTER
- name: mongodb_deletes
- name: mongodb_deletes_per_sec
- name: mongodb_distinct_command_failed
type: COUNTER
- name: mongodb_distinct_command_total
type: COUNTER
- name: mongodb_document_deleted
- name: mongodb_document_inserted
- name: mongodb_document_returned
- name: mongodb_document_updated
- name: mongodb_find_and_modify_command_failed
type: COUNTER
- name: mongodb_find_and_modify_command_total
type: COUNTER
- name: mongodb_find_command_failed
type: COUNTER
- name: mongodb_find_command_total
type: COUNTER
- name: mongodb_flushes
type: COUNTER
- name: mongodb_flushes_per_sec
- name: mongodb_flushes_total_time_ns
type: COUNTER
- name: mongodb_get_more_command_failed
type: COUNTER
- name: mongodb_get_more_command_total
type: COUNTER
- name: mongodb_getmores
- name: mongodb_getmores_per_sec
- name: mongodb_insert_command_failed
type: COUNTER
- name: mongodb_insert_command_total
type: COUNTER
- name: mongodb_inserts
- name: mongodb_inserts_per_sec
- name: mongodb_jumbo_chunks
- name: mongodb_latency_commands
type: COUNTER
- name: mongodb_latency_commands_count
type: COUNTER
- name: mongodb_latency_reads
- name: mongodb_latency_reads_count
- name: mongodb_latency_writes
- name: mongodb_latency_writes_count
- name: mongodb_net_in_bytes
- name: mongodb_net_in_bytes_count
- name: mongodb_net_out_bytes
- name: mongodb_net_out_bytes_count
- name: mongodb_open_connections
- name: mongodb_operation_scan_and_order
- name: mongodb_operation_write_conflicts
- name: mongodb_page_faults
type: COUNTER
- name: mongodb_percent_cache_dirty
- name: mongodb_percent_cache_used
- name: mongodb_resident_megabytes
- name: mongodb_storage_freelist_search_bucket_exhausted
- name: mongodb_storage_freelist_search_requests
- name: mongodb_storage_freelist_search_scanned
- name: mongodb_tcmalloc_central_cache_free_bytes
- name: mongodb_tcmalloc_current_allocated_bytes
- name: mongodb_tcmalloc_current_total_thread_cache_bytes
- name: mongodb_tcmalloc_heap_size
- name: mongodb_tcmalloc_max_total_thread_cache_bytes
- name: mongodb_tcmalloc_pageheap_commit_count
- name: mongodb_tcmalloc_pageheap_committed_bytes
- name: mongodb_tcmalloc_pageheap_decommit_count
- name: mongodb_tcmalloc_pageheap_free_bytes
- name: mongodb_tcmalloc_pageheap_reserve_count
- name: mongodb_tcmalloc_pageheap_scavenge_count
- name: mongodb_tcmalloc_pageheap_total_commit_bytes
- name: mongodb_tcmalloc_pageheap_total_decommit_bytes
- name: mongodb_tcmalloc_pageheap_total_reserve_bytes
- name: mongodb_tcmalloc_pageheap_unmapped_bytes
- name: mongodb_tcmalloc_spinlock_total_delay_ns
- name: mongodb_tcmalloc_thread_cache_free_bytes
- name: mongodb_tcmalloc_total_free_bytes
- name: mongodb_tcmalloc_transfer_cache_free_bytes
- name: mongodb_total_available
- name: mongodb_total_created
type: COUNTER
- name: mongodb_total_docs_scanned
- name: mongodb_total_in_use
- name: mongodb_total_keys_scanned
- name: mongodb_total_refreshing
- name: mongodb_total_tickets_reads
- name: mongodb_total_tickets_writes
- name: mongodb_ttl_deletes
- name: mongodb_ttl_deletes_per_sec
- name: mongodb_ttl_passes
- name: mongodb_ttl_passes_per_sec
- name: mongodb_update_command_failed
type: COUNTER
- name: mongodb_update_command_total
type: COUNTER
- name: mongodb_updates
- name: mongodb_updates_per_sec
- name: mongodb_uptime_ns
- name: mongodb_vsize_megabytes
- name: mongodb_wtcache_app_threads_page_read_count
type: COUNTER
- name: mongodb_wtcache_app_threads_page_read_time
type: COUNTER
- name: mongodb_wtcache_app_threads_page_write_count
type: COUNTER
- name: mongodb_wtcache_bytes_read_into
- name: mongodb_wtcache_bytes_written_from
- name: mongodb_wtcache_current_bytes
- name: mongodb_wtcache_internal_pages_evicted
- name: mongodb_wtcache_max_bytes_configured
- name: mongodb_wtcache_modified_pages_evicted
- name: mongodb_wtcache_pages_evicted_by_app_thread
- name: mongodb_wtcache_pages_queued_for_eviction
- name: mongodb_wtcache_pages_read_into
- name: mongodb_wtcache_pages_requested_from
- name: mongodb_wtcache_pages_written_from
- name: mongodb_wtcache_server_evicting_pages
- name: mongodb_wtcache_tracked_dirty_bytes
- name: mongodb_wtcache_unmodified_pages_evicted
- name: mongodb_wtcache_worker_thread_evictingpages

View File

@ -1,849 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: mysql_queries
type: COUNTER
- name: mysql_transactions
type: COUNTER
expr: mysql_com_commit + mysql_com_rollback
- name: mysql_threads_running
type: GAUGE
comment: "并发数"
- name: mysql_threads_connected
type: GAUGE
comment: "当前连接数"
- name: mysql_variables_max_connections
type: GAUGE
comment: "最大连接数"
- name: mysql_innodb_buffer_pool_read_requests
type: COUNTER
comment: "innodb缓冲池查询总数"
- name: mysql_innodb_buffer_pool_reads
type: COUNTER
comment: "innodb从磁盘查询数"
- name: mysql_binary_files_count
type: COUNTER
- name: mysql_binary_size_bytes
type: COUNTER
- name: mysql_binlog_bytes_written
type: COUNTER
- name: mysql_binlog_cache_disk_use
type: COUNTER
- name: mysql_binlog_cache_use
type: COUNTER
- name: mysql_binlog_commits
type: COUNTER
- name: mysql_com_begin
type: COUNTER
- name: mysql_com_binlog
type: COUNTER
- name: mysql_com_commit
type: COUNTER
- name: mysql_com_create_table
type: COUNTER
- name: mysql_com_delete
type: COUNTER
- name: mysql_com_delete_multi
type: COUNTER
- name: mysql_com_drop_table
type: COUNTER
- name: mysql_com_empty_query
type: COUNTER
- name: mysql_com_execute_sql
type: COUNTER
- name: mysql_com_flush
type: COUNTER
- name: mysql_com_insert
type: COUNTER
- name: mysql_com_lock_tables
type: COUNTER
- name: mysql_com_rollback
type: COUNTER
- name: mysql_com_stmt_close
type: COUNTER
- name: mysql_com_stmt_execute
type: COUNTER
- name: mysql_com_stmt_prepare
type: COUNTER
- name: mysql_com_stmt_reprepare
type: COUNTER
- name: mysql_com_stmt_reset
type: COUNTER
- name: mysql_com_stmt_fetch
type: COUNTER
- name: mysql_com_update
type: COUNTER
- name: mysql_com_update_multi
type: COUNTER
- name: mysql_compression
type: COUNTER
- name: mysql_connections
type: GAUGE
- name: mysql_max_used_connections
type: COUNTER
- name: mysql_open_files
type: GAUGE
- name: mysql_open_streams
type: GAUGE
- name: mysql_open_tables
type: GAUGE
- name: mysql_opened_files
type: COUNTER
- name: mysql_opened_table_definitions
type: COUNTER
- name: mysql_opened_tables
type: COUNTER
- name: mysql_opened_views
type: COUNTER
- name: mysql_rows_read
type: COUNTER
- name: mysql_rows_sent
type: COUNTER
- name: mysql_sort_rows
type: COUNTER
trash:
- name: mysql_aborted_clients
type: COUNTER
comment: "mysql aborted clients number"
- name: mysql_aborted_connects
type: COUNTER
- name: mysql_access_denied_errors
type: COUNTER
- name: mysql_aria_pagecache_blocks_not_flushed
type: COUNTER
- name: mysql_aria_pagecache_blocks_unused
type: COUNTER
- name: mysql_aria_pagecache_blocks_used
type: COUNTER
- name: mysql_aria_pagecache_read_requests
type: COUNTER
- name: mysql_aria_pagecache_reads
type: COUNTER
- name: mysql_aria_pagecache_write_requests
type: COUNTER
- name: mysql_aria_pagecache_writes
type: COUNTER
- name: mysql_aria_transaction_log_syncs
type: COUNTER
- name: mysql_binlog_group_commits
- name: mysql_binlog_snapshot_position
- name: mysql_binlog_stmt_cache_disk_use
- name: mysql_binlog_stmt_cache_use
- name: mysql_busy_time
- name: mysql_bytes_received
- name: mysql_bytes_sent
- name: mysql_com_admin_commands
- name: mysql_com_alter_db
- name: mysql_com_alter_db_upgrade
- name: mysql_com_alter_event
- name: mysql_com_alter_function
- name: mysql_com_alter_procedure
- name: mysql_com_alter_server
- name: mysql_com_alter_table
- name: mysql_com_alter_tablespace
- name: mysql_com_analyze
- name: mysql_com_assign_to_keycache
- name: mysql_com_call_procedure
- name: mysql_com_change_db
- name: mysql_com_change_master
- name: mysql_com_check
- name: mysql_com_checksum
- name: mysql_com_create_db
- name: mysql_com_create_event
- name: mysql_com_create_function
- name: mysql_com_create_index
- name: mysql_com_create_procedure
- name: mysql_com_create_server
- name: mysql_com_create_trigger
- name: mysql_com_create_udf
- name: mysql_com_create_user
- name: mysql_com_create_view
- name: mysql_com_dealloc_sql
- name: mysql_com_do
- name: mysql_com_drop_db
- name: mysql_com_drop_event
- name: mysql_com_drop_function
- name: mysql_com_drop_index
- name: mysql_com_drop_procedure
- name: mysql_com_drop_server
- name: mysql_com_drop_trigger
- name: mysql_com_drop_user
- name: mysql_com_drop_view
- name: mysql_com_grant
- name: mysql_com_ha_close
- name: mysql_com_ha_open
- name: mysql_com_ha_read
- name: mysql_com_help
- name: mysql_com_insert_select
- name: mysql_com_install_plugin
- name: mysql_com_kill
- name: mysql_com_load
- name: mysql_com_optimize
- name: mysql_com_preload_keys
- name: mysql_com_prepare_sql
- name: mysql_com_purge
- name: mysql_com_purge_before_date
- name: mysql_com_release_savepoint
- name: mysql_com_rename_table
- name: mysql_com_rename_user
- name: mysql_com_repair
- name: mysql_com_replace
- name: mysql_com_replace_select
- name: mysql_com_reset
- name: mysql_com_resignal
- name: mysql_com_revoke
- name: mysql_com_revoke_all
- name: mysql_com_rollback_to_savepoint
- name: mysql_com_savepoint
- name: mysql_com_select
- name: mysql_com_set_option
- name: mysql_com_show_authors
- name: mysql_com_show_binlog_events
- name: mysql_com_show_binlogs
- name: mysql_com_show_charsets
- name: mysql_com_show_client_statistics
- name: mysql_com_show_collations
- name: mysql_com_show_contributors
- name: mysql_com_show_create_db
- name: mysql_com_show_create_event
- name: mysql_com_show_create_func
- name: mysql_com_show_create_proc
- name: mysql_com_show_create_table
- name: mysql_com_show_create_trigger
- name: mysql_com_show_databases
- name: mysql_com_show_engine_logs
- name: mysql_com_show_engine_mutex
- name: mysql_com_show_engine_status
- name: mysql_com_show_errors
- name: mysql_com_show_events
- name: mysql_com_show_fields
- name: mysql_com_show_function_status
- name: mysql_com_show_grants
- name: mysql_com_show_index_statistics
- name: mysql_com_show_keys
- name: mysql_com_show_master_status
- name: mysql_com_show_open_tables
- name: mysql_com_show_plugins
- name: mysql_com_show_privileges
- name: mysql_com_show_procedure_status
- name: mysql_com_show_processlist
- name: mysql_com_show_profile
- name: mysql_com_show_profiles
- name: mysql_com_show_relaylog_events
- name: mysql_com_show_slave_hosts
- name: mysql_com_show_slave_status
- name: mysql_com_show_status
- name: mysql_com_show_storage_engines
- name: mysql_com_show_table_statistics
- name: mysql_com_show_table_status
- name: mysql_com_show_tables
- name: mysql_com_show_triggers
- name: mysql_com_show_user_statistics
- name: mysql_com_show_variables
- name: mysql_com_show_warnings
- name: mysql_com_signal
- name: mysql_com_slave_start
- name: mysql_com_slave_stop
- name: mysql_com_stmt_send_long_data
- name: mysql_com_truncate
- name: mysql_com_uninstall_plugin
- name: mysql_com_unlock_tables
- name: mysql_com_xa_commit
- name: mysql_com_xa_end
- name: mysql_com_xa_prepare
- name: mysql_com_xa_recover
- name: mysql_com_xa_rollback
- name: mysql_com_xa_start
- name: mysql_cpu_time
- name: mysql_created_tmp_disk_tables
- name: mysql_created_tmp_files
- name: mysql_created_tmp_tables
- name: mysql_delayed_errors
- name: mysql_delayed_insert_threads
- name: mysql_delayed_writes
- name: mysql_empty_queries
- name: mysql_executed_events
- name: mysql_executed_triggers
- name: mysql_feature_dynamic_columns
- name: mysql_feature_fulltext
- name: mysql_feature_gis
- name: mysql_feature_locale
- name: mysql_feature_subquery
- name: mysql_feature_timezone
- name: mysql_feature_trigger
- name: mysql_feature_xml
- name: mysql_flush_commands
- name: mysql_handler_commit
- name: mysql_handler_delete
- name: mysql_handler_discover
- name: mysql_handler_icp_attempts
- name: mysql_handler_icp_match
- name: mysql_handler_mrr_init
- name: mysql_handler_mrr_key_refills
- name: mysql_handler_mrr_rowid_refills
- name: mysql_handler_prepare
- name: mysql_handler_read_first
- name: mysql_handler_read_key
- name: mysql_handler_read_last
- name: mysql_handler_read_next
- name: mysql_handler_read_prev
- name: mysql_handler_read_rnd
- name: mysql_handler_read_rnd_deleted
- name: mysql_handler_read_rnd_next
- name: mysql_handler_rollback
- name: mysql_handler_savepoint
- name: mysql_handler_savepoint_rollback
- name: mysql_handler_tmp_update
- name: mysql_handler_tmp_write
- name: mysql_handler_update
- name: mysql_handler_write
- name: mysql_innodb_adaptive_hash_cells
- name: mysql_innodb_adaptive_hash_hash_searches
- name: mysql_innodb_adaptive_hash_heap_buffers
- name: mysql_innodb_adaptive_hash_non_hash_searches
- name: mysql_innodb_background_log_sync
- name: mysql_innodb_buffer_pool_bytes_data
- name: mysql_innodb_buffer_pool_bytes_dirty
- name: mysql_innodb_buffer_pool_pages_data
- name: mysql_innodb_buffer_pool_pages_dirty
- name: mysql_innodb_buffer_pool_pages_flushed
- name: mysql_innodb_buffer_pool_pages_free
- name: mysql_innodb_buffer_pool_pages_lru_flushed
- name: mysql_innodb_buffer_pool_pages_made_not_young
- name: mysql_innodb_buffer_pool_pages_made_young
- name: mysql_innodb_buffer_pool_pages_misc
- name: mysql_innodb_buffer_pool_pages_old
- name: mysql_innodb_buffer_pool_pages_total
- name: mysql_innodb_buffer_pool_read_ahead
- name: mysql_innodb_buffer_pool_read_ahead_evicted
- name: mysql_innodb_buffer_pool_read_ahead_rnd
- name: mysql_innodb_buffer_pool_wait_free
- name: mysql_innodb_buffer_pool_write_requests
- name: mysql_innodb_checkpoint_age
- name: mysql_innodb_checkpoint_max_age
- name: mysql_innodb_checkpoint_target_age
- name: mysql_innodb_current_row_locks
- name: mysql_innodb_data_fsyncs
- name: mysql_innodb_data_pending_fsyncs
- name: mysql_innodb_data_pending_reads
- name: mysql_innodb_data_pending_writes
- name: mysql_innodb_data_read
- name: mysql_innodb_data_reads
- name: mysql_innodb_data_writes
- name: mysql_innodb_data_written
- name: mysql_innodb_dblwr_pages_written
- name: mysql_innodb_dblwr_writes
- name: mysql_innodb_deadlocks
- name: mysql_innodb_descriptors_memory
- name: mysql_innodb_dict_tables
- name: mysql_innodb_have_atomic_builtins
- name: mysql_innodb_history_list_length
- name: mysql_innodb_ibuf_discarded_delete_marks
- name: mysql_innodb_ibuf_discarded_deletes
- name: mysql_innodb_ibuf_discarded_inserts
- name: mysql_innodb_ibuf_free_list
- name: mysql_innodb_ibuf_merged_delete_marks
- name: mysql_innodb_ibuf_merged_deletes
- name: mysql_innodb_ibuf_merged_inserts
- name: mysql_innodb_ibuf_merges
- name: mysql_innodb_ibuf_segment_size
- name: mysql_innodb_ibuf_size
- name: mysql_innodb_log_waits
- name: mysql_innodb_log_write_requests
- name: mysql_innodb_log_writes
- name: mysql_innodb_lsn_current
- name: mysql_innodb_lsn_flushed
- name: mysql_innodb_lsn_last_checkpoint
- name: mysql_innodb_master_thread_10_second_loops
- name: mysql_innodb_master_thread_1_second_loops
- name: mysql_innodb_master_thread_background_loops
- name: mysql_innodb_master_thread_main_flush_loops
- name: mysql_innodb_master_thread_sleeps
- name: mysql_innodb_max_trx_id
- name: mysql_innodb_mem_adaptive_hash
- name: mysql_innodb_mem_dictionary
- name: mysql_innodb_mem_total
- name: mysql_innodb_mutex_os_waits
- name: mysql_innodb_mutex_spin_rounds
- name: mysql_innodb_mutex_spin_waits
- name: mysql_innodb_oldest_view_low_limit_trx_id
- name: mysql_innodb_os_log_fsyncs
- name: mysql_innodb_os_log_pending_fsyncs
- name: mysql_innodb_os_log_pending_writes
- name: mysql_innodb_os_log_written
- name: mysql_innodb_page_size
- name: mysql_innodb_pages_created
- name: mysql_innodb_pages_read
- name: mysql_innodb_pages_written
- name: mysql_innodb_purge_trx_id
- name: mysql_innodb_purge_undo_no
- name: mysql_innodb_read_views_memory
- name: mysql_innodb_row_lock_current_waits
- name: mysql_innodb_row_lock_time
- name: mysql_innodb_row_lock_time_avg
- name: mysql_innodb_row_lock_time_max
- name: mysql_innodb_row_lock_waits
- name: mysql_innodb_rows_deleted
- name: mysql_innodb_rows_inserted
- name: mysql_innodb_rows_read
- name: mysql_innodb_rows_updated
- name: mysql_innodb_s_lock_os_waits
- name: mysql_innodb_s_lock_spin_rounds
- name: mysql_innodb_s_lock_spin_waits
- name: mysql_innodb_truncated_status_writes
- name: mysql_innodb_x_lock_os_waits
- name: mysql_innodb_x_lock_spin_rounds
- name: mysql_innodb_x_lock_spin_waits
- name: mysql_key_blocks_not_flushed
- name: mysql_key_blocks_unused
- name: mysql_key_blocks_used
- name: mysql_key_blocks_warm
- name: mysql_key_read_requests
- name: mysql_key_reads
- name: mysql_key_write_requests
- name: mysql_key_writes
- name: mysql_last_query_cost
- name: mysql_not_flushed_delayed_rows
- name: mysql_open_table_definitions
- name: mysql_performance_schema_cond_classes_lost
- name: mysql_performance_schema_cond_instances_lost
- name: mysql_performance_schema_file_classes_lost
- name: mysql_performance_schema_file_handles_lost
- name: mysql_performance_schema_file_instances_lost
- name: mysql_performance_schema_locker_lost
- name: mysql_performance_schema_mutex_classes_lost
- name: mysql_performance_schema_mutex_instances_lost
- name: mysql_performance_schema_rwlock_classes_lost
- name: mysql_performance_schema_rwlock_instances_lost
- name: mysql_performance_schema_table_handles_lost
- name: mysql_performance_schema_table_instances_lost
- name: mysql_performance_schema_thread_classes_lost
- name: mysql_performance_schema_thread_instances_lost
- name: mysql_prepared_stmt_count
- name: mysql_process_list_threads_after_create
- name: mysql_process_list_threads_altering_table
- name: mysql_process_list_threads_analyzing
- name: mysql_process_list_threads_checking_permissions
- name: mysql_process_list_threads_checking_table
- name: mysql_process_list_threads_cleaning_up
- name: mysql_process_list_threads_closing_tables
- name: mysql_process_list_threads_converting_heap_to_myisam
- name: mysql_process_list_threads_copying_to_tmp_table
- name: mysql_process_list_threads_creating_sort_index
- name: mysql_process_list_threads_creating_table
- name: mysql_process_list_threads_creating_tmp_table
- name: mysql_process_list_threads_deleting
- name: mysql_process_list_threads_end
- name: mysql_process_list_threads_executing
- name: mysql_process_list_threads_execution_of_init_command
- name: mysql_process_list_threads_flushing_tables
- name: mysql_process_list_threads_freeing_items
- name: mysql_process_list_threads_fulltext_initialization
- name: mysql_process_list_threads_idle
- name: mysql_process_list_threads_init
- name: mysql_process_list_threads_killed
- name: mysql_process_list_threads_logging_slow_query
- name: mysql_process_list_threads_login
- name: mysql_process_list_threads_manage_keys
- name: mysql_process_list_threads_opening_tables
- name: mysql_process_list_threads_optimizing
- name: mysql_process_list_threads_other
- name: mysql_process_list_threads_preparing
- name: mysql_process_list_threads_reading_from_net
- name: mysql_process_list_threads_removing_duplicates
- name: mysql_process_list_threads_removing_tmp_table
- name: mysql_process_list_threads_reopen_tables
- name: mysql_process_list_threads_repair_by_sorting
- name: mysql_process_list_threads_repair_done
- name: mysql_process_list_threads_repair_with_keycache
- name: mysql_process_list_threads_replication_master
- name: mysql_process_list_threads_rolling_back
- name: mysql_process_list_threads_searching_rows_for_update
- name: mysql_process_list_threads_sending_data
- name: mysql_process_list_threads_sorting_for_group
- name: mysql_process_list_threads_sorting_for_order
- name: mysql_process_list_threads_sorting_index
- name: mysql_process_list_threads_sorting_result
- name: mysql_process_list_threads_statistics
- name: mysql_process_list_threads_updating
- name: mysql_process_list_threads_waiting_for_lock
- name: mysql_process_list_threads_waiting_for_table_flush
- name: mysql_process_list_threads_waiting_for_tables
- name: mysql_process_list_threads_waiting_on_cond
- name: mysql_process_list_threads_writing_to_net
- name: mysql_qcache_free_blocks
- name: mysql_qcache_free_memory
- name: mysql_qcache_hits
- name: mysql_qcache_inserts
- name: mysql_qcache_lowmem_prunes
- name: mysql_qcache_not_cached
- name: mysql_qcache_queries_in_cache
- name: mysql_qcache_total_blocks
- name: mysql_questions
- name: mysql_rows_tmp_read
- name: mysql_select_full_join
- name: mysql_select_full_range_join
- name: mysql_select_range
- name: mysql_select_range_check
- name: mysql_select_scan
- name: mysql_slave_heartbeat_period
- name: mysql_slave_open_temp_tables
- name: mysql_slave_received_heartbeats
- name: mysql_slave_retried_transactions
- name: mysql_slave_running
- name: mysql_slow_launch_threads
- name: mysql_slow_queries
- name: mysql_sort_merge_passes
- name: mysql_sort_range
- name: mysql_sort_scan
- name: mysql_ssl_accept_renegotiates
- name: mysql_ssl_accepts
- name: mysql_ssl_callback_cache_hits
- name: mysql_ssl_client_connects
- name: mysql_ssl_connect_renegotiates
- name: mysql_ssl_ctx_verify_depth
- name: mysql_ssl_ctx_verify_mode
- name: mysql_ssl_default_timeout
- name: mysql_ssl_finished_accepts
- name: mysql_ssl_finished_connects
- name: mysql_ssl_session_cache_hits
- name: mysql_ssl_session_cache_misses
- name: mysql_ssl_session_cache_overflows
- name: mysql_ssl_session_cache_size
- name: mysql_ssl_session_cache_timeouts
- name: mysql_ssl_sessions_reused
- name: mysql_ssl_used_session_cache_entries
- name: mysql_ssl_verify_depth
- name: mysql_ssl_verify_mode
- name: mysql_subquery_cache_hit
- name: mysql_subquery_cache_miss
- name: mysql_syncs
- name: mysql_table_locks_immediate
- name: mysql_table_locks_waited
- name: mysql_tc_log_max_pages_used
- name: mysql_tc_log_page_size
- name: mysql_tc_log_page_waits
- name: mysql_threadpool_idle_threads
- name: mysql_threadpool_threads
- name: mysql_threads_cached
- name: mysql_threads_created
- name: mysql_uptime
- name: mysql_uptime_since_flush_status
- name: mysql_users_connections
- name: mysql_variables_aria_block_size
- name: mysql_variables_aria_checkpoint_interval
- name: mysql_variables_aria_checkpoint_log_activity
- name: mysql_variables_aria_force_start_after_recovery_failures
- name: mysql_variables_aria_group_commit_interval
- name: mysql_variables_aria_log_file_size
- name: mysql_variables_aria_max_sort_file_size
- name: mysql_variables_aria_page_checksum
- name: mysql_variables_aria_pagecache_age_threshold
- name: mysql_variables_aria_pagecache_buffer_size
- name: mysql_variables_aria_pagecache_division_limit
- name: mysql_variables_aria_repair_threads
- name: mysql_variables_aria_sort_buffer_size
- name: mysql_variables_aria_used_for_temp_tables
- name: mysql_variables_auto_increment_increment
- name: mysql_variables_auto_increment_offset
- name: mysql_variables_autocommit
- name: mysql_variables_automatic_sp_privileges
- name: mysql_variables_back_log
- name: mysql_variables_big_tables
- name: mysql_variables_binlog_annotate_row_events
- name: mysql_variables_binlog_cache_size
- name: mysql_variables_binlog_direct_non_transactional_updates
- name: mysql_variables_binlog_optimize_thread_scheduling
- name: mysql_variables_binlog_stmt_cache_size
- name: mysql_variables_bulk_insert_buffer_size
- name: mysql_variables_connect_timeout
- name: mysql_variables_deadlock_search_depth_long
- name: mysql_variables_deadlock_search_depth_short
- name: mysql_variables_deadlock_timeout_long
- name: mysql_variables_deadlock_timeout_short
- name: mysql_variables_debug_no_thread_alarm
- name: mysql_variables_default_week_format
- name: mysql_variables_delay_key_write
- name: mysql_variables_delayed_insert_limit
- name: mysql_variables_delayed_insert_timeout
- name: mysql_variables_delayed_queue_size
- name: mysql_variables_div_precision_increment
- name: mysql_variables_engine_condition_pushdown
- name: mysql_variables_event_scheduler
- name: mysql_variables_expensive_subquery_limit
- name: mysql_variables_expire_logs_days
- name: mysql_variables_extra_max_connections
- name: mysql_variables_extra_port
- name: mysql_variables_flush
- name: mysql_variables_flush_time
- name: mysql_variables_foreign_key_checks
- name: mysql_variables_ft_max_word_len
- name: mysql_variables_ft_min_word_len
- name: mysql_variables_ft_query_expansion_limit
- name: mysql_variables_general_log
- name: mysql_variables_group_concat_max_len
- name: mysql_variables_have_compress
- name: mysql_variables_have_crypt
- name: mysql_variables_have_csv
- name: mysql_variables_have_dynamic_loading
- name: mysql_variables_have_geometry
- name: mysql_variables_have_innodb
- name: mysql_variables_have_ndbcluster
- name: mysql_variables_have_partitioning
- name: mysql_variables_have_profiling
- name: mysql_variables_have_query_cache
- name: mysql_variables_have_rtree_keys
- name: mysql_variables_ignore_builtin_innodb
- name: mysql_variables_innodb_adaptive_flushing
- name: mysql_variables_innodb_adaptive_hash_index
- name: mysql_variables_innodb_adaptive_hash_index_partitions
- name: mysql_variables_innodb_additional_mem_pool_size
- name: mysql_variables_innodb_autoextend_increment
- name: mysql_variables_innodb_autoinc_lock_mode
- name: mysql_variables_innodb_blocking_buffer_pool_restore
- name: mysql_variables_innodb_buffer_pool_instances
- name: mysql_variables_innodb_buffer_pool_populate
- name: mysql_variables_innodb_buffer_pool_restore_at_startup
- name: mysql_variables_innodb_buffer_pool_shm_checksum
- name: mysql_variables_innodb_buffer_pool_shm_key
- name: mysql_variables_innodb_buffer_pool_size
- name: mysql_variables_innodb_checkpoint_age_target
- name: mysql_variables_innodb_checksums
- name: mysql_variables_innodb_commit_concurrency
- name: mysql_variables_innodb_concurrency_tickets
- name: mysql_variables_innodb_dict_size_limit
- name: mysql_variables_innodb_doublewrite
- name: mysql_variables_innodb_fake_changes
- name: mysql_variables_innodb_fast_checksum
- name: mysql_variables_innodb_fast_shutdown
- name: mysql_variables_innodb_file_format_check
- name: mysql_variables_innodb_file_per_table
- name: mysql_variables_innodb_flush_log_at_trx_commit
- name: mysql_variables_innodb_force_load_corrupted
- name: mysql_variables_innodb_force_recovery
- name: mysql_variables_innodb_ibuf_accel_rate
- name: mysql_variables_innodb_ibuf_active_contract
- name: mysql_variables_innodb_ibuf_max_size
- name: mysql_variables_innodb_import_table_from_xtrabackup
- name: mysql_variables_innodb_io_capacity
- name: mysql_variables_innodb_kill_idle_transaction
- name: mysql_variables_innodb_large_prefix
- name: mysql_variables_innodb_lazy_drop_table
- name: mysql_variables_innodb_lock_wait_timeout
- name: mysql_variables_innodb_locking_fake_changes
- name: mysql_variables_innodb_locks_unsafe_for_binlog
- name: mysql_variables_innodb_log_block_size
- name: mysql_variables_innodb_log_buffer_size
- name: mysql_variables_innodb_log_file_size
- name: mysql_variables_innodb_log_files_in_group
- name: mysql_variables_innodb_max_bitmap_file_size
- name: mysql_variables_innodb_max_changed_pages
- name: mysql_variables_innodb_max_dirty_pages_pct
- name: mysql_variables_innodb_max_purge_lag
- name: mysql_variables_innodb_merge_sort_block_size
- name: mysql_variables_innodb_mirrored_log_groups
- name: mysql_variables_innodb_old_blocks_pct
- name: mysql_variables_innodb_old_blocks_time
- name: mysql_variables_innodb_open_files
- name: mysql_variables_innodb_page_size
- name: mysql_variables_innodb_print_all_deadlocks
- name: mysql_variables_innodb_purge_batch_size
- name: mysql_variables_innodb_purge_threads
- name: mysql_variables_innodb_random_read_ahead
- name: mysql_variables_innodb_read_ahead_threshold
- name: mysql_variables_innodb_read_io_threads
- name: mysql_variables_innodb_recovery_stats
- name: mysql_variables_innodb_recovery_update_relay_log
- name: mysql_variables_innodb_replication_delay
- name: mysql_variables_innodb_rollback_on_timeout
- name: mysql_variables_innodb_rollback_segments
- name: mysql_variables_innodb_show_locks_held
- name: mysql_variables_innodb_show_verbose_locks
- name: mysql_variables_innodb_simulate_comp_failures
- name: mysql_variables_innodb_spin_wait_delay
- name: mysql_variables_innodb_stats_auto_update
- name: mysql_variables_innodb_stats_modified_counter
- name: mysql_variables_innodb_stats_on_metadata
- name: mysql_variables_innodb_stats_sample_pages
- name: mysql_variables_innodb_stats_traditional
- name: mysql_variables_innodb_stats_update_need_lock
- name: mysql_variables_innodb_strict_mode
- name: mysql_variables_innodb_support_xa
- name: mysql_variables_innodb_sync_spin_loops
- name: mysql_variables_innodb_table_locks
- name: mysql_variables_innodb_thread_concurrency
- name: mysql_variables_innodb_thread_concurrency_timer_based
- name: mysql_variables_innodb_thread_sleep_delay
- name: mysql_variables_innodb_track_changed_pages
- name: mysql_variables_innodb_use_atomic_writes
- name: mysql_variables_innodb_use_fallocate
- name: mysql_variables_innodb_use_global_flush_log_at_trx_commit
- name: mysql_variables_innodb_use_native_aio
- name: mysql_variables_innodb_use_stacktrace
- name: mysql_variables_innodb_use_sys_malloc
- name: mysql_variables_innodb_use_sys_stats_table
- name: mysql_variables_innodb_write_io_threads
- name: mysql_variables_interactive_timeout
- name: mysql_variables_join_buffer_size
- name: mysql_variables_join_buffer_space_limit
- name: mysql_variables_join_cache_level
- name: mysql_variables_keep_files_on_create
- name: mysql_variables_key_buffer_size
- name: mysql_variables_key_cache_age_threshold
- name: mysql_variables_key_cache_block_size
- name: mysql_variables_key_cache_division_limit
- name: mysql_variables_key_cache_segments
- name: mysql_variables_large_files_support
- name: mysql_variables_large_page_size
- name: mysql_variables_large_pages
- name: mysql_variables_local_infile
- name: mysql_variables_lock_wait_timeout
- name: mysql_variables_locked_in_memory
- name: mysql_variables_log
- name: mysql_variables_log_bin
- name: mysql_variables_log_bin_trust_function_creators
- name: mysql_variables_log_queries_not_using_indexes
- name: mysql_variables_log_slave_updates
- name: mysql_variables_log_slow_queries
- name: mysql_variables_log_slow_rate_limit
- name: mysql_variables_log_warnings
- name: mysql_variables_long_query_time
- name: mysql_variables_low_priority_updates
- name: mysql_variables_lower_case_file_system
- name: mysql_variables_lower_case_table_names
- name: mysql_variables_master_verify_checksum
- name: mysql_variables_max_allowed_packet
- name: mysql_variables_max_binlog_cache_size
- name: mysql_variables_max_binlog_size
- name: mysql_variables_max_binlog_stmt_cache_size
- name: mysql_variables_max_connect_errors
- name: mysql_variables_max_delayed_threads
- name: mysql_variables_max_error_count
- name: mysql_variables_max_heap_table_size
- name: mysql_variables_max_insert_delayed_threads
- name: mysql_variables_max_join_size
- name: mysql_variables_max_length_for_sort_data
- name: mysql_variables_max_long_data_size
- name: mysql_variables_max_prepared_stmt_count
- name: mysql_variables_max_relay_log_size
- name: mysql_variables_max_seeks_for_key
- name: mysql_variables_max_sort_length
- name: mysql_variables_max_sp_recursion_depth
- name: mysql_variables_max_tmp_tables
- name: mysql_variables_max_user_connections
- name: mysql_variables_max_write_lock_count
- name: mysql_variables_metadata_locks_cache_size
- name: mysql_variables_min_examined_row_limit
- name: mysql_variables_mrr_buffer_size
- name: mysql_variables_multi_range_count
- name: mysql_variables_myisam_block_size
- name: mysql_variables_myisam_data_pointer_size
- name: mysql_variables_myisam_max_sort_file_size
- name: mysql_variables_myisam_mmap_size
- name: mysql_variables_myisam_repair_threads
- name: mysql_variables_myisam_sort_buffer_size
- name: mysql_variables_myisam_use_mmap
- name: mysql_variables_net_buffer_length
- name: mysql_variables_net_read_timeout
- name: mysql_variables_net_retry_count
- name: mysql_variables_net_write_timeout
- name: mysql_variables_old
- name: mysql_variables_old_alter_table
- name: mysql_variables_old_passwords
- name: mysql_variables_open_files_limit
- name: mysql_variables_optimizer_prune_level
- name: mysql_variables_optimizer_search_depth
- name: mysql_variables_performance_schema
- name: mysql_variables_performance_schema_events_waits_history_long_size
- name: mysql_variables_performance_schema_events_waits_history_size
- name: mysql_variables_performance_schema_max_cond_classes
- name: mysql_variables_performance_schema_max_cond_instances
- name: mysql_variables_performance_schema_max_file_classes
- name: mysql_variables_performance_schema_max_file_handles
- name: mysql_variables_performance_schema_max_file_instances
- name: mysql_variables_performance_schema_max_mutex_classes
- name: mysql_variables_performance_schema_max_mutex_instances
- name: mysql_variables_performance_schema_max_rwlock_classes
- name: mysql_variables_performance_schema_max_rwlock_instances
- name: mysql_variables_performance_schema_max_table_handles
- name: mysql_variables_performance_schema_max_table_instances
- name: mysql_variables_performance_schema_max_thread_classes
- name: mysql_variables_performance_schema_max_thread_instances
- name: mysql_variables_port
- name: mysql_variables_preload_buffer_size
- name: mysql_variables_profiling
- name: mysql_variables_profiling_history_size
- name: mysql_variables_progress_report_time
- name: mysql_variables_protocol_version
- name: mysql_variables_query_alloc_block_size
- name: mysql_variables_query_cache_limit
- name: mysql_variables_query_cache_min_res_unit
- name: mysql_variables_query_cache_size
- name: mysql_variables_query_cache_strip_comments
- name: mysql_variables_query_cache_type
- name: mysql_variables_query_cache_wlock_invalidate
- name: mysql_variables_query_prealloc_size
- name: mysql_variables_range_alloc_block_size
- name: mysql_variables_read_buffer_size
- name: mysql_variables_read_only
- name: mysql_variables_read_rnd_buffer_size
- name: mysql_variables_relay_log_purge
- name: mysql_variables_relay_log_recovery
- name: mysql_variables_relay_log_space_limit
- name: mysql_variables_replicate_annotate_row_events
- name: mysql_variables_report_port
- name: mysql_variables_rowid_merge_buff_size
- name: mysql_variables_rpl_recovery_rank
- name: mysql_variables_secure_auth
- name: mysql_variables_server_id
- name: mysql_variables_skip_external_locking
- name: mysql_variables_skip_name_resolve
- name: mysql_variables_skip_networking
- name: mysql_variables_skip_show_database
- name: mysql_variables_slave_compressed_protocol
- name: mysql_variables_slave_max_allowed_packet
- name: mysql_variables_slave_net_timeout
- name: mysql_variables_slave_skip_errors
- name: mysql_variables_slave_sql_verify_checksum
- name: mysql_variables_slave_transaction_retries
- name: mysql_variables_slow_launch_time
- name: mysql_variables_slow_query_log
- name: mysql_variables_sort_buffer_size
- name: mysql_variables_sql_auto_is_null
- name: mysql_variables_sql_big_selects
- name: mysql_variables_sql_big_tables
- name: mysql_variables_sql_buffer_result
- name: mysql_variables_sql_log_bin
- name: mysql_variables_sql_log_off
- name: mysql_variables_sql_low_priority_updates
- name: mysql_variables_sql_max_join_size
- name: mysql_variables_sql_notes
- name: mysql_variables_sql_quote_show_create
- name: mysql_variables_sql_safe_updates
- name: mysql_variables_sql_select_limit
- name: mysql_variables_sql_slave_skip_counter
- name: mysql_variables_sql_warnings
- name: mysql_variables_stored_program_cache
- name: mysql_variables_sync_binlog
- name: mysql_variables_sync_frm
- name: mysql_variables_sync_master_info
- name: mysql_variables_sync_relay_log
- name: mysql_variables_sync_relay_log_info
- name: mysql_variables_table_definition_cache
- name: mysql_variables_table_open_cache
- name: mysql_variables_thread_cache_size
- name: mysql_variables_thread_concurrency
- name: mysql_variables_thread_pool_idle_timeout
- name: mysql_variables_thread_pool_max_threads
- name: mysql_variables_thread_pool_oversubscribe
- name: mysql_variables_thread_pool_size
- name: mysql_variables_thread_pool_stall_limit
- name: mysql_variables_thread_stack
- name: mysql_variables_timed_mutexes
- name: mysql_variables_tmp_table_size
- name: mysql_variables_transaction_alloc_block_size
- name: mysql_variables_transaction_prealloc_size
- name: mysql_variables_unique_checks
- name: mysql_variables_updatable_views_with_limit
- name: mysql_variables_userstat
- name: mysql_variables_wait_timeout

View File

@ -1,5 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: net_response_result_code
- name: net_response_response_time

View File

@ -1,9 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: nginx_accepts
- name: nginx_active
- name: nginx_handled
- name: nginx_reading
- name: nginx_requests
- name: nginx_waiting
- name: nginx_writing

View File

@ -1,15 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: ping_percentile95_ms
- name: ping_percentile99_ms
- name: ping_percentile50_ms
- name: ping_percent_packet_loss
- name: ping_ttl
- name: ping_maximum_response_ms
- name: ping_standard_deviation_ms
- name: ping_packets_received
- name: ping_packets_transmitted
- name: ping_minimum_response_ms
- name: ping_result_code
- name: ping_average_response_ms

View File

@ -1 +0,0 @@
mode: all

View File

@ -1,82 +0,0 @@
mode: whitelist # whitelist(default),all
metrics:
- name: redis_maxmemory
- name: redis_used_memory
- name: redis_used_memory_peak
- name: redis_used_memory_rss
- name: redis_mem_fragmentation_ratio
- name: redis_total_commands_processed
type: COUNTER
- name: redis_total_connections_received
type: COUNTER
- name: redis_expired_keys
- name: mongodb_queries
- name: mongodb_queries_per_sec
- name: mongodb_queued_reads
- name: mongodb_queued_writes
trash:
- name: redis_aof_current_rewrite_time_sec
- name: redis_aof_enabled
- name: redis_aof_last_rewrite_time_sec
- name: redis_aof_rewrite_in_progress
- name: redis_aof_rewrite_scheduled
- name: redis_blocked_clients
- name: redis_client_biggest_input_buf
- name: redis_client_longest_output_list
- name: redis_clients
- name: redis_cluster_enabled
- name: redis_cmdstat_calls
- name: redis_cmdstat_usec
- name: redis_cmdstat_usec_per_call
- name: redis_connected_slaves
- name: redis_evicted_keys
- name: redis_instantaneous_input_kbps
- name: redis_instantaneous_ops_per_sec
- name: redis_instantaneous_output_kbps
- name: redis_keyspace_avg_ttl
- name: redis_keyspace_expires
- name: redis_keyspace_hitrate
- name: redis_keyspace_hits
type: COUNTER
- name: redis_keyspace_keys
- name: redis_keyspace_misses
type: COUNTER
- name: redis_latest_fork_usec
- name: redis_loading
- name: redis_lru_clock
type: COUNTER
- name: redis_master_repl_offset
- name: redis_migrate_cached_sockets
- name: redis_pubsub_channels
- name: redis_pubsub_patterns
- name: redis_rdb_bgsave_in_progress
- name: redis_rdb_changes_since_last_save
- name: redis_rdb_current_bgsave_time_sec
- name: redis_rdb_last_bgsave_time_sec
- name: redis_rdb_last_save_time
type: COUNTER
- name: redis_rdb_last_save_time_elapsed
- name: redis_rejected_connections
- name: redis_repl_backlog_active
- name: redis_repl_backlog_first_byte_offset
- name: redis_repl_backlog_histlen
- name: redis_repl_backlog_size
- name: redis_sync_full
- name: redis_sync_partial_err
- name: redis_sync_partial_ok
- name: redis_total_net_input_bytes
type: COUNTER
- name: redis_total_net_output_bytes
type: COUNTER
- name: redis_total_system_memory
type: COUNTER
- name: redis_uptime
type: COUNTER
- name: redis_used_cpu_sys
- name: redis_used_cpu_sys_children
- name: redis_used_cpu_user
- name: redis_used_cpu_user_children
- name: redis_used_memory_lua

View File

@ -1 +0,0 @@
mode: all # whitelist(default),all

View File

@ -1 +0,0 @@
mode: all # whitelist(default),all

View File

@ -1,13 +0,0 @@
workerProcesses: 5
logger:
dir: logs/prober
level: INFO
keepHours: 24
pluginsConfig: etc/plugins
report:
region: default
collectRule:
token: monapi-internal-third-module-pass-fjsdi

View File

@ -1,120 +0,0 @@
[
{
"name": "容器资源监控",
"node_path": "",
"tags": [
{
"name": "cpu",
"weight": 0,
"charts": [
{
"configs": "{\"title\":\"容器cpu使用率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.util\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"cpu\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 0
},
{
"configs": "{\"title\":\"容器cpu 用户态使用率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.user\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}]}",
"weight": 1
},
{
"configs": "{\"title\":\"容器cpu 内核态使用率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.sys\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}]}",
"weight": 2
},
{
"configs": "{\"title\":\"容器cpu idle\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.idle\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"cpu\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}]}",
"weight": 3
},
{
"configs": "{\"title\":\"容器cpu占用核数(=1代表占用1个核)\",\"type\":\"chart\",\"now\":\"1611720899999\",\"start\":\"1611717299999\",\"end\":\"1611720899999\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.cores.occupy\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"cpu\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":5}],\"id\":5}",
"weight": 4
},
{
"configs": "{\"title\":\"容器cpu 节流率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"cpu.throttled.util\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}]}",
"weight": 5
}
]
},
{
"name": "mem(单位为byte)",
"weight": 1,
"charts": [
{
"configs": "{\"title\":\"容器总内存大小\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"mem.bytes.total\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 0
},
{
"configs": "{\"title\":\"容器已用内存大小\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"mem.bytes.used\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 1
},
{
"configs": "{\"title\":\"容器内存工作集大小\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"mem.bytes.workingset\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 2
},
{
"configs": "{\"title\":\"容器内存使用率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"mem.bytes.used.percent\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 3
},
{
"configs": "{\"title\":\"容器内存工作集占用率(此为判定容器oom的依据)\",\"type\":\"chart\",\"now\":\"1611904149511\",\"start\":\"1611900549511\",\"end\":\"1611904149511\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"threshold\":null,\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"mem.bytes.workingset.percent\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":5}],\"id\":717}",
"weight": 4
}
]
},
{
"name": "文件系统和diskio(单位为byte)",
"weight": 2,
"charts": [
{
"configs": "{\"title\":\"容器文件系统总大小\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"disk.bytes.total\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 0
},
{
"configs": "{\"title\":\"容器文件系统已用大小\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"disk.bytes.used\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 1
},
{
"configs": "{\"title\":\"容器文件系统使用率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"disk.bytes.used.percent\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 2
},
{
"configs": "{\"title\":\"容器分区读取速率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"disk.io.read.bytes\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":3}],\"id\":15}",
"weight": 3
},
{
"configs": "{\"title\":\"容器分区写入速率\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"disk.io.write.bytes\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":3}]}",
"weight": 4
}
]
},
{
"name": "系统",
"weight": 4,
"charts": [
{
"configs": "{\"title\":\"容器已用fd数\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.fd.count.used\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 0
},
{
"configs": "{\"title\":\"容器fd数上限数\",\"type\":\"chart\",\"now\":\"1611727764407\",\"start\":\"1611724164407\",\"end\":\"1611727764407\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.fd.soft.ulimits\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"node_ip\",\"tagv\":[\"=all\"]},{\"tagk\":\"node_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":5}],\"id\":24}",
"weight": 1
},
{
"configs": "{\"title\":\"容器进程数\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.ps.process.count\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 2
},
{
"configs": "{\"title\":\"容器线程数\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.ps.thread.count\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 3
},
{
"configs": "{\"title\":\"容器socket数\",\"type\":\"chart\",\"now\":\"1610679026228\",\"start\":\"1610675426228\",\"end\":\"1610679026228\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.socket.count.used\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 4
},
{
"configs": "{\"title\":\"容器状态=sleeping\",\"type\":\"chart\",\"now\":\"1611727764407\",\"start\":\"1611724164407\",\"end\":\"1611727764407\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":5,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"5\"],\"selectedMetric\":\"sys.task.state\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"5\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"state\",\"tagv\":[\"sleeping\"]}],\"counterListCount\":5}],\"id\":28}",
"weight": 5
}
]
}
]
}
]

View File

@ -1,240 +0,0 @@
[
{
"name": "k8s控制平面大盘",
"node_path": "",
"tags": [
{
"name": "apiserver (延迟单位为秒)",
"weight": 0,
"charts": [
{
"configs": "{\"title\":\"请求总qps\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"code\",\"tagv\":[\"=all\"]},{\"tagk\":\"component\",\"tagv\":[\"=all\"]},{\"tagk\":\"contentType\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"group\",\"tagv\":[\"=all\"]},{\"tagk\":\"resource\",\"tagv\":[\"=all\"]},{\"tagk\":\"scope\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"subresource\",\"tagv\":[\"=all\"]},{\"tagk\":\"verb\",\"tagv\":[\"=all\"]},{\"tagk\":\"version\",\"tagv\":[\"=all\"]}],\"counterListCount\":11,\"aggrFunc\":\"sum\",\"aggrGroup\":[]}],\"id\":29}",
"weight": 0
},
{
"configs": "{\"title\":\"请求成功率(code=2xx|3xx /code=all)\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_successful_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"code\"]}],\"id\":76}",
"weight": 1
},
{
"configs": "{\"title\":\"wq 入队总qps\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"workqueue_adds_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"api-server\"]},{\"tagk\":\"name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":20,\"aggrGroup\":[],\"aggrFunc\":\"sum\"}],\"id\":35}",
"weight": 2
},
{
"configs": "{\"title\":\"apiserver延迟平均值\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_duration_seconds_avg\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrGroup\":[\"code\"]}],\"id\":77}",
"weight": 3
},
{
"configs": "{\"title\":\" apiserver延迟分位值\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_duration_seconds_all_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[\"code\"]}],\"id\":77}",
"weight": 4
},
{
"configs": "{\"title\":\"apiserver verb=list的延迟分位值(其余verb自行配置)\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_duration_seconds_verb_list_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[\"code\"]}],\"id\":78}",
"weight": 5
},
{
"configs": "{\"title\":\"apiserver响应大小分位值(单位byte)\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_response_sizes_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[\"code\"]}],\"id\":80}",
"weight": 6
},
{
"configs": "{\"title\":\"apiserver workqueue 项目在队列中等待延迟分位值\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_workqueue_queue_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[\"code\"]}],\"id\":77}",
"weight": 7
},
{
"configs": "{\"title\":\"请求qps按code分布\",\"type\":\"chart\",\"now\":\"1611309504049\",\"start\":\"1611305904049\",\"end\":\"1611309504049\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"code\",\"tagv\":[\"=all\"]},{\"tagk\":\"component\",\"tagv\":[\"=all\"]},{\"tagk\":\"contentType\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"group\",\"tagv\":[\"=all\"]},{\"tagk\":\"resource\",\"tagv\":[\"=all\"]},{\"tagk\":\"scope\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"subresource\",\"tagv\":[\"=all\"]},{\"tagk\":\"verb\",\"tagv\":[\"=all\"]},{\"tagk\":\"version\",\"tagv\":[\"=all\"]}],\"counterListCount\":9,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"code\"]}],\"id\":29}",
"weight": 8
},
{
"configs": "{\"title\":\"请求qps按verb分布\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_request_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"code\",\"tagv\":[\"=all\"]},{\"tagk\":\"component\",\"tagv\":[\"=all\"]},{\"tagk\":\"contentType\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"group\",\"tagv\":[\"=all\"]},{\"tagk\":\"resource\",\"tagv\":[\"=all\"]},{\"tagk\":\"scope\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"subresource\",\"tagv\":[\"=all\"]},{\"tagk\":\"verb\",\"tagv\":[\"=all\"]},{\"tagk\":\"version\",\"tagv\":[\"=all\"]}],\"counterListCount\":11,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"verb\"]}],\"id\":30}",
"weight": 9
},
{
"configs": "{\"title\":\"认证尝试数\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"authentication_attempts_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"result\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":2,\"aggrGroup\":[]}],\"id\":31}",
"weight": 10
},
{
"configs": "{\"title\":\"tls握手失败数\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_tls_handshake_errors_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrGroup\":[]}],\"id\":32}",
"weight": 11
},
{
"configs": "{\"title\":\"正在处理的请求数量的高水位线\",\"type\":\"chart\",\"now\":\"1610681549046\",\"start\":\"1610677949046\",\"end\":\"1610681549046\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_current_inflight_requests\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"request_kind\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":2,\"aggrGroup\":[]}],\"id\":29}",
"weight": 12
},
{
"configs": "{\"title\":\"最近排队请求数量的高水位线\",\"type\":\"chart\",\"now\":\"1610681549046\",\"start\":\"1610677949046\",\"end\":\"1610681549046\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"apiserver_current_inqueue_requests\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"request_kind\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":2,\"aggrGroup\":[]}],\"id\":29}",
"weight": 13
},
{
"configs": "{\"title\":\"wq retry数\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"workqueue_retries_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":19,\"aggrGroup\":[]}],\"id\":36}",
"weight": 14
},
{
"configs": "{\"title\":\"wq中最长运行时间\",\"type\":\"chart\",\"now\":\"1610681549046\",\"start\":\"1610677949046\",\"end\":\"1610681549046\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"workqueue_longest_running_processor_seconds\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":20,\"aggrGroup\":[]}],\"id\":29}",
"weight": 15
}
]
},
{
"name": "etcd",
"weight": 1,
"charts": [
{
"configs": "{\"title\":\"grpc qps\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"grpc_server_handled_total_rate\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"grpc_code\",\"tagv\":[\"=all\"]},{\"tagk\":\"grpc_method\",\"tagv\":[\"=all\"]},{\"tagk\":\"grpc_service\",\"tagv\":[\"=all\"]},{\"tagk\":\"grpc_type\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":697,\"aggrFunc\":\"sum\",\"aggrGroup\":[]}],\"id\":93}",
"weight": 0
},
{
"configs": "{\"title\":\"db 文件总大小\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_server_quota_backend_bytes\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":134}",
"weight": 1
},
{
"configs": "{\"title\":\"当前db文件大小\",\"type\":\"chart\",\"now\":\"1611720851130\",\"start\":\"1611717251130\",\"end\":\"1611720851130\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_mvcc_db_total_size_in_bytes\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":39}",
"weight": 2
},
{
"configs": "{\"title\":\"etcd入流量\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_network_client_grpc_received_bytes_total_rate\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":91}",
"weight": 3
},
{
"configs": "{\"title\":\"etcd出流量\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_network_client_grpc_sent_bytes_total_rate\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":92}",
"weight": 4
},
{
"configs": "{\"title\":\"总key数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_debugging_mvcc_keys_total\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":135}",
"weight": 5
},
{
"configs": "{\"title\":\"逻辑db文件大小\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_mvcc_db_total_size_in_use_in_bytes\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":86}",
"weight": 6
},
{
"configs": "{\"title\":\"wal fsync延迟分位值\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_disk_wal_fsync_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":89}",
"weight": 7
},
{
"configs": "{\"title\":\"db sync延迟分位值\",\"type\":\"chart\",\"now\":\"1611729986666\",\"start\":\"1611726386666\",\"end\":\"1611729986666\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"etcd_disk_backend_commit_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":90}",
"weight": 8
}
]
},
{
"name": "scheduler指标",
"weight": 2,
"charts": [
{
"configs": "{\"title\":\"调度队列pending pod数\",\"type\":\"chart\",\"now\":\"1610681549046\",\"start\":\"1610677949046\",\"end\":\"1610681549046\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"scheduler_pending_pods\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"__nid__6__\"]},{\"tagk\":\"queue\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":3}],\"id\":41}",
"weight": 0
},
{
"configs": "{\"title\":\" scheduler 端到端调度平均延迟\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"scheduler_e2e_scheduling_duration_seconds_avg\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":41}",
"weight": 1
},
{
"configs": "{\"title\":\"scheduler 成功调度一个pod 的平均尝试次数\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"scheduler_pod_scheduling_attempts_avg\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":41}",
"weight": 2
},
{
"configs": "{\"title\":\"请求apiserver速率\",\"type\":\"chart\",\"now\":\"1611661026507\",\"start\":\"1611657426507\",\"end\":\"1611661026507\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"rest_client_requests_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"code\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"kube-scheduler\"]},{\"tagk\":\"host\",\"tagv\":[\"=all\"]},{\"tagk\":\"method\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":3}],\"id\":106}",
"weight": 3
},
{
"configs": "{\"title\":\"请求apiserver延迟\",\"type\":\"chart\",\"now\":\"1611661026507\",\"start\":\"1611657426507\",\"end\":\"1611661026507\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"scheduler_rest_client_request_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":108}",
"weight": 4
},
{
"configs": "{\"title\":\"workqueue 项目在队列中等待延迟分位值\",\"type\":\"chart\",\"now\":\"1611730820804\",\"start\":\"1611727220804\",\"end\":\"1611730820804\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"scheduler_workqueue_queue_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":136}",
"weight": 5
}
]
},
{
"name": "controller-manager",
"weight": 3,
"charts": [
{
"configs": "{\"title\":\"工作队列新增速率\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"workqueue_adds_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"kube-controller-manager\"]},{\"tagk\":\"name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":44,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"func_name\",\"server_addr\"]}],\"id\":42}",
"weight": 0
},
{
"configs": "{\"title\":\"当前工作队列深度\",\"type\":\"chart\",\"now\":\"1610682325050\",\"start\":\"1610678725050\",\"end\":\"1610682325050\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"workqueue_depth\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":44}]}",
"weight": 1
},
{
"configs": "{\"title\":\"kube-api请求速率\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"rest_client_requests_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"code\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"kube-controller-manager\"]},{\"tagk\":\"host\",\"tagv\":[\"=all\"]},{\"tagk\":\"method\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":12,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"func_name\",\"server_addr\"]}],\"id\":44}",
"weight": 2
},
{
"configs": "{\"title\":\"controller_manager workqueue 项目在队列中等待延迟分位值\",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"controller_manager_workqueue_queue_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}]}",
"weight": 3
},
{
"configs": "{\"title\":\"controller_manager请求apiserver 的延迟分位值 \",\"type\":\"chart\",\"now\":\"1611658938170\",\"start\":\"1611655338170\",\"end\":\"1611658938170\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"controller_manager_rest_client_request_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}]}",
"weight": 4
},
{
"configs": "{\"title\":\"请求apiserver延迟\",\"type\":\"chart\",\"now\":\"1611730899017\",\"start\":\"1611727299017\",\"end\":\"1611730899017\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"controller_manager_rest_client_request_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":137}",
"weight": 6
}
]
},
{
"name": "coredns",
"weight": 4,
"charts": [
{
"configs": "{\"title\":\"解析请求数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_dns_requests_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"family\",\"tagv\":[\"=all\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"proto\",\"tagv\":[\"=all\"]},{\"tagk\":\"server\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"type\",\"tagv\":[\"=all\"]},{\"tagk\":\"zone\",\"tagv\":[\"=all\"]}],\"counterListCount\":6,\"aggrFunc\":\"sum\",\"aggrGroup\":[]}],\"id\":94}",
"weight": 0
},
{
"configs": "{\"title\":\"解析响应数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_dns_responses_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"rcode\",\"tagv\":[\"=all\"]},{\"tagk\":\"server\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"zone\",\"tagv\":[\"=all\"]}],\"counterListCount\":6,\"aggrFunc\":\"sum\",\"aggrGroup\":[]}],\"id\":95}",
"weight": 1
},
{
"configs": "{\"title\":\"缓存记录数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_cache_entries\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"type\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[]}],\"id\":96}",
"weight": 2
},
{
"configs": "{\"title\":\"缓存命中数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_cache_hits_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]},{\"tagk\":\"type\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrFunc\":\"sum\",\"aggrGroup\":[]}],\"id\":94}",
"weight": 3
},
{
"configs": "{\"title\":\"解析延迟记录分位值\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_dns_request_duration_seconds_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[]}],\"id\":98}",
"weight": 4
},
{
"configs": "{\"title\":\"解析响应大小分位值\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"coredns_dns_response_size_bytes_quantile\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrGroup\":[]}],\"id\":98}",
"weight": 5
}
]
},
{
"name": "进程监控",
"weight": 5,
"charts": [
{
"configs": "{\"title\":\"进程常驻内存大小单位byte\",\"type\":\"chart\",\"now\":\"1611730899017\",\"start\":\"1611727299017\",\"end\":\"1611730899017\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"process_resident_memory_bytes\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}],\"id\":100}",
"weight": 0
},
{
"configs": "{\"title\":\"进程打开fd数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"process_open_fds\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 1
},
{
"configs": "{\"title\":\"进程cpu核数\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"process_cpu_seconds_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 2
},
{
"configs": "{\"title\":\"goroutine数量\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"go_goroutines\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}]}",
"weight": 3
},
{
"configs": "{\"title\":\"最长gc耗时(单位秒)\",\"type\":\"chart\",\"now\":\"1611730899017\",\"start\":\"1611727299017\",\"end\":\"1611730899017\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"go_gc_duration_seconds\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"quantile\",\"tagv\":[\"1\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}],\"id\":104}",
"weight": 4
},
{
"configs": "{\"title\":\"alloc 内存\",\"type\":\"chart\",\"now\":\"1611658255494\",\"start\":\"1611654655494\",\"end\":\"1611658255494\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":[6],\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"go_memstats_alloc_bytes\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"func_name\",\"tagv\":[\"=all\"]},{\"tagk\":\"server_addr\",\"tagv\":[\"=all\"]}],\"counterListCount\":8}],\"id\":104}",
"weight": 5
}
]
}
]
}
]

View File

@ -1,216 +0,0 @@
[
{
"name": "k8s资源使用情况",
"node_path": "",
"tags": [
{
"name": "资源数总览",
"weight": 0,
"charts": [
{
"configs": "{\"title\":\"pod总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"host_ip\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod_ip\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 0
},
{
"configs": "{\"title\":\"容器总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_configmap_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"configmap\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":21,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 1
},
{
"configs": "{\"title\":\"node总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"kernel_version\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"os_image\",\"tagv\":[\"=all\"]}],\"counterListCount\":2,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 2
},
{
"configs": "{\"title\":\"deployment总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_deployment_labels\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"deployment\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":8,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 3
},
{
"configs": "{\"title\":\"daemonset总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_daemonset_labels\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"daemonset\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":4,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 4
},
{
"configs": "{\"title\":\"statefulset总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_statefulset_labels\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"statefulset\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 5
},
{
"configs": "{\"title\":\"configmap总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_configmap_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"configmap\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":21,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 6
},
{
"configs": "{\"title\":\"pvc总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_persistentvolumeclaim_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"persistentvolumeclaim\",\"tagv\":[\"=all\"]},{\"tagk\":\"storageclass\",\"tagv\":[\"=all\"]},{\"tagk\":\"volumename\",\"tagv\":[\"=all\"]}],\"counterListCount\":1,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 7
},
{
"configs": "{\"title\":\"secret总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_secret_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"secret\",\"tagv\":[\"=all\"]}],\"counterListCount\":57,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":117}",
"weight": 8
}
]
},
{
"name": "node指标",
"weight": 1,
"charts": [
{
"configs": "{\"title\":\"节点总数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"kernel_version\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"os_image\",\"tagv\":[\"=all\"]}],\"counterListCount\":2,\"aggrFunc\":\"sum\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":112}",
"weight": 0
},
{
"configs": "{\"title\":\"节点可以分配cpu核数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_status_allocatable_cpu_cores\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]}],\"counterListCount\":2}],\"chartTypeOptions\":{\"chartType\":\"table\",\"tableType\":\"stats\",\"columnsKey\":[\"last\"],\"valueMap\":\"range\",\"mapConf\":[{\"text\":\"\",\"from\":null,\"to\":null}]},\"id\":45}",
"weight": 1
},
{
"configs": "{\"title\":\"节点可以分配内存总量(单位:字节)\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_status_allocatable_memory_bytes\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]}],\"counterListCount\":2}],\"chartTypeOptions\":{\"chartType\":\"table\",\"tableType\":\"stats\",\"columnsKey\":[\"last\"],\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":46}",
"weight": 2
},
{
"configs": "{\"title\":\"节点可运行的pod总数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_status_capacity_pods\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]}],\"counterListCount\":2}],\"chartTypeOptions\":{\"chartType\":\"pie\",\"pieType\":\"pie\",\"targetValue\":\"avg\"},\"id\":47}",
"weight": 3
},
{
"configs": "{\"title\":\"运行pod数\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_num_value\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 4
},
{
"configs": "{\"title\":\"内存压力节点\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_status_condition\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"condition\",\"tagv\":[\"MemoryPressure\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"status\",\"tagv\":[\"true\"]}],\"counterListCount\":2}],\"id\":50}",
"weight": 5
},
{
"configs": "{\"title\":\"网络不可用节点\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_status_condition\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"condition\",\"tagv\":[\"NetworkUnavailable\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"status\",\"tagv\":[\"true\"]}],\"counterListCount\":2}],\"id\":51}",
"weight": 6
},
{
"configs": "{\"title\":\"cpu限制核数\",\"type\":\"chart\",\"now\":\"1611826614336\",\"start\":\"1611823014336\",\"end\":\"1611826614336\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_cpu_limits_value\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 7
},
{
"configs": "{\"title\":\"cpu限制率\",\"type\":\"chart\",\"now\":\"1611826681754\",\"start\":\"1611823081754\",\"end\":\"1611826681754\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_cpu_requests_percent\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 8
},
{
"configs": "{\"title\":\"cpu请求核数\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_cpu_requests_value\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 9
},
{
"configs": "{\"title\":\"cpu请求率\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_cpu_requests_percent\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 10
},
{
"configs": "{\"title\":\"内存请求\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_memory_requests_value\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 11
},
{
"configs": "{\"title\":\"内存请求率\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_memory_requests_percent\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 12
},
{
"configs": "{\"title\":\"内存限制\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_memory_limits_value\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 13
},
{
"configs": "{\"title\":\"内存限制率\",\"type\":\"chart\",\"now\":\"1611828002150\",\"start\":\"1611824402150\",\"end\":\"1611828002150\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_container_memory_limits_percent\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":381}",
"weight": 14
},
{
"configs": "{\"title\":\"运行pod数分位比\",\"type\":\"chart\",\"now\":\"1611827407063\",\"start\":\"1611823807063\",\"end\":\"1611827407063\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_node_pod_num_percent\",\"selectedTagkv\":[],\"counterListCount\":2}],\"id\":50}",
"weight": 15
}
]
},
{
"name": "pod指标",
"weight": 2,
"charts": [
{
"configs": "{\"title\":\"pengding 容器数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_status_phase\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\",\"__nid__5__\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"phase\",\"tagv\":[\"Pending\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"pod\"]}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":53}",
"weight": 0
},
{
"configs": "{\"title\":\"pengding 容器数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_container_status_waiting\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\",\"__nid__5__\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"pod\"]}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":54}",
"weight": 1
},
{
"configs": "{\"title\":\"pod处于waiting状态\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_container_status_waiting\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\",\"__nid__5__\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"max\",\"aggrGroup\":[\"container\"]}],\"id\":55}",
"weight": 2
},
{
"configs": "{\"title\":\"pod处于waiting状态(pull image error)\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_container_status_waiting_reason\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\",\"__nid__5__\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"reason\",\"tagv\":[\"ErrImagePull\"]}],\"counterListCount\":18,\"aggrFunc\":\"max\",\"aggrGroup\":[\"container\",\"reason\"]}],\"id\":56}",
"weight": 3
},
{
"configs": "{\"title\":\"pod容器重启qps\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"threshold\":0,\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_container_status_restarts_total_rate\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"max\",\"aggrGroup\":[\"container\",\"pod\"]}],\"id\":57}",
"weight": 4
},
{
"configs": "{\"title\":\"pod数按namespace分布\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"threshold\":null,\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"host_ip\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod_ip\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"namespace\"]}],\"id\":114}",
"weight": 5
},
{
"configs": "{\"title\":\"pod数按namespace分布\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"host_ip\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod_ip\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"namespace\"]}],\"chartTypeOptions\":{\"chartType\":\"pie\",\"pieType\":\"pie\",\"targetValue\":\"avg\"},\"id\":115}",
"weight": 6
},
{
"configs": "{\"title\":\"pod数按node分布\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"host_ip\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"node\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod_ip\",\"tagv\":[\"=all\"]}],\"counterListCount\":18,\"aggrFunc\":\"sum\",\"aggrGroup\":[\"host_ip\"]}],\"chartTypeOptions\":{\"chartType\":\"pie\",\"pieType\":\"pie\",\"targetValue\":\"avg\"},\"id\":116}",
"weight": 7
},
{
"configs": "{\"title\":\"\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_pod_container_info\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"container\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"pod\",\"tagv\":[\"=all\"]}],\"counterListCount\":18}],\"chartTypeOptions\":{\"chartType\":\"table\",\"tableType\":\"stats\",\"columnsKey\":[\"last\"],\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":127,\"sortOrder\":{\"columnKey\":\"last\"}}",
"weight": 8
}
]
},
{
"name": "deployment指标",
"weight": 3,
"charts": [
{
"configs": "{\"title\":\"可用副本数\",\"type\":\"chart\",\"now\":\"1610682325050\",\"start\":\"1610678725050\",\"end\":\"1610682325050\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_deployment_status_replicas_available\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"deployment\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":58}",
"weight": 0
},
{
"configs": "{\"title\":\"不可用副本数\",\"type\":\"chart\",\"now\":\"1610682325050\",\"start\":\"1610678725050\",\"end\":\"1610682325050\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_deployment_status_replicas_unavailable\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"deployment\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":58}",
"weight": 1
},
{
"configs": "{\"title\":\"deployment期望副本数\",\"type\":\"chart\",\"now\":\"1610682325050\",\"start\":\"1610678725050\",\"end\":\"1610682325050\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_deployment_status_replicas\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\",\"__nid__6__\"]},{\"tagk\":\"deployment\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"chartTypeOptions\":{\"chartType\":\"pie\",\"pieType\":\"pie\",\"targetValue\":\"avg\"}}",
"weight": 2
}
]
},
{
"name": "daemonset指标",
"weight": 4,
"charts": [
{
"configs": "{\"title\":\"应该运行ds的节点数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_daemonset_status_desired_number_scheduled\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"10.178.27.152\"]},{\"tagk\":\"daemonset\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":61}",
"weight": 0
},
{
"configs": "{\"title\":\"当前运行ds的节点数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_daemonset_status_current_number_scheduled\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"daemonset\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":61}",
"weight": 1
},
{
"configs": "{\"title\":\"ds可用数\",\"type\":\"chart\",\"now\":\"1611728391441\",\"start\":\"1611724791441\",\"end\":\"1611728391441\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_daemonset_status_number_available\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"daemonset\",\"tagv\":[\"=all\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]}],\"counterListCount\":4}],\"id\":129}",
"weight": 2
}
]
},
{
"name": "statefulset",
"weight": 5,
"charts": [
{
"configs": "{\"title\":\"当前副本数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_statefulset_status_replicas_current\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"statefulset\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":130}",
"weight": 0
},
{
"configs": "{\"title\":\"当前ready数\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_statefulset_status_replicas_ready\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"statefulset\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":130}",
"weight": 1
},
{
"configs": "{\"title\":\"创建时间\",\"type\":\"chart\",\"now\":\"1611727764211\",\"start\":\"1611724164211\",\"end\":\"1611727764211\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":6,\"endpointsKey\":\"nids\",\"selectedEndpoint\":[\"6\"],\"selectedMetric\":\"kube_statefulset_created\",\"selectedTagkv\":[{\"tagk\":\"nids\",\"tagv\":[\"6\"]},{\"tagk\":\"namespace\",\"tagv\":[\"=all\"]},{\"tagk\":\"statefulset\",\"tagv\":[\"=all\"]}],\"counterListCount\":1}],\"id\":132}",
"weight": 2
}
]
}
]
}
]

View File

@ -1,38 +0,0 @@
[
{
"name": "日常巡检大盘",
"node_path": "",
"tags": [
{
"name": "机器负载",
"weight": 0,
"charts": [
{
"configs": "{\"title\":\"CPU使用率\",\"type\":\"chart\",\"now\":\"1611191937020\",\"start\":\"1611188337020\",\"end\":\"1611191937020\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"threshold\":75,\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"cpu.util\",\"selectedTagkv\":[],\"counterListCount\":6}],\"id\":152}",
"weight": 0
},
{
"configs": "{\"title\":\"进程总数\",\"type\":\"chart\",\"now\":\"1611192346064\",\"start\":\"1611188746064\",\"end\":\"1611192346064\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"sys.ps.process.total\",\"selectedTagkv\":[],\"counterListCount\":6,\"aggrFunc\":\"avg\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"normal\",\"valueMap\":\"range\",\"mapConf\":[{\"from\":0,\"to\":3000,\"color\":\"#07cf82\"},{\"from\":3000,\"to\":5000,\"color\":\"#ef900b\"},{\"from\":5000,\"to\":999999,\"color\":\"#f50505\"}],\"suffix\":\"个\"},\"id\":10}",
"weight": 1
},
{
"configs": "{\"title\":\"硬盘使用率\",\"type\":\"chart\",\"now\":\"1611211473892\",\"start\":\"1611207873892\",\"end\":\"1611211473892\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"disk.bytes.used.percent\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"=all\"]},{\"tagk\":\"mount\",\"tagv\":[\"=all\"]}],\"counterListCount\":11}],\"chartTypeOptions\":{\"chartType\":\"table\",\"tableType\":\"stats\",\"columnsKey\":[\"last\"],\"valueMap\":\"range\",\"mapConf\":[{}]},\"id\":13,\"sortOrder\":{\"columnKey\":\"last\",\"order\":\"descend\"}}",
"weight": 2
},
{
"configs": "{\"title\":\"内存使用率均值-纯演示扇形图\",\"type\":\"chart\",\"now\":\"1611231230645\",\"start\":\"1611227630645\",\"end\":\"1611231230645\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"mem.bytes.used.percent\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"=all\"]}],\"counterListCount\":6,\"aggrFunc\":\"avg\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"solidGauge\",\"valueMap\":\"range\",\"mapConf\":[{\"from\":0,\"to\":40,\"color\":\"#06c663\"},{\"from\":40,\"to\":70,\"color\":\"#da8e0b\"},{\"from\":70,\"to\":90,\"color\":\"#f48b71\"},{\"from\":90,\"to\":111,\"color\":\"#fa0505\"}]},\"id\":11}",
"weight": 3
},
{
"configs": "{\"title\":\"IO使用率-纯演示水位图\",\"type\":\"chart\",\"now\":\"1611231230645\",\"start\":\"1611227630645\",\"end\":\"1611231230645\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"disk.io.util\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"=all\"]},{\"tagk\":\"device\",\"tagv\":[\"=all\"]}],\"counterListCount\":24,\"aggrFunc\":\"avg\"}],\"chartTypeOptions\":{\"chartType\":\"singleValue\",\"targetValue\":\"avg\",\"subType\":\"liquidFillGauge\",\"valueMap\":\"range\",\"mapConf\":[{\"color\":\"#07b904\",\"from\":0,\"to\":50},{\"from\":50,\"to\":100,\"color\":\"#e01a1a\"}]},\"id\":12}",
"weight": 4
},
{
"configs": "{\"title\":\"进程数-纯演示饼图\",\"type\":\"chart\",\"now\":\"1611231230645\",\"start\":\"1611227630645\",\"end\":\"1611231230645\",\"comparisonOptions\":[{\"label\":\"1小时\",\"labelEn\":\"1 hour\",\"value\":\"3600000\"},{\"label\":\"2小时\",\"labelEn\":\"2 hours\",\"value\":\"7200000\"},{\"label\":\"1天\",\"labelEn\":\"1 day\",\"value\":\"86400000\"},{\"label\":\"2天\",\"labelEn\":\"2 days\",\"value\":\"172800000\"},{\"label\":\"7天\",\"labelEn\":\"7 days\",\"value\":\"604800000\"}],\"legend\":false,\"shared\":true,\"linkVisible\":true,\"metrics\":[{\"selectedNid\":1,\"endpointsKey\":\"endpoints\",\"selectedEndpoint\":[\"=all\"],\"selectedMetric\":\"sys.ps.process.total\",\"selectedTagkv\":[{\"tagk\":\"endpoint\",\"tagv\":[\"=all\"]}],\"counterListCount\":6}],\"chartTypeOptions\":{\"chartType\":\"pie\",\"pieType\":\"donut\",\"targetValue\":\"avg\"},\"id\":14}",
"weight": 5
}
]
}
]
}
]

80
etc/script/notify.py Executable file
View File

@ -0,0 +1,80 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
import json
import os
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 希望的demo实现效果
# 1. 从stdin拿到告警信息之后格式化为一个有缩进的json写入一个临时文件
# 2. 文件路径和名字是.alerts/${timestamp}_${ruleid}
# 3. 调用SMTP服务器发送告警微信、钉钉、飞书、slack、jira、短信、电话等等留给社区实现
mail_host = "smtp.163.com"
mail_port = 994
mail_user = "ulricqin"
mail_pass = "password"
mail_from = "ulricqin@163.com"
# just for test
mail_body = """
<p>邮件发送测试</p>
<p><a href="https://www.baidu.com">baidu</a></p>
"""
def main():
payload = json.load(sys.stdin)
persist(payload)
def persist(payload):
if not os.path.exists(".alerts"):
os.makedirs(".alerts")
filename = '%d_%d' % (payload['event']['trigger_time'], payload['rule']['id'])
filepath = os.path.join(".alerts", filename)
f = open(filepath, 'w')
print(json.dumps(payload, indent=4), file=f)
f.close()
def send_mail(payload):
print("send_mail")
def send_wecom(payload):
print("send_wecom")
def send_dingtalk(payload):
print("send_dingtalk")
def mail_test():
print("mail_test_todo")
recipients = ["ulricqin@qq.com", "ulric@163.com"]
message = MIMEText(mail_body, 'html', 'utf-8')
message['From'] = mail_from
message['To'] = ", ".join(recipients)
message["Subject"] = "n9e alert"
smtp = smtplib.SMTP_SSL(mail_host, mail_port)
smtp.login(mail_user, mail_pass)
smtp.sendmail(mail_from, recipients, message.as_string())
smtp.close()
print("mail_test_done")
if __name__ == "__main__":
if len(sys.argv) == 1:
main()
elif sys.argv[1] == "mail":
mail_test()
else:
print("I am confused")

View File

@ -1,201 +1,121 @@
logger:
dir: logs/server
level: INFO
# rotate by time
keepHours: 24
## rotate by size
#rotatenum: 3
#rotatesize: 256 # unit: MB
dir: logs
level: DEBUG
# # rotate by time
# keepHours: 4
# rotate by size
rotatenum: 3
rotatesize: 256 # unit: MB
http:
mode: release
showLog: true
session:
cookieName: ecmc-sid
cookieDomain: ""
httpOnly: true
gcInterval: 60
cookieLifetime: 86400 # unit: second, 0: cookie life same to browser
# whether print access log to DEBUG.log
access: false
listen: 0.0.0.0:8000
pprof: false
cookieName: n9e
cookieDomain: ""
cookieMaxAge: 86400
cookieSecure: false
cookieHttpOnly: true
cookieSecret: 4696709ab8cc3ff2fea17b930158516b
csrfSecret: 15b8ea164b5d3d9254677053c72a19f1
tokens:
- rdb-builtin-token
- ams-builtin-token
rpc:
listen: 0.0.0.0:9000
redis:
# as queue
local:
enable: true
addr: 127.0.0.1:6379
pass: ""
idle: 5
timeout:
conn: 500
read: 3000
write: 3000
mysql:
addr: "root:1234@tcp(127.0.0.1:3306)/n9e?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
max: 128
idle: 16
debug: false
# i18n:
# # zh | en
# lang: zh
# dictPath: etc/i18n.json
rdb:
# for ldap authorization
ldap:
host: "ldap.example.org"
port: 389
baseDn: "dc=example,dc=org"
# AD: manange@example.org
bindUser: "cn=manager,dc=example,dc=org"
bindPass: "*******"
# openldap: (&(uid=%s))
# AD: (&(sAMAccountName=%s))
authFilter: "(&(uid=%s))"
attributes:
dispname: "cn"
email: "mail"
phone: "mobile"
im: ""
coverAttributes: false
autoRegist: true
tls: false
startTLS: false
sender:
mail:
# three choice: smtp|shell|api
way: smtp
worker: 10
api: http://127.0.0.1:2008/mail
sms:
# two choice: shell|api
way: api
worker: 10
api: http://127.0.0.1:2008/sms
voice:
# two choice: shell|api
way: shell
worker: 10
api: http://127.0.0.1:2008/voice
im:
# five choice: shell|api|wechat|wechat_robot|dingtalk_robot
way: shell
worker: 10
api: http://127.0.0.1:2008/im
## for enterprise edition
#sso:
# enable: false
# ssoAddr: "http://{sso-host}"
# redirectURL: "http://{rdb-host}/auth-callback"
# clientId: ""
# clientSecret: ""
# apiKey: ""
# attributes:
# dispname: "display_name"
# email: "email"
# phone: "phone"
# im: ""
# coverAttributes: false
# stateExpiresIn: 300
#auth:
# captcha: false
# extraMode:
# enable: false # enable whiteList, login retry lock, userControl, ...
# whiteList: false
# frozenDays: 90 # frozen time (day)
# writenOffDays: 365 # writenOff time (day)
# heartbeat:
# # auto detect if blank
# ip: ""
# # unit: ms
# interval: 1000
# ldap:
# enable: false
# host: ldap.example.org
# port: 389
# baseDn: "dc=example,dc=org"
# # AD: manange@example.org
# bindUser: "cn=manager,dc=example,dc=org"
# bindPass: "*******"
# # openldap: (&(uid=%s))
# # AD: (&(sAMAccountName=%s))
# authFilter: "(&(uid=%s))"
# attributes:
# nickname: "cn"
# email: "mail"
# phone: "mobile"
# coverAttributes: false
# autoRegist: true
# tls: false
# startTLS: false
#i18n:
# lang: zh
# judge:
# readBatch: 2000
# connTimeout: 2000
# callTimeout: 5000
# writerNum: 256
# connMax: 2560
# connIdle: 256
job:
enable: true
## database | remote
#outputComeFrom: database
#remoteAgtdPort: 2080
# alert:
# notifyScriptPath: ./etc/script/notify.py
# notifyConcurrency: 200
# mutedAlertPersist: true
transfer:
trans:
enable: true
backend:
datasource: "m3db"
m3db:
enabled: true
maxSeriesPoints: 720 # default 720
name: "m3db"
namespace: "default"
seriesLimit: 0
docsLimit: 0
daysLimit: 7 # max query time
datasource: "prometheus"
prometheus:
enable: true
name: prometheus
batch: 100000
maxRetry: 5
# prometheus 查询返回最大点数query.max-samples
maxSamples: 50000000
# prometheus并发的查询 query.max-concurrency
maxConcurrentQuery: 20
# prometheus 回查窗口 query.lookback-delta
lookbackDeltaMinute: 2
# 查询全量索引时时间窗口限制,降低高基数
maxFetchAllSeriesLimitMinute: 5
remoteWrite:
# m3db的配置
#- name: m3db01
# url: http://localhost:7201/api/v1/prom/remote/write
# remoteTimeoutSecond: 5
# https://m3db.github.io/m3/m3db/architecture/consistencylevels/
writeConsistencyLevel: "majority" # one|majority|all
readConsistencyLevel: "unstrict_majority" # one|unstrict_majority|majority|all
writeTimeout: 5s
fetchTimeout: 5s
connectTimeout: 5s
config:
service:
# KV environment, zone, and service from which to write/read KV data (placement
# and configuration). Leave these as the default values unless you know what
# you're doing.
env: default_env
zone: embedded
service: m3db
etcdClusters:
- zone: embedded
endpoints:
- 127.0.0.1:2379
#tls:
# caCrtPath: /etc/etcd/certs/ca.pem
# crtPath: /etc/etcd/certs/etcd-client.pem
# keyPath: /etc/etcd/certs/etcd-client-key.pem
#tsdb:
# enabled: false
# name: "tsdb"
# cluster:
# tsdb01: 127.0.0.1:8011
#influxdb:
# enabled: false
# username: "influx"
# password: "admin123"
# precision: "s"
# database: "n9e"
# address: "http://127.0.0.1:8086"
#opentsdb:
# enabled: false
# address: "127.0.0.1:4242"
#kafka:
# enabled: false
# brokersPeers: "192.168.1.1:9092,192.168.1.2:9092"
# topic: "n9e"
monapi:
indexMod: server
alarmEnabled: true
region:
- default
# clean history event
cleaner:
# retention days
days: 100
# number of events deleted per time
batch: 100
notify:
p1: ["voice", "sms", "mail", "im"]
p2: ["sms", "mail", "im"]
p3: ["mail", "im"]
# prometheus的配置
- name: prome01
url: http://localhost:9090/api/v1/write
remoteTimeoutSecond: 5
remoteRead:
- name: prome01
url: http://localhost:9090/api/v1/read
remoteTimeoutSecond: 5
# addresses accessible using browser
link:
stra: http://n9e.com/mon/strategy/%v
event: http://n9e.com/mon/history/his/%v
claim: http://n9e.com/mon/history/cur/%v
judge:
query:
maxConn: 2000
maxIdle: 100
connTimeout: 1000
callTimeout: 2000
indexCallTimeout: 2000
indexMod: server
contactKeys:
- label: "Wecom Robot Token"
key: wecom_robot_token
- label: "Dingtalk Robot Token"
key: dingtalk_robot_token
wechat:
corp_id: "xxxxxxxxxxxxx"
agent_id: 1000000
secret: "xxxxxxxxxxxxxxxxx"
notifyChannels:
- email
- sms
- voice
- dingtalk
- wecom

View File

@ -1,21 +0,0 @@
[Unit]
Description=n9e agent
After=network-online.target
Wants=network-online.target
[Service]
# modify when deploy in prod env
User=root
Group=root
Type=simple
Environment="GIN_MODE=release"
ExecStart=/home/n9e/n9e-agentd
WorkingDirectory=/home/n9e
Restart=always
RestartSec=1
StartLimitInterval=0
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,19 @@
[Unit]
Description="n9e-agentd"
[Service]
Type=simple
ExecStart=/opt/n9e/n9e-agentd -c /opt/n9e/etc/agentd.yml
WorkingDirectory=/opt/n9e
Restart=always
RestartSecs=1s
SuccessExitStatus=0
LimitNOFILE=65536
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=n9e-agentd
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,19 @@
[Unit]
Description="n9e-server"
[Service]
Type=simple
ExecStart=/opt/n9e/n9e-server
WorkingDirectory=/opt/n9e
Restart=always
RestartSecs=1s
SuccessExitStatus=0
LimitNOFILE=65536
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=n9e-server
[Install]
WantedBy=multi-user.target

View File

@ -1,21 +0,0 @@
[Unit]
Description=n9e prober
After=network-online.target
Wants=network-online.target
[Service]
# modify when deploy in prod env
User=root
Group=root
Type=simple
Environment="GIN_MODE=release"
ExecStart=/home/n9e/n9e-prober
WorkingDirectory=/home/n9e
Restart=always
RestartSec=1
StartLimitInterval=0
[Install]
WantedBy=multi-user.target

View File

@ -1,24 +0,0 @@
[Unit]
Description=n9e server
After=network-online.target
Wants=network-online.target
[Service]
# modify when deploy in prod env
User=root
Group=root
Type=simple
Environment="GIN_MODE=release"
ExecStart=/home/n9e/n9e-server
WorkingDirectory=/home/n9e
Restart=always
RestartSec=1
StartLimitInterval=0
# LimitNOFILE=60000
# LimitNPROC=10000
[Install]
WantedBy=multi-user.target

View File

@ -1 +0,0 @@
您好,您的验证码为 {{.Code}}

View File

@ -1 +0,0 @@
您好,您的验证码为 {{.Code}}

View File

@ -1,245 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>夜莺告警通知</title>
<style type="text/css">
.wrapper {
background-color: #f8f8f8;
padding: 15px;
height: 100%;
}
.main {
width: 600px;
padding: 30px;
margin: 0 auto;
background-color: #fff;
font-size: 12px;
font-family: verdana,'Microsoft YaHei',Consolas,'Deja Vu Sans Mono','Bitstream Vera Sans Mono';
}
header {
border-radius: 2px 2px 0 0;
}
header .title {
font-size: 16px;
color: #333333;
margin: 0;
}
header .sub-desc {
color: #333;
font-size: 14px;
margin-top: 6px;
margin-bottom: 0;
}
hr {
margin: 20px 0;
height: 0;
border: none;
border-top: 1px solid #e5e5e5;
}
em {
font-weight: 600;
}
table {
margin: 20px 0;
width: 100%;
}
table tbody tr{
font-weight: 200;
font-size: 12px;
color: #666;
height: 32px;
}
.succ {
background-color: green;
color: white;
}
.fail {
background-color: red;
color: white;
}
table tbody tr th {
width: 80px;
text-align: right;
}
.text-right {
text-align: right;
}
.body {
margin-top: 24px;
}
.body-text {
color: #666666;
-webkit-font-smoothing: antialiased;
}
.body-extra {
-webkit-font-smoothing: antialiased;
}
.body-extra.text-right a {
text-decoration: none;
color: #333;
}
.body-extra.text-right a:hover {
color: #666;
}
.button {
width: 200px;
height: 50px;
margin-top: 20px;
text-align: center;
border-radius: 2px;
background: #2D77EE;
line-height: 50px;
font-size: 20px;
color: #FFFFFF;
cursor: pointer;
}
.button:hover {
background: rgb(25, 115, 255);
border-color: rgb(25, 115, 255);
color: #fff;
}
footer {
margin-top: 10px;
text-align: right;
}
.footer-logo {
text-align: right;
}
.footer-logo-image {
width: 108px;
height: 27px;
margin-right: 10px;
}
.copyright {
margin-top: 10px;
font-size: 12px;
text-align: right;
color: #999;
-webkit-font-smoothing: antialiased;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="main">
<header>
<h3 class="title">{{.Sname}}</h3>
<p class="sub-desc"></p>
</header>
<hr>
<div class="body">
<div class="body-text">
<div style="color: red">
{{if .IsUpgrade}}
注意,告警已触发升级!
{{end}}
</div>
</div>
<table cellspacing="0" cellpadding="0" border="0">
<tbody>
{{if .IsAlert}}
<tr class="fail">
<th>级别状态:</th>
<td>{{.Status}}</td>
</tr>
{{else}}
<tr class="succ">
<th>级别状态:</th>
<td>{{.Status}}</td>
</tr>
{{end}}
{{if .IsMachineDep}}
<tr>
<th>告警设备:</th>
<td>{{.Endpoint}}</td>
</tr>
<tr>
<th>设备名称:</th>
<td>{{.Name}}</td>
</tr>
<tr>
<th>设备备注:</th>
<td>{{.Note}}</td>
</tr>
<tr>
<th>挂载节点:</th>
<td>
{{range .Bindings}}
{{.}}<br />
{{end}}
</td>
</tr>
{{else}}
<tr>
<th>所属节点:</th>
<td>{{.CurNodePath}}</td>
</tr>
{{end}}
<tr>
<th>监控指标:</th>
<td>{{.Metric}}</td>
</tr>
<tr>
<th>tags</th>
<td>{{.Tags}}</td>
</tr>
<tr>
<th>当前值:</th>
<td>{{.Value}}</td>
</tr>
<tr>
<th>报警说明:</th>
<td>
{{.Info}}
</td>
</tr>
<tr>
<th>触发时间:</th>
<td>
{{.Etime}}
</td>
</tr>
<tr>
<th>报警详情:</th>
<td>{{.Elink}}</td>
</tr>
<tr>
<th>报警策略:</th>
<td>{{.Slink}}</td>
</tr>
{{if .HasClaim}}
<tr>
<th>认领报警:</th>
<td>{{.Clink}}</td>
</tr>
{{end}}
</tbody>
</table>
<hr>
<footer>
<div class="footer-logo">
<a href="https://n9e.didiyun.com">
<img src="https://s3-gz01.didistatic.com/n9e-pub/image/n9e-logo-bg-white.png" class="footer-logo-image" alt="">
</a>
</div>
<div class="copyright" style="font-style: italic">
我们希望与您一起,将监控这个事情,做到极致!
</div>
</footer>
</div>
</div>
</div>
</body>
</html>

View File

@ -1 +0,0 @@
您好,您的密码已被重置

View File

@ -1,16 +0,0 @@
{{if .IsUpgrade}}注意,告警已触发升级!{{end}}
级别状态:{{.Status}}
策略名称:{{.Sname}}
告警设备:{{.Endpoint}}
设备名称:{{.Name}}
设备备注:{{.Note}}
挂载节点:
{{range .Bindings}}{{.}}
{{end}}监控指标:{{.Metric}}
指标标签:{{.Tags}}
当前值:{{.Value}}
报警说明:{{.Info | unescaped}}
触发时间:{{.Etime}}
报警详情:{{.Elink | urlconvert}}
报警策略:{{.Slink | urlconvert}}
{{if .HasClaim}}认领报警:{{.Clink | urlconvert}}{{end}}

108
go.mod
View File

@ -1,86 +1,56 @@
module github.com/didi/nightingale/v4
module github.com/didi/nightingale/v5
go 1.12
go 1.14
require (
github.com/Shopify/sarama v1.27.2
github.com/alouca/gologger v0.0.0-20120904114645-7d4b7291de9c // indirect
github.com/blang/semver v3.5.1+incompatible
github.com/cespare/xxhash v1.1.0
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/freedomkk-qfeng/go-fastping v0.0.0-20160109021039-d7bb493dee3e // indirect
github.com/gaochao1/gosnmp v0.0.0-20150630013918-783a67a067fd // indirect
github.com/gaochao1/sw v4.0.0+incompatible
github.com/garyburd/redigo v1.6.2
github.com/armon/go-metrics v0.3.4 // indirect
github.com/gin-contrib/gzip v0.0.3
github.com/gin-contrib/pprof v1.3.0
github.com/gin-contrib/sessions v0.0.3
github.com/gin-gonic/gin v1.6.3
github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663
github.com/go-kit/kit v0.10.0
github.com/go-ldap/ldap/v3 v3.2.4
github.com/go-sql-driver/mysql v1.5.0
github.com/google/uuid v1.1.2
github.com/hashicorp/golang-lru v0.5.4
github.com/hpcloud/tail v1.0.0
github.com/influxdata/influxdb v1.8.0
github.com/influxdata/telegraf v1.17.2
github.com/jackc/pgx v3.6.0+incompatible
github.com/lib/pq v1.6.0
github.com/m3db/m3 v0.15.17
github.com/gogo/protobuf v1.3.2
github.com/golang/snappy v0.0.2
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
github.com/gorilla/sessions v1.2.0 // indirect
github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.1-0.20190611123218-cf7d376da96d // indirect
github.com/magiconair/properties v1.8.2 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-sqlite3 v1.14.0 // indirect
github.com/mojocn/base64Captcha v1.3.1
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f // indirect
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62 // indirect
github.com/shirou/gopsutil v3.20.11+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c
github.com/n9e/agent-payload v0.0.0-20210619031503-b72325474651
github.com/opentracing-contrib/go-stdlib v1.0.0
github.com/opentracing/opentracing-go v1.2.0
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/common v0.17.0
github.com/prometheus/prometheus v1.8.2-0.20210220213500-8c8de46003d1
github.com/smartystreets/assertions v1.0.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/cast v1.3.1-0.20190531151931-f31dc0aaab5a // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.7.1
github.com/streadway/amqp v1.0.0
github.com/stretchr/testify v1.6.1
github.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07
github.com/toolkits/pkg v1.1.4
github.com/toolkits/sys v0.0.0-20170615103026-1f33b217ffaf // indirect
github.com/subosito/gotenv v1.2.1-0.20190917103637-de67a6614a4d // indirect
github.com/toolkits/csrf v1.0.5
github.com/toolkits/pkg v1.1.3
github.com/ugorji/go/codec v1.1.7
go.uber.org/automaxprocs v1.3.0 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/text v0.3.3
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ldap.v3 v3.1.0
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v2 v2.3.0
xorm.io/core v0.7.3
xorm.io/xorm v0.8.1
go.uber.org/atomic v1.7.0
go.uber.org/automaxprocs v1.4.0 // indirect
golang.org/x/text v0.3.5
gopkg.in/ini.v1 v1.51.1 // indirect
xorm.io/builder v0.3.7
xorm.io/xorm v1.0.7
)
replace github.com/satori/go.uuid => github.com/satori/go.uuid v1.2.0
// branch 0.9.3-pool-read-binary-3
replace github.com/apache/thrift => github.com/m3db/thrift v0.0.0-20190820191926-05b5a2227fe4
// NB(nate): upgrading to the latest msgpack is not backwards compatibile as msgpack will no longer attempt to automatically
// write an integer into the smallest number of bytes it will fit in. We rely on this behavior by having helper methods
// in at least two encoders (see below) take int64s and expect that msgpack will size them down accordingly. We'll have
// to make integer sizing explicit before attempting to upgrade.
//
// Encoders:
// src/metrics/encoding/msgpack/base_encoder.go
// src/dbnode/persist/fs/msgpack/encoder.go
replace gopkg.in/vmihailenco/msgpack.v2 => github.com/vmihailenco/msgpack v2.8.3+incompatible
replace github.com/stretchr/testify => github.com/stretchr/testify v1.1.4-0.20160305165446-6fe211e49392
replace github.com/prometheus/common => github.com/prometheus/common v0.9.1
// Fix legacy import path - https://github.com/uber-go/atomic/pull/60
replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0
// Pull in https://github.com/etcd-io/bbolt/pull/220, required for go 1.14 compatibility
//
// etcd 3.14.13 depends on v1.3.3, but everything before v1.3.5 has unsafe misuses, and fails hard on go 1.14
// TODO: remove after etcd pulls in the change to a new release on 3.4 branch
replace go.etcd.io/bbolt => go.etcd.io/bbolt v1.3.5
// https://github.com/ory/dockertest/issues/212
replace golang.org/x/sys => golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6
// for transfer
replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0

1205
go.sum

File diff suppressed because it is too large Load Diff

391
http/http_funcs.go Normal file
View File

@ -0,0 +1,391 @@
package http
import (
"net/http"
"strconv"
"strings"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
"github.com/didi/nightingale/v5/pkg/i18n"
"github.com/didi/nightingale/v5/pkg/ierr"
)
const defaultLimit = 20
func dangerous(v interface{}, code ...int) {
ierr.Dangerous(v, code...)
}
func bomb(code int, format string, a ...interface{}) {
ierr.Bomb(code, i18n.Sprintf(format, a...))
}
func bind(c *gin.Context, ptr interface{}) {
dangerous(c.ShouldBindJSON(ptr), http.StatusBadRequest)
}
func urlParamStr(c *gin.Context, field string) string {
val := c.Param(field)
if val == "" {
bomb(http.StatusBadRequest, "url param[%s] is blank", field)
}
return val
}
func urlParamInt64(c *gin.Context, field string) int64 {
strval := urlParamStr(c, field)
intval, err := strconv.ParseInt(strval, 10, 64)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert %s to int64", strval)
}
return intval
}
func urlParamInt(c *gin.Context, field string) int {
return int(urlParamInt64(c, field))
}
func queryStr(c *gin.Context, key string, defaultVal ...string) string {
val := c.Query(key)
if val != "" {
return val
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryInt(c *gin.Context, key string, defaultVal ...int) int {
strv := c.Query(key)
if strv != "" {
intv, err := strconv.Atoi(strv)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert [%s] to int", strv)
}
return intv
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryInt64(c *gin.Context, key string, defaultVal ...int64) int64 {
strv := c.Query(key)
if strv != "" {
intv, err := strconv.ParseInt(strv, 10, 64)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert [%s] to int64", strv)
}
return intv
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryBool(c *gin.Context, key string, defaultVal ...bool) bool {
strv := c.Query(key)
if strv != "" {
if strv == "true" || strv == "1" || strv == "on" || strv == "checked" || strv == "yes" || strv == "Y" {
return true
} else if strv == "false" || strv == "0" || strv == "off" || strv == "no" || strv == "N" {
return false
} else {
bomb(http.StatusBadRequest, "unknown arg[%s] value: %s", key, strv)
}
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "arg[%s] is necessary", key)
}
return defaultVal[0]
}
func offset(c *gin.Context, limit int) int {
if limit <= 0 {
limit = 10
}
page := queryInt(c, "p", 1)
return (page - 1) * limit
}
func renderMessage(c *gin.Context, v interface{}, statusCode ...int) {
code := 200
if len(statusCode) > 0 {
code = statusCode[0]
}
if v == nil {
c.JSON(code, gin.H{"err": ""})
return
}
switch t := v.(type) {
case string:
c.JSON(code, gin.H{"err": i18n.Sprintf(t)})
case error:
c.JSON(code, gin.H{"err": t.Error()})
}
}
func renderData(c *gin.Context, data interface{}, err error, statusCode ...int) {
code := 200
if len(statusCode) > 0 {
code = statusCode[0]
}
if err == nil {
c.JSON(code, gin.H{"dat": data, "err": ""})
return
}
renderMessage(c, err.Error(), code)
}
func renderZeroPage(c *gin.Context) {
renderData(c, gin.H{
"list": []int{},
"total": 0,
}, nil)
}
type idsForm struct {
Ids []int64 `json:"ids"`
}
func (f idsForm) Validate() {
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids empty")
}
}
func cookieUsername(c *gin.Context) string {
session := sessions.Default(c)
value := session.Get("username")
if value == nil {
return ""
}
return value.(string)
}
func headerUsername(c *gin.Context) string {
token := c.GetHeader("Authorization")
if token == "" {
return ""
}
ut, err := models.UserTokenGet("token=?", strings.TrimPrefix(token, "Bearer "))
if err != nil {
return ""
}
if ut == nil {
return ""
}
return ut.Username
}
// must get username
func loginUsername(c *gin.Context) string {
usernameInterface, has := c.Get("username")
if has {
return usernameInterface.(string)
}
username := cookieUsername(c)
if username == "" {
username = headerUsername(c)
}
if username == "" {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
c.Set("username", username)
return username
}
func loginUser(c *gin.Context) *models.User {
username := loginUsername(c)
user, err := models.UserGetByUsername(username)
dangerous(err)
if user == nil {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
if user.Status == 1 {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
return user
}
func User(id int64) *models.User {
obj, err := models.UserGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such user")
}
return obj
}
func UserGroup(id int64) *models.UserGroup {
obj, err := models.UserGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such user group")
}
return obj
}
func Classpath(id int64) *models.Classpath {
obj, err := models.ClasspathGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such classpath")
}
return obj
}
func Mute(id int64) *models.Mute {
obj, err := models.MuteGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such mute config")
}
return obj
}
func Dashboard(id int64) *models.Dashboard {
obj, err := models.DashboardGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such dashboard")
}
return obj
}
func ChartGroup(id int64) *models.ChartGroup {
obj, err := models.ChartGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such chart group")
}
return obj
}
func Chart(id int64) *models.Chart {
obj, err := models.ChartGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such chart")
}
return obj
}
func AlertRule(id int64) *models.AlertRule {
obj, err := models.AlertRuleGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert rule")
}
return obj
}
func AlertRuleGroup(id int64) *models.AlertRuleGroup {
obj, err := models.AlertRuleGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert rule group")
}
return obj
}
func AlertEvent(id int64) *models.AlertEvent {
obj, err := models.AlertEventGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert event")
}
return obj
}
func CollectRule(id int64) *models.CollectRule {
obj, err := models.CollectRuleGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such collect rule")
}
return obj
}
func MetricDescription(id int64) *models.MetricDescription {
obj, err := models.MetricDescriptionGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such metric description")
}
return obj
}
func Resource(id int64) *models.Resource {
obj, err := models.ResourceGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such resource")
}
classpathResources, err := models.ClasspathResourceGets("res_ident=?", obj.Ident)
dangerous(err)
for _, cr := range classpathResources {
obj.ClasspathIds = append(obj.ClasspathIds, cr.ClasspathId)
}
return obj
}

32
http/http_middle.go Normal file
View File

@ -0,0 +1,32 @@
package http
import (
"net/http"
"github.com/didi/nightingale/v5/pkg/ierr"
"github.com/gin-gonic/gin"
)
func login() gin.HandlerFunc {
return func(c *gin.Context) {
username := loginUsername(c)
c.Set("username", username)
// 这里调用loginUser主要是为了判断当前用户是否被disable了
loginUser(c)
c.Next()
}
}
func admin() gin.HandlerFunc {
return func(c *gin.Context) {
username := loginUsername(c)
c.Set("username", username)
user := loginUser(c)
if user.Role != "Admin" {
ierr.Bomb(http.StatusForbidden, "forbidden")
}
c.Next()
}
}

122
http/http_server.go Normal file
View File

@ -0,0 +1,122 @@
package http
import (
"context"
"fmt"
"net/http"
"os"
"path"
"strings"
"time"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/pkg/iaop"
)
var srv = &http.Server{
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
var skipPaths = []string{
"/api/n9e/auth/login",
"/api/n9e/self/password",
"/api/n9e/push",
"/v1/n9e/series",
}
func Start() {
c := config.Config
loggerMid := iaop.LoggerWithConfig(iaop.LoggerConfig{SkipPaths: skipPaths})
recoveryMid := iaop.Recovery()
if strings.ToLower(c.HTTP.Mode) == "release" {
gin.SetMode(gin.ReleaseMode)
iaop.DisableConsoleColor()
}
r := gin.New()
r.Use(recoveryMid)
// whether print access log
if c.HTTP.Access {
r.Use(loggerMid)
}
// use cookie to save session
store := cookie.NewStore([]byte(config.Config.HTTP.CookieSecret))
store.Options(sessions.Options{
Domain: config.Config.HTTP.CookieDomain,
MaxAge: config.Config.HTTP.CookieMaxAge,
Secure: config.Config.HTTP.CookieSecure,
HttpOnly: config.Config.HTTP.CookieHttpOnly,
Path: "/",
})
session := sessions.Sessions(config.Config.HTTP.CookieName, store)
r.Use(session)
configRoutes(r)
configNoRoute(r)
srv.Addr = c.HTTP.Listen
srv.Handler = r
go func() {
fmt.Println("http.listening:", srv.Addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("listening %s occur error: %s\n", srv.Addr, err)
os.Exit(3)
}
}()
}
// Shutdown http server
func Shutdown() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
fmt.Println("cannot shutdown http server:", err)
os.Exit(2)
}
// catching ctx.Done(). timeout of 5 seconds.
select {
case <-ctx.Done():
fmt.Println("shutdown http server timeout of 5 seconds.")
default:
fmt.Println("http server stopped")
}
}
func configNoRoute(r *gin.Engine) {
r.NoRoute(func(c *gin.Context) {
arr := strings.Split(c.Request.URL.Path, ".")
suffix := arr[len(arr)-1]
switch suffix {
case "png":
fallthrough
case "jpeg":
fallthrough
case "jpg":
fallthrough
case "gif":
fallthrough
case "css":
fallthrough
case "js":
fallthrough
case "html":
fallthrough
case "htm":
c.File(path.Join(strings.Split("pub/"+c.Request.URL.Path, "/")...))
default:
c.File(path.Join("pub", "index.html"))
}
})
}

293
http/router.go Normal file
View File

@ -0,0 +1,293 @@
package http
import (
"fmt"
"os"
"github.com/gin-contrib/gzip"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/toolkits/csrf"
"github.com/didi/nightingale/v5/config"
)
func configRoutes(r *gin.Engine) {
csrfMid := csrf.Middleware(csrf.Options{
Secret: config.Config.HTTP.CsrfSecret,
ErrorFunc: func(c *gin.Context) {
c.JSON(452, gin.H{"err": "csrf token mismatch"})
c.Abort()
},
})
if config.Config.HTTP.Pprof {
pprof.Register(r, "/api/debug/pprof")
}
guest := r.Group("/api/n9e")
{
guest.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
guest.GET("/pid", func(c *gin.Context) {
c.String(200, fmt.Sprintf("%d", os.Getpid()))
})
guest.GET("/addr", func(c *gin.Context) {
c.String(200, c.Request.RemoteAddr)
})
guest.POST("/auth/login", loginPost)
guest.GET("/auth/logout", logoutGet)
}
// for brower, expose location in nginx.conf
pages := r.Group("/api/n9e", csrfMid)
{
pages.GET("/csrf", func(c *gin.Context) {
renderData(c, csrf.GetToken(c), nil)
})
pages.GET("/roles", rolesGet)
pages.GET("/self/profile", selfProfileGet)
pages.PUT("/self/profile", selfProfilePut)
pages.PUT("/self/password", selfPasswordPut)
pages.GET("/self/token", selfTokenGets)
pages.POST("/self/token", selfTokenPost)
pages.PUT("/self/token", selfTokenPut)
pages.GET("/users", login(), userGets)
pages.POST("/users", admin(), userAddPost)
pages.GET("/user/:id/profile", login(), userProfileGet)
pages.PUT("/user/:id/profile", admin(), userProfilePut)
pages.PUT("/user/:id/status", admin(), userStatusPut)
pages.PUT("/user/:id/password", admin(), userPasswordPut)
pages.DELETE("/user/:id", admin(), userDel)
pages.GET("/user-groups", login(), userGroupListGet)
pages.GET("/user-groups/mine", login(), userGroupMineGet)
pages.POST("/user-groups", login(), userGroupAdd)
pages.PUT("/user-group/:id", login(), userGroupPut)
pages.GET("/user-group/:id", login(), userGroupGet)
pages.POST("/user-group/:id/members", login(), userGroupMemberAdd)
pages.DELETE("/user-group/:id/members", login(), userGroupMemberDel)
pages.DELETE("/user-group/:id", login(), userGroupDel)
pages.GET("/classpaths", login(), classpathListGets)
pages.POST("/classpaths", login(), classpathAdd)
pages.PUT("/classpath/:id", login(), classpathPut)
pages.DELETE("/classpath/:id", login(), classpathDel)
pages.POST("/classpath/:id/resources", login(), classpathAddResources)
pages.DELETE("/classpath/:id/resources", login(), classpathDelResources)
pages.GET("/classpath/:id/resources", login(), classpathGetsResources)
pages.GET("/classpaths/favorites", login(), classpathFavoriteGet)
pages.POST("/classpath/:id/favorites", login(), classpathFavoriteAdd)
pages.DELETE("/classpath/:id/favorites", login(), classpathFavoriteDel)
pages.GET("/resources", login(), resourcesQuery)
pages.PUT("/resources/note", resourceNotePut)
pages.PUT("/resources/tags", resourceTagsPut)
pages.PUT("/resources/classpaths", resourceClasspathsPut)
pages.PUT("/resources/mute", resourceMutePut)
pages.GET("/resource/:id", login(), resourceGet)
pages.DELETE("/resource/:id", login(), resourceDel)
pages.GET("/mutes", login(), muteGets)
pages.POST("/mutes", login(), muteAdd)
pages.GET("/mute/:id", login(), muteGet)
pages.DELETE("/mute/:id", login(), muteDel)
pages.GET("/dashboards", login(), dashboardGets)
pages.POST("/dashboards", login(), dashboardAdd)
pages.POST("/dashboards-clone", login(), dashboardClone)
pages.GET("/dashboard/:id", login(), dashboardGet)
pages.PUT("/dashboard/:id", login(), dashboardPut)
pages.DELETE("/dashboard/:id", login(), dashboardDel)
pages.POST("/dashboard/:id/favorites", login(), dashboardFavoriteAdd)
pages.DELETE("/dashboard/:id/favorites", login(), dashboardFavoriteDel)
pages.GET("/dashboard/:id/chart-groups", login(), chartGroupGets)
pages.POST("/dashboard/:id/chart-groups", login(), chartGroupAdd)
pages.PUT("/chart-groups", login(), chartGroupsPut)
pages.DELETE("/chart-group/:id", login(), chartGroupDel)
pages.GET("/chart-group/:id/charts", login(), chartGets)
pages.POST("/chart-group/:id/charts", login(), chartAdd)
pages.PUT("/chart/:id", login(), chartPut)
pages.DELETE("/chart/:id", login(), chartDel)
pages.PUT("/charts/configs", login(), chartConfigsPut)
pages.GET("/charts/tmps", login(), chartTmpGets)
pages.POST("/charts/tmps", login(), chartTmpAdd)
pages.GET("/alert-rule-groups", login(), alertRuleGroupGets)
pages.GET("/alert-rule-groups/favorites", login(), alertRuleGroupFavoriteGet)
pages.POST("/alert-rule-groups", login(), alertRuleGroupAdd)
pages.GET("/alert-rule-group/:id", login(), alertRuleGroupGet)
pages.GET("/alert-rule-group/:id/alert-rules", login(), alertRuleOfGroupGet)
pages.DELETE("/alert-rule-group/:id/alert-rules", login(), alertRuleOfGroupDel)
pages.PUT("/alert-rule-group/:id", login(), alertRuleGroupPut)
pages.DELETE("/alert-rule-group/:id", login(), alertRuleGroupDel)
pages.POST("/alert-rule-group/:id/favorites", login(), alertRuleGroupFavoriteAdd)
pages.DELETE("/alert-rule-group/:id/favorites", login(), alertRuleGroupFavoriteDel)
pages.GET("/check-promql", checkPromeQl)
pages.POST("/alert-rules", login(), alertRuleAdd)
pages.PUT("/alert-rules/status", login(), alertRuleStatusPut)
pages.GET("/alert-rule/:id", login(), alertRuleGet)
pages.PUT("/alert-rule/:id", login(), alertRulePut)
pages.DELETE("/alert-rule/:id", login(), alertRuleDel)
pages.GET("/alert-events", login(), alertEventGets)
pages.DELETE("/alert-events", login(), alertEventsDel)
pages.GET("/alert-event/:id", login(), alertEventGet)
pages.DELETE("/alert-event/:id", login(), alertEventDel)
pages.GET("/classpath/:id/collect-rules", login(), collectRuleGets)
pages.POST("/collect-rules", login(), collectRuleAdd)
pages.DELETE("/collect-rules", login(), collectRuleDel)
pages.PUT("/collect-rule/:id", login(), collectRulePut)
pages.POST("/log/check", regExpCheck) // check collect rule
pages.GET("/metric-descriptions", metricDescriptionGets)
pages.POST("/metric-descriptions", login(), metricDescriptionAdd)
pages.DELETE("/metric-descriptions", login(), metricDescriptionDel)
pages.PUT("/metric-description/:id", login(), metricDescriptionPut)
pages.GET("/contact-channels", contactChannelsGet)
pages.GET("/notify-channels", notifyChannelsGet)
pages.POST("/query", GetData)
pages.POST("/tag-keys", GetTagKeys)
pages.POST("/tag-values", GetTagValues)
pages.POST("/tag-metrics", GetMetrics)
pages.POST("/tag-pairs", GetTagPairs)
}
// for thirdparty, do not expose location in nginx.conf
v1 := r.Group("/v1/n9e")
{
v1.GET("/roles", rolesGet)
v1.GET("/self/profile", selfProfileGet)
v1.PUT("/self/profile", selfProfilePut)
v1.PUT("/self/password", selfPasswordPut)
v1.GET("/self/token", selfTokenGets)
v1.POST("/self/token", selfTokenPost)
v1.PUT("/self/token", selfTokenPut)
v1.GET("/users", login(), userGets)
v1.POST("/users", admin(), userAddPost)
v1.GET("/user/:id/profile", login(), userProfileGet)
v1.PUT("/user/:id/profile", admin(), userProfilePut)
v1.PUT("/user/:id/status", admin(), userStatusPut)
v1.PUT("/user/:id/password", admin(), userPasswordPut)
v1.DELETE("/user/:id", admin(), userDel)
v1.GET("/user-groups", login(), userGroupListGet)
v1.GET("/user-groups/mine", login(), userGroupMineGet)
v1.POST("/user-groups", login(), userGroupAdd)
v1.PUT("/user-group/:id", login(), userGroupPut)
v1.GET("/user-group/:id", login(), userGroupGet)
v1.POST("/user-group/:id/members", login(), userGroupMemberAdd)
v1.DELETE("/user-group/:id/members", login(), userGroupMemberDel)
v1.DELETE("/user-group/:id", login(), userGroupDel)
v1.GET("/classpaths", login(), classpathListGets)
v1.POST("/classpaths", login(), classpathAdd)
v1.PUT("/classpath/:id", login(), classpathPut)
v1.DELETE("/classpath/:id", login(), classpathDel)
v1.POST("/classpath/:id/resources", login(), classpathAddResources)
v1.DELETE("/classpath/:id/resources", login(), classpathDelResources)
v1.GET("/classpath/:id/resources", login(), classpathGetsResources)
v1.GET("/classpaths/favorites", login(), classpathFavoriteGet)
v1.POST("/classpath/:id/favorites", login(), classpathFavoriteAdd)
v1.DELETE("/classpath/:id/favorites", login(), classpathFavoriteDel)
v1.GET("/resources", login(), resourcesQuery)
v1.PUT("/resources/note", resourceNotePut)
v1.PUT("/resources/tags", resourceTagsPut)
v1.PUT("/resources/classpaths", resourceClasspathsPut)
v1.PUT("/resources/mute", resourceMutePut)
v1.GET("/resource/:id", login(), resourceGet)
v1.DELETE("/resource/:id", login(), resourceDel)
v1.GET("/classpath/:id/collect-rules", login(), collectRuleGets)
v1.GET("/mutes", login(), muteGets)
v1.POST("/mutes", login(), muteAdd)
v1.GET("/mute/:id", login(), muteGet)
v1.DELETE("/mute/:id", login(), muteDel)
v1.GET("/dashboards", login(), dashboardGets)
v1.POST("/dashboards", login(), dashboardAdd)
v1.GET("/dashboard/:id", login(), dashboardGet)
v1.PUT("/dashboard/:id", login(), dashboardPut)
v1.DELETE("/dashboard/:id", login(), dashboardDel)
v1.POST("/dashboard/:id/favorites", login(), dashboardFavoriteAdd)
v1.DELETE("/dashboard/:id/favorites", login(), dashboardFavoriteDel)
v1.GET("/dashboard/:id/chart-groups", login(), chartGroupGets)
v1.POST("/dashboard/:id/chart-groups", login(), chartGroupAdd)
v1.PUT("/chart-groups", login(), chartGroupsPut)
v1.DELETE("/chart-group/:id", login(), chartGroupDel)
v1.GET("/chart-group/:id/charts", login(), chartGets)
v1.POST("/chart-group/:id/charts", login(), chartAdd)
v1.PUT("/chart/:id", login(), chartPut)
v1.DELETE("/chart/:id", login(), chartDel)
v1.PUT("/charts/configs", login(), chartConfigsPut)
v1.GET("/charts/tmps", login(), chartTmpGets)
v1.POST("/charts/tmps", login(), chartTmpAdd)
v1.GET("/alert-rule-groups", login(), alertRuleGroupGets)
v1.POST("/alert-rule-groups", login(), alertRuleGroupAdd)
v1.GET("/alert-rule-group/:id", login(), alertRuleGroupGet)
v1.PUT("/alert-rule-group/:id", login(), alertRuleGroupPut)
v1.DELETE("/alert-rule-group/:id", login(), alertRuleGroupDel)
v1.GET("/alert-rule-groups/favorites", login(), alertRuleGroupFavoriteGet)
v1.DELETE("/alert-rule-group/:id/favorites", login(), alertRuleGroupFavoriteDel)
v1.POST("/alert-rule-group/:id/favorites", login(), alertRuleGroupFavoriteAdd)
v1.GET("/alert-rule-group/:id/alert-rules", login(), alertRuleOfGroupGet)
v1.DELETE("/alert-rule-group/:id/alert-rules", login(), alertRuleOfGroupDel)
v1.POST("/alert-rules", login(), alertRuleAdd)
v1.PUT("/alert-rules/status", login(), alertRuleStatusPut)
v1.GET("/alert-rule/:id", login(), alertRuleGet)
v1.PUT("/alert-rule/:id", login(), alertRulePut)
v1.DELETE("/alert-rule/:id", login(), alertRuleDel)
v1.GET("/alert-events", login(), alertEventGets)
v1.DELETE("/alert-events", login(), alertEventsDel)
v1.GET("/alert-event/:id", login(), alertEventGet)
v1.DELETE("/alert-event/:id", login(), alertEventDel)
v1.POST("/collect-rules", login(), collectRuleAdd)
v1.DELETE("/collect-rules", login(), collectRuleDel)
v1.PUT("/collect-rule/:id", login(), collectRulePut)
v1.GET("/collect-rules-belong-to-ident", collectRuleGetsByIdent)
v1.GET("/collect-rules-summary", collectRuleSummaryGetByIdent)
v1.GET("/metric-descriptions", metricDescriptionGets)
v1.POST("/metric-descriptions", login(), metricDescriptionAdd)
v1.DELETE("/metric-descriptions", login(), metricDescriptionDel)
v1.PUT("/metric-description/:id", login(), metricDescriptionPut)
v1.GET("/contact-channels", contactChannelsGet)
v1.GET("/notify-channels", notifyChannelsGet)
v1.POST("/push", PushData)
v1.POST("/query", GetData)
v1.GET("/check-promql", checkPromeQl)
v1.POST("/tag-keys", GetTagKeys)
v1.POST("/tag-values", GetTagValues)
v1.POST("/tag-metrics", GetMetrics)
v1.POST("/tag-pairs", GetTagPairs)
}
push := r.Group("/v1/n9e/series").Use(gzip.Gzip(gzip.DefaultCompression))
{
push.POST("", PushSeries)
}
}

View File

@ -0,0 +1,66 @@
package http
import (
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func alertEventGets(c *gin.Context) {
stime := queryInt64(c, "stime", 0)
etime := queryInt64(c, "etime", 0)
hours := queryInt64(c, "hours", 0)
now := time.Now().Unix()
if hours != 0 {
stime = now - 3600*hours
etime = now + 3600*24
}
if stime != 0 && etime == 0 {
etime = now + 3600*24
}
query := queryStr(c, "query", "")
priority := queryInt(c, "priority", -1)
status := queryInt(c, "status", -1)
limit := queryInt(c, "limit", defaultLimit)
total, err := models.AlertEventTotal(stime, etime, query, status, priority)
dangerous(err)
list, err := models.AlertEventGets(stime, etime, query, status, priority, limit, offset(c, limit))
dangerous(err)
for i := 0; i < len(list); i++ {
dangerous(list[i].FillObjs())
}
if len(list) == 0 {
renderZeroPage(c)
return
}
renderData(c, map[string]interface{}{
"total": total,
"list": list,
}, nil)
}
func alertEventGet(c *gin.Context) {
renderData(c, AlertEvent(urlParamInt64(c, "id")), nil)
}
func alertEventDel(c *gin.Context) {
loginUser(c).MustPerm("alert_event_delete")
renderMessage(c, AlertEvent(urlParamInt64(c, "id")).Del())
}
func alertEventsDel(c *gin.Context) {
var f idsForm
bind(c, &f)
f.Validate()
loginUser(c).MustPerm("alert_event_delete")
renderMessage(c, models.AlertEventsDel(f.Ids))
}

165
http/router_alert_rule.go Normal file
View File

@ -0,0 +1,165 @@
package http
import (
"encoding/json"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/models"
)
func alertRuleGet(c *gin.Context) {
renderData(c, AlertRule(urlParamInt64(c, "id")), nil)
}
type alertRuleForm struct {
GroupId int64 `json:"group_id"`
Name string `json:"name"`
Note string `json:"note"`
Type int `json:"type"`
Status int `json:"status"`
Expression json.RawMessage `json:"expression"`
AppendTags string `json:"append_tags"`
EnableStime string `json:"enable_stime"`
EnableEtime string `json:"enable_etime"`
EnableDaysOfWeek string `json:"enable_days_of_week"`
AlertDuration int `json:"alert_duration"`
RecoveryDuration int `json:"recovery_duration"`
RecoveryNotify int `json:"recovery_notify"`
Priority int `json:"priority"`
NotifyChannels string `json:"notify_channels"`
NotifyGroups string `json:"notify_groups"`
NotifyUsers string `json:"notify_users"`
Callbacks string `json:"callbacks"`
RunbookUrl string `json:"runbook_url"`
}
func alertRuleAdd(c *gin.Context) {
var f []alertRuleForm
bind(c, &f)
me := loginUser(c).MustPerm("alert_rule_create")
for _, alertRule := range f {
arg := AlertRuleGroup(alertRule.GroupId)
alertRuleWritePermCheck(arg, me)
ar := models.AlertRule{
GroupId: alertRule.GroupId,
Name: alertRule.Name,
Type: alertRule.Type,
Note: alertRule.Note,
Expression: alertRule.Expression,
AlertDuration: alertRule.AlertDuration,
AppendTags: alertRule.AppendTags,
EnableStime: alertRule.EnableStime,
EnableEtime: alertRule.EnableEtime,
EnableDaysOfWeek: alertRule.EnableDaysOfWeek,
RecoveryNotify: alertRule.RecoveryNotify,
Priority: alertRule.Priority,
NotifyChannels: alertRule.NotifyChannels,
NotifyGroups: alertRule.NotifyGroups,
NotifyUsers: alertRule.NotifyUsers,
Callbacks: alertRule.Callbacks,
RunbookUrl: alertRule.RunbookUrl,
CreateBy: me.Username,
UpdateBy: me.Username,
}
dangerous(ar.Add())
}
renderMessage(c, nil)
}
func alertRulePut(c *gin.Context) {
var f alertRuleForm
bind(c, &f)
me := loginUser(c).MustPerm("alert_rule_modify")
ar := AlertRule(urlParamInt64(c, "id"))
arg := AlertRuleGroup(ar.GroupId)
alertRuleWritePermCheck(arg, me)
ar.Name = f.Name
ar.Note = f.Note
ar.Status = f.Status
ar.AlertDuration = f.AlertDuration
ar.Expression = f.Expression
ar.AppendTags = f.AppendTags
ar.EnableStime = f.EnableStime
ar.EnableEtime = f.EnableEtime
ar.EnableDaysOfWeek = f.EnableDaysOfWeek
ar.RecoveryNotify = f.RecoveryNotify
ar.Priority = f.Priority
ar.NotifyChannels = f.NotifyChannels
ar.NotifyGroups = f.NotifyGroups
ar.NotifyUsers = f.NotifyUsers
ar.Callbacks = f.Callbacks
ar.RunbookUrl = f.RunbookUrl
ar.CreateBy = me.Username
ar.UpdateAt = time.Now().Unix()
ar.UpdateBy = me.Username
renderMessage(c, ar.Update(
"name",
"note",
"status",
"alert_duration",
"expression",
"res_filters",
"tags_filters",
"append_tags",
"enable_stime",
"enable_etime",
"enable_days_of_week",
"recovery_duration",
"recovery_notify",
"priority",
"notify_channels",
"notify_groups",
"notify_users",
"callbacks",
"runbook_url",
"update_at",
"update_by",
))
}
type alertRuleStatusForm struct {
Ids []int64 `json:"ids"`
Status int `json:"status"`
}
func alertRuleStatusPut(c *gin.Context) {
var f alertRuleStatusForm
bind(c, &f)
me := loginUser(c).MustPerm("alert_rule_modify")
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids is empty")
}
for _, id := range f.Ids {
alertRule := AlertRule(id)
arg := AlertRuleGroup(alertRule.GroupId)
alertRuleWritePermCheck(arg, me)
}
renderMessage(c, models.AlertRuleUpdateStatus(f.Ids, f.Status))
}
func alertRuleDel(c *gin.Context) {
me := loginUser(c).MustPerm("alert_rule_delete")
alertRule := AlertRule(urlParamInt64(c, "id"))
arg := AlertRuleGroup(alertRule.GroupId)
alertRuleWritePermCheck(arg, me)
renderMessage(c, alertRule.Del())
}
func notifyChannelsGet(c *gin.Context) {
renderData(c, config.Config.NotifyChannels, nil)
}

View File

@ -0,0 +1,165 @@
package http
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
)
func alertRuleGroupGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.AlertRuleGroupTotal(query)
dangerous(err)
list, err := models.AlertRuleGroupGets(query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
func alertRuleGroupFavoriteGet(c *gin.Context) {
lst, err := loginUser(c).FavoriteAlertRuleGroups()
renderData(c, lst, err)
}
type alertRuleGroupForm struct {
Name string `json:"name"`
UserGroupIds string `json:"user_group_ids"`
}
func alertRuleGroupAdd(c *gin.Context) {
var f alertRuleGroupForm
bind(c, &f)
me := loginUser(c).MustPerm("alert_rule_group_create")
arg := models.AlertRuleGroup{
Name: f.Name,
UserGroupIds: f.UserGroupIds,
CreateBy: me.Username,
UpdateBy: me.Username,
}
err := arg.Add()
if err == nil {
// 我创建的,顺便设置为我关注的
models.AlertRuleGroupFavoriteAdd(arg.Id, me.Id)
}
renderMessage(c, err)
}
func alertRuleGroupGet(c *gin.Context) {
alertRuleGroup := AlertRuleGroup(urlParamInt64(c, "id"))
alertRuleGroup.FillUserGroups()
renderData(c, alertRuleGroup, nil)
}
func alertRuleOfGroupGet(c *gin.Context) {
ars, err := models.AlertRulesOfGroup(urlParamInt64(c, "id"))
renderData(c, ars, err)
}
func alertRuleOfGroupDel(c *gin.Context) {
var f idsForm
bind(c, &f)
f.Validate()
loginUser(c).MustPerm("alert_rule_delete")
renderMessage(c, models.AlertRulesDel(f.Ids))
}
func alertRuleGroupPut(c *gin.Context) {
var f alertRuleGroupForm
bind(c, &f)
me := loginUser(c).MustPerm("alert_rule_group_modify")
arg := AlertRuleGroup(urlParamInt64(c, "id"))
alertRuleWritePermCheck(arg, me)
if arg.Name != f.Name {
num, err := models.AlertRuleGroupCount("name=? and id<>?", f.Name, arg.Id)
dangerous(err)
if num > 0 {
bomb(200, "AlertRuleGroup %s already exists", f.Name)
}
}
arg.Name = f.Name
arg.UserGroupIds = f.UserGroupIds
arg.UpdateBy = me.Username
arg.UpdateAt = time.Now().Unix()
renderMessage(c, arg.Update("name", "update_by", "update_at", "user_group_ids"))
}
func alertRuleGroupDel(c *gin.Context) {
me := loginUser(c).MustPerm("alert_rule_group_delete")
arg := AlertRuleGroup(urlParamInt64(c, "id"))
alertRuleWritePermCheck(arg, me)
renderMessage(c, arg.Del())
}
func alertRuleGroupFavoriteAdd(c *gin.Context) {
me := loginUser(c)
arg := AlertRuleGroup(urlParamInt64(c, "id"))
renderMessage(c, models.AlertRuleGroupFavoriteAdd(arg.Id, me.Id))
}
func alertRuleGroupFavoriteDel(c *gin.Context) {
me := loginUser(c)
arg := AlertRuleGroup(urlParamInt64(c, "id"))
renderMessage(c, models.AlertRuleGroupFavoriteDel(arg.Id, me.Id))
}
func alertRuleWritePermCheck(alertRuleGroup *models.AlertRuleGroup, user *models.User) {
if user.Role == "Admin" {
return
}
gids := IdsInt64(alertRuleGroup.UserGroupIds)
if len(gids) == 0 {
// 压根没有配置管理团队表示对所有Standard角色放开那就不校验了
return
}
for _, gid := range gids {
if cache.UserGroupMember.Exists(gid, user.Id) {
return
}
}
bomb(http.StatusForbidden, "no permission")
}
func IdsInt64(ids string) []int64 {
if ids == "" {
return []int64{}
}
arr := strings.Fields(ids)
count := len(arr)
ret := make([]int64, 0, count)
for i := 0; i < count; i++ {
if arr[i] != "" {
id, err := strconv.ParseInt(arr[i], 10, 64)
if err == nil {
ret = append(ret, id)
}
}
}
return ret
}

58
http/router_auth.go Normal file
View File

@ -0,0 +1,58 @@
package http
import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/models"
)
type loginForm struct {
Username string `json:"username"`
Password string `json:"password"`
}
func loginPost(c *gin.Context) {
var f loginForm
bind(c, &f)
user, err1 := models.PassLogin(f.Username, f.Password)
if err1 == nil {
if user.Status == 1 {
renderMessage(c, "User disabled")
return
}
session := sessions.Default(c)
session.Set("username", f.Username)
session.Save()
renderData(c, user, nil)
return
}
// password login fail, try ldap
if config.Config.LDAP.Enable {
user, err2 := models.LdapLogin(f.Username, f.Password)
if err2 == nil {
if user.Status == 1 {
renderMessage(c, "User disabled")
return
}
session := sessions.Default(c)
session.Set("username", f.Username)
session.Save()
renderData(c, user, nil)
return
}
}
// password and ldap both fail
renderMessage(c, err1)
}
func logoutGet(c *gin.Context) {
session := sessions.Default(c)
session.Set("username", "")
session.Save()
renderMessage(c, nil)
}

82
http/router_chart.go Normal file
View File

@ -0,0 +1,82 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func chartGets(c *gin.Context) {
objs, err := models.ChartGets(urlParamInt64(c, "id"))
renderData(c, objs, err)
}
type chartForm struct {
Configs string `json:"configs"`
Weight int `json:"weight"`
}
func chartAdd(c *gin.Context) {
var f chartForm
bind(c, &f)
loginUser(c).MustPerm("dashboard_modify")
cg := ChartGroup(urlParamInt64(c, "id"))
ct := models.Chart{
GroupId: cg.Id,
Configs: f.Configs,
Weight: f.Weight,
}
dangerous(ct.Add())
renderData(c, ct, nil)
}
type chartPutForm struct {
Configs string `json:"configs"`
}
func chartPut(c *gin.Context) {
var f chartPutForm
bind(c, &f)
loginUser(c).MustPerm("dashboard_modify")
ct := Chart(urlParamInt64(c, "id"))
ct.Configs = f.Configs
dangerous(ct.Update("configs"))
renderData(c, ct, nil)
}
func chartDel(c *gin.Context) {
loginUser(c).MustPerm("dashboard_modify")
renderMessage(c, Chart(urlParamInt64(c, "id")).Del())
}
type chartConfig struct {
Id int64 `json:"id"`
GroupId int64 `json:"group_id"`
Configs string `json:"configs"`
}
func chartConfigsPut(c *gin.Context) {
var arr []chartConfig
bind(c, &arr)
loginUser(c).MustPerm("dashboard_modify")
for i := 0; i < len(arr); i++ {
ct := Chart(arr[i].Id)
ct.Configs = arr[i].Configs
if arr[i].GroupId > 0 {
ct.GroupId = arr[i].GroupId
}
dangerous(ct.Update("configs", "group_id"))
}
renderMessage(c, nil)
}

View File

@ -0,0 +1,55 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func chartGroupGets(c *gin.Context) {
objs, err := models.ChartGroupGets(urlParamInt64(c, "id"))
renderData(c, objs, err)
}
type chartGroupForm struct {
Name string `json:"name"`
Weight int `json:"weight"`
}
func chartGroupAdd(c *gin.Context) {
var f chartGroupForm
bind(c, &f)
loginUser(c).MustPerm("dashboard_modify")
d := Dashboard(urlParamInt64(c, "id"))
cg := models.ChartGroup{
DashboardId: d.Id,
Name: f.Name,
Weight: f.Weight,
}
dangerous(cg.Add())
renderData(c, cg, nil)
}
func chartGroupsPut(c *gin.Context) {
var arr []models.ChartGroup
bind(c, &arr)
loginUser(c).MustPerm("dashboard_modify")
for i := 0; i < len(arr); i++ {
dangerous(arr[i].Update("name", "weight"))
}
renderMessage(c, nil)
}
func chartGroupDel(c *gin.Context) {
loginUser(c).MustPerm("dashboard_modify")
cg := models.ChartGroup{Id: urlParamInt64(c, "id")}
renderMessage(c, cg.Del())
}

50
http/router_chart_tmp.go Normal file
View File

@ -0,0 +1,50 @@
package http
import (
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
type chartTmpForm struct {
Configs string `json:"configs"`
}
func chartTmpAdd(c *gin.Context) {
ids := []int64{}
var forms []chartTmpForm
bind(c, &forms)
for _, f := range forms {
chart := models.ChartTmp{
Configs: f.Configs,
CreateBy: loginUsername(c),
CreateAt: time.Now().Unix(),
}
dangerous(chart.Add())
ids = append(ids, chart.Id)
}
renderData(c, ids, nil)
}
func chartTmpGets(c *gin.Context) {
objs := []*models.ChartTmp{}
idStr := queryStr(c, "ids")
ids := strings.Split(idStr, ",")
for _, id := range ids {
i, err := strconv.ParseInt(id, 10, 64)
dangerous(err)
obj, err := models.ChartTmpGet("id=?", i)
dangerous(err)
objs = append(objs, obj)
}
renderData(c, objs, nil)
}

136
http/router_classpath.go Normal file
View File

@ -0,0 +1,136 @@
package http
import (
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func classpathListGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.ClasspathTotal(query)
dangerous(err)
list, err := models.ClasspathGets(query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
func classpathFavoriteGet(c *gin.Context) {
lst, err := loginUser(c).FavoriteClasspaths()
renderData(c, lst, err)
}
type classpathForm struct {
Path string `json:"path"`
Note string `json:"note"`
}
func classpathAdd(c *gin.Context) {
var f classpathForm
bind(c, &f)
me := loginUser(c).MustPerm("classpath_create")
cp := models.Classpath{
Path: f.Path,
Note: f.Note,
Preset: 0,
CreateBy: me.Username,
UpdateBy: me.Username,
}
renderMessage(c, cp.Add())
}
func classpathPut(c *gin.Context) {
var f classpathForm
bind(c, &f)
me := loginUser(c).MustPerm("classpath_modify")
cp := Classpath(urlParamInt64(c, "id"))
if cp.Path != f.Path {
num, err := models.ClasspathCount("path=? and id<>?", f.Path, cp.Id)
dangerous(err)
if num > 0 {
bomb(200, "Classpath %s already exists", f.Path)
}
}
cp.Path = f.Path
cp.Note = f.Note
cp.UpdateBy = me.Username
cp.UpdateAt = time.Now().Unix()
renderMessage(c, cp.Update("path", "note", "update_by", "update_at"))
}
func classpathDel(c *gin.Context) {
loginUser(c).MustPerm("classpath_delete")
cp := Classpath(urlParamInt64(c, "id"))
if cp.Preset == 1 {
bomb(200, "Preset classpath %s cannot delete", cp.Path)
}
renderMessage(c, cp.Del())
}
func classpathAddResources(c *gin.Context) {
var arr []string
bind(c, &arr)
me := loginUser(c).MustPerm("classpath_add_resource")
cp := Classpath(urlParamInt64(c, "id"))
dangerous(cp.AddResources(arr))
cp.UpdateAt = time.Now().Unix()
cp.UpdateBy = me.Username
cp.Update("update_at", "update_by")
renderMessage(c, nil)
}
func classpathDelResources(c *gin.Context) {
var arr []string
bind(c, &arr)
classpathId := urlParamInt64(c, "id")
me := loginUser(c).MustPerm("classpath_del_resource")
if classpathId == 1 {
bomb(200, "Resource cannot delete in preset classpath")
}
cp := Classpath(classpathId)
dangerous(cp.DelResources(arr))
cp.UpdateAt = time.Now().Unix()
cp.UpdateBy = me.Username
cp.Update("update_at", "update_by")
renderMessage(c, nil)
}
func classpathFavoriteAdd(c *gin.Context) {
me := loginUser(c)
cp := Classpath(urlParamInt64(c, "id"))
renderMessage(c, models.ClasspathFavoriteAdd(cp.Id, me.Id))
}
func classpathFavoriteDel(c *gin.Context) {
me := loginUser(c)
cp := Classpath(urlParamInt64(c, "id"))
renderMessage(c, models.ClasspathFavoriteDel(cp.Id, me.Id))
}

View File

@ -1,176 +1,137 @@
package http
import (
"bytes"
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/didi/nightingale/v4/src/models"
"github.com/didi/nightingale/v4/src/modules/server/cache"
"github.com/didi/nightingale/v4/src/modules/server/collector"
"github.com/didi/nightingale/v4/src/modules/server/config"
"time"
"github.com/gin-gonic/gin"
"github.com/toolkits/pkg/errors"
"github.com/toolkits/pkg/logger"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
)
type CollectRecv struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
type collectRuleForm struct {
ClasspathId int64 `json:"classpath_id"`
PrefixMatch int `json:"prefix_match"`
Name string `json:"name"`
Note string `json:"note"`
Step int `json:"step"`
Type string `json:"type"`
Data string `json:"data"`
AppendTags string `json:"append_tags"`
}
func collectRulePost(c *gin.Context) {
var recv []CollectRecv
errors.Dangerous(c.ShouldBind(&recv))
func collectRuleAdd(c *gin.Context) {
var f collectRuleForm
bind(c, &f)
buf := &bytes.Buffer{}
creator := loginUsername(c)
for _, obj := range recv {
cl, err := collector.GetCollector(obj.Type)
errors.Dangerous(err)
me := loginUser(c).MustPerm("collect_rule_create")
if err := cl.Create([]byte(obj.Data), creator); err != nil {
if _, ok := err.(collector.DryRun); ok {
fmt.Fprintf(buf, "%s\n", err)
} else {
errors.Bomb("%s add rule err %s", obj.Type, err)
}
}
cr := models.CollectRule{
ClasspathId: f.ClasspathId,
PrefixMatch: f.PrefixMatch,
Name: f.Name,
Note: f.Note,
Step: f.Step,
Type: f.Type,
Data: f.Data,
AppendTags: f.AppendTags,
CreateBy: me.Username,
UpdateBy: me.Username,
}
buf.WriteString("ok")
renderData(c, buf.String(), nil)
}
func collectRulesGetByLocalEndpoint(c *gin.Context) {
collect := cache.CollectCache.GetBy(urlParamStr(c, "endpoint"))
renderData(c, collect, nil)
}
func collectRuleGet(c *gin.Context) {
t := queryStr(c, "type")
id := queryInt64(c, "id")
cl, err := collector.GetCollector(t)
errors.Dangerous(err)
ret, err := cl.Get(id)
renderData(c, ret, err)
}
func collectRulesGet(c *gin.Context) {
nid := queryInt64(c, "nid", -1)
tp := queryStr(c, "type", "")
var resp []interface{}
var types []string
if tp == "" {
types = []string{"port", "proc", "log", "plugin"}
} else {
types = []string{tp}
}
nids := []int64{nid}
for _, t := range types {
cl, err := collector.GetCollector(t)
if err != nil {
logger.Warning(t, err)
continue
}
ret, err := cl.Gets(nids)
if err != nil {
logger.Warning(t, err)
continue
}
resp = append(resp, ret...)
}
renderData(c, resp, nil)
}
func collectRulesGetV2(c *gin.Context) {
nid := queryInt64(c, "nid", 0)
limit := queryInt(c, "limit", 20)
typ := queryStr(c, "type", "")
total, list, err := models.GetCollectRules(typ, nid, limit, offset(c, limit))
renderData(c, map[string]interface{}{
"total": total,
"list": list,
}, err)
renderMessage(c, cr.Add())
}
func collectRulePut(c *gin.Context) {
var recv CollectRecv
errors.Dangerous(c.ShouldBind(&recv))
var f collectRuleForm
bind(c, &f)
cl, err := collector.GetCollector(recv.Type)
errors.Dangerous(err)
me := loginUser(c).MustPerm("collect_rule_modify")
cr := CollectRule(urlParamInt64(c, "id"))
buf := &bytes.Buffer{}
creator := loginUsername(c)
if err := cl.Update([]byte(recv.Data), creator); err != nil {
if _, ok := err.(collector.DryRun); ok {
fmt.Fprintf(buf, "%s\n", err)
} else {
errors.Bomb("%s update rule err %s", recv.Type, err)
}
cr.PrefixMatch = f.PrefixMatch
cr.Name = f.Name
cr.Note = f.Note
cr.Step = f.Step
cr.Type = f.Type
cr.Data = f.Data
cr.AppendTags = f.AppendTags
cr.UpdateAt = time.Now().Unix()
cr.UpdateBy = me.Username
renderMessage(c, cr.Update(
"prefix_match",
"name",
"note",
"step",
"type",
"data",
"update_at",
"update_by",
"append_tags",
))
}
func collectRuleDel(c *gin.Context) {
var f idsForm
bind(c, &f)
f.Validate()
loginUser(c).MustPerm("collect_rule_delete")
renderMessage(c, models.CollectRulesDel(f.Ids))
}
func collectRuleGets(c *gin.Context) {
classpathId := urlParamInt64(c, "id")
where := "classpath_id = ?"
param := []interface{}{classpathId}
typ := queryStr(c, "type", "")
if typ != "" {
where += " and type = ?"
param = append(param, typ)
}
buf.WriteString("ok")
renderData(c, buf.String(), nil)
objs, err := models.CollectRuleGets(where, param...)
renderData(c, objs, err)
}
type CollectsDelRev struct {
Type string `json:"type"`
Ids []int64 `json:"ids"`
func collectRuleGetsByIdent(c *gin.Context) {
ident := queryStr(c, "ident")
objs := cache.CollectRulesOfIdent.GetBy(ident)
renderData(c, objs, nil)
}
func collectsRuleDel(c *gin.Context) {
var recv []CollectsDelRev
errors.Dangerous(c.ShouldBind(&recv))
type Summary struct {
LatestUpdatedAt int64 `json:"latestUpdatedAt"`
Total int `json:"total"`
}
username := loginUsername(c)
for _, obj := range recv {
for i := 0; i < len(obj.Ids); i++ {
cl, err := collector.GetCollector(obj.Type)
errors.Dangerous(err)
if err := cl.Delete(obj.Ids[i], username); err != nil {
errors.Dangerous(err)
func collectRuleSummaryGetByIdent(c *gin.Context) {
ident := queryStr(c, "ident")
var summary Summary
objs := cache.CollectRulesOfIdent.GetBy(ident)
total := len(objs)
if total > 0 {
summary.Total = total
var latestUpdatedAt int64
for _, obj := range objs {
if latestUpdatedAt < obj.UpdateAt {
latestUpdatedAt = obj.UpdateAt
}
}
summary.LatestUpdatedAt = latestUpdatedAt
}
renderData(c, "ok", nil)
renderData(c, summary, nil)
}
func collectRuleTypesGet(c *gin.Context) {
category := queryStr(c, "category")
switch category {
case "remote":
renderData(c, collector.GetRemoteCollectors(), nil)
case "local":
renderData(c, collector.GetLocalCollectors(), nil)
default:
renderData(c, nil, nil)
}
}
func collectRuleTemplateGet(c *gin.Context) {
t := urlParamStr(c, "type")
collector, err := collector.GetCollector(t)
errors.Dangerous(err)
tpl, err := collector.Template()
renderData(c, tpl, err)
}
type RegExpCheckDto struct {
type RegExpCheck struct {
Success bool `json:"success"`
Data []map[string]string `json:"tags"`
}
@ -178,10 +139,10 @@ type RegExpCheckDto struct {
var RegExpExcludePatition string = "```EXCLUDE```"
func regExpCheck(c *gin.Context) {
param := make(map[string]string, 0)
errors.Dangerous(c.ShouldBind(&param))
param := make(map[string]string)
dangerous(c.ShouldBind(&param))
ret := &RegExpCheckDto{
ret := &RegExpCheck{
Success: true,
Data: make([]map[string]string, 0),
}
@ -207,7 +168,7 @@ func regExpCheck(c *gin.Context) {
}
// 计算方式
calc_method, _ := param["calc_method"]
calc_method := param["calc_method"]
// 处理主正则(with exclude)
if re, ok := param["re"]; !ok || re == "" {
@ -375,39 +336,5 @@ func genSubErrMsg(sign string) string {
// 生成子串匹配错误信息
func genIllegalCharErrMsg() string {
return fmt.Sprintf(`正则匹配成功。但是tag的key或者value包含非法字符:[:,/=\r\n\t], 请重新调整`)
}
func collectRulesGetByRemoteEndpoint(c *gin.Context) {
rules := cache.CollectRuleCache.GetBy(urlParamStr(c, "endpoint"))
renderData(c, rules, nil)
}
func apiCollectsGet(c *gin.Context) {
node := queryStr(c, "node")
region := queryStr(c, "region")
key := region + "-" + node
collects := cache.ApiCollectCache.GetBy(key)
renderData(c, collects, nil)
}
func snmpCollectsGet(c *gin.Context) {
node := queryStr(c, "node")
region := queryStr(c, "region")
key := region + "-" + node
collects := cache.SnmpCollectCache.GetBy(key)
renderData(c, collects, nil)
}
func snmpHWsGet(c *gin.Context) {
node := queryStr(c, "node")
region := queryStr(c, "region")
key := region + "-" + node
hws := cache.SnmpHWCache.GetBy(key)
renderData(c, hws, nil)
}
func apiRegionGet(c *gin.Context) {
renderData(c, config.Config.Monapi.Region, nil)
return `正则匹配成功。但是tag的key或者value包含非法字符:[:,/=\r\n\t], 请重新调整`
}

154
http/router_dashboard.go Normal file
View File

@ -0,0 +1,154 @@
package http
import (
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func dashboardGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
onlyfavorite := queryBool(c, "onlyfavorite", false)
me := loginUser(c)
ids, err := me.FavoriteDashboardIds()
dangerous(err)
// 我的收藏是空的,所以直接返回空列表
if onlyfavorite && len(ids) == 0 {
renderZeroPage(c)
return
}
total, err := models.DashboardTotal(onlyfavorite, ids, query)
dangerous(err)
list, err := models.DashboardGets(onlyfavorite, ids, query, limit, offset(c, limit))
dangerous(err)
if onlyfavorite {
for i := 0; i < len(list); i++ {
list[i].Favorite = 1
}
} else {
for i := 0; i < len(list); i++ {
list[i].FillFavorite(ids)
}
}
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
func dashboardGet(c *gin.Context) {
renderData(c, Dashboard(urlParamInt64(c, "id")), nil)
}
type dashboardForm struct {
Id int64 `json:"id"`
Name string `json:"name"`
Tags string `json:"tags"`
Configs string `json:"configs"`
}
func dashboardAdd(c *gin.Context) {
var f dashboardForm
bind(c, &f)
me := loginUser(c).MustPerm("dashboard_create")
d := &models.Dashboard{
Name: f.Name,
Tags: f.Tags,
Configs: f.Configs,
CreateBy: me.Username,
UpdateBy: me.Username,
}
dangerous(d.Add())
renderData(c, d, nil)
}
func dashboardPut(c *gin.Context) {
var f dashboardForm
bind(c, &f)
me := loginUser(c).MustPerm("dashboard_modify")
d := Dashboard(urlParamInt64(c, "id"))
if d.Name != f.Name {
num, err := models.DashboardCount("name=? and id<>?", f.Name, d.Id)
dangerous(err)
if num > 0 {
bomb(200, "Dashboard %s already exists", f.Name)
}
}
d.Name = f.Name
d.Tags = f.Tags
d.Configs = f.Configs
d.UpdateAt = time.Now().Unix()
d.UpdateBy = me.Username
dangerous(d.Update("name", "tags", "configs", "update_at", "update_by"))
renderData(c, d, nil)
}
func dashboardClone(c *gin.Context) {
var f dashboardForm
bind(c, &f)
me := loginUser(c).MustPerm("dashboard_create")
d := &models.Dashboard{
Name: f.Name,
Tags: f.Tags,
Configs: f.Configs,
CreateBy: me.Username,
UpdateBy: me.Username,
}
dangerous(d.AddOnly())
chartGroups, err := models.ChartGroupGets(f.Id)
dangerous(err)
for _, chartGroup := range chartGroups {
charts, err := models.ChartGets(chartGroup.Id)
dangerous(err)
chartGroup.DashboardId = d.Id
chartGroup.Id = 0
dangerous(chartGroup.Add())
for _, chart := range charts {
chart.Id = 0
chart.GroupId = chartGroup.Id
dangerous(chart.Add())
}
}
renderData(c, d, nil)
}
func dashboardDel(c *gin.Context) {
loginUser(c).MustPerm("dashboard_delete")
renderMessage(c, Dashboard(urlParamInt64(c, "id")).Del())
}
func dashboardFavoriteAdd(c *gin.Context) {
me := loginUser(c)
d := Dashboard(urlParamInt64(c, "id"))
renderMessage(c, models.DashboardFavoriteAdd(d.Id, me.Id))
}
func dashboardFavoriteDel(c *gin.Context) {
me := loginUser(c)
d := Dashboard(urlParamInt64(c, "id"))
renderMessage(c, models.DashboardFavoriteDel(d.Id, me.Id))
}

View File

@ -0,0 +1,82 @@
package http
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func metricDescriptionGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.MetricDescriptionTotal(query)
dangerous(err)
list, err := models.MetricDescriptionGets(query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
type metricDescriptionFrom struct {
Data string `json:"data"`
}
// 没有单个新增的功能,只有批量导入
func metricDescriptionAdd(c *gin.Context) {
var f metricDescriptionFrom
var metricDescriptions []models.MetricDescription
bind(c, &f)
lines := strings.Split(f.Data, "\n")
for _, md := range lines {
arr := strings.Split(md, ":")
if len(arr) != 2 {
bomb(200, "metric description %s is illegal", md)
}
m := models.MetricDescription{
Metric: arr[0],
Description: arr[1],
}
metricDescriptions = append(metricDescriptions, m)
}
if len(metricDescriptions) == 0 {
bomb(http.StatusBadRequest, "Decoded metric description empty")
}
loginUser(c).MustPerm("metric_description_create")
renderMessage(c, models.MetricDescriptionUpdate(metricDescriptions))
}
func metricDescriptionDel(c *gin.Context) {
var f idsForm
bind(c, &f)
loginUser(c).MustPerm("metric_description_delete")
renderMessage(c, models.MetricDescriptionDel(f.Ids))
}
type metricDescriptionForm struct {
Description string `json:"description"`
}
func metricDescriptionPut(c *gin.Context) {
var f metricDescriptionForm
bind(c, &f)
loginUser(c).MustPerm("metric_description_modify")
md := MetricDescription(urlParamInt64(c, "id"))
md.Description = f.Description
renderMessage(c, md.Update("description"))
}

60
http/router_mute.go Normal file
View File

@ -0,0 +1,60 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func muteGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.MuteTotal(query)
dangerous(err)
list, err := models.MuteGets(query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
type muteForm struct {
Metric string `json:"metric"`
ResFilters string `json:"res_filters"`
TagFilters string `json:"tags_filters"`
Cause string `json:"cause"`
Btime int64 `json:"btime"`
Etime int64 `json:"etime"`
}
func muteAdd(c *gin.Context) {
var f muteForm
bind(c, &f)
me := loginUser(c).MustPerm("mute_create")
mt := models.Mute{
Metric: f.Metric,
ResFilters: f.ResFilters,
TagFilters: f.TagFilters,
Cause: f.Cause,
Btime: f.Btime,
Etime: f.Etime,
CreateBy: me.Username,
}
renderMessage(c, mt.Add())
}
func muteGet(c *gin.Context) {
renderData(c, Mute(urlParamInt64(c, "id")), nil)
}
func muteDel(c *gin.Context) {
loginUser(c).MustPerm("mute_delete")
renderMessage(c, Mute(urlParamInt64(c, "id")).Del())
}

24
http/router_prome.go Normal file
View File

@ -0,0 +1,24 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/prometheus/prometheus/promql/parser"
"github.com/didi/nightingale/v5/vos"
)
func checkPromeQl(c *gin.Context) {
ql := c.Query("promql")
_, err := parser.ParseExpr(ql)
respD := &vos.PromQlCheckResp{}
isCorrect := true
if err != nil {
isCorrect = false
respD.ParseError = err.Error()
}
respD.QlCorrect = isCorrect
renderData(c, respD, nil)
}

190
http/router_resources.go Normal file
View File

@ -0,0 +1,190 @@
package http
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/toolkits/pkg/str"
"github.com/didi/nightingale/v5/models"
)
func classpathGetsResources(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
prefix := queryInt(c, "prefix", 0)
query := queryStr(c, "query", "")
cp := Classpath(urlParamInt64(c, "id"))
var classpathIds []int64
if prefix == 1 {
cps, err := models.ClasspathGetsByPrefix(cp.Path)
dangerous(err)
for i := range cps {
classpathIds = append(classpathIds, cps[i].Id)
}
} else {
classpathIds = append(classpathIds, cp.Id)
}
total, err := models.ResourceTotalByClasspathId(classpathIds, query)
dangerous(err)
reses, err := models.ResourceGetsByClasspathId(classpathIds, query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"classpath": cp,
"list": reses,
"total": total,
}, nil)
}
func resourcesQuery(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
qres := queryStr(c, "qres", "")
// qpaths 可以选择多个英文逗号分隔的多个id
qpaths := str.IdsInt64(queryStr(c, "qpaths", ""))
total, err := models.ResourceTotalByClasspathQuery(qpaths, qres)
dangerous(err)
reses, err := models.ResourceGetsByClasspathQuery(qpaths, qres, limit, offset(c, limit))
dangerous(err)
if len(reses) == 0 {
renderZeroPage(c)
return
}
renderData(c, gin.H{
"list": reses,
"total": total,
}, nil)
}
func resourceGet(c *gin.Context) {
renderData(c, Resource(urlParamInt64(c, "id")), nil)
}
func resourceDel(c *gin.Context) {
loginUser(c).MustPerm("resource_modify")
renderData(c, Resource(urlParamInt64(c, "id")).Del(), nil)
}
type resourceNoteForm struct {
Ids []int64 `json:"ids"`
Note string `json:"note"`
}
// 修改主机设备的备注
func resourceNotePut(c *gin.Context) {
var f resourceNoteForm
bind(c, &f)
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids is empty")
}
loginUser(c).MustPerm("resource_modify")
renderMessage(c, models.ResourceUpdateNote(f.Ids, f.Note))
}
type resourceTagsForm struct {
Ids []int64 `json:"ids"`
Tags string `json:"tags"`
}
func resourceTagsPut(c *gin.Context) {
var f resourceTagsForm
bind(c, &f)
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids is empty")
}
loginUser(c).MustPerm("resource_modify")
renderMessage(c, models.ResourceUpdateTags(f.Ids, f.Tags))
}
type resourceMuteForm struct {
Ids []int64 `json:"ids"`
Btime int64 `json:"btime"`
Etime int64 `json:"etime"`
}
func resourceMutePut(c *gin.Context) {
var f resourceMuteForm
bind(c, &f)
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids is empty")
}
loginUser(c).MustPerm("resource_modify")
renderMessage(c, models.ResourceUpdateMute(f.Ids, f.Btime, f.Etime))
}
type resourceClasspathsForm struct {
ResIdents []string `json:"res_idents"`
ClasspathIds []int64 `json:"classpath_ids"`
}
func resourceClasspathsPut(c *gin.Context) {
var f resourceClasspathsForm
m := make(map[string]map[int64]struct{}) //store database data to compare
toAdd := make(map[string][]int64)
bind(c, &f)
loginUser(c).MustPerm("resource_modify")
sql := "res_ident in (\"" + strings.Join(f.ResIdents, ",") + "\")"
oldClasspathResources, err := models.ClasspathResourceGets(sql)
dangerous(err)
for _, obj := range oldClasspathResources {
if _, exists := m[obj.ResIdent]; !exists {
m[obj.ResIdent] = make(map[int64]struct{})
}
m[obj.ResIdent][obj.ClasspathId] = struct{}{}
}
for _, ident := range f.ResIdents {
toAdd[ident] = []int64{}
if _, exists := m[ident]; exists {
for _, classpathId := range f.ClasspathIds {
if _, exists := m[ident][classpathId]; exists {
// classpathResource 在数据库中已存在,不做处理
delete(m[ident], classpathId)
} else {
toAdd[ident] = append(toAdd[ident], classpathId)
}
}
} else {
toAdd[ident] = f.ClasspathIds
}
}
//删除数据库中多余的classpathResources
for ident := range m {
for classpathId := range m[ident] {
if classpathId == 1 {
continue
}
dangerous(models.ClasspathResourceDel(classpathId, []string{ident}))
}
}
//添加数据库没有的classpathResources
for ident, cids := range toAdd {
for _, cid := range cids {
dangerous(models.ClasspathResourceAdd(cid, ident))
}
}
renderMessage(c, nil)
}

12
http/router_role.go Normal file
View File

@ -0,0 +1,12 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func rolesGet(c *gin.Context) {
lst, err := models.RoleGetsAll()
renderData(c, lst, err)
}

58
http/router_self.go Normal file
View File

@ -0,0 +1,58 @@
package http
import (
"encoding/json"
"time"
"github.com/gin-gonic/gin"
)
func selfProfileGet(c *gin.Context) {
renderData(c, loginUser(c), nil)
}
type selfProfileForm struct {
Nickname string `json:"nickname"`
Phone string `json:"phone"`
Email string `json:"email"`
Portrait string `json:"portrait"`
Contacts json.RawMessage `json:"contacts"`
}
func selfProfilePut(c *gin.Context) {
var f selfProfileForm
bind(c, &f)
user := loginUser(c)
user.Nickname = f.Nickname
user.Phone = f.Phone
user.Email = f.Email
user.Portrait = f.Portrait
user.Contacts = f.Contacts
user.UpdateAt = time.Now().Unix()
user.UpdateBy = user.Username
renderMessage(
c,
user.Update(
"nickname",
"phone",
"email",
"portrait",
"contacts",
"update_at",
"update_by",
),
)
}
type selfPasswordForm struct {
OldPass string `json:"oldpass" binding:"required"`
NewPass string `json:"newpass" binding:"required"`
}
func selfPasswordPut(c *gin.Context) {
var f selfPasswordForm
bind(c, &f)
renderMessage(c, loginUser(c).ChangePassword(f.OldPass, f.NewPass))
}

32
http/router_token.go Normal file
View File

@ -0,0 +1,32 @@
package http
import (
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func selfTokenGets(c *gin.Context) {
objs, err := models.UserTokenGets("user_id=?", loginUser(c).Id)
renderData(c, objs, err)
}
func selfTokenPost(c *gin.Context) {
user := loginUser(c)
obj, err := models.UserTokenNew(user.Id, user.Username)
renderData(c, obj, err)
}
type selfTokenForm struct {
Token string `json:"token"`
}
func selfTokenPut(c *gin.Context) {
user := loginUser(c)
var f selfTokenForm
bind(c, &f)
obj, err := models.UserTokenReset(user.Id, f.Token)
renderData(c, obj, err)
}

176
http/router_ts_data.go Normal file
View File

@ -0,0 +1,176 @@
package http
import (
"errors"
"fmt"
"github.com/didi/nightingale/v5/backend"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/trans"
"github.com/didi/nightingale/v5/vos"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
agentpayload "github.com/n9e/agent-payload/gogen"
"github.com/toolkits/pkg/logger"
)
// 错误消息也是返回了200是和客户端的约定客户端如果发现code!=200就会重试
func PushSeries(c *gin.Context) {
req := agentpayload.N9EMetricsPayload{}
if c.ContentType() == "application/x-protobuf" {
err := c.ShouldBindBodyWith(&req, binding.ProtoBuf)
if err != nil {
message := fmt.Sprintf("error: decode protobuf body occur error: %v", err)
logger.Warning(message)
c.String(200, message)
return
}
count := len(req.Samples)
if count == 0 {
c.String(200, "error: samples is empty")
return
}
metricPoints := make([]*vos.MetricPoint, 0, count)
for i := 0; i < count; i++ {
logger.Debugf("recv %v", req.Samples[i])
metricPoints = append(metricPoints, convertAgentdPoint(req.Samples[i]))
}
if err = trans.Push(metricPoints); err != nil {
logger.Debugf("error: trans.push %+v err:%v", req.Samples, err)
c.String(200, "error: "+err.Error())
} else {
c.String(200, "success: received %d points", len(metricPoints))
}
} else {
logger.Debugf("error: trans.push %+v Content-Type(%s) not equals application/x-protobuf", req.Samples)
c.String(200, "error: Content-Type(%s) not equals application/x-protobuf")
}
}
func convertAgentdPoint(obj *agentpayload.N9EMetricsPayload_Sample) *vos.MetricPoint {
return &vos.MetricPoint{
Metric: obj.Metric,
Ident: obj.Ident,
Alias: obj.Alias,
TagsMap: obj.Tags,
Time: obj.Time,
ValueUntyped: obj.Value,
}
}
func PushData(c *gin.Context) {
var points []*vos.MetricPoint
err := c.ShouldBindJSON(&points)
if err != nil {
message := fmt.Sprintf("error: decode json body occur error: %v", err)
logger.Warning(message)
c.String(200, message)
return
}
if err = trans.Push(points); err != nil {
c.String(200, "error: "+err.Error())
} else {
c.String(200, "success")
}
}
func GetTagKeys(c *gin.Context) {
recv := vos.CommonTagQueryParam{}
dangerous(c.ShouldBindJSON(&recv))
dataSource, err := backend.GetDataSourceFor("")
if err != nil {
logger.Warningf("could not find datasource")
renderMessage(c, err)
return
}
resp := dataSource.QueryTagKeys(recv)
renderData(c, resp, nil)
}
func GetTagValues(c *gin.Context) {
recv := vos.CommonTagQueryParam{}
dangerous(c.ShouldBindJSON(&recv))
dataSource, err := backend.GetDataSourceFor("")
if err != nil {
logger.Warningf("could not find datasource")
renderMessage(c, err)
return
}
if recv.TagKey == "" {
renderMessage(c, errors.New("missing tagkey"))
return
}
resp := dataSource.QueryTagValues(recv)
renderData(c, resp, nil)
}
func GetMetrics(c *gin.Context) {
recv := vos.MetricQueryParam{}
dangerous(c.ShouldBindJSON(&recv))
dataSource, err := backend.GetDataSourceFor("")
if err != nil {
logger.Warningf("could not find datasource")
renderMessage(c, err)
return
}
resp := dataSource.QueryMetrics(recv)
logger.Debugf("[GetMetrics][recv:%+v][resp:%+v]", recv, resp)
res := &vos.MetricDesQueryResp{
Metrics: make([]vos.MetricsWithDescription, 0),
}
for _, metric := range resp.Metrics {
t := vos.MetricsWithDescription{
Name: metric,
}
description, exists := cache.MetricDescMapper.Get(metric)
if exists {
t.Description = description.(string)
}
res.Metrics = append(res.Metrics, t)
}
renderData(c, res, nil)
}
func GetTagPairs(c *gin.Context) {
recv := vos.CommonTagQueryParam{}
dangerous(c.ShouldBindJSON(&recv))
dataSource, err := backend.GetDataSourceFor("")
if err != nil {
logger.Warningf("could not find datasource")
renderMessage(c, err)
return
}
resp := dataSource.QueryTagPairs(recv)
renderData(c, resp, nil)
}
func GetData(c *gin.Context) {
dataSource, err := backend.GetDataSourceFor("")
if err != nil {
logger.Warningf("could not find datasource")
renderMessage(c, err)
return
}
var input vos.DataQueryParam
dangerous(c.ShouldBindJSON(&input))
resp := dataSource.QueryData(input)
renderData(c, resp, nil)
}

168
http/router_user.go Normal file
View File

@ -0,0 +1,168 @@
package http
import (
"encoding/json"
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/models"
)
func userGets(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.UserTotal(query)
dangerous(err)
list, err := models.UserGets(query, limit, offset(c, limit))
dangerous(err)
admin := loginUser(c).Role == "Admin"
renderData(c, gin.H{
"list": list,
"total": total,
"admin": admin,
}, nil)
}
type userAddForm struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Nickname string `json:"nickname"`
Phone string `json:"phone"`
Email string `json:"email"`
Portrait string `json:"portrait"`
Role string `json:"role"`
Contacts json.RawMessage `json:"contacts"`
}
func userAddPost(c *gin.Context) {
var f userAddForm
bind(c, &f)
password, err := models.CryptoPass(f.Password)
dangerous(err)
now := time.Now().Unix()
username := loginUsername(c)
u := models.User{
Username: f.Username,
Password: password,
Nickname: f.Nickname,
Phone: f.Phone,
Email: f.Email,
Portrait: f.Portrait,
Role: f.Role,
Contacts: f.Contacts,
CreateAt: now,
UpdateAt: now,
CreateBy: username,
UpdateBy: username,
}
if u.Role == "" {
u.Role = "Standard"
}
renderMessage(c, u.Add())
}
func userProfileGet(c *gin.Context) {
renderData(c, User(urlParamInt64(c, "id")), nil)
}
type userProfileForm struct {
Nickname string `json:"nickname"`
Phone string `json:"phone"`
Email string `json:"email"`
Portrait string `json:"portrait"`
Role string `json:"role"`
Status int `json:"status"`
Contacts json.RawMessage `json:"contacts"`
}
func userProfilePut(c *gin.Context) {
var f userProfileForm
bind(c, &f)
target := User(urlParamInt64(c, "id"))
target.Nickname = f.Nickname
target.Phone = f.Phone
target.Email = f.Email
target.Portrait = f.Portrait
target.Role = f.Role
target.Status = f.Status
target.Contacts = f.Contacts
target.UpdateAt = time.Now().Unix()
target.UpdateBy = loginUsername(c)
renderMessage(
c,
target.Update(
"nickname",
"phone",
"email",
"portrait",
"role",
"status",
"contacts",
"update_at",
"update_by",
),
)
}
type userPasswordForm struct {
Password string `json:"password" binding:"required"`
}
func userPasswordPut(c *gin.Context) {
var f userPasswordForm
bind(c, &f)
target := User(urlParamInt64(c, "id"))
cryptoPass, err := models.CryptoPass(f.Password)
dangerous(err)
target.Password = cryptoPass
target.UpdateAt = time.Now().Unix()
target.UpdateBy = loginUsername(c)
renderMessage(c, target.Update("password", "update_at", "update_by"))
}
type userStatusForm struct {
Status int `json:"status"`
}
func userStatusPut(c *gin.Context) {
var f userStatusForm
bind(c, &f)
target := User(urlParamInt64(c, "id"))
target.Status = f.Status
target.UpdateAt = time.Now().Unix()
target.UpdateBy = loginUsername(c)
renderMessage(c, target.Update("status", "update_at", "update_by"))
}
func userDel(c *gin.Context) {
id := urlParamInt64(c, "id")
target, err := models.UserGet("id=?", id)
dangerous(err)
if target == nil {
renderMessage(c, nil)
return
}
renderMessage(c, target.Del())
}
func contactChannelsGet(c *gin.Context) {
renderData(c, config.Config.ContactKeys, nil)
}

173
http/router_user_group.go Normal file
View File

@ -0,0 +1,173 @@
package http
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
)
func userGroupListGet(c *gin.Context) {
limit := queryInt(c, "limit", defaultLimit)
query := queryStr(c, "query", "")
total, err := models.UserGroupTotal(query)
dangerous(err)
list, err := models.UserGroupGets(query, limit, offset(c, limit))
dangerous(err)
renderData(c, gin.H{
"list": list,
"total": total,
}, nil)
}
// 与我相关的用户组,我创建的,或者我是其中一员
// 这个量不大,搜索和分页都放在前端来做,后端搞起来比较麻烦
func userGroupMineGet(c *gin.Context) {
list, err := loginUser(c).MyUserGroups()
renderData(c, list, err)
}
type userGroupForm struct {
Name string `json:"name"`
Note string `json:"note"`
}
func userGroupAdd(c *gin.Context) {
var f userGroupForm
bind(c, &f)
me := loginUser(c)
ug := models.UserGroup{
Name: f.Name,
Note: f.Note,
CreateBy: me.Username,
UpdateBy: me.Username,
}
dangerous(ug.Add())
// 顺便把创建者也作为团队的一员,失败了也没关系,用户会重新添加成员
models.UserGroupMemberAdd(ug.Id, me.Id)
renderMessage(c, nil)
}
func userGroupPut(c *gin.Context) {
var f userGroupForm
bind(c, &f)
me := loginUser(c)
ug := UserGroup(urlParamInt64(c, "id"))
can, err := me.CanModifyUserGroup(ug)
dangerous(err)
if !can {
bomb(http.StatusForbidden, "forbidden")
}
if ug.Name != f.Name {
// 如果name发生变化需要检查这个新name是否与别的group重名
num, err := models.UserGroupCount("name=? and id<>?", f.Name, ug.Id)
dangerous(err)
if num > 0 {
bomb(200, "UserGroup %s already exists", f.Name)
}
}
ug.Name = f.Name
ug.Note = f.Note
ug.UpdateBy = me.Username
ug.UpdateAt = time.Now().Unix()
renderMessage(c, ug.Update("name", "note", "update_at", "update_by"))
}
// 不但返回UserGroup的信息也把成员信息返回成员不会特别多所以
// 成员全部返回,由前端分页、查询
func userGroupGet(c *gin.Context) {
ug := UserGroup(urlParamInt64(c, "id"))
ids, err := ug.MemberIds()
dangerous(err)
users, err := models.UserGetsByIds(ids)
renderData(c, gin.H{
"users": users,
"user_group": ug,
}, err)
}
func userGroupMemberAdd(c *gin.Context) {
var f idsForm
bind(c, &f)
f.Validate()
me := loginUser(c)
ug := UserGroup(urlParamInt64(c, "id"))
can, err := me.CanModifyUserGroup(ug)
dangerous(err)
if !can {
bomb(http.StatusForbidden, "forbidden")
}
dangerous(ug.AddMembers(f.Ids))
// 用户组的成员发生变化,相当于更新了用户组
// 如果更新失败了直接忽略,不是啥大事
ug.UpdateAt = time.Now().Unix()
ug.UpdateBy = me.Username
ug.Update("update_at", "update_by")
renderMessage(c, nil)
}
func userGroupMemberDel(c *gin.Context) {
var f idsForm
bind(c, &f)
f.Validate()
me := loginUser(c)
ug := UserGroup(urlParamInt64(c, "id"))
can, err := me.CanModifyUserGroup(ug)
dangerous(err)
if !can {
bomb(http.StatusForbidden, "forbidden")
}
dangerous(ug.DelMembers(f.Ids))
// 用户组的成员发生变化,相当于更新了用户组
// 如果更新失败了直接忽略,不是啥大事
ug.UpdateAt = time.Now().Unix()
ug.UpdateBy = me.Username
ug.Update("update_at", "update_by")
renderMessage(c, nil)
}
func userGroupDel(c *gin.Context) {
me := loginUser(c)
ug := UserGroup(urlParamInt64(c, "id"))
can, err := me.CanModifyUserGroup(ug)
dangerous(err)
if !can {
bomb(http.StatusForbidden, "forbidden")
}
renderMessage(c, ug.Del())
}

View File

@ -18,11 +18,11 @@ import (
"fmt"
"math"
"github.com/didi/nightingale/v4/src/common/dataobj"
"github.com/didi/nightingale/v5/vos"
)
type Function interface {
Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool)
Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool)
}
type MaxFunction struct {
@ -32,7 +32,7 @@ type MaxFunction struct {
RightValue float64
}
func (f MaxFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f MaxFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
@ -57,7 +57,7 @@ type MinFunction struct {
RightValue float64
}
func (f MinFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f MinFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
@ -83,7 +83,7 @@ type AllFunction struct {
RightValue float64
}
func (f AllFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f AllFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
@ -107,13 +107,13 @@ type SumFunction struct {
RightValue float64
}
func (f SumFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f SumFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
count := len(vs)
if count < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < count; i++ {
sum += vs[i].Value
}
@ -130,19 +130,19 @@ type AvgFunction struct {
RightValue float64
}
func (f AvgFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f AvgFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
sum += vs[i].Value
}
leftValue = sum / dataobj.JsonFloat(vsLen)
leftValue = sum / vos.JsonFloat(vsLen)
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
}
@ -153,7 +153,7 @@ type StddevFunction struct {
Limit int
}
func (f StddevFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f StddevFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
var sum float64
vsLen := len(vs)
if vsLen < 1 {
@ -188,7 +188,7 @@ type DiffFunction struct {
}
// 只要有一个点的diff触发阈值就报警
func (f DiffFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f DiffFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
@ -217,7 +217,7 @@ type PDiffFunction struct {
RightValue float64
}
func (f PDiffFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f PDiffFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
@ -248,7 +248,7 @@ type HappenFunction struct {
RightValue float64
}
func (f HappenFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f HappenFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
for n, i := 0, 0; i < len(vs); i++ {
if checkIsTriggered(vs[i].Value, f.Operator, f.RightValue) {
n++
@ -262,19 +262,6 @@ func (f HappenFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.Js
return
}
type NodataFunction struct {
Function
}
func (f NodataFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
for _, value := range vs {
if !math.IsNaN(float64(value.Value)) {
return value.Value, false
}
}
return dataobj.JsonFloat(math.NaN()), true
}
type CAvgAbsFunction struct {
Function
Limit int
@ -283,20 +270,20 @@ type CAvgAbsFunction struct {
CompareValue float64
}
func (f CAvgAbsFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f CAvgAbsFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
sum += vs[i].Value
}
value := sum / dataobj.JsonFloat(vsLen)
leftValue = dataobj.JsonFloat(math.Abs(float64(value) - float64(f.CompareValue)))
value := sum / vos.JsonFloat(vsLen)
leftValue = vos.JsonFloat(math.Abs(float64(value) - float64(f.CompareValue)))
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
@ -310,18 +297,18 @@ type CAvgFunction struct {
CompareValue float64
}
func (f CAvgFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f CAvgFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
sum += vs[i].Value
}
leftValue = sum/dataobj.JsonFloat(vsLen) - dataobj.JsonFloat(f.CompareValue)
leftValue = sum/vos.JsonFloat(vsLen) - vos.JsonFloat(f.CompareValue)
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
@ -335,19 +322,19 @@ type CAvgRateAbsFunction struct {
CompareValue float64
}
func (f CAvgRateAbsFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f CAvgRateAbsFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
sum += vs[i].Value
}
value := sum / dataobj.JsonFloat(vsLen)
leftValue = dataobj.JsonFloat(math.Abs((float64(value)-float64(f.CompareValue))/f.CompareValue)) * 100.00
value := sum / vos.JsonFloat(vsLen)
leftValue = vos.JsonFloat(math.Abs((float64(value)-float64(f.CompareValue))/f.CompareValue)) * 100.00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
@ -361,19 +348,19 @@ type CAvgRateFunction struct {
CompareValue float64
}
func (f CAvgRateFunction) Compute(vs []*dataobj.HistoryData) (leftValue dataobj.JsonFloat, isTriggered bool) {
func (f CAvgRateFunction) Compute(vs []*vos.HPoint) (leftValue vos.JsonFloat, isTriggered bool) {
vsLen := len(vs)
if vsLen < 1 {
return
}
sum := dataobj.JsonFloat(0.0)
sum := vos.JsonFloat(0.0)
for i := 0; i < vsLen; i++ {
sum += vs[i].Value
}
value := sum / dataobj.JsonFloat(vsLen)
leftValue = (value - dataobj.JsonFloat(f.CompareValue)) / dataobj.JsonFloat(math.Abs(f.CompareValue)) * 100.00
value := sum / vos.JsonFloat(vsLen)
leftValue = (value - vos.JsonFloat(f.CompareValue)) / vos.JsonFloat(math.Abs(f.CompareValue)) * 100.00
isTriggered = checkIsTriggered(leftValue, f.Operator, f.RightValue)
return
@ -404,8 +391,6 @@ func ParseFuncFromString(str string, span []interface{}, operator string, rightV
fn = &PDiffFunction{Limit: limit, Operator: operator, RightValue: rightValue}
case "happen":
fn = &HappenFunction{Limit: limit, Num: span[1].(int), Operator: operator, RightValue: rightValue}
case "nodata":
fn = &NodataFunction{}
case "c_avg":
fn = &CAvgFunction{Limit: limit, CompareValue: span[1].(float64), Operator: operator, RightValue: rightValue}
case "c_avg_abs":
@ -421,7 +406,7 @@ func ParseFuncFromString(str string, span []interface{}, operator string, rightV
return
}
func checkIsTriggered(leftValue dataobj.JsonFloat, operator string, rightValue float64) (isTriggered bool) {
func checkIsTriggered(leftValue vos.JsonFloat, operator string, rightValue float64) (isTriggered bool) {
switch operator {
case "=", "==":
isTriggered = math.Abs(float64(leftValue)-rightValue) < 0.0001

513
judge/handler.go Normal file
View File

@ -0,0 +1,513 @@
// Copyright 2017 Xiaomi, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package judge
import (
"bytes"
"encoding/json"
"fmt"
"math"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/toolkits/pkg/logger"
"github.com/toolkits/pkg/str"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
"github.com/didi/nightingale/v5/vos"
)
var (
bufferPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
EVENT_ALERT = "alert"
EVENT_RECOVER = "recovery"
)
func Send(points []*vos.MetricPoint) {
for i := range points {
alertRules := getMatchAlertRules(points[i])
rulesCount := len(alertRules)
if rulesCount == 0 {
// 这个监控数据没有关联任何告警策略,省事了不用处理
continue
}
logger.Debugf("[point_match_alertRules][point:%+v][alertRuleNum:%+v]", points[i], rulesCount)
// 不同的告警规则alert_duration字段大小不同找到最大的按照最大的值来缓存历史数据
var maxAliveDuration = 0
for j := range alertRules {
if maxAliveDuration < alertRules[j].AlertDuration {
maxAliveDuration = alertRules[j].AlertDuration
}
}
if len(points[i].PK) < 2 {
logger.Debugf("[point:%+v] len(pk)<2", points[i])
continue
}
ll := PointCaches[points[i].PK[0:2]].PutPoint(points[i], int64(maxAliveDuration))
for j := range alertRules {
go ToJudge(ll, alertRules[j], points[i])
}
}
}
func getMatchAlertRules(point *vos.MetricPoint) []*models.AlertRule {
alertRules := cache.AlertRulesByMetric.GetBy(point.Metric)
matchRules := make([]*models.AlertRule, 0, len(alertRules))
for i := range alertRules {
if alertRules[i].Type == models.PULL {
continue
}
if matchAlertRule(point, alertRules[i]) {
matchRules = append(matchRules, alertRules[i])
}
}
return matchRules
}
func matchAlertRule(item *vos.MetricPoint, alertRule *models.AlertRule) bool {
//TODO 过滤方式待优化
for _, filter := range alertRule.PushExpr.ResFilters {
if !valueMatch(item.Ident, filter.Func, filter.Params) {
return false
}
}
for _, filter := range alertRule.PushExpr.TagFilters {
value, exists := item.TagsMap[filter.Key]
if !exists {
return false
}
if !valueMatch(value, filter.Func, filter.Params) {
return false
}
}
return true
}
func valueMatch(value, f string, params []string) bool {
switch f {
case "InClasspath":
for i := range params {
if cache.ResClasspath.Exists(value, params[i]) {
return true
}
}
return false
case "NotInClasspath":
for i := range params {
if cache.ResClasspath.Exists(value, params[i]) {
return false
}
}
return true
case "InClasspathPrefix":
classpaths := cache.ResClasspath.GetValues(value)
for _, classpath := range classpaths {
for i := range params {
if strings.HasPrefix(classpath, params[i]) {
return true
}
}
}
return false
case "NotInClasspathPrefix":
classpaths := cache.ResClasspath.GetValues(value)
for _, classpath := range classpaths {
for i := range params {
if strings.HasPrefix(classpath, params[i]) {
return false
}
}
}
return true
case "InList":
for i := range params {
if value == params[i] {
return true
}
}
return false
case "NotInList":
for i := range params {
if value == params[i] {
return false
}
}
return true
case "InResourceList":
for i := range params {
if value == params[i] {
return true
}
}
return false
case "NotInResourceList":
for i := range params {
if value == params[i] {
return false
}
}
return true
case "HasPrefixString":
for i := range params {
if strings.HasPrefix(value, params[i]) {
return true
}
}
return false
case "NoPrefixString":
for i := range params {
if strings.HasPrefix(value, params[i]) {
return false
}
}
return true
case "HasSuffixString":
for i := range params {
if strings.HasSuffix(value, params[i]) {
return true
}
}
return false
case "NoSuffixString":
for i := range params {
if strings.HasSuffix(value, params[i]) {
return false
}
}
return true
case "ContainsString":
for i := range params {
if strings.Contains(value, params[i]) {
return true
}
}
return false
case "NotContainsString":
for i := range params {
if strings.Contains(value, params[i]) {
return false
}
}
return true
case "MatchRegexp":
for i := range params {
r, _ := regexp.Compile(params[i])
if r.MatchString(value) {
return true
}
}
return false
case "NotMatchRegexp":
for i := range params {
r, _ := regexp.Compile(params[i])
if r.MatchString(value) {
return false
}
}
return true
}
return false
}
func ToJudge(linkedList *SafeLinkedList, stra *models.AlertRule, val *vos.MetricPoint) {
logger.Debugf("[ToJudge.start][stra:%+v][val:%+v]", stra, val)
now := val.Time
hps := linkedList.HistoryPoints(now - int64(stra.AlertDuration))
if len(hps) == 0 {
return
}
historyArr := []vos.HistoryPoints{}
statusArr := []bool{}
eventInfo := ""
value := ""
if len(stra.PushExpr.Exps) == 1 {
for _, expr := range stra.PushExpr.Exps {
history, info, lastValue, status := Judge(stra, expr, hps, val, now)
statusArr = append(statusArr, status)
if value == "" {
value = fmt.Sprintf("%s: %s", expr.Metric, lastValue)
} else {
value += fmt.Sprintf("; %s: %s", expr.Metric, lastValue)
}
historyArr = append(historyArr, history)
eventInfo += info
}
} else { //与条件
for _, expr := range stra.PushExpr.Exps {
respData, err := GetData(stra, expr, val, now)
if err != nil {
logger.Errorf("stra:%+v get query data err:%v", stra, err)
return
}
if len(respData) <= 0 {
logger.Errorf("stra:%+v get query data respData:%v err", stra, respData)
return
}
history, info, lastValue, status := Judge(stra, expr, respData, val, now)
statusArr = append(statusArr, status)
if value == "" {
value = fmt.Sprintf("%s: %s", expr.Metric, lastValue)
} else {
value += fmt.Sprintf("; %s: %s", expr.Metric, lastValue)
}
historyArr = append(historyArr, history)
if eventInfo == "" {
eventInfo = info
} else {
eventInfo += fmt.Sprintf(" & %s", info)
}
}
}
bs, err := json.Marshal(historyArr)
if err != nil {
logger.Errorf("Marshal history:%+v err:%v", historyArr, err)
}
event := &models.AlertEvent{
RuleId: stra.Id,
RuleName: stra.Name,
RuleNote: stra.Note,
HashId: str.MD5(fmt.Sprintf("%d_%s", stra.Id, val.PK)),
ResIdent: val.Ident,
Priority: stra.Priority,
HistoryPoints: bs,
TriggerTime: now,
Values: value,
NotifyChannels: stra.NotifyChannels,
NotifyGroups: stra.NotifyGroups,
NotifyUsers: stra.NotifyUsers,
RunbookUrl: stra.RunbookUrl,
ReadableExpression: eventInfo,
TagMap: val.TagsMap,
}
logger.Debugf("[ToJudge.event.create][type=push][stra:%+v][val:%+v][event:%+v]", stra, val, event)
sendEventIfNeed(statusArr, event, stra)
}
func Judge(stra *models.AlertRule, exp models.Exp, historyData []*vos.HPoint, firstItem *vos.MetricPoint, now int64) (history vos.HistoryPoints, info string, lastValue string, status bool) {
var leftValue vos.JsonFloat
if exp.Func == "stddev" {
info = fmt.Sprintf(" %s (%s,%ds) %v", exp.Metric, exp.Func, stra.AlertDuration, exp.Params)
} else if exp.Func == "happen" {
info = fmt.Sprintf(" %s (%s,%ds) %v %s %v", exp.Metric, exp.Func, stra.AlertDuration, exp.Params, exp.Optr, exp.Threshold)
} else {
info = fmt.Sprintf(" %s(%s,%ds) %s %v", exp.Metric, exp.Func, stra.AlertDuration, exp.Optr, exp.Threshold)
}
leftValue, status = judgeItemWithStrategy(stra, historyData, exp, firstItem, now)
lastValue = "null"
if !math.IsNaN(float64(leftValue)) {
lastValue = strconv.FormatFloat(float64(leftValue), 'f', -1, 64)
}
history = vos.HistoryPoints{
Metric: exp.Metric,
Tags: firstItem.TagsMap,
Points: historyData,
}
return
}
func judgeItemWithStrategy(stra *models.AlertRule, historyData []*vos.HPoint, exp models.Exp, firstItem *vos.MetricPoint, now int64) (leftValue vos.JsonFloat, isTriggered bool) {
straFunc := exp.Func
var straParam []interface{}
straParam = append(straParam, stra.AlertDuration)
switch straFunc {
case "happen", "stddev":
if len(exp.Params) < 1 {
logger.Errorf("stra:%d exp:%+v stra param is null", stra.Id, exp)
return
}
straParam = append(straParam, exp.Params[0])
case "c_avg", "c_avg_abs", "c_avg_rate", "c_avg_rate_abs":
if len(exp.Params) < 1 {
logger.Errorf("stra:%d exp:%+v stra param is null", stra.Id, exp)
return
}
hisD, err := GetData(stra, exp, firstItem, now-int64(exp.Params[0]))
if err != nil {
logger.Errorf("stra:%v %+v get compare data err:%v", stra.Id, exp, err)
return
}
if len(hisD) != 1 {
logger.Errorf("stra:%d %+v get compare data err, respItems:%v", stra.Id, exp, hisD)
return
}
var sum float64
for _, i := range hisD {
sum += float64(i.Value)
}
//环比数据的平均值
straParam = append(straParam, sum/float64(len(hisD)))
}
fn, err := ParseFuncFromString(straFunc, straParam, exp.Optr, exp.Threshold)
if err != nil {
logger.Errorf("stra:%d %+v parse func fail: %v", stra.Id, exp, err)
return
}
return fn.Compute(historyData)
}
func GetData(stra *models.AlertRule, exp models.Exp, firstItem *vos.MetricPoint, now int64) ([]*vos.HPoint, error) {
var respData []*vos.HPoint
var err error
//多查一些数据,防止由于查询不到最新点,导致点数不够
start := now - int64(stra.AlertDuration) - 2
// 这里的参数肯定只有一个
queryParam, err := NewQueryRequest(firstItem.Ident, exp.Metric, firstItem.TagsMap, start, now)
if err != nil {
return respData, err
}
respData = Query(queryParam)
logger.Debugf("[exp:%+v][queryParam:%+v][respData:%+v]\n", exp, queryParam, respData)
return respData, err
}
// 虽然最近的数据确实产生了事件(产生事件很频繁),但是未必一定要发送,只有告警/恢复状态发生变化的时候才需发送
func sendEventIfNeed(status []bool, event *models.AlertEvent, stra *models.AlertRule) {
isTriggered := true
for _, s := range status {
isTriggered = isTriggered && s
}
now := time.Now().Unix()
lastEvent, exists := LastEvents.Get(event.HashId)
switch event.IsPromePull {
case 0:
// push型的 && 与条件型的
if exists && lastEvent.IsPromePull == 1 {
// 之前内存中的事件是pull型的先清空内存中的事件
LastEvents.Del(event.HashId)
}
if isTriggered {
// 新告警或者上次是恢复事件,都需要立即发送
if !exists || lastEvent.IsRecov() {
event.MarkAlert()
SendEvent(event)
}
} else {
// 上次是告警事件,现在恢复了,自然需要通知
if exists && lastEvent.IsAlert() {
event.MarkRecov()
SendEvent(event)
}
}
case 1:
// pull型的产生的事件一定是触发了阈值的即这个case里不存在recovery的场景recovery的场景用resolve_timeout的cron来处理
if exists && lastEvent.IsPromePull == 0 {
// 之前内存中的事件是push型的先清空内存中的事件
LastEvents.Del(event.HashId)
}
// 1. 第一次来并且AlertDuration=0直接发送
// 2. 触发累计到AlertDuration时长后触发一条
if !exists {
// 这是个新事件,之前未曾产生过的
if stra.AlertDuration == 0 {
// 代表prometheus rule for 配置为0直接发送
event.LastSend = true
event.MarkAlert()
SendEvent(event)
} else {
// 只有一条事件显然无法满足for AlertDuration的时间放到内存里等待
LastEvents.Set(event.HashId, event)
}
return
}
// 内存里有事件虽然AlertDuration是0但是上次没有发过(可能是中间调整过AlertDuration比如从某个大于0的值调整为0)
if stra.AlertDuration == 0 && !lastEvent.LastSend {
event.LastSend = true
event.MarkAlert()
SendEvent(event)
return
}
// 内存里有事件AlertDuration也是大于0的需要判断Prometheus里的for的逻辑
if now-lastEvent.TriggerTime < int64(stra.AlertDuration) {
// 距离上次告警的时间小于告警统计周期即不满足for的条件不产生告警通知
return
}
logger.Debugf("[lastEvent.LastSend:%+v][event.LastSend:%+v][now:%+v][lastEvent.TriggerTime:%+v][stra.AlertDuration:%+v][now-lastEvent.TriggerTime:%+v]\n",
lastEvent.LastSend,
event.LastSend,
now,
lastEvent.TriggerTime,
stra.AlertDuration,
now-lastEvent.TriggerTime,
)
// 满足for的条件了应产生事件但是未必一定要发送上次没发送或者上次是恢复这次才发送即保证只发一条
if !lastEvent.LastSend || lastEvent.IsRecov() {
event.LastSend = true
event.MarkAlert()
SendEvent(event)
}
}
}
func SendEvent(event *models.AlertEvent) {
// update last event
LastEvents.Set(event.HashId, event)
ok := EventQueue.PushFront(event)
if !ok {
logger.Errorf("push event:%v err", event)
}
logger.Debugf("[SendEvent.event.success][type:%+v][event:%+v]", event.IsPromePull, event)
}

Some files were not shown because too many files have changed in this diff Show More