Merge branch 'master' of https://github.com/didi/nightingale
This commit is contained in:
commit
77c6e0dbff
|
@ -20,6 +20,7 @@ type DataSource interface {
|
|||
PushEndpoint
|
||||
|
||||
QueryData(inputs vos.DataQueryParam) []*vos.DataQueryResp // 查询一段时间
|
||||
QueryDataInstant(ql string) []*vos.DataQueryInstanceResp // 查询一个时间点数据 等同于prometheus instant_query
|
||||
QueryTagKeys(recv vos.CommonTagQueryParam) *vos.TagKeyQueryResp // 获取标签的names
|
||||
QueryTagValues(recv vos.CommonTagQueryParam) *vos.TagValueQueryResp // 根据一个label_name获取 values
|
||||
QueryTagPairs(recv vos.CommonTagQueryParam) *vos.TagPairQueryResp // 根据匹配拿到所有 series 上面三个使用统一的结构体
|
||||
|
|
|
@ -24,7 +24,7 @@ const (
|
|||
LABEL_IDENT = "ident"
|
||||
LABEL_NAME = "__name__"
|
||||
DEFAULT_QL = `{__name__=~".*a.*|.*e.*"}`
|
||||
DEFAULT_STEP = 14
|
||||
DEFAULT_STEP = 15
|
||||
)
|
||||
|
||||
type commonQueryObj struct {
|
||||
|
@ -207,13 +207,15 @@ func (pd *PromeDataSource) QueryData(inputs vos.DataQueryParam) []*vos.DataQuery
|
|||
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(inputs.Step)
|
||||
if inputs.Step == 0 {
|
||||
// step==0 说明要自己算 grafana和prometheus ui都是前端传入
|
||||
delta := (inputs.End - inputs.Start) / 3600
|
||||
if delta <= 0 {
|
||||
delta = 1
|
||||
}
|
||||
resolution = time.Second * time.Duration(delta*DEFAULT_STEP)
|
||||
}
|
||||
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)
|
||||
|
@ -253,7 +255,8 @@ func (pd *PromeDataSource) QueryData(inputs vos.DataQueryParam) []*vos.DataQuery
|
|||
pNum := len(m.Points)
|
||||
for _, p := range m.Points {
|
||||
tmpP := &vos.Point{
|
||||
Timestamp: p.T,
|
||||
// 毫秒时间时间戳转 秒时间戳
|
||||
Timestamp: p.T / 1e3,
|
||||
Value: vos.JsonFloat(p.V),
|
||||
}
|
||||
oneResp.Values = append(oneResp.Values, tmpP)
|
||||
|
@ -266,7 +269,7 @@ func (pd *PromeDataSource) QueryData(inputs vos.DataQueryParam) []*vos.DataQuery
|
|||
}
|
||||
tagStr = strings.TrimRight(tagStr, ",")
|
||||
oneResp.Tags = tagStr
|
||||
oneResp.Resolution = delta * DEFAULT_STEP
|
||||
oneResp.Resolution = int64(resolution / time.Second)
|
||||
oneResp.PNum = pNum
|
||||
respD = append(respD, oneResp)
|
||||
|
||||
|
@ -616,6 +619,36 @@ func (pd *PromeDataSource) QueryTagPairs(recv vos.CommonTagQueryParam) *vos.TagP
|
|||
return respD
|
||||
}
|
||||
|
||||
func (pd *PromeDataSource) QueryDataInstant(ql string) []*vos.DataQueryInstanceResp {
|
||||
respD := make([]*vos.DataQueryInstanceResp, 0)
|
||||
pv := pd.QueryVector(ql)
|
||||
if pv == nil {
|
||||
|
||||
return respD
|
||||
}
|
||||
|
||||
for _, s := range pv {
|
||||
metricOne := make(map[string]interface{})
|
||||
valueOne := make([]float64, 0)
|
||||
|
||||
for _, l := range s.Metric {
|
||||
if l.Name == LABEL_NAME {
|
||||
continue
|
||||
}
|
||||
metricOne[l.Name] = l.Value
|
||||
}
|
||||
// 毫秒时间时间戳转 秒时间戳
|
||||
valueOne = append(valueOne, float64(s.Point.T)/1e3)
|
||||
valueOne = append(valueOne, s.Point.V)
|
||||
respD = append(respD, &vos.DataQueryInstanceResp{
|
||||
Metric: metricOne,
|
||||
Value: valueOne,
|
||||
})
|
||||
|
||||
}
|
||||
return respD
|
||||
}
|
||||
|
||||
func (pd *PromeDataSource) QueryVector(ql string) promql.Vector {
|
||||
t := time.Now()
|
||||
q, err := pd.QueryEngine.NewInstantQuery(pd.Queryable, ql, t)
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
[
|
||||
{
|
||||
"id": 0,
|
||||
"name": "jmx_exporter",
|
||||
"tags": "",
|
||||
"configs": "{\"tags\":[{\"tagName\":\"java_app\",\"key\":\"java_app\",\"value\":\"*\",\"prefix\":false}]}",
|
||||
"chart_groups": [
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "jvm统计",
|
||||
"weight": 1,
|
||||
"charts": [
|
||||
{
|
||||
"id": 278,
|
||||
"group_id": 75,
|
||||
"configs": "{\"name\":\"jvm版本信息\",\"mode\":\"promethues\",\"prome_ql\":[\"avg(jvm_info{java_app=~\\\"$java_app\\\"}) without (runtime,vendor)\"],\"layout\":{\"h\":2,\"w\":12,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 309,
|
||||
"group_id": 75,
|
||||
"configs": "{\"name\":\"java进程启动时间 单位:小时\",\"mode\":\"promethues\",\"prome_ql\":[\"(time() - process_start_time_seconds{java_app=~\\\"$java_app\\\"})/3600\"],\"layout\":{\"h\":2,\"w\":12,\"x\":12,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "jvm内存使用",
|
||||
"weight": 2,
|
||||
"charts": [
|
||||
{
|
||||
"id": 279,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"jvm内存使用 - nonheap 非堆区\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_used{java_app=~\\\"$java_app\\\",area=\\\"nonheap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 280,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"jvm内存使用 - heap堆区\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_used{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 281,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"提交给 Java虚拟机使用的内存量 heap 堆区\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_committed{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":0,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 282,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"提交给 Java虚拟机使用的内存量 nonheap 非堆区\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_committed{java_app=~\\\"$java_app\\\",area=\\\"nonheap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":18,\"y\":0,\"i\":\"3\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 283,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"jvm最大内存 \",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_max{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":2,\"i\":\"4\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 285,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"jvm 初始化内存\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_bytes_init{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":2,\"i\":\"5\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 286,
|
||||
"group_id": 76,
|
||||
"configs": "{\"name\":\"jvm内存使用百分比% heap堆区 \",\"mode\":\"promethues\",\"prome_ql\":[\"100 * jvm_memory_bytes_used{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}/jvm_memory_bytes_max{java_app=~\\\"$java_app\\\",area=\\\"heap\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":2,\"i\":\"6\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "jvm内存池",
|
||||
"weight": 3,
|
||||
"charts": [
|
||||
{
|
||||
"id": 287,
|
||||
"group_id": 77,
|
||||
"configs": "{\"name\":\"jvm内存池分pool展示\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_memory_pool_bytes_max{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":24,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 316,
|
||||
"group_id": 77,
|
||||
"configs": "{\"name\":\" JVM 缓冲池使用缓存大小\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_buffer_pool_used_bytes{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":2,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 317,
|
||||
"group_id": 77,
|
||||
"configs": "{\"name\":\"JVM 缓冲池的字节容量\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_buffer_pool_capacity_bytes{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":2,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 318,
|
||||
"group_id": 77,
|
||||
"configs": "{\"name\":\"JVM 缓冲池使用的字节大小\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_buffer_pool_used_bytes{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":2,\"i\":\"3\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "jvm gc情况",
|
||||
"weight": 4,
|
||||
"charts": [
|
||||
{
|
||||
"id": 288,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"新生代gc耗时 1分钟\",\"mode\":\"promethues\",\"prome_ql\":[\"increase(jvm_gc_collection_seconds_sum{java_app=~\\\"$java_app\\\",gc=\\\"G1 Young Generation\\\" }[1m])\"],\"layout\":{\"h\":2,\"w\":8,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 289,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"老生代gc耗时 1分钟\",\"mode\":\"promethues\",\"prome_ql\":[\"increase(jvm_gc_collection_seconds_sum{java_app=~\\\"$java_app\\\",gc=\\\"G1 Old Generation\\\" }[1m])\"],\"layout\":{\"h\":2,\"w\":8,\"x\":8,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 290,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"新生代gc次数 1分钟\",\"mode\":\"promethues\",\"prome_ql\":[\"increase(jvm_gc_collection_seconds_count{java_app=~\\\"$java_app\\\",gc=\\\"G1 Young Generation\\\" }[1m])\"],\"layout\":{\"h\":2,\"w\":8,\"x\":16,\"y\":0,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 291,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"老生代gc次数 1分钟\",\"mode\":\"promethues\",\"prome_ql\":[\"increase(jvm_gc_collection_seconds_count{java_app=~\\\"$java_app\\\",gc=\\\"G1 Old Generation\\\" }[1m])\"],\"layout\":{\"h\":2,\"w\":8,\"x\":0,\"y\":2,\"i\":\"3\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 292,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"新生代平均gc耗时 秒\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_gc_collection_seconds_sum{java_app=~\\\"$java_app\\\",gc=\\\"G1 Young Generation\\\" }/jvm_gc_collection_seconds_count{java_app=~\\\"$java_app\\\",gc=\\\"G1 Young Generation\\\" }\"],\"layout\":{\"h\":2,\"w\":8,\"x\":8,\"y\":2,\"i\":\"4\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 293,
|
||||
"group_id": 78,
|
||||
"configs": "{\"name\":\"老生代平均gc耗时\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_gc_collection_seconds_sum{java_app=~\\\"$java_app\\\",gc=\\\"G1 Old Generation\\\"}/jvm_gc_collection_seconds_count{java_app=~\\\"$java_app\\\",gc=\\\"G1 Old Generation\\\" }\"],\"layout\":{\"h\":2,\"w\":8,\"x\":16,\"y\":2,\"i\":\"5\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "jvm线程情况",
|
||||
"weight": 5,
|
||||
"charts": [
|
||||
{
|
||||
"id": 294,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前线程数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_current{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 295,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"守护线程数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_daemon{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 296,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"死锁线程数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_deadlocked{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":0,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 297,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"活动线程峰值\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_peak{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":18,\"y\":0,\"i\":\"3\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 298,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"自JVM启动后,启动的线程总量(包括daemon,non-daemon和终止了的)\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_started_total{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":2,\"i\":\"4\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 299,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前TERMINATED线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"TERMINATED\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":4,\"i\":\"5\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 300,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前RUNNABLE线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"RUNNABLE\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":2,\"i\":\"6\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 301,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前NEW线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"NEW\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":18,\"y\":2,\"i\":\"7\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 302,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前TIMED_WAITING线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"TIMED_WAITING\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":0,\"y\":4,\"i\":\"8\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 303,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前BLOCKED线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"BLOCKED\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":18,\"y\":4,\"i\":\"9\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 304,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前WAITING线程个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\",state=\\\"WAITING\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":12,\"y\":4,\"i\":\"10\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 305,
|
||||
"group_id": 79,
|
||||
"configs": "{\"name\":\"当前线程状态汇总\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_threads_state{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":6,\"x\":6,\"y\":2,\"i\":\"11\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "加载类情况",
|
||||
"weight": 6,
|
||||
"charts": [
|
||||
{
|
||||
"id": 306,
|
||||
"group_id": 80,
|
||||
"configs": "{\"name\":\"jvm 当前加载的类个数 \",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_classes_loaded{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 307,
|
||||
"group_id": 80,
|
||||
"configs": "{\"name\":\"jvm启动以来加载的类总个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_classes_loaded_total{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":8,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 308,
|
||||
"group_id": 80,
|
||||
"configs": "{\"name\":\"jvm启动以来卸载的类总个数\",\"mode\":\"promethues\",\"prome_ql\":[\"jvm_classes_unloaded_total{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":16,\"y\":0,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"dashboard_id": 0,
|
||||
"name": "机器指标(配置了java.lang才有)",
|
||||
"weight": 7,
|
||||
"charts": [
|
||||
{
|
||||
"id": 311,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"java进程打开fd数\",\"mode\":\"promethues\",\"prome_ql\":[\"os_open_file_descriptor_count{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":0,\"y\":0,\"i\":\"0\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 312,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"机器总内存\",\"mode\":\"promethues\",\"prome_ql\":[\"os_total_memory_size{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":8,\"y\":0,\"i\":\"1\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 313,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"机器可用内存数\",\"mode\":\"promethues\",\"prome_ql\":[\"os_free_memory_size{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":16,\"y\":0,\"i\":\"2\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 314,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"机器近期cpu使用率\",\"mode\":\"promethues\",\"link\":\"https://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html#getSystemCpuLoad()\",\"prome_ql\":[\"100 * os_system_cpu_load{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":0,\"y\":2,\"i\":\"3\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 315,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"java进程cpu使用\",\"mode\":\"promethues\",\"link\":\"https://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html#getProcessCpuLoad()\",\"prome_ql\":[\"os_process_cpu_load{java_app=~\\\"$java_app\\\"}\"],\"layout\":{\"h\":2,\"w\":8,\"x\":8,\"y\":2,\"i\":\"4\"}}",
|
||||
"weight": 0
|
||||
},
|
||||
{
|
||||
"id": 319,
|
||||
"group_id": 81,
|
||||
"configs": "{\"name\":\"jvm cpu百分比\",\"mode\":\"promethues\",\"prome_ql\":[\"100 *(os_process_cpu_load{java_app=~\\\"$java_app\\\"}/os_system_cpu_load{java_app=~\\\"$java_app\\\"})\"],\"layout\":{\"h\":2,\"w\":8,\"x\":16,\"y\":2,\"i\":\"5\"}}",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -2,6 +2,7 @@ package http
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/didi/nightingale/v5/pkg/ierr"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -23,7 +24,17 @@ func admin() gin.HandlerFunc {
|
|||
c.Set("username", username)
|
||||
|
||||
user := loginUser(c)
|
||||
if user.Role != "Admin" {
|
||||
|
||||
roles := strings.Fields(user.RolesForDB)
|
||||
found := false
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if roles[i] == "Admin" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
ierr.Bomb(http.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
|
|
|
@ -42,10 +42,12 @@ func configRoutes(r *gin.Engine) {
|
|||
|
||||
// 开源版本,为了支持图表分享功能,允许匿名查询数据
|
||||
guest.POST("/query", GetData)
|
||||
guest.POST("/instant-query", GetDataInstant)
|
||||
guest.POST("/tag-pairs", GetTagPairs)
|
||||
guest.POST("/tag-keys", GetTagKeys)
|
||||
guest.POST("/tag-values", GetTagValues)
|
||||
guest.POST("/tag-metrics", GetMetrics)
|
||||
guest.GET("/check-promql", checkPromeQl)
|
||||
}
|
||||
|
||||
// for brower, expose location in nginx.conf
|
||||
|
@ -138,7 +140,6 @@ func configRoutes(r *gin.Engine) {
|
|||
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)
|
||||
|
@ -169,6 +170,7 @@ func configRoutes(r *gin.Engine) {
|
|||
pages.GET("/tpl/content", tplGet)
|
||||
|
||||
pages.GET("/status", Status)
|
||||
|
||||
}
|
||||
|
||||
// for thirdparty, do not expose location in nginx.conf
|
||||
|
@ -288,11 +290,12 @@ func configRoutes(r *gin.Engine) {
|
|||
v1.GET("/status", Status)
|
||||
|
||||
v1.POST("/query", GetData)
|
||||
v1.GET("/check-promql", checkPromeQl)
|
||||
v1.POST("/instant-query", GetDataInstant)
|
||||
v1.POST("/tag-keys", GetTagKeys)
|
||||
v1.POST("/tag-values", GetTagValues)
|
||||
v1.POST("/tag-metrics", GetMetrics)
|
||||
v1.POST("/tag-pairs", GetTagPairs)
|
||||
v1.GET("/check-promql", checkPromeQl)
|
||||
}
|
||||
|
||||
push := r.Group("/v1/n9e/series").Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
|
|
|
@ -129,8 +129,11 @@ func alertRuleGroupFavoriteDel(c *gin.Context) {
|
|||
}
|
||||
|
||||
func alertRuleWritePermCheck(alertRuleGroup *models.AlertRuleGroup, user *models.User) {
|
||||
if user.Role == "Admin" {
|
||||
return
|
||||
roles := strings.Fields(user.RolesForDB)
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if roles[i] == "Admin" {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
gids := IdsInt64(alertRuleGroup.UserGroupIds)
|
||||
|
|
|
@ -205,3 +205,17 @@ func GetData(c *gin.Context) {
|
|||
resp := dataSource.QueryData(input)
|
||||
renderData(c, resp, nil)
|
||||
}
|
||||
|
||||
func GetDataInstant(c *gin.Context) {
|
||||
dataSource, err := backend.GetDataSourceFor("")
|
||||
if err != nil {
|
||||
logger.Warningf("could not find datasource")
|
||||
renderMessage(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
var input vos.DataQueryInstantParam
|
||||
dangerous(c.ShouldBindJSON(&input))
|
||||
resp := dataSource.QueryDataInstant(input.PromeQl)
|
||||
renderData(c, resp, nil)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package http
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -20,7 +21,14 @@ func userGets(c *gin.Context) {
|
|||
list, err := models.UserGets(query, limit, offset(c, limit))
|
||||
dangerous(err)
|
||||
|
||||
admin := loginUser(c).Role == "Admin"
|
||||
admin := false
|
||||
roles := strings.Fields(loginUser(c).RolesForDB)
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if roles[i] == "Admin" {
|
||||
admin = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
renderData(c, gin.H{
|
||||
"list": list,
|
||||
|
@ -36,7 +44,7 @@ type userAddForm struct {
|
|||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Role string `json:"role"`
|
||||
Roles []string `json:"roles"`
|
||||
Contacts json.RawMessage `json:"contacts"`
|
||||
}
|
||||
|
||||
|
@ -50,23 +58,23 @@ func userAddPost(c *gin.Context) {
|
|||
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 len(f.Roles) == 0 {
|
||||
bomb(200, "roles empty")
|
||||
}
|
||||
|
||||
if u.Role == "" {
|
||||
u.Role = "Standard"
|
||||
u := models.User{
|
||||
Username: f.Username,
|
||||
Password: password,
|
||||
Nickname: f.Nickname,
|
||||
Phone: f.Phone,
|
||||
Email: f.Email,
|
||||
Portrait: f.Portrait,
|
||||
RolesForDB: strings.Join(f.Roles, " "),
|
||||
Contacts: f.Contacts,
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
CreateBy: username,
|
||||
UpdateBy: username,
|
||||
}
|
||||
|
||||
renderMessage(c, u.Add())
|
||||
|
@ -81,7 +89,7 @@ type userProfileForm struct {
|
|||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Role string `json:"role"`
|
||||
Roles []string `json:"roles"`
|
||||
Status int `json:"status"`
|
||||
Contacts json.RawMessage `json:"contacts"`
|
||||
}
|
||||
|
@ -90,12 +98,16 @@ func userProfilePut(c *gin.Context) {
|
|||
var f userProfileForm
|
||||
bind(c, &f)
|
||||
|
||||
if len(f.Roles) == 0 {
|
||||
bomb(200, "roles empty")
|
||||
}
|
||||
|
||||
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.RolesForDB = strings.Join(f.Roles, " ")
|
||||
target.Status = f.Status
|
||||
target.Contacts = f.Contacts
|
||||
target.UpdateAt = time.Now().Unix()
|
||||
|
@ -107,7 +119,7 @@ func userProfilePut(c *gin.Context) {
|
|||
"phone",
|
||||
"email",
|
||||
"portrait",
|
||||
"role",
|
||||
"roles",
|
||||
"status",
|
||||
"contacts",
|
||||
"update_at",
|
||||
|
|
|
@ -44,7 +44,7 @@ func ResourceTotalByClasspathId(classpathIds []int64, query string) (int64, erro
|
|||
}
|
||||
|
||||
q := "%" + query + "%"
|
||||
num, err := DB.Where("ident in (select res_ident from classpath_resource where classpath_id in ("+str.IdsString(classpathIds)+")) and (ident like ? or alias like ?)", q, q).Count(new(Resource))
|
||||
num, err := DB.Where("ident in (select res_ident from classpath_resource where classpath_id in ("+str.IdsString(classpathIds)+")) and (ident like ? or alias like ? or tags like ? or note like ?)", q, q, q, q).Count(new(Resource))
|
||||
if err != nil {
|
||||
logger.Errorf("mysql.error count resource in classpath(id=%v) query=%s fail: %v", classpathIds, query, err)
|
||||
return 0, internalServerError
|
||||
|
@ -60,7 +60,7 @@ func ResourceGetsByClasspathId(classpathIds []int64, query string, limit, offset
|
|||
q := "%" + query + "%"
|
||||
|
||||
var objs []Resource
|
||||
err := DB.Where("ident in (select res_ident from classpath_resource where classpath_id in ("+str.IdsString(classpathIds)+")) and (ident like ? or alias like ?)", q, q).OrderBy("ident").Limit(limit, offset).Find(&objs)
|
||||
err := DB.Where("ident in (select res_ident from classpath_resource where classpath_id in ("+str.IdsString(classpathIds)+")) and (ident like ? or alias like ? or tags like ? or note like ?)", q, q, q, q).OrderBy("ident").Limit(limit, offset).Find(&objs)
|
||||
if err != nil {
|
||||
logger.Errorf("mysql.error query resource in classpath(id=%d) query=%s fail: %v", classpathIds, query, err)
|
||||
return nil, internalServerError
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package models
|
||||
|
||||
import "github.com/toolkits/pkg/logger"
|
||||
import (
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type RoleOperation struct {
|
||||
RoleName string
|
||||
|
@ -11,8 +14,11 @@ func (RoleOperation) TableName() string {
|
|||
return "role_operation"
|
||||
}
|
||||
|
||||
func RoleHasOperation(roleName, operation string) (bool, error) {
|
||||
num, err := DB.Where("role_name=? and operation=?", roleName, operation).Count(new(RoleOperation))
|
||||
func RoleHasOperation(roles []string, operation string) (bool, error) {
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.In("role_name", roles))
|
||||
cond = cond.And(builder.Eq{"operation": operation})
|
||||
num, err := DB.Where(cond).Count(new(RoleOperation))
|
||||
if err != nil {
|
||||
logger.Errorf("mysql.error query role_operation fail: %v", err)
|
||||
return false, internalServerError
|
||||
|
|
|
@ -15,20 +15,21 @@ import (
|
|||
)
|
||||
|
||||
type User struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"-"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Status int `json:"status"`
|
||||
Role string `json:"role"`
|
||||
Contacts json.RawMessage `json:"contacts"` //内容为 map[string]string 结构
|
||||
CreateAt int64 `json:"create_at"`
|
||||
CreateBy string `json:"create_by"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
UpdateBy string `json:"update_by"`
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"-"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Portrait string `json:"portrait"`
|
||||
Status int `json:"status"`
|
||||
RolesForDB string `json:"-" xorm:"'roles'"` // 这个字段写入数据库
|
||||
RolesForFE []string `json:"roles" xorm:"-"` // 这个字段和前端交互
|
||||
Contacts json.RawMessage `json:"contacts"` // 内容为 map[string]string 结构
|
||||
CreateAt int64 `json:"create_at"`
|
||||
CreateBy string `json:"create_by"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
UpdateBy string `json:"update_by"`
|
||||
}
|
||||
|
||||
func (u *User) TableName() string {
|
||||
|
@ -110,16 +111,16 @@ func InitRoot() {
|
|||
now := time.Now().Unix()
|
||||
|
||||
u = User{
|
||||
Username: "root",
|
||||
Password: pass,
|
||||
Nickname: "超管",
|
||||
Portrait: "",
|
||||
Role: "Admin",
|
||||
Contacts: []byte("{}"),
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
CreateBy: "system",
|
||||
UpdateBy: "system",
|
||||
Username: "root",
|
||||
Password: pass,
|
||||
Nickname: "超管",
|
||||
Portrait: "",
|
||||
RolesForDB: "Admin",
|
||||
Contacts: []byte("{}"),
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
CreateBy: "system",
|
||||
UpdateBy: "system",
|
||||
}
|
||||
|
||||
_, err = DB.Insert(u)
|
||||
|
@ -151,6 +152,8 @@ func UserGet(where string, args ...interface{}) (*User, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
obj.RolesForFE = strings.Fields(obj.RolesForDB)
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
|
@ -188,6 +191,10 @@ func UserGets(query string, limit, offset int) ([]User, error) {
|
|||
return []User{}, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].RolesForFE = strings.Fields(users[i].RolesForDB)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
|
@ -204,6 +211,10 @@ func UserGetAll() ([]User, error) {
|
|||
return []User{}, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].RolesForFE = strings.Fields(users[i].RolesForDB)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
|
@ -223,23 +234,31 @@ func UserGetsByIds(ids []int64) ([]User, error) {
|
|||
return []User{}, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].RolesForFE = strings.Fields(users[i].RolesForDB)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func UserGetsByIdsStr(ids []string) ([]User, error) {
|
||||
var objs []User
|
||||
var users []User
|
||||
|
||||
err := DB.Where("id in (" + strings.Join(ids, ",") + ")").Find(&objs)
|
||||
err := DB.Where("id in (" + strings.Join(ids, ",") + ")").Find(&users)
|
||||
if err != nil {
|
||||
logger.Errorf("mysql.error: UserGetsByIds fail: %v", err)
|
||||
return nil, internalServerError
|
||||
}
|
||||
|
||||
if len(objs) == 0 {
|
||||
if len(users) == 0 {
|
||||
return []User{}, nil
|
||||
}
|
||||
|
||||
return objs, nil
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].RolesForFE = strings.Fields(users[i].RolesForDB)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func PassLogin(username, pass string) (*User, error) {
|
||||
|
@ -312,7 +331,8 @@ func LdapLogin(username, pass string) (*User, error) {
|
|||
|
||||
user.Password = "******"
|
||||
user.Portrait = "/img/linux.jpeg"
|
||||
user.Role = "Standard"
|
||||
user.RolesForDB = "Standard"
|
||||
user.RolesForFE = []string{"Standard"}
|
||||
user.Contacts = []byte("{}")
|
||||
user.CreateAt = now
|
||||
user.UpdateAt = now
|
||||
|
@ -474,8 +494,11 @@ func (u *User) MyUserGroups() ([]UserGroup, error) {
|
|||
|
||||
func (u *User) CanModifyUserGroup(ug *UserGroup) (bool, error) {
|
||||
// 我是管理员,自然可以
|
||||
if u.Role == "Admin" {
|
||||
return true, nil
|
||||
roles := strings.Fields(u.RolesForDB)
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if roles[i] == "Admin" {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 我是创建者,自然可以
|
||||
|
@ -493,11 +516,14 @@ func (u *User) CanModifyUserGroup(ug *UserGroup) (bool, error) {
|
|||
}
|
||||
|
||||
func (u *User) CanDo(op string) (bool, error) {
|
||||
if u.Role == "Admin" {
|
||||
return true, nil
|
||||
roles := strings.Fields(u.RolesForDB)
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if roles[i] == "Admin" {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return RoleHasOperation(u.Role, op)
|
||||
return RoleHasOperation(roles, op)
|
||||
}
|
||||
|
||||
// MustPerm return *User for link program
|
||||
|
|
|
@ -333,12 +333,12 @@ insert into metric_description(metric, description) values('system_cpu_num_cores
|
|||
insert into metric_description(metric, description) values('system_cpu_steal', '等待处理其他虚拟核的时间占比(单位:%)');
|
||||
insert into metric_description(metric, description) values('system_cpu_system', '内核态CPU时间占比(单位:%)');
|
||||
insert into metric_description(metric, description) values('system_cpu_user', '用户态CPU时间占比(单位:%)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_free', '磁盘某分区余量大小(单位:kb)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_free', '磁盘某分区余量大小(单位:byte)');
|
||||
insert into metric_description(metric, description) values('system_disk_used_percent', '磁盘某分区用量占比(单位:%)');
|
||||
insert into metric_description(metric, description) values('system_disk_read_time', '设备读操作耗时(单位:ms)');
|
||||
insert into metric_description(metric, description) values('system_disk_read_time_percent', '读取磁盘时间百分比(单位:%)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_total', '磁盘某分区总量(单位:kb)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_used', '磁盘某分区用量大小(单位:kb)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_total', '磁盘某分区总量(单位:byte)');
|
||||
insert into metric_description(metric, description) values('system_disk_bytes_used', '磁盘某分区用量大小(单位:byte)');
|
||||
insert into metric_description(metric, description) values('system_disk_write_time', '设备写操作耗时(单位:ms)');
|
||||
insert into metric_description(metric, description) values('system_disk_write_time_percent', '');
|
||||
insert into metric_description(metric, description) values('system_files_allocated', '系统已分配文件句柄数');
|
||||
|
|
10
vos/query.go
10
vos/query.go
|
@ -31,6 +31,11 @@ type DataQueryParam struct {
|
|||
Limit int `json:"limit"`
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Step int64 `json:"step"`
|
||||
}
|
||||
|
||||
type DataQueryInstantParam struct {
|
||||
PromeQl string `json:"prome_ql"`
|
||||
}
|
||||
|
||||
type DataQueryParamOne struct {
|
||||
|
@ -59,6 +64,11 @@ type DataQueryResp struct {
|
|||
PNum int `json:"pNum"`
|
||||
}
|
||||
|
||||
type DataQueryInstanceResp struct {
|
||||
Metric map[string]interface{} `json:"metric"`
|
||||
Value []float64 `json:"value"`
|
||||
}
|
||||
|
||||
type DataQL struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
|
|
Loading…
Reference in New Issue