clean code
This commit is contained in:
parent
654e4278fa
commit
86b31575eb
|
@ -1 +0,0 @@
|
|||
web
|
11
Dockerfile
11
Dockerfile
|
@ -1,11 +0,0 @@
|
|||
FROM golang:1.13
|
||||
|
||||
LABEL maintainer="llitfkitfk@gmail.com,chenjiandongx@qq.com"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install net-tools -y
|
||||
|
||||
COPY . .
|
||||
RUN ./control build docker
|
||||
RUN mv /app/bin/* /usr/local/bin
|
231
control
231
control
|
@ -1,231 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# release version
|
||||
version=2.8.0
|
||||
|
||||
CWD=$(cd $(dirname $0)/; pwd)
|
||||
cd $CWD
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $"Usage: $0 {start|stop|restart|status|build|pack} <module>"
|
||||
exit 0
|
||||
}
|
||||
|
||||
start_all()
|
||||
{
|
||||
# http: 5800
|
||||
test -x n9e-monapi && start monapi
|
||||
# http: 5810 ; rpc: 5811
|
||||
test -x n9e-transfer && start transfer
|
||||
# http: 5820 ; rpc: 5821
|
||||
test -x n9e-tsdb && start tsdb
|
||||
# http: 5830 ; rpc: 5831
|
||||
test -x n9e-index && start index
|
||||
# http: 5840 ; rpc: 5841
|
||||
test -x n9e-judge && start judge
|
||||
# http: 2058
|
||||
test -x n9e-collector && start collector
|
||||
}
|
||||
|
||||
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-monapi && stop monapi
|
||||
test -x n9e-transfer && stop transfer
|
||||
test -x n9e-tsdb && stop tsdb
|
||||
test -x n9e-index && stop index
|
||||
test -x n9e-judge && stop judge
|
||||
test -x n9e-collector && stop collector
|
||||
}
|
||||
|
||||
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
|
||||
go build -ldflags "-X main.version=${version} -X main.buildTime=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.gitHash=`git rev-parse HEAD`" -mod=vendor -o n9e-${mod} src/modules/${mod}/${mod}.go
|
||||
}
|
||||
|
||||
build_docker()
|
||||
{
|
||||
mod=$1
|
||||
go build -ldflags "-X main.version=${version} -X main.buildTime=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.gitHash=`git rev-parse HEAD`" -mod=vendor -o bin/n9e-${mod} src/modules/${mod}/${mod}.go
|
||||
}
|
||||
|
||||
build()
|
||||
{
|
||||
export GO111MODULE=on
|
||||
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
build_one monapi
|
||||
build_one transfer
|
||||
build_one index
|
||||
build_one judge
|
||||
build_one collector
|
||||
build_one tsdb
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "x${mod}" = "xdocker" ]; then
|
||||
build_docker monapi
|
||||
build_docker transfer
|
||||
build_docker index
|
||||
build_docker judge
|
||||
build_docker collector
|
||||
build_docker tsdb
|
||||
return
|
||||
fi
|
||||
|
||||
build_one $mod
|
||||
}
|
||||
|
||||
reload()
|
||||
{
|
||||
mod=$1
|
||||
if [ "x${mod}" = "x" ]; then
|
||||
echo "arg: <mod> is necessary"
|
||||
return
|
||||
fi
|
||||
|
||||
build_one $mod
|
||||
restart $mod
|
||||
}
|
||||
|
||||
pack()
|
||||
{
|
||||
v=$1
|
||||
if [ "x${v}" = "x" ]; then
|
||||
v=$(date +%Y-%m-%d-%H-%M-%S)
|
||||
fi
|
||||
|
||||
tar zcvf n9e-$v.tar.gz control sql plugin pub etc/log etc/port etc/service etc/nginx.conf etc/mysql.yml etc/address.yml \
|
||||
n9e-collector etc/collector.yml \
|
||||
n9e-tsdb etc/tsdb.yml \
|
||||
n9e-index etc/index.yml \
|
||||
n9e-judge etc/judge.yml \
|
||||
n9e-transfer etc/transfer.yml \
|
||||
n9e-monapi etc/monapi.yml
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start $2
|
||||
;;
|
||||
stop)
|
||||
stop $2
|
||||
;;
|
||||
restart)
|
||||
restart $2
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
build)
|
||||
build $2
|
||||
;;
|
||||
reload)
|
||||
reload $2
|
||||
;;
|
||||
pack)
|
||||
pack $2
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
esac
|
689
doc/api.md
689
doc/api.md
|
@ -1,689 +0,0 @@
|
|||
# 前端接口
|
||||
|
||||
`POST /api/portal/auth/login`
|
||||
|
||||
校验用户登录信息的接口,is_ldap=0表示不使用LDAP账号验证,is_ldap=1表示使用LDAP账号验证
|
||||
|
||||
```
|
||||
{
|
||||
"username": "",
|
||||
"password": "",
|
||||
"is_ldap": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/auth/logout`
|
||||
|
||||
退出当前账号,如果请求成功,前端需要跳转到登录页面
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/self/profile`
|
||||
|
||||
获取个人信息,可以用此接口校验用户是否登录了
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/self/profile`
|
||||
|
||||
更新个人信息
|
||||
|
||||
```
|
||||
{
|
||||
"dispname": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"im": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/self/password`
|
||||
|
||||
更新个人密码,新密码输入两次做校验,在前端完成
|
||||
|
||||
```
|
||||
{
|
||||
"oldpass": "",
|
||||
"newpass": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/user`
|
||||
|
||||
获取用户列表,支持搜索,搜索条件参数是query,每页显示条数是limit,页码是p,如果当前用户是root,则展示相关操作按钮,如果不是,则所有按钮不展示,只是查看
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/user`
|
||||
|
||||
root账号新增一个用户,is_root字段表示新增的这个用户是否是个root
|
||||
|
||||
```
|
||||
{
|
||||
"username": "",
|
||||
"password": "",
|
||||
"dispname": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"im": "",
|
||||
"is_root": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/user/:id/profile`
|
||||
|
||||
获取某个人的信息
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/user/:id/profile`
|
||||
|
||||
root账号修改某人的信息
|
||||
|
||||
```
|
||||
{
|
||||
"dispname": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"im": "",
|
||||
"is_root": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/user/:id/password`
|
||||
|
||||
root账号重置某人的密码,输入两次新密码保证一致的校验由前端来做
|
||||
|
||||
```
|
||||
{
|
||||
"password": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/user/:id`
|
||||
|
||||
root账号来删除某个用户
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/team`
|
||||
|
||||
获取团队列表,支持搜索,搜索条件参数是query,每页显示条数是limit,页码是p
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/team`
|
||||
|
||||
创建团队,mgmt=0表示成员管理制,mgmt=1表示管理员管理制,admins是团队管理员的id列表,members是团队普通成员的id列表
|
||||
|
||||
```
|
||||
{
|
||||
"ident": "",
|
||||
"name": "",
|
||||
"mgmt: 0,
|
||||
"admins": [],
|
||||
"members": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/team/:id`
|
||||
|
||||
修改团队信息
|
||||
|
||||
```
|
||||
{
|
||||
"ident": "",
|
||||
"name": "",
|
||||
"mgmt: 0,
|
||||
"admins": [],
|
||||
"members": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/team/:id`
|
||||
|
||||
删除团队
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/endpoint`
|
||||
|
||||
获取endpoint列表,用于【服务树】-【对象列表】页面,该页展示endpoint列表,搜索条件参数是query,每页显示条数是limit,页码是p,如果要做批量筛选,则同时要指定用哪个字段(参数名字是field)来筛选,只支持ident和alias,批量筛选的内容是batch,即batch和field一般是同时出现的
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/endpoint`
|
||||
|
||||
导入endpoint,要求传入列表,每一条是ident::alias拼接在一起
|
||||
|
||||
```
|
||||
{
|
||||
"endpoints": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/endpoint/:id`
|
||||
|
||||
修改一个endpoint的alias信息
|
||||
|
||||
```
|
||||
{
|
||||
"alias": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/endpoint`
|
||||
|
||||
删除多个endpoint,ids参数放到request body里
|
||||
|
||||
```
|
||||
{
|
||||
"ids": [10000, 200000]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/endpoints/bindings`
|
||||
|
||||
查询endpoint的绑定关系,QueryString:idents,逗号分隔多个
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/endpoints/bynodeids`
|
||||
|
||||
根据节点id查询挂载了哪些endpoint,QueryString:ids,逗号分隔的多个节点id
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/tree`
|
||||
|
||||
查询整颗服务树
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/tree/search`
|
||||
|
||||
根据节点路径(path)查询服务树子树
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/node`
|
||||
|
||||
创建服务树节点,pid表示父节点id,leaf=0表示非叶子节点,leaf=1表示叶子节点,note是备注信息
|
||||
|
||||
```
|
||||
{
|
||||
"pid": 0,
|
||||
"name": "",
|
||||
"leaf": 0,
|
||||
"note": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/node/:id/name`
|
||||
|
||||
服务树节点改名
|
||||
|
||||
```
|
||||
{
|
||||
"name": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/node/:id`
|
||||
|
||||
删除服务树节点
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/node/:id/endpoint`
|
||||
|
||||
获取节点下面的endpoint列表,查询字符串使用query,每页展示多少条使用limit,页码使用p,如要批量筛选,一行一个,使用batch,同时必须指定field,即使用哪个字段进行批量筛选,有ident和alias可选
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/node/:id/endpoint-bind`
|
||||
|
||||
绑定一批endpoint到当前节点,del_old=1表示同时删除老的挂载关系
|
||||
|
||||
```
|
||||
{
|
||||
"idents": [],
|
||||
"del_old": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/node/:id/endpoint-unbind`
|
||||
|
||||
解绑endpoint和节点的挂载关系
|
||||
|
||||
```
|
||||
{
|
||||
"idents": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/nodes/search`
|
||||
|
||||
搜索节点,limit表示最多返回多少条,query是搜索条件
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/nodes/leafids`
|
||||
|
||||
获取节点对应的叶子节点的id,参数是ids,逗号分隔的多个节点id
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/nodes/pids`
|
||||
|
||||
获取节点对应的父、祖节点的id,参数是ids,逗号分隔的多个节点id
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/nodes/byids`
|
||||
|
||||
查询节点的信息,参数是ids,逗号分隔的多个节点id,返回这多个节点的信息
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/node/:id/maskconf`
|
||||
|
||||
获取报警屏蔽列表,因为已经是某个节点下的了,量比较少,后端不分页
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/maskconf`
|
||||
|
||||
创建一个报警屏蔽策略
|
||||
|
||||
```
|
||||
{
|
||||
"nid": 0,
|
||||
"endpoints": [],
|
||||
"metric": "",
|
||||
"tags": "",
|
||||
"cause": "",
|
||||
"btime": 1563838361,
|
||||
"etime": 1563838461
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/maskconf/:id`
|
||||
|
||||
修改一个报警屏蔽策略
|
||||
|
||||
```
|
||||
{
|
||||
"endpoints": [],
|
||||
"metric": "",
|
||||
"tags": "",
|
||||
"cause": "",
|
||||
"btime": 1563838361,
|
||||
"etime": 1563838461
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/maskconf/:id`
|
||||
|
||||
删除一个报警屏蔽策略
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/node/:id/screen`
|
||||
|
||||
获取screen列表,因为已经是某个节点下的了,量比较少,后端不分页
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/node/:id/screen`
|
||||
|
||||
创建screen
|
||||
|
||||
```
|
||||
{
|
||||
"name": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/screen/:id`
|
||||
|
||||
修改screen,其中node_id顺带也可以修改,这样screen相当于直接挪动了挂载节点
|
||||
|
||||
```
|
||||
{
|
||||
"name": "",
|
||||
"node_id": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/screen/:id`
|
||||
|
||||
删除某个screen
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/screen/:id/subclass`
|
||||
|
||||
获取screen下面的子类,返回的subclass按照weight字段排序
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/screen/:id/subclass`
|
||||
|
||||
创建subclass
|
||||
|
||||
```
|
||||
{
|
||||
"name": "",
|
||||
"weight": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/subclass`
|
||||
|
||||
批量修改subclass
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "a",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "b",
|
||||
"weight": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/subclass/:id`
|
||||
|
||||
删除某个subclass
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/subclasses/loc`
|
||||
|
||||
修改subclass的location,即所属的screen
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"screen_id": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"screen_id": 1
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/subclass/:id/chart`
|
||||
|
||||
获取chart列表,根据chart的weight排序,不分页
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/subclass/:id/chart`
|
||||
|
||||
创建chart
|
||||
|
||||
```
|
||||
{
|
||||
"configs": "",
|
||||
"weight": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/chart/:id`
|
||||
|
||||
修改某个chart的信息
|
||||
|
||||
```
|
||||
{
|
||||
"subclass_id": 1,
|
||||
"configs": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/chart/:id`
|
||||
|
||||
删除某个chart
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/charts/weights`
|
||||
|
||||
修改chart的排序权重
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1,
|
||||
"weight": 9
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/tmpchart`
|
||||
|
||||
获取临时图,参数是QueryString:ids,逗号分隔的多个id
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/tmpchart`
|
||||
|
||||
创建一个临时图,返回生成的临时图的id列表
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"configs": ""
|
||||
},
|
||||
{
|
||||
"configs": ""
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/event/cur`
|
||||
|
||||
获取某个节点下的未恢复报警列表,QueryString:
|
||||
|
||||
- 节点路径:nodepath
|
||||
- 开始时间:stime
|
||||
- 结束时间:etime
|
||||
- 每页条数:limit
|
||||
- 查询条件:query
|
||||
- 优先级:priorities,逗号分隔的多个
|
||||
- 发送类型:sendtypes,逗号分隔的多个
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/event/cur/:id`
|
||||
|
||||
获取当前某一个未恢复的报警
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/event/cur/:id`
|
||||
|
||||
删除当前某一个未恢复的报警
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/event/curs/claim`
|
||||
|
||||
认领某一些未恢复的告警,避免告警升级到老板那里,id和nodepath只能传入一个,不能同时传入,也不能一个都不传,业务上的语义是:要么认领某一个告警事件,要么认领某个节点下的所有告警事件
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1,
|
||||
"nodepath": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/event/his`
|
||||
|
||||
获取某个节点下的所有报警列表,QueryString:
|
||||
|
||||
- 节点路径:nodepath
|
||||
- 开始时间:stime
|
||||
- 结束时间:etime
|
||||
- 每页条数:limit
|
||||
- 查询条件:query
|
||||
- 优先级:priorities,逗号分隔的多个
|
||||
- 发送类型:sendtypes,逗号分隔的多个
|
||||
- 事件类型:type
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/event/his/:id`
|
||||
|
||||
获取某个历史告警事件
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/collect/list`
|
||||
|
||||
获取某个节点下面配置的采集策略,必传QueryString: nid表示节点id,后端不分页,返回全部
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/collect`
|
||||
|
||||
获取单个采集配置的详情,QueryString:type和id,都必传,type是port、proc、log之一。
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/collect`
|
||||
|
||||
创建一个采集策略
|
||||
|
||||
```
|
||||
{
|
||||
"type": "",
|
||||
"data": {
|
||||
# 端口、进程、日志配置不同,参阅model/collect.go
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/collect`
|
||||
|
||||
修改一个采集策略
|
||||
|
||||
```
|
||||
{
|
||||
"type": "",
|
||||
"data": {
|
||||
# 端口、进程、日志配置不同,参阅model/collect.go
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/collect`
|
||||
|
||||
删除采集策略
|
||||
|
||||
```
|
||||
{
|
||||
"type": "",
|
||||
"ids": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/collect/check`
|
||||
|
||||
校验用户输入的数据是否匹配正则,跟商业版本数据结构一致
|
||||
|
||||
---
|
||||
|
||||
`POST /api/portal/stra`
|
||||
|
||||
新增告警策略,跟商业版本数据结构一致
|
||||
|
||||
---
|
||||
|
||||
`PUT /api/portal/stra`
|
||||
|
||||
修改告警策略,跟商业版本数据结构一致
|
||||
|
||||
---
|
||||
|
||||
`DELETE /api/portal/stra`
|
||||
|
||||
删除告警策略,跟商业版本数据结构一致
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/stra`
|
||||
|
||||
获取告警策略列表,跟商业版本数据结构一致
|
||||
|
||||
---
|
||||
|
||||
`GET /api/portal/stra/:id`
|
||||
|
||||
获取单个告警策略,跟商业版本数据结构一致
|
|
@ -1,90 +0,0 @@
|
|||
version: "3"
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:stable-alpine
|
||||
network_mode: host
|
||||
ports:
|
||||
- 80:80
|
||||
volumes:
|
||||
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./docker/nginx/conf.d:/etc/nginx/conf.d
|
||||
- ./pub:/home/n9e/pub
|
||||
|
||||
nightingale:
|
||||
build: .
|
||||
image: nightingale
|
||||
|
||||
monapi:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-monapi
|
||||
ports:
|
||||
- 5800:5800
|
||||
|
||||
transfer:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-transfer
|
||||
ports:
|
||||
- 5810:5810
|
||||
- 5811:5811
|
||||
|
||||
tsdb:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-tsdb
|
||||
ports:
|
||||
- 5820:5820
|
||||
- 5821:5821
|
||||
|
||||
index:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-index
|
||||
ports:
|
||||
- 5830:5830
|
||||
- 5831:5831
|
||||
|
||||
judge:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-judge
|
||||
ports:
|
||||
- 5840:5840
|
||||
- 5841:5841
|
||||
|
||||
collector:
|
||||
image: nightingale
|
||||
network_mode: host
|
||||
restart: always
|
||||
command: n9e-collector
|
||||
ports:
|
||||
- 2058:2058
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
network_mode: host
|
||||
restart: always
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
network_mode: host
|
||||
restart: always
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=1234
|
||||
ports:
|
||||
- 3306:3306
|
||||
volumes:
|
||||
- ./sql:/docker-entrypoint-initdb.d
|
||||
- mysql-data:/var/lib/mysql
|
|
@ -1,89 +0,0 @@
|
|||
user root;
|
||||
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
|
||||
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 '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$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;
|
||||
|
||||
upstream n9e.monapi {
|
||||
server localhost:5800;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
upstream n9e.index {
|
||||
server localhost:5830;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
upstream n9e.transfer {
|
||||
server localhost:5810;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# Load configuration files for the default server block.
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
|
||||
location / {
|
||||
root /home/n9e/pub;
|
||||
}
|
||||
|
||||
location /api/portal {
|
||||
proxy_pass http://n9e.monapi;
|
||||
}
|
||||
|
||||
location /api/index {
|
||||
proxy_pass http://n9e.index;
|
||||
}
|
||||
|
||||
location /api/transfer {
|
||||
proxy_pass http://n9e.transfer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
monapi:
|
||||
http: 0.0.0.0:5800
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
transfer:
|
||||
http: 0.0.0.0:5810
|
||||
rpc: 0.0.0.0:5811
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
|
||||
tsdb:
|
||||
http: 0.0.0.0:5820
|
||||
rpc: 0.0.0.0:5821
|
||||
|
||||
index:
|
||||
http: 0.0.0.0:5830
|
||||
rpc: 0.0.0.0:5831
|
||||
|
||||
judge:
|
||||
http: 0.0.0.0:5840
|
||||
rpc: 0.0.0.0:5841
|
||||
|
||||
collector:
|
||||
http: 0.0.0.0:2058
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
logger:
|
||||
dir: logs/collector
|
||||
level: WARNING
|
||||
keepHours: 2
|
||||
|
||||
identity:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||
|
||||
stra:
|
||||
enable: true
|
||||
portPath: ./etc/port
|
||||
procPath: ./etc/proc
|
||||
logPath: ./etc/log
|
||||
|
||||
sys:
|
||||
enable: true
|
||||
# timeout in ms
|
||||
# interval in second
|
||||
timeout: 1000
|
||||
interval: 20
|
||||
plugin: ./plugin
|
||||
|
||||
# monitor nic which filtered by prefix
|
||||
ifacePrefix:
|
||||
- eth
|
||||
- em
|
||||
- ens
|
||||
|
||||
# ignore disk mount point
|
||||
mountIgnore:
|
||||
prefix:
|
||||
- /var/lib
|
||||
- /run
|
||||
# collect anyway
|
||||
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
|
|
@ -1,7 +0,0 @@
|
|||
logger:
|
||||
dir: logs/index
|
||||
level: WARNING
|
||||
keepHours: 2
|
||||
identity:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
|
@ -1,25 +0,0 @@
|
|||
query:
|
||||
maxConn: 100
|
||||
connTimeout: 1000
|
||||
callTimeout: 2000
|
||||
indexCallTimeout: 2000
|
||||
indexMod: "index"
|
||||
|
||||
redis:
|
||||
addrs:
|
||||
- 127.0.0.1:6379
|
||||
db: 0
|
||||
pass: ""
|
||||
# timeout:
|
||||
# conn: 500
|
||||
# read: 3000
|
||||
# write: 3000
|
||||
|
||||
identity:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||
|
||||
logger:
|
||||
dir: logs/judge
|
||||
level: WARNING
|
||||
keepHours: 2
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"name": "log.sys.oom",
|
||||
"file_path": "/var/log/messages",
|
||||
"time_format": "mmm dd HH:MM:SS",
|
||||
"pattern": "Out of memory",
|
||||
"interval": 10,
|
||||
"tags": {},
|
||||
"func": "cnt",
|
||||
"degree": 6,
|
||||
"unit": "次数",
|
||||
"comment": "有进程oom了"
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
---
|
||||
salt: "PLACE_SALT"
|
||||
|
||||
logger:
|
||||
dir: "logs/monapi"
|
||||
level: "WARNING"
|
||||
keepHours: 24
|
||||
|
||||
http:
|
||||
secret: "PLACE_SECRET"
|
||||
|
||||
# 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: false
|
||||
tls: false
|
||||
startTLS: false
|
||||
|
||||
# notify support: voice, sms, mail, im
|
||||
# if we have all of notice channel
|
||||
# notify:
|
||||
# p1: ["voice", "sms", "mail", "im"]
|
||||
# p2: ["sms", "mail", "im"]
|
||||
# p3: ["mail", "im"]
|
||||
|
||||
# if we only have mail channel
|
||||
notify:
|
||||
p1: ["mail"]
|
||||
p2: ["mail"]
|
||||
p3: ["mail"]
|
||||
|
||||
# addresses accessible using browsers
|
||||
link:
|
||||
stra: http://n9e.example.com/#/monitor/strategy/%v
|
||||
event: http://n9e.example.com/#/monitor/history/his/%v
|
||||
claim: http://n9e.example.com/#/monitor/history/cur/%v
|
||||
|
||||
# for alarm event and message queue
|
||||
redis:
|
||||
addr: "127.0.0.1:6379"
|
||||
db: 0
|
||||
pass: ""
|
||||
# in ms
|
||||
# timeout:
|
||||
# conn: 500
|
||||
# read: 3000
|
||||
# write: 3000
|
||||
|
||||
tokens:
|
||||
- 7dcd606e0462f9df2fea0bf505c9e622
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
uic:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_uic?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
mon:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_mon?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
||||
hbs:
|
||||
addr: "root:1234@tcp(127.0.0.1:3306)/n9e_hbs?charset=utf8&parseTime=True&loc=Asia%2FShanghai"
|
||||
max: 16
|
||||
idle: 4
|
||||
debug: false
|
|
@ -1,97 +0,0 @@
|
|||
user root;
|
||||
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
|
||||
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 '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$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;
|
||||
|
||||
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.monapi {
|
||||
server 127.0.0.1:5800;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
upstream n9e.index {
|
||||
server 127.0.0.1:5830;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
upstream n9e.transfer {
|
||||
server 127.0.0.1:5810;
|
||||
keepalive 10;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# Load configuration files for the default server block.
|
||||
include /etc/nginx/default.d/*.conf;
|
||||
|
||||
location / {
|
||||
root /home/n9e/pub;
|
||||
}
|
||||
|
||||
location /api/portal {
|
||||
proxy_pass http://n9e.monapi;
|
||||
}
|
||||
|
||||
location /api/index {
|
||||
proxy_pass http://n9e.index;
|
||||
}
|
||||
|
||||
location /api/transfer {
|
||||
proxy_pass http://n9e.transfer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
sshd
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale collector
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-collector
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale index
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-index
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale judge
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-judge
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale monapi
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-monapi
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale transfer
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-transfer
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,20 +0,0 @@
|
|||
[Unit]
|
||||
Description=Nightingale tsdb
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# modify when deploy in prod env
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
Type=simple
|
||||
ExecStart=/home/n9e/n9e-tsdb
|
||||
WorkingDirectory=/home/n9e
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,31 +0,0 @@
|
|||
backend:
|
||||
datasource: "tsdb"
|
||||
tsdb:
|
||||
enabled: true
|
||||
name: "tsdb"
|
||||
cluster:
|
||||
tsdb01: 127.0.0.1:5821
|
||||
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"
|
||||
|
||||
identity:
|
||||
specify: ""
|
||||
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||
|
||||
|
||||
logger:
|
||||
dir: logs/transfer
|
||||
level: WARNING
|
||||
keepHours: 2
|
|
@ -1,8 +0,0 @@
|
|||
rrd:
|
||||
storage: data/5821
|
||||
cache:
|
||||
keepMinutes: 120
|
||||
logger:
|
||||
dir: logs/tsdb
|
||||
level: WARNING
|
||||
keepHours: 2
|
34
go.mod
34
go.mod
|
@ -1,34 +0,0 @@
|
|||
module github.com/didi/nightingale
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/Shopify/sarama v1.26.4
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/codegangsta/negroni v1.0.0
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe
|
||||
github.com/garyburd/redigo v1.6.0
|
||||
github.com/gin-contrib/pprof v1.2.1
|
||||
github.com/gin-contrib/sessions v0.0.3
|
||||
github.com/gin-gonic/gin v1.5.0
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/gorilla/mux v1.6.2
|
||||
github.com/hpcloud/tail v1.0.0
|
||||
github.com/influxdata/influxdb v1.8.0
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad
|
||||
github.com/shirou/gopsutil v2.20.4+incompatible
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72
|
||||
github.com/spf13/viper v1.6.2
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/toolkits/pkg v1.1.1
|
||||
github.com/ugorji/go/codec v1.1.7
|
||||
github.com/unrolled/render v1.0.2
|
||||
go.uber.org/automaxprocs v1.3.0 // indirect
|
||||
gopkg.in/ldap.v3 v3.1.0
|
||||
xorm.io/core v0.7.3
|
||||
xorm.io/xorm v0.8.1
|
||||
)
|
607
go.sum
607
go.sum
|
@ -1,607 +0,0 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
|
||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/sarama v1.26.4 h1:+17TxUq/PJEAfZAll0T7XJjSgQWCpaQSoki/x5yN8o8=
|
||||
github.com/Shopify/sarama v1.26.4/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe h1:VOrqop9SqFzqwZpROEOZpIufuLEUoJ3reNhdOdC9Zzw=
|
||||
github.com/dgryski/go-tsz v0.0.0-20180227144327-03b7d791f4fe/go.mod h1:ft6P746mYUFQBCsH3OkFBG8FtjLx1XclLMo+9Jh1Yts=
|
||||
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
|
||||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/pprof v1.2.1 h1:p6mY/FsE3tDx2+Wp3ksrMe1QL5egQ7p+lsZ7WbQLT1U=
|
||||
github.com/gin-contrib/pprof v1.2.1/go.mod h1:u2l4P4YNkLXYz+xBbrl7Pxu1Btng6VCD7j3O3pUPP2w=
|
||||
github.com/gin-contrib/sessions v0.0.3 h1:PoBXki+44XdJdlgDqDrY5nDVe3Wk7wDV/UCOuLP6fBI=
|
||||
github.com/gin-contrib/sessions v0.0.3/go.mod h1:8C/J6cad3Il1mWYYgtw0w+hqasmpvy25mPkXdOgeB9I=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
|
||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY=
|
||||
github.com/influxdata/influxdb v1.8.0 h1:/X+G+i3udzHVxpBMuXdPZcUbkIE0ouT+6U+CzQTsOys=
|
||||
github.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ=
|
||||
github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo=
|
||||
github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=
|
||||
github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=
|
||||
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
|
||||
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.8 h1:VMAMUUOh+gaxKTMk+zqbjsSjsIcUcL/LF4o63i82QyA=
|
||||
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad h1:GXUy5t8CYdaaEj1lRnE22CbHVY1M5h6Rv4kk0PJQc54=
|
||||
github.com/open-falcon/rrdlite v0.0.0-20200214140804-bf5829f786ad/go.mod h1:pXROoG0iWVnqq4u2Ii97S0Vt9iCTVypshsl9HXsV6cs=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4 v2.4.1+incompatible h1:mFe7ttWaflA46Mhqh+jUfjp2qTbPYxLB2/OyBppH9dg=
|
||||
github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v2.20.4+incompatible h1:cMT4rxS55zx9NVUnCkrmXCsEB/RNfG9SwHY9evtX8Ng=
|
||||
github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
|
||||
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/toolkits/pkg v1.1.1 h1:m57zdoBKQmTzhY83F3g56seDfLm+l/toBs8cKv8QFiE=
|
||||
github.com/toolkits/pkg v1.1.1/go.mod h1:ge83E8FQqUnFk+2wtVtZ8kvbmoSjE1l8FP3f+qmR0fY=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/unrolled/render v1.0.2 h1:dGS3EmChQP3yOi1YeFNO/Dx+MbWZhdvhQJTXochM5bs=
|
||||
github.com/unrolled/render v1.0.2/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
|
||||
go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 h1:+ELyKg6m8UBf0nPFSqD0mi7zUfwPyXo23HNjMnXPz7w=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f h1:kDxGY2VmgABOe55qheT/TFqUMtcTHnomIPS1iv3G4Ms=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178 h1:f5gMxb6FbpY48csegk9UPd7IAHVrBD013CU7N4pWzoE=
|
||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||
gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
|
||||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI=
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlIrg=
|
||||
gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||
gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE=
|
||||
gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
|
||||
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/xorm v0.8.1 h1:4f2KXuQxVdaX3RdI3Fw81NzMiSpZeyCZt8m3sEVeIkQ=
|
||||
xorm.io/xorm v0.8.1/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
BIN
pub/favicon.ico
BIN
pub/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index-15091d1f2769ed59d987.js","sources":["webpack:///index-15091d1f2769ed59d987.js"],"mappings":"AAAA;;;;;;AA+wGA;;;;;;;AAmqqCA","sourceRoot":""}
|
|
@ -1 +0,0 @@
|
|||
<!doctype html><html><head><meta charset="UTF-8"><title>Nightingale</title><link rel="shortcut icon" href="/favicon.ico"><link href="/index-15091d1f2769ed59d987.css" rel="stylesheet"></head><body><div id="react-content"></div><script src="/lib-033bee8514de110e36ef.dll.js"></script><script src="/index-15091d1f2769ed59d987.js"></script></body></html>
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 90 KiB |
Binary file not shown.
Before Width: | Height: | Size: 224 KiB |
|
@ -1,17 +0,0 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_hbs;
|
||||
create database n9e_hbs;
|
||||
use n9e_hbs;
|
||||
|
||||
create table `instance` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`module` varchar(32) not null,
|
||||
`identity` varchar(255) not null,
|
||||
`rpc_port` varchar(16) not null,
|
||||
`http_port` varchar(16) not null,
|
||||
`remark` text,
|
||||
`ts` int unsigned not null,
|
||||
primary key (`id`),
|
||||
key(`module`,`identity`,`rpc_port`,`http_port`)
|
||||
) engine=innodb default charset=utf8;
|
288
sql/n9e_mon.sql
288
sql/n9e_mon.sql
|
@ -1,288 +0,0 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_mon;
|
||||
create database n9e_mon;
|
||||
use n9e_mon;
|
||||
|
||||
CREATE TABLE `node` (
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`pid` int unsigned not null,
|
||||
`name` varchar(64) not null,
|
||||
`path` varchar(255) not null,
|
||||
`leaf` int(1) not null,
|
||||
`note` varchar(128) not null default '',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`path`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `endpoint` (
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`ident` varchar(255) not null,
|
||||
`alias` varchar(255) not null default '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`ident`),
|
||||
KEY (`alias`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `node_endpoint` (
|
||||
`node_id` int unsigned not null,
|
||||
`endpoint_id` int unsigned not null,
|
||||
KEY(`node_id`),
|
||||
KEY(`endpoint_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
create table `maskconf` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`nid` int unsigned not null,
|
||||
`metric` varchar(255) not null,
|
||||
`tags` varchar(255) not null default '',
|
||||
`cause` varchar(255) not null default '',
|
||||
`user` varchar(32) not null default 'operate user',
|
||||
`btime` bigint not null default 0 comment 'begin time',
|
||||
`etime` bigint not null default 0 comment 'end time',
|
||||
primary key (`id`),
|
||||
key(`nid`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `maskconf_endpoints` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`mask_id` int unsigned not null,
|
||||
`endpoint` varchar(255) not null,
|
||||
primary key (`id`),
|
||||
key(`mask_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `screen` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`node_id` int unsigned not null comment 'service tree node id',
|
||||
`name` varchar(255) not null,
|
||||
`last_updator` varchar(64) not null default '',
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
primary key (`id`),
|
||||
key(`node_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `screen_subclass` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`screen_id` int unsigned not null,
|
||||
`name` varchar(255) not null,
|
||||
`weight` int not null default 0,
|
||||
primary key (`id`),
|
||||
key(`screen_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `chart` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`subclass_id` int unsigned not null,
|
||||
`configs` varchar(8192),
|
||||
`weight` int not null default 0,
|
||||
primary key (`id`),
|
||||
key(`subclass_id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `tmp_chart` (
|
||||
`id` int unsigned not null auto_increment,
|
||||
`configs` varchar(8192),
|
||||
`creator` varchar(64) not null,
|
||||
`last_updated` timestamp not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
primary key (`id`)
|
||||
) engine=innodb default charset=utf8;
|
||||
|
||||
create table `event_cur` (
|
||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||
`node_path` varchar(255) not null default '' comment 'node path',
|
||||
`nid` int unsigned not null default '0' comment 'node id',
|
||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||
`priority` tinyint(4) not null default 2 comment '优先级',
|
||||
`event_type` varchar(45) not null default '' comment 'alert|recovery',
|
||||
`category` tinyint(4) not null default 2 comment '1阈值 2智能',
|
||||
`status` int(10) not null default 0 comment 'event status',
|
||||
`detail` text comment 'counter points pred_points 详情',
|
||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||
`value` varchar(255) not null default '' comment '当前值',
|
||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||
`info` varchar(512) not null default '' comment 'strategy info',
|
||||
`ignore_alert` int(2) not null default 0 comment 'ignore event',
|
||||
`claimants` varchar(512) not null default '[]' comment 'claimants',
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text comment 'alert upgrade',
|
||||
`created` DATETIME not null default '1971-1-1 00:00:00' comment 'created',
|
||||
KEY `idx_id` (`id`),
|
||||
KEY `idx_sid` (`sid`),
|
||||
KEY `idx_hashid` (`hashid`),
|
||||
KEY `idx_node_path` (`node_path`),
|
||||
KEY `idx_etime` (`etime`)
|
||||
) engine=innodb default charset=utf8 comment 'event';
|
||||
|
||||
create table `event` (
|
||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||
`node_path` varchar(255) not null default '' comment 'node path',
|
||||
`nid` int unsigned not null default '0' comment 'node id',
|
||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||
`priority` tinyint(4) not null default 2 comment '优先级',
|
||||
`event_type` varchar(45) not null default '' comment 'alert|recovery',
|
||||
`category` tinyint(4) not null default 2 comment '1阈值 2智能',
|
||||
`status` int(10) not null default 0 comment 'event status',
|
||||
`detail` text comment 'counter points pred_points 详情',
|
||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||
`value` varchar(255) not null default '' comment '当前值',
|
||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||
`info` varchar(512) not null default '' comment 'strategy info',
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text not null comment 'alert upgrade',
|
||||
`created` DATETIME not null default '1971-1-1 00:00:00' comment 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_id` (`id`),
|
||||
KEY `idx_sid` (`sid`),
|
||||
KEY `idx_hashid` (`hashid`),
|
||||
KEY `idx_node_path` (`node_path`),
|
||||
KEY `idx_etime` (`etime`),
|
||||
KEY `idx_event_type` (`event_type`),
|
||||
KEY `idx_status` (`status`)
|
||||
) engine=innodb default charset=utf8 comment 'event';
|
||||
|
||||
CREATE TABLE `stra` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL COMMENT 'strategy name',
|
||||
`category` int(1) NOT NULL COMMENT '1 机器 2业务',
|
||||
`nid` int(10) NOT NULL COMMENT '服务树节点id',
|
||||
`excl_nid` varchar(255) NOT NULL COMMENT '被排除的服务树叶子节点id',
|
||||
`alert_dur` int(4) NOT NULL COMMENT '单位秒,持续异常n秒则产生异常event',
|
||||
`recovery_dur` int(4) NOT NULL DEFAULT 0 COMMENT '单位秒,持续正常n秒则产生恢复event,0表示立即产生恢复event',
|
||||
`exprs` varchar(1024) NOT NULL DEFAULT '' COMMENT '规则表达式',
|
||||
`tags` varchar(1024) DEFAULT '' COMMENT 'tags过滤',
|
||||
`enable_stime` varchar(6) NOT NULL DEFAULT '00:00' COMMENT '策略生效开始时间',
|
||||
`enable_etime` varchar(6) NOT NULL DEFAULT '23:59' COMMENT '策略生效终止时间',
|
||||
`enable_days_of_week` varchar(1024) NOT NULL DEFAULT '[0,1,2,3,4,5,6]' COMMENT '策略生效日期',
|
||||
`converge` varchar(45) NOT NULL DEFAULT '' COMMENT 'n秒最多报m次警',
|
||||
`recovery_notify` int(1) NOT NULL DEFAULT 1 COMMENT '1 发送恢复通知 0不发送恢复通知',
|
||||
`priority` int(1) NOT NULL DEFAULT 3 COMMENT '告警等级',
|
||||
`notify_group` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知组',
|
||||
`notify_user` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知人',
|
||||
`callback` varchar(1024) NOT NULL DEFAULT '' COMMENT 'callback url',
|
||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
`last_updator` varchar(64) NOT NULL DEFAULT '',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`need_upgrade` int(2) not null default 0 comment 'need upgrade',
|
||||
`alert_upgrade` text comment 'alert upgrade',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `stra_log` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`sid` bigint(20) NOT NULL DEFAULT '0' COMMENT 'collect id',
|
||||
`action` varchar(255) NOT NULL DEFAULT '' COMMENT '动作 update, delete',
|
||||
`body` text COMMENT '修改之前采集的内容',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'creator',
|
||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_sid` (`sid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `port_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PORT' COMMENT 'type',
|
||||
`nid` int(10) NOT NULL COMMENT '服务树节点id',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`port` int(11) NOT NULL DEFAULT '0' COMMENT 'port',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`timeout` int(11) NOT NULL DEFAULT '0' COMMENT 'connect time',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(255) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last_updated',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'port collect';
|
||||
|
||||
CREATE TABLE `proc_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PROC' COMMENT 'type',
|
||||
`collect_method` varchar(64) NOT NULL DEFAULT 'name' COMMENT '采集方式',
|
||||
`target` varchar(255) NOT NULL DEFAULT '' COMMENT '采集对象',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(255) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'proc collect';
|
||||
|
||||
CREATE TABLE `log_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'tags',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PROC' COMMENT 'type',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`file_path` varchar(255) NOT NULL DEFAULT '' COMMENT 'file path',
|
||||
`time_format` varchar(128) NOT NULL DEFAULT '' COMMENT 'time format',
|
||||
`pattern` varchar(1024) NOT NULL DEFAULT '' COMMENT 'pattern',
|
||||
`func` varchar(64) NOT NULL DEFAULT '' COMMENT 'func',
|
||||
`degree` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'degree',
|
||||
`func_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'func_type',
|
||||
`aggregate` varchar(64) NOT NULL DEFAULT '' COMMENT 'aggr',
|
||||
`unit` varchar(64) NOT NULL DEFAULT '' COMMENT 'unit',
|
||||
`zero_fill` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'zero fill',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(255) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'log collect';
|
||||
|
||||
CREATE TABLE `plugin_collect` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'nid',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name',
|
||||
`collect_type` varchar(64) NOT NULL DEFAULT 'PROC' COMMENT 'type',
|
||||
`step` int(11) NOT NULL DEFAULT '0' COMMENT '采集周期',
|
||||
`file_path` varchar(255) NOT NULL COMMENT 'file_path',
|
||||
`params` varchar(255) NOT NULL COMMENT 'params',
|
||||
`stdin` text NOT NULL COMMENT 'stdin',
|
||||
`env` text NOT NULL COMMENT 'env',
|
||||
`comment` varchar(512) NOT NULL DEFAULT '' COMMENT 'comment',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '' COMMENT 'creator',
|
||||
`created` datetime NOT NULL COMMENT 'created',
|
||||
`last_updator` varchar(128) NOT NULL DEFAULT '' COMMENT 'last_updator',
|
||||
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_nid` (`nid`),
|
||||
KEY `idx_collect_type` (`collect_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'plugin collect';
|
||||
|
||||
CREATE TABLE `collect_hist` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`cid` bigint(20) NOT NULL DEFAULT '0' COMMENT 'collect id',
|
||||
`collect_type` varchar(255) NOT NULL DEFAULT '' COMMENT '采集的种类 log,port,proc,plugin',
|
||||
`action` varchar(255) NOT NULL DEFAULT '' COMMENT '动作 update, delete',
|
||||
`body` text COMMENT '修改之前采集的内容',
|
||||
`creator` varchar(255) NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'creator',
|
||||
`created` datetime NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_cid` (`cid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'hist';
|
|
@ -1,44 +0,0 @@
|
|||
set names utf8;
|
||||
|
||||
drop database if exists n9e_uic;
|
||||
create database n9e_uic;
|
||||
use n9e_uic;
|
||||
|
||||
CREATE TABLE `user` (
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`username` varchar(32) not null comment 'login name, cannot rename',
|
||||
`password` varchar(128) not null default '',
|
||||
`dispname` varchar(32) not null default '' comment 'display name, chinese name',
|
||||
`phone` varchar(16) not null default '',
|
||||
`email` varchar(64) not null default '',
|
||||
`im` varchar(64) not null default '',
|
||||
`is_root` int(1) not null,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `invite` (
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`token` varchar(128) not null,
|
||||
`expire` bigint not null,
|
||||
`creator` varchar(32) not null,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`token`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `team` (
|
||||
`id` int unsigned not null AUTO_INCREMENT,
|
||||
`ident` varchar(255) not null,
|
||||
`name` varchar(255) not null default '',
|
||||
`mgmt` int(1) not null comment '0: member manage; 1: admin manage',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`ident`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `team_user` (
|
||||
`team_id` int unsigned not null,
|
||||
`user_id` int unsigned not null,
|
||||
`is_admin` int(1) not null,
|
||||
KEY (`team_id`),
|
||||
KEY (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -1,3 +0,0 @@
|
|||
use n9e_mon;
|
||||
ALTER TABLE plugin_collect ADD stdin text AFTER params;
|
||||
ALTER TABLE plugin_collect ADD env text AFTER params;
|
|
@ -1,56 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
// Event 传递到alarm的结构体, 尽可能少的字段, 发出通知需要的信息由alarm自己补全
|
||||
type Event struct {
|
||||
ID string `json:"-"`
|
||||
Sid int64 `json:"sid"`
|
||||
EventType string `json:"event_type"` // alert/recover
|
||||
Hashid uint64 `json:"hashid"` // 全局唯一 根据counter计算
|
||||
Etime int64 `json:"etime"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
History []History `json:"-"`
|
||||
Detail string `json:"detail"`
|
||||
Info string `json:"info"`
|
||||
Value string `json:"value"`
|
||||
Partition string `json:"-"`
|
||||
}
|
||||
|
||||
type History struct {
|
||||
Key string `json:"-"` // 用于计算event的hashid
|
||||
Metric string `json:"metric"` // 指标名
|
||||
Tags map[string]string `json:"tags,omitempty"` // endpoint/counter
|
||||
Granularity int `json:"-"` // alarm补齐数据时需要
|
||||
Points []*HistoryData `json:"points"` // 现场值
|
||||
}
|
||||
|
||||
type HistoryData struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value JsonFloat `json:"value"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
func RRDData2HistoryData(datas []*RRDData) []*HistoryData {
|
||||
historyDatas := make([]*HistoryData, len(datas))
|
||||
|
||||
for i := range datas {
|
||||
historyData := &HistoryData{
|
||||
Timestamp: datas[i].Timestamp,
|
||||
Value: datas[i].Value,
|
||||
}
|
||||
historyDatas[i] = historyData
|
||||
}
|
||||
return historyDatas
|
||||
}
|
||||
|
||||
func HistoryData2RRDData(datas []*HistoryData) []*RRDData {
|
||||
rrdDatas := make([]*RRDData, len(datas))
|
||||
|
||||
for i := range datas {
|
||||
data := &RRDData{
|
||||
Timestamp: datas[i].Timestamp,
|
||||
Value: datas[i].Value,
|
||||
}
|
||||
rrdDatas[i] = data
|
||||
}
|
||||
return rrdDatas
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
type IndexModel struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
DsType string `json:"dsType"`
|
||||
Step int `json:"step"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Timestamp int64 `json:"ts"`
|
||||
}
|
||||
|
||||
type IndexResp struct {
|
||||
Msg string
|
||||
Total int
|
||||
Invalid int
|
||||
Latency int64
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
type InfluxdbItem struct {
|
||||
Measurement string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Fields map[string]interface{} `json:"fields"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/didi/nightingale/src/toolkits/str"
|
||||
|
||||
gstr "github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type JudgeItem struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Sid int64 `json:"sid"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
func (j *JudgeItem) PrimaryKey() string {
|
||||
return str.PK(j.Endpoint, j.Metric, j.Tags)
|
||||
}
|
||||
|
||||
func (j *JudgeItem) MD5() string {
|
||||
return gstr.MD5(str.PK(strconv.FormatInt(j.Sid, 16), j.Endpoint, j.Metric, str.SortedTags(j.TagsMap)))
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
GAUGE = "GAUGE"
|
||||
COUNTER = "COUNTER"
|
||||
SUBTRACT = "SUBTRACT"
|
||||
DERIVE = "DERIVE"
|
||||
SPLIT = "/"
|
||||
)
|
||||
|
||||
type MetricValue struct {
|
||||
Metric string `json:"metric"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Step int64 `json:"step"`
|
||||
ValueUntyped interface{} `json:"value"`
|
||||
Value float64 `json:"-"`
|
||||
CounterType string `json:"counterType"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"` //保留2种格式,方便后端组件使用
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func (m *MetricValue) String() string {
|
||||
return fmt.Sprintf("<MetaData Endpoint:%s, Metric:%s, CounterType:%s Timestamp:%d, Step:%d, Value:%v, Tags:%v(%v)>",
|
||||
m.Endpoint, m.Metric, m.CounterType, m.Timestamp, m.Step, m.ValueUntyped, m.Tags, m.TagsMap)
|
||||
}
|
||||
|
||||
func (m *MetricValue) PK() string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if m.TagsMap == nil || len(m.TagsMap) == 0 {
|
||||
ret.WriteString(m.Endpoint)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(m.Metric)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(m.Endpoint)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(m.Metric)
|
||||
ret.WriteString(SPLIT)
|
||||
ret.WriteString(SortedTags(m.TagsMap))
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func (m *MetricValue) CheckValidity(now int64) (err error) {
|
||||
if m == nil {
|
||||
err = fmt.Errorf("item is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Metric == "" || m.Endpoint == "" {
|
||||
err = fmt.Errorf("metric or endpoint should not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
// 检测保留字
|
||||
reservedWords := "[\\t] [\\r] [\\n] [,] [ ] [=]"
|
||||
if HasReservedWords(m.Metric) {
|
||||
err = fmt.Errorf("metric:%s contains reserved words: %s", m.Metric, reservedWords)
|
||||
return
|
||||
}
|
||||
if HasReservedWords(m.Endpoint) {
|
||||
err = fmt.Errorf("endpoint:%s contains reserved words: %s", m.Endpoint, reservedWords)
|
||||
return
|
||||
}
|
||||
|
||||
if m.CounterType == "" {
|
||||
m.CounterType = GAUGE
|
||||
}
|
||||
|
||||
if m.CounterType != GAUGE && m.CounterType != COUNTER && m.CounterType != SUBTRACT {
|
||||
err = fmt.Errorf("wrong counter type")
|
||||
return
|
||||
}
|
||||
|
||||
if m.ValueUntyped == "" {
|
||||
err = fmt.Errorf("value is nil")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Step <= 0 {
|
||||
err = fmt.Errorf("step should larger than 0")
|
||||
return
|
||||
}
|
||||
|
||||
if len(m.TagsMap) == 0 {
|
||||
m.TagsMap, err = SplitTagsString(m.Tags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.TagsMap) > 20 {
|
||||
err = fmt.Errorf("tagkv count is too large > 20")
|
||||
}
|
||||
|
||||
if len(m.Metric) > 128 {
|
||||
err = fmt.Errorf("len(m.Metric) is too large")
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range m.TagsMap {
|
||||
delete(m.TagsMap, k)
|
||||
k = filterString(k)
|
||||
v = filterString(v)
|
||||
if len(k) == 0 || len(v) == 0 {
|
||||
err = fmt.Errorf("tag key and value should not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
m.TagsMap[k] = v
|
||||
}
|
||||
|
||||
m.Tags = SortedTags(m.TagsMap)
|
||||
if len(m.Tags) > 512 {
|
||||
err = fmt.Errorf("len(m.Tags) is too large")
|
||||
return
|
||||
}
|
||||
|
||||
//时间超前5分钟则报错
|
||||
if m.Timestamp-now > 300 {
|
||||
err = fmt.Errorf("point timestamp:%d is ahead of now:%d", m.Timestamp, now)
|
||||
return
|
||||
}
|
||||
|
||||
if m.Timestamp <= 0 {
|
||||
m.Timestamp = now
|
||||
}
|
||||
|
||||
m.Timestamp = alignTs(m.Timestamp, int64(m.Step))
|
||||
|
||||
valid := true
|
||||
var vv float64
|
||||
|
||||
switch cv := m.ValueUntyped.(type) {
|
||||
case string:
|
||||
vv, err = strconv.ParseFloat(cv, 64)
|
||||
if err != nil {
|
||||
valid = false
|
||||
}
|
||||
case float64:
|
||||
vv = cv
|
||||
case uint64:
|
||||
vv = float64(cv)
|
||||
case int64:
|
||||
vv = float64(cv)
|
||||
case int:
|
||||
vv = float64(cv)
|
||||
default:
|
||||
valid = false
|
||||
}
|
||||
|
||||
if !valid {
|
||||
err = fmt.Errorf("value [%v] is illegal", m.Value)
|
||||
return
|
||||
}
|
||||
|
||||
m.Value = vv
|
||||
return
|
||||
}
|
||||
|
||||
func HasReservedWords(str string) bool {
|
||||
idx := strings.IndexFunc(str, func(r rune) bool {
|
||||
return r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '='
|
||||
})
|
||||
return idx != -1
|
||||
}
|
||||
|
||||
func filterString(str string) string {
|
||||
if -1 == strings.IndexFunc(str,
|
||||
func(r rune) bool {
|
||||
return r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '='
|
||||
}) {
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r == '\t' ||
|
||||
r == '\r' ||
|
||||
r == '\n' ||
|
||||
r == ',' ||
|
||||
r == ' ' ||
|
||||
r == '=' {
|
||||
return '_'
|
||||
}
|
||||
return r
|
||||
}, str)
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func SortedTags(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
size := len(tags)
|
||||
if size == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if size == 1 {
|
||||
for k, v := range tags {
|
||||
ret.WriteString(k)
|
||||
ret.WriteString("=")
|
||||
ret.WriteString(v)
|
||||
}
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
keys := make([]string, size)
|
||||
i := 0
|
||||
for k := range tags {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for j, key := range keys {
|
||||
ret.WriteString(key)
|
||||
ret.WriteString("=")
|
||||
ret.WriteString(tags[key])
|
||||
if j != size-1 {
|
||||
ret.WriteString(",")
|
||||
}
|
||||
}
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func SplitTagsString(s string) (tags map[string]string, err error) {
|
||||
tags = make(map[string]string)
|
||||
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
|
||||
tagSlice := strings.Split(s, ",")
|
||||
for _, tag := range tagSlice {
|
||||
tagPair := strings.SplitN(tag, "=", 2)
|
||||
if len(tagPair) == 2 {
|
||||
tags[tagPair[0]] = tagPair[1]
|
||||
} else {
|
||||
err = fmt.Errorf("bad tag %s", tag)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func DictedTagstring(s string) map[string]string {
|
||||
if s == "" {
|
||||
return map[string]string{}
|
||||
}
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
|
||||
result := make(map[string]string)
|
||||
tags := strings.Split(s, ",")
|
||||
for _, tag := range tags {
|
||||
pair := strings.SplitN(tag, "=", 2)
|
||||
if len(pair) == 2 {
|
||||
result[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func PKWithCounter(endpoint, counter string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(counter)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func GetCounter(metric, tag string, tagMap map[string]string) (counter string, err error) {
|
||||
if tagMap == nil {
|
||||
tagMap, err = SplitTagsString(tag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tagStr := SortedTags(tagMap)
|
||||
counter = PKWithTags(metric, tagStr)
|
||||
return
|
||||
}
|
||||
|
||||
func PKWithTags(metric, tags string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if tags == "" {
|
||||
ret.WriteString(metric)
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(metric)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(tags)
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func PKWhitEndpointAndTags(endpoint, metric, tags string) string {
|
||||
ret := bufferPool.Get().(*bytes.Buffer)
|
||||
ret.Reset()
|
||||
defer bufferPool.Put(ret)
|
||||
|
||||
if tags == "" {
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(metric)
|
||||
|
||||
return ret.String()
|
||||
}
|
||||
ret.WriteString(endpoint)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(metric)
|
||||
ret.WriteString("/")
|
||||
ret.WriteString(tags)
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
// e.g. tcp.port.listen or proc.num
|
||||
type BuiltinMetric struct {
|
||||
Metric string
|
||||
Tags string
|
||||
}
|
||||
|
||||
func (bm *BuiltinMetric) String() string {
|
||||
return fmt.Sprintf("%s/%s", bm.Metric, bm.Tags)
|
||||
}
|
||||
|
||||
type BuiltinMetricRequest struct {
|
||||
Ty int
|
||||
IP string
|
||||
Checksum string
|
||||
}
|
||||
|
||||
type BuiltinMetricResponse struct {
|
||||
Metrics []*BuiltinMetric
|
||||
Checksum string
|
||||
Timestamp int64
|
||||
ErrCode int
|
||||
}
|
||||
|
||||
func (br *BuiltinMetricResponse) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Metrics:%v, Checksum:%s, Timestamp:%v>",
|
||||
br.Metrics,
|
||||
br.Checksum,
|
||||
br.Timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
type BuiltinMetricSlice []*BuiltinMetric
|
||||
|
||||
func (bm BuiltinMetricSlice) Len() int {
|
||||
return len(bm)
|
||||
}
|
||||
func (bm BuiltinMetricSlice) Swap(i, j int) {
|
||||
bm[i], bm[j] = bm[j], bm[i]
|
||||
}
|
||||
func (bm BuiltinMetricSlice) Less(i, j int) bool {
|
||||
return bm[i].String() < bm[j].String()
|
||||
}
|
||||
|
||||
func alignTs(ts int64, period int64) int64 {
|
||||
return ts - ts%period
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpenTsdbItem struct {
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (t *OpenTsdbItem) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Metric:%s, Tags:%v, Value:%v, TS:%d>",
|
||||
t.Metric,
|
||||
t.Tags,
|
||||
t.Value,
|
||||
t.Timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *OpenTsdbItem) OpenTsdbString() (s string) {
|
||||
s = fmt.Sprintf("put %s %d %.3f ", t.Metric, t.Timestamp, t.Value)
|
||||
|
||||
for k, v := range t.Tags {
|
||||
key := strings.ToLower(strings.Replace(k, " ", "_", -1))
|
||||
value := strings.Replace(v, " ", "_", -1)
|
||||
s += key + "=" + value + " "
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
type QueryData struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Counters []string `json:"counters"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
||||
|
||||
type QueryDataForUI struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Metric string `json:"metric"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
GroupKey []string `json:"groupKey"` //聚合维度
|
||||
AggrFunc string `json:"aggrFunc"` //聚合计算
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Comparisons []int64 `json:"comparisons"` //环比多少时间
|
||||
}
|
||||
|
||||
type QueryDataForUIResp struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Counter string `json:"counter"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Values []*RRDData `json:"values"`
|
||||
Comparison int64 `json:"comparison"`
|
||||
}
|
||||
|
||||
type QueryDataResp struct {
|
||||
Data []*TsdbQueryResponse
|
||||
Msg string
|
||||
}
|
||||
|
||||
// judge 数据层 必须
|
||||
func (req *QueryData) Key() string {
|
||||
return req.Endpoints[0] + "/" + req.Counters[0]
|
||||
}
|
||||
|
||||
func (resp *TsdbQueryResponse) Key() string {
|
||||
return resp.Endpoint + "/" + resp.Counter
|
||||
}
|
||||
|
||||
type EndpointsRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
}
|
||||
|
||||
type MetricResp struct {
|
||||
Metrics []string `json:"metrics"`
|
||||
}
|
||||
|
||||
type EndpointMetricRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metrics []string `json:"metrics"`
|
||||
}
|
||||
|
||||
type IndexTagkvResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tagkv []*TagPair `json:"tagkv"`
|
||||
}
|
||||
|
||||
type TagPair struct {
|
||||
Key string `json:"tagk"` // json 和变量不一致为了兼容前端
|
||||
Values []string `json:"tagv"`
|
||||
}
|
||||
|
||||
type CludeRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Include []*TagPair `json:"include"`
|
||||
Exclude []*TagPair `json:"exclude"`
|
||||
}
|
||||
|
||||
type XcludeResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
||||
|
||||
type IndexByFullTagsRecv struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tagkv []TagPair `json:"tagkv"`
|
||||
}
|
||||
|
||||
type IndexByFullTagsResp struct {
|
||||
Endpoints []string `json:"endpoints"`
|
||||
Metric string `json:"metric"`
|
||||
Tags []string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dstype"`
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
import "fmt"
|
||||
|
||||
// code == 0 => success
|
||||
// code == 1 => bad request
|
||||
type SimpleRpcResponse struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type NullRpcRequest struct {
|
||||
}
|
||||
|
||||
type TransferResp struct {
|
||||
Msg string
|
||||
Total int
|
||||
Invalid int
|
||||
Latency int64
|
||||
}
|
||||
|
||||
func (t *TransferResp) String() string {
|
||||
s := fmt.Sprintf("TransferResp total=%d, err_invalid=%d, latency=%dms",
|
||||
t.Total, t.Invalid, t.Latency)
|
||||
if t.Msg != "" {
|
||||
s = fmt.Sprintf("%s, msg=%s", s, t.Msg)
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
type File struct {
|
||||
Key interface{}
|
||||
Filename string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
type RRDFileResp struct {
|
||||
Files []File
|
||||
Msg string
|
||||
}
|
||||
|
||||
type RRDFileQuery struct {
|
||||
Files []RRDFile
|
||||
}
|
||||
|
||||
type RRDFile struct {
|
||||
Key interface{}
|
||||
Filename string
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
type StraData struct {
|
||||
Dat []Stra `json:"dat"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
type Stra struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Category int `json:"category"`
|
||||
Nid int64 `json:"nid"`
|
||||
AlertDur int `json:"alert_dur"`
|
||||
RecoveryDur int `json:"recovery_dur"`
|
||||
EnableStime string `json:"enable_stime"`
|
||||
EnableEtime string `json:"enable_etime"`
|
||||
Priority int `json:"priority"`
|
||||
Callback string `json:"callback"`
|
||||
Creator string `json:"creator"`
|
||||
Created string `json:"created"`
|
||||
LastUpdator string `json:"last_updator"`
|
||||
LastUpdated string `json:"last_updated"`
|
||||
ExclNid []int64 `json:"excl_nid"`
|
||||
Exprs []Exp `json:"exprs"`
|
||||
Tags []Tag `json:"tags"`
|
||||
EnableDaysOfWeek []int `json:"enable_days_of_week"`
|
||||
Converge []int `json:"converge"`
|
||||
RecoveryNotify int `json:"recovery_notify"`
|
||||
NotifyGroup []int64 `json:"notify_group"`
|
||||
NotifyUser []int64 `json:"notify_user"`
|
||||
LeafNids interface{} `json:"leaf_nids"`
|
||||
NeedUpgrade int `json:"need_upgrade"`
|
||||
AlertUpgrade AlertUpgrade `json:"alert_upgrade"`
|
||||
}
|
||||
|
||||
type Exp struct {
|
||||
Eopt string `json:"eopt"`
|
||||
Func string `json:"func"`
|
||||
Metric string `json:"metric"`
|
||||
Params []int `json:"params"`
|
||||
Threshold float64 `json:"threshold"`
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Tkey string `json:"tkey"`
|
||||
Topt string `json:"topt"`
|
||||
Tval []string `json:"tval"` //修改为数组
|
||||
}
|
||||
|
||||
type AlertUpgrade struct {
|
||||
Users []int64 `json:"users"`
|
||||
Groups []int64 `json:"groups"`
|
||||
Duration int `json:"duration"`
|
||||
Level int `json:"level"`
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package dataobj
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/toolkits/str"
|
||||
)
|
||||
|
||||
type JsonFloat float64
|
||||
|
||||
func (v JsonFloat) MarshalJSON() ([]byte, error) {
|
||||
f := float64(v)
|
||||
if math.IsNaN(f) || math.IsInf(f, 0) {
|
||||
return []byte("null"), nil
|
||||
} else {
|
||||
return []byte(fmt.Sprintf("%f", f)), nil
|
||||
}
|
||||
}
|
||||
|
||||
type RRDData struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value JsonFloat `json:"value"`
|
||||
}
|
||||
|
||||
type RRDValues []*RRDData
|
||||
|
||||
func (r RRDValues) Len() int { return len(r) }
|
||||
func (r RRDValues) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r RRDValues) Less(i, j int) bool { return r[i].Timestamp < r[j].Timestamp }
|
||||
|
||||
func NewRRDData(ts int64, val float64) *RRDData {
|
||||
return &RRDData{Timestamp: ts, Value: JsonFloat(val)}
|
||||
}
|
||||
|
||||
func (rrd *RRDData) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<RRDData:Value:%v TS:%d %v>",
|
||||
rrd.Value,
|
||||
rrd.Timestamp,
|
||||
time.Unix(rrd.Timestamp, 0).Format("2006-01-02 15:04:05"),
|
||||
)
|
||||
}
|
||||
|
||||
type TsdbQueryResponse struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Counter string `json:"counter"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Values []*RRDData `json:"values"`
|
||||
}
|
||||
|
||||
type TsdbItem struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
TagsMap map[string]string `json:"tagsMap"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
DsType string `json:"dstype"`
|
||||
Step int `json:"step"`
|
||||
Heartbeat int `json:"heartbeat"`
|
||||
Min string `json:"min"`
|
||||
Max string `json:"max"`
|
||||
From int `json:"from"`
|
||||
}
|
||||
|
||||
const GRAPH = 1
|
||||
|
||||
func (t *TsdbItem) String() string {
|
||||
return fmt.Sprintf(
|
||||
"<Endpoint:%s, Metric:%s, Tags:%v, TagsMap:%v, Value:%v, TS:%d %v DsType:%s, Step:%d, Heartbeat:%d, Min:%s, Max:%s>",
|
||||
t.Endpoint,
|
||||
t.Metric,
|
||||
t.Tags,
|
||||
t.TagsMap,
|
||||
t.Value,
|
||||
t.Timestamp,
|
||||
str.UnixTsFormat(t.Timestamp),
|
||||
t.DsType,
|
||||
t.Step,
|
||||
t.Heartbeat,
|
||||
t.Min,
|
||||
t.Max,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *TsdbItem) PrimaryKey() string {
|
||||
return str.PK(t.Endpoint, t.Metric, t.Tags)
|
||||
}
|
||||
|
||||
func (t *TsdbItem) MD5() string {
|
||||
return str.MD5(t.Endpoint, t.Metric, str.SortedTags(t.TagsMap))
|
||||
}
|
||||
|
||||
func (t *TsdbItem) UUID() string {
|
||||
return str.UUID(t.Endpoint, t.Metric, t.Tags, t.DsType, t.Step)
|
||||
}
|
||||
|
||||
// ConsolFunc 是RRD中的概念,比如:MIN|MAX|AVERAGE
|
||||
type TsdbQueryParam struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
ConsolFunc string `json:"consolFunc"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Counter string `json:"counter"`
|
||||
Step int `json:"step"`
|
||||
DsType string `json:"dsType"`
|
||||
}
|
||||
|
||||
func (g *TsdbQueryParam) PK() string {
|
||||
return PKWithCounter(g.Endpoint, g.Counter)
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package model
|
||||
|
||||
type Chart struct {
|
||||
Id int64 `json:"id"`
|
||||
SubclassId int64 `json:"subclass_id"`
|
||||
Configs string `json:"configs"`
|
||||
Weight int `json:"weight"`
|
||||
}
|
||||
|
||||
func (c *Chart) Add() error {
|
||||
_, err := DB["mon"].InsertOne(c)
|
||||
return err
|
||||
}
|
||||
|
||||
func ChartGets(subclassId int64) ([]Chart, error) {
|
||||
var objs []Chart
|
||||
err := DB["mon"].Where("subclass_id=?", subclassId).OrderBy("weight").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ChartGet(col string, val interface{}) (*Chart, error) {
|
||||
var obj Chart
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (c *Chart) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", c.Id).Cols(cols...).Update(c)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Chart) Del() error {
|
||||
_, err := DB["mon"].Where("id=?", c.Id).Delete(new(Chart))
|
||||
return err
|
||||
}
|
|
@ -1,534 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type Collect struct {
|
||||
sync.RWMutex
|
||||
Ports map[int]*PortCollect `json:"ports"`
|
||||
Procs map[string]*ProcCollect `json:"procs"`
|
||||
Logs map[string]*LogCollect `json:"logs"`
|
||||
Plugins map[string]*PluginCollect `json:"plugins"`
|
||||
}
|
||||
|
||||
func NewCollect() *Collect {
|
||||
return &Collect{
|
||||
Ports: make(map[int]*PortCollect),
|
||||
Procs: make(map[string]*ProcCollect),
|
||||
Logs: make(map[string]*LogCollect),
|
||||
Plugins: make(map[string]*PluginCollect),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Collect) Update(cc *Collect) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
//更新端口采集配置
|
||||
c.Ports = make(map[int]*PortCollect)
|
||||
for k, v := range cc.Ports {
|
||||
c.Ports[k] = v
|
||||
}
|
||||
|
||||
//更新进程采集配置
|
||||
c.Procs = make(map[string]*ProcCollect)
|
||||
for k, v := range cc.Procs {
|
||||
c.Procs[k] = v
|
||||
}
|
||||
|
||||
//更新log采集配置
|
||||
c.Logs = make(map[string]*LogCollect)
|
||||
for k, v := range cc.Logs {
|
||||
c.Logs[k] = v
|
||||
}
|
||||
|
||||
//更新plugin采集配置
|
||||
c.Plugins = make(map[string]*PluginCollect)
|
||||
for k, v := range cc.Plugins {
|
||||
c.Plugins[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Collect) GetPorts() map[int]*PortCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[int]*PortCollect)
|
||||
for k, v := range c.Ports {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetProcs() map[string]*ProcCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*ProcCollect)
|
||||
for k, v := range c.Procs {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetLogConfig() map[string]*LogCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*LogCollect)
|
||||
for k, v := range c.Logs {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func (c *Collect) GetPlugin() map[string]*PluginCollect {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
tmp := make(map[string]*PluginCollect)
|
||||
for k, v := range c.Plugins {
|
||||
tmp[k] = v
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
type PortCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Tags string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Port int `json:"port"`
|
||||
Timeout int `json:"timeout"`
|
||||
}
|
||||
|
||||
type ProcCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Tags string `json:"tags"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Target string `json:"target"`
|
||||
CollectMethod string `json:"collect_method"`
|
||||
}
|
||||
|
||||
type PluginCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
Step int `json:"step"`
|
||||
FilePath string `json:"file_path"`
|
||||
Params string `json:"params"`
|
||||
Stdin string `json:"stdin"`
|
||||
Env string `json:"env"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
}
|
||||
|
||||
type LogCollect struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Name string `json:"name"`
|
||||
TagsStr string `xorm:"tags" json:"-"`
|
||||
Step int `json:"step"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"updated" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"updated" json:"last_updated"`
|
||||
|
||||
Tags map[string]string `xorm:"-" json:"tags"`
|
||||
|
||||
FilePath string `json:"file_path"`
|
||||
TimeFormat string `json:"time_format"`
|
||||
Pattern string `json:"pattern"`
|
||||
Func string `json:"func"`
|
||||
FuncType string `json:"func_type"`
|
||||
Unit string `json:"unit"`
|
||||
|
||||
Degree int `json:"degree"`
|
||||
Zerofill int `xorm:"zero_fill" json:"zerofill"`
|
||||
Aggregate string `json:"aggregate"`
|
||||
|
||||
LocalUpdated int64 `xorm:"-" json:"-"`
|
||||
TimeReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
PatternReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
ExcludeReg *regexp.Regexp `xorm:"-" json:"-"`
|
||||
TagRegs map[string]*regexp.Regexp `xorm:"-" json:"-"`
|
||||
ParseSucc bool `xorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
type CollectHist struct {
|
||||
Id int64 `json:"id"`
|
||||
Cid int64 `json:"cid"`
|
||||
CollectType string `json:"collect_type"`
|
||||
Action string `json:"action"`
|
||||
Body string `json:"body"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
}
|
||||
|
||||
func (l *LogCollect) Encode() error {
|
||||
tags, err := json.Marshal(l.Tags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode excl_nid err:%v", err)
|
||||
}
|
||||
l.TagsStr = string(tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LogCollect) Decode() error {
|
||||
err := json.Unmarshal([]byte(l.TagsStr), &l.Tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPortCollects() ([]*PortCollect, error) {
|
||||
collects := []*PortCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *PortCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.ID(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
portByte, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "port", "update", p.Creator, string(portByte), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetProcCollects() ([]*ProcCollect, error) {
|
||||
collects := []*ProcCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *ProcCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.ID(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "port", "update", p.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetLogCollects() ([]*LogCollect, error) {
|
||||
collects := []*LogCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (l *LogCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.ID(l.Id).AllCols().Update(l); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(l)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(l.Id, "log", "update", l.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetPluginCollects() ([]*PluginCollect, error) {
|
||||
collects := []*PluginCollect{}
|
||||
err := DB["mon"].Find(&collects)
|
||||
return collects, err
|
||||
}
|
||||
|
||||
func (p *PluginCollect) Update() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Id(p.Id).AllCols().Update(p); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(p.Id, "plugin", "update", p.Creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = session.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateCollect(collectType, creator string, collect interface{}) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Insert(collect); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(collect)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(0, collectType, "create", creator, string(b), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func GetCollectByNid(collectType string, nids []int64) ([]interface{}, error) {
|
||||
var res []interface{}
|
||||
switch collectType {
|
||||
case "port":
|
||||
collects := []PortCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "proc":
|
||||
collects := []ProcCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "log":
|
||||
collects := []LogCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
c.Decode()
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
case "plugin":
|
||||
collects := []PluginCollect{}
|
||||
err := DB["mon"].In("nid", nids).Find(&collects)
|
||||
for _, c := range collects {
|
||||
res = append(res, c)
|
||||
}
|
||||
return res, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("illegal collectType")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetCollectById(collectType string, cid int64) (interface{}, error) {
|
||||
switch collectType {
|
||||
case "port":
|
||||
collect := new(PortCollect)
|
||||
_, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
return collect, err
|
||||
case "proc":
|
||||
collect := new(ProcCollect)
|
||||
_, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
return collect, err
|
||||
case "log":
|
||||
collect := new(LogCollect)
|
||||
_, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
collect.Decode()
|
||||
return collect, err
|
||||
case "plugin":
|
||||
collect := new(PluginCollect)
|
||||
_, err := DB["mon"].Where("id = ?", cid).Get(collect)
|
||||
return collect, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("illegal collectType")
|
||||
}
|
||||
}
|
||||
|
||||
func GetCollectByNameAndNid(collectType string, name string, nid int64) (interface{}, error) {
|
||||
switch collectType {
|
||||
case "port":
|
||||
collect := new(PortCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "proc":
|
||||
collect := new(ProcCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
case "log":
|
||||
collect := new(LogCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
collect.Decode()
|
||||
return collect, err
|
||||
case "plugin":
|
||||
collect := new(PluginCollect)
|
||||
has, err := DB["mon"].Where("name = ? and nid = ?", name, nid).Get(collect)
|
||||
if !has {
|
||||
return nil, err
|
||||
}
|
||||
return collect, err
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("采集类型不合法")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DeleteCollectById(collectType, creator string, cid int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
sql := "delete from " + collectType + "_collect where id = ?"
|
||||
_, err := DB["mon"].Exec(sql, cid)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := saveHist(cid, collectType, "delete", creator, strconv.FormatInt(cid, 10), session); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func saveHist(id int64, tp string, action, username, body string, session *xorm.Session) error {
|
||||
h := CollectHist{
|
||||
Cid: id,
|
||||
CollectType: tp,
|
||||
Action: action,
|
||||
Creator: username,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
_, err := session.Insert(&h)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Endpoint struct {
|
||||
Id int64 `json:"id"`
|
||||
Ident string `json:"ident"`
|
||||
Alias string `json:"alias"`
|
||||
}
|
||||
|
||||
func EndpointGet(col string, val interface{}) (*Endpoint, error) {
|
||||
var obj Endpoint
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (e *Endpoint) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", e.Id).Cols(cols...).Update(e)
|
||||
return err
|
||||
}
|
||||
|
||||
func EndpointTotal(query, batch, field string) (int64, error) {
|
||||
session := buildEndpointWhere(query, batch, field)
|
||||
return session.Count(new(Endpoint))
|
||||
}
|
||||
|
||||
func EndpointGets(query, batch, field string, limit, offset int) ([]Endpoint, error) {
|
||||
session := buildEndpointWhere(query, batch, field).OrderBy(field).Limit(limit, offset)
|
||||
var objs []Endpoint
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func buildEndpointWhere(query, batch, field string) *xorm.Session {
|
||||
session := DB["mon"].Table(new(Endpoint))
|
||||
|
||||
if batch == "" && query != "" {
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("ident like ? or alias like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
if batch != "" {
|
||||
endpoints := str.ParseCommaTrim(batch)
|
||||
if len(endpoints) > 0 {
|
||||
session = session.In(field, endpoints)
|
||||
}
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func EndpointImport(endpoints []string) error {
|
||||
count := len(endpoints)
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
arr := strings.Split(endpoints[i], "::")
|
||||
|
||||
ident := strings.TrimSpace(arr[0])
|
||||
if ident == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
alias := ""
|
||||
if len(arr) == 2 {
|
||||
alias = strings.TrimSpace(arr[1])
|
||||
}
|
||||
err := endpointImport(session, ident, alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func endpointImport(session *xorm.Session, ident, alias string) error {
|
||||
var endpoint Endpoint
|
||||
has, err := session.Where("ident=?", ident).Get(&endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
if alias != "" {
|
||||
endpoint.Alias = alias
|
||||
_, err = session.Where("ident=?", ident).Cols("alias").Update(endpoint)
|
||||
}
|
||||
} else {
|
||||
_, err = session.Insert(Endpoint{Ident: ident, Alias: alias})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func EndpointDel(ids []int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bindings, err := NodeEndpointGetByEndpointIds(ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(bindings); i++ {
|
||||
err = NodeEndpointUnbind(bindings[i].NodeId, bindings[i].EndpointId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := DB["mon"].In("id", ids).Delete(new(Endpoint)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildEndpointUnderNodeWhere(leafids []int64, query, batch, field string) *xorm.Session {
|
||||
session := DB["mon"].Where("id in (select endpoint_id from node_endpoint where node_id in (" + str.IdsString(leafids) + "))")
|
||||
|
||||
if batch == "" && query != "" {
|
||||
arr := strings.Fields(query)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
q := "%" + arr[i] + "%"
|
||||
session = session.Where("ident like ? or alias like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
if batch != "" {
|
||||
endpoints := str.ParseCommaTrim(batch)
|
||||
if len(endpoints) > 0 {
|
||||
session = session.In(field, endpoints)
|
||||
}
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func EndpointUnderNodeTotal(leafids []int64, query, batch, field string) (int64, error) {
|
||||
session := buildEndpointUnderNodeWhere(leafids, query, batch, field)
|
||||
return session.Count(new(Endpoint))
|
||||
}
|
||||
|
||||
func EndpointUnderNodeGets(leafids []int64, query, batch, field string, limit, offset int) ([]Endpoint, error) {
|
||||
session := buildEndpointUnderNodeWhere(leafids, query, batch, field).Limit(limit, offset).OrderBy(field)
|
||||
var objs []Endpoint
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func EndpointIdsByIdents(idents []string) ([]int64, error) {
|
||||
idents = str.TrimStringSlice(idents)
|
||||
if len(idents) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var objs []Endpoint
|
||||
err := DB["mon"].In("ident", idents).Find(&objs)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
|
||||
cnt := len(objs)
|
||||
ret := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
ret = append(ret, objs[i].Id)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type EndpointBinding struct {
|
||||
Ident string `json:"ident"`
|
||||
Alias string `json:"alias"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
}
|
||||
|
||||
func EndpointBindings(endpointIds []int64) ([]EndpointBinding, error) {
|
||||
var nes []NodeEndpoint
|
||||
err := DB["mon"].In("endpoint_id", endpointIds).Find(&nes)
|
||||
if err != nil {
|
||||
return []EndpointBinding{}, err
|
||||
}
|
||||
|
||||
cnt := len(nes)
|
||||
if cnt == 0 {
|
||||
return []EndpointBinding{}, nil
|
||||
}
|
||||
|
||||
h2n := make(map[int64][]int64)
|
||||
arr := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr = append(arr, nes[i].EndpointId)
|
||||
h2n[nes[i].EndpointId] = append(h2n[nes[i].EndpointId], nes[i].NodeId)
|
||||
}
|
||||
|
||||
var endpoints []Endpoint
|
||||
err = DB["mon"].In("id", arr).Find(&endpoints)
|
||||
if err != nil {
|
||||
return []EndpointBinding{}, err
|
||||
}
|
||||
|
||||
cnt = len(endpoints)
|
||||
ret := make([]EndpointBinding, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
nodeids := h2n[endpoints[i].Id]
|
||||
if len(nodeids) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err = DB["mon"].In("id", nodeids).Find(&nodes)
|
||||
if err != nil {
|
||||
return []EndpointBinding{}, err
|
||||
}
|
||||
|
||||
b := EndpointBinding{
|
||||
Ident: endpoints[i].Ident,
|
||||
Alias: endpoints[i].Alias,
|
||||
Nodes: nodes,
|
||||
}
|
||||
|
||||
ret = append(ret, b)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func EndpointUnderLeafs(leafIds []int64) ([]Endpoint, error) {
|
||||
var endpoints []Endpoint
|
||||
if len(leafIds) == 0 {
|
||||
return []Endpoint{}, nil
|
||||
}
|
||||
|
||||
err := DB["mon"].Where("id in (select endpoint_id from node_endpoint where node_id in (" + str.IdsString(leafIds) + "))").Find(&endpoints)
|
||||
return endpoints, err
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Sname string `json:"sname"`
|
||||
NodePath string `json:"node_path"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
EndpointAlias string `json:"endpoint_alias"`
|
||||
Priority int `json:"priority"`
|
||||
EventType string `json:"event_type"` // alert|recovery
|
||||
Category int `json:"category"`
|
||||
Status uint16 `json:"status"`
|
||||
HashId uint64 `json:"hashid" xorm:"hashid"`
|
||||
Etime int64 `json:"etime"`
|
||||
Value string `json:"value"`
|
||||
Info string `json:"info"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
Detail string `json:"detail"`
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Nid int64 `json:"nid"`
|
||||
NeedUpgrade int `json:"need_upgrade"`
|
||||
AlertUpgrade string `json:"alert_upgrade"`
|
||||
RecvUserIDs []int64 `json:"recv_user_ids" xorm:"-"`
|
||||
RecvUserObjs []User `json:"recv_user_objs" xorm:"-"`
|
||||
RealUpgrade bool `json:"real_upgrade" xorm:"-"`
|
||||
}
|
||||
|
||||
type EventDetail struct {
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Points []*EventDetailPoint `json:"points"`
|
||||
PredPoints []*EventDetailPoint `json:"pred_points,omitempty"` // 预测值, 预测值不为空时, 现场值对应的是实际值
|
||||
}
|
||||
|
||||
type EventDetailPoint struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Value float64 `json:"value"`
|
||||
Extra string `json:"extra"`
|
||||
}
|
||||
|
||||
type EventAlertUpgrade struct {
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Duration int `json:"duration"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
func ParseEtime(etime int64) string {
|
||||
t := time.Unix(etime, 0)
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
type EventSlice []*Event
|
||||
|
||||
func (e EventSlice) Len() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
func (e EventSlice) Less(i, j int) bool {
|
||||
return e[i].Etime < e[j].Etime
|
||||
}
|
||||
|
||||
func (e EventSlice) Swap(i, j int) {
|
||||
e[i], e[j] = e[j], e[i]
|
||||
}
|
||||
|
||||
func SaveEvent(event *Event) error {
|
||||
_, err := DB["mon"].Insert(event)
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventStatus(id int64, status string) error {
|
||||
sql := "update event set status = status | ? where id = ?"
|
||||
_, err := DB["mon"].Exec(sql, GetStatus(status), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateEventPriority(id int64, priority int) error {
|
||||
sql := "update event set priority=? where id=?"
|
||||
_, err := DB["mon"].Exec(sql, priority, id)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Event) GetEventDetail() ([]EventDetail, error) {
|
||||
var detail []EventDetail
|
||||
err := json.Unmarshal([]byte(e.Detail), &detail)
|
||||
return detail, err
|
||||
}
|
||||
|
||||
func EventTotal(stime, etime int64, nodePath, query, eventType string, priorities, sendTypes []string) (int64, error) {
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?)", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if eventType != "" {
|
||||
session = session.Where("event_type=?", eventType)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
total, err := session.Count(new(Event))
|
||||
return total, err
|
||||
}
|
||||
|
||||
func EventGets(stime, etime int64, nodePath, query, eventType string, priorities, sendTypes []string, limit, offset int) ([]Event, error) {
|
||||
var objs []Event
|
||||
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?)", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if eventType != "" {
|
||||
session = session.Where("event_type=?", eventType)
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
err := session.Desc("etime").Limit(limit, offset).Find(&objs)
|
||||
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func EventGet(col string, value interface{}) (*Event, error) {
|
||||
var obj Event
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func DelEventOlder(ts int64, batch int) (int64, error) {
|
||||
sql := "delete from event where etime < ? limit ?"
|
||||
ret, err := DB["mon"].Exec(sql, ts, batch)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ret.RowsAffected()
|
||||
}
|
||||
|
||||
func EventAlertUpgradeUnMarshal(str string) (EventAlertUpgrade, error) {
|
||||
var obj EventAlertUpgrade
|
||||
if strings.TrimSpace(str) == "" {
|
||||
return EventAlertUpgrade{
|
||||
Users: "[]",
|
||||
Groups: "[]",
|
||||
Duration: 0,
|
||||
Level: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(str), &obj)
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func EventCnt(hashid uint64, stime, etime string, isUpgrade bool) (int64, error) {
|
||||
session := DB["mon"].Where("hashid = ? and event_type = ? and created between ? and ?", hashid, config.ALERT, stime, etime)
|
||||
|
||||
if isUpgrade {
|
||||
return session.In("status", GetFlagsByStatus([]string{STATUS_UPGRADE, STATUS_SEND})).Count(new(Event))
|
||||
}
|
||||
|
||||
return session.In("status", GetFlagsByStatus([]string{STATUS_SEND})).Count(new(Event))
|
||||
}
|
||||
|
||||
func EventAlertUpgradeMarshal(alertUpgrade AlertUpgrade) (string, error) {
|
||||
eventAlertUpgrade := EventAlertUpgrade{
|
||||
Duration: alertUpgrade.Duration,
|
||||
Level: alertUpgrade.Level,
|
||||
}
|
||||
|
||||
if alertUpgrade.Users == nil {
|
||||
eventAlertUpgrade.Users = "[]"
|
||||
} else {
|
||||
upgradeUsers, err := json.Marshal(alertUpgrade.Users)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
eventAlertUpgrade.Users = string(upgradeUsers)
|
||||
}
|
||||
|
||||
if alertUpgrade.Groups == nil {
|
||||
eventAlertUpgrade.Groups = "[]"
|
||||
} else {
|
||||
upgradeGroups, err := json.Marshal(alertUpgrade.Groups)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
eventAlertUpgrade.Groups = string(upgradeGroups)
|
||||
}
|
||||
|
||||
alertUpgradebytes, err := json.Marshal(eventAlertUpgrade)
|
||||
|
||||
return string(alertUpgradebytes), err
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/slice"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
type EventCur struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Sname string `json:"sname"`
|
||||
NodePath string `json:"node_path"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
EndpointAlias string `json:"endpoint_alias"`
|
||||
Priority int `json:"priority"`
|
||||
EventType string `json:"event_type"` // alert|recovery
|
||||
Category int `json:"category"`
|
||||
Status uint16 `json:"status"`
|
||||
HashId uint64 `json:"hashid" xorm:"hashid"`
|
||||
Etime int64 `json:"etime"`
|
||||
Value string `json:"value"`
|
||||
Info string `json:"info"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
Detail string `json:"detail"`
|
||||
Users string `json:"users"`
|
||||
Groups string `json:"groups"`
|
||||
Nid int64 `json:"nid"`
|
||||
IgnoreAlert int `json:"ignore_alert"`
|
||||
Claimants string `json:"claimants"`
|
||||
NeedUpgrade int `json:"need_upgrade"`
|
||||
AlertUpgrade string `json:"alert_upgrade"`
|
||||
}
|
||||
|
||||
func UpdateEventCurPriority(hashid uint64, priority int) error {
|
||||
sql := "update event_cur set priority=? where hashid=?"
|
||||
_, err := DB["mon"].Exec(sql, priority, hashid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventCur(eventCur *EventCur) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := session.Where("hashid=?", eventCur.HashId).Get(new(EventCur))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
if _, err := session.Where("hashid=?", eventCur.HashId).Cols("sid", "sname", "node_path", "endpoint", "priority", "category", "status", "etime", "detail", "value", "info", "users", "groups", "nid", "alert_upgrade", "need_upgrade", "endpoint_alias").Update(eventCur); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := session.Insert(eventCur); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateClaimantsById(userId, id int64) error {
|
||||
var obj EventCur
|
||||
has, err := DB["mon"].Where("id=?", id).Cols("claimants").Get(&obj)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return fmt.Errorf("event not exists")
|
||||
}
|
||||
|
||||
var users []int64
|
||||
if err = json.Unmarshal([]byte(obj.Claimants), &users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
users = append(users, userId)
|
||||
data, err := json.Marshal(slice.UniqueInt64(users))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Exec("update event_cur set claimants=? where id=?", string(data), id)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateClaimantsByNodePath(userId int64, nodePath string) error {
|
||||
var objs []EventCur
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := session.Where("node_path = ?", nodePath).Find(&objs); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
var users []int64
|
||||
if err := json.Unmarshal([]byte(objs[i].Claimants), &users); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
users = append(users, userId)
|
||||
data, err := json.Marshal(slice.UniqueInt64(users))
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = session.Exec("update event_cur set claimants=? where id=?", string(data), objs[i].Id)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func EventCurDel(hashid uint64) error {
|
||||
_, err := DB["mon"].Where("hashid=?", hashid).Delete(new(EventCur))
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveEventCurStatus(hashid uint64, status string) error {
|
||||
sql := "update event_cur set status = status | ? where hashid = ?"
|
||||
_, err := DB["mon"].Exec(sql, GetStatus(status), hashid)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func EventCurTotal(stime, etime int64, nodePath, query string, priorities, sendTypes []string) (int64, error) {
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?) and ignore_alert=0", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
total, err := session.Count(new(EventCur))
|
||||
return total, err
|
||||
}
|
||||
|
||||
func EventCurGets(stime, etime int64, nodePath, query string, priorities, sendTypes []string, limit, offset int) ([]EventCur, error) {
|
||||
var obj []EventCur
|
||||
|
||||
session := DB["mon"].Where("etime > ? and etime < ? and (node_path = ? or node_path like ?) and ignore_alert=0", stime, etime, nodePath, nodePath+".%")
|
||||
if len(priorities) > 0 && priorities[0] != "" {
|
||||
session = session.In("priority", priorities)
|
||||
}
|
||||
|
||||
if len(sendTypes) > 0 && sendTypes[0] != "" {
|
||||
session = session.In("status", GetFlagsByStatus(sendTypes))
|
||||
}
|
||||
|
||||
if query != "" {
|
||||
fields := strings.Fields(query)
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
q := "%" + fields[i] + "%"
|
||||
session = session.Where("sname like ? or endpoint like ?", q, q)
|
||||
}
|
||||
}
|
||||
|
||||
err := session.Desc("etime").Limit(limit, offset).Find(&obj)
|
||||
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func EventCurGet(col string, value interface{}) (*EventCur, error) {
|
||||
var obj EventCur
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (e *EventCur) EventIgnore() error {
|
||||
_, err := DB["mon"].Where("id=?", e.Id).Delete(new(EventCur))
|
||||
return err
|
||||
}
|
||||
|
||||
func DelEventCurOlder(ts int64, batch int) (int64, error) {
|
||||
sql := "delete from event_cur where etime < ? limit ?"
|
||||
ret, err := DB["mon"].Exec(sql, ts, batch)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ret.RowsAffected()
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
package model
|
||||
|
||||
// 0 0 0 0 0 0 处理中
|
||||
// 0 0 0 0 x 1 已发送
|
||||
// 0 0 0 0 1 x 已回调
|
||||
// 0 0 0 1 0 0 已屏蔽
|
||||
// 0 0 1 0 0 0 被收敛
|
||||
// 0 1 0 0 x 0 无接收人
|
||||
// 1 0 0 0 x 0 升级发送
|
||||
const (
|
||||
FLAG_SEND = iota
|
||||
FLAG_CALLBACK
|
||||
FLAG_MASK
|
||||
FLAG_CONVERGE
|
||||
FLAG_NONEUSER
|
||||
FLAG_UPGRADE
|
||||
)
|
||||
|
||||
const (
|
||||
STATUS_DOING = "doing" // 处理中
|
||||
STATUS_SEND = "send" // 已发送
|
||||
STATUS_NONEUSER = "none-user" // 无接收人
|
||||
STATUS_CALLBACK = "callback" // 已回调
|
||||
STATUS_MASK = "mask" // 已屏蔽
|
||||
STATUS_CONVERGE = "converge" // 频率限制
|
||||
STATUS_UPGRADE = "upgrade" // 升级报警
|
||||
)
|
||||
|
||||
func StatusConvert(s []string) []string {
|
||||
status := []string{}
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case STATUS_DOING:
|
||||
status = append(status, "处理中")
|
||||
case STATUS_SEND:
|
||||
status = append(status, "已发送")
|
||||
case STATUS_NONEUSER:
|
||||
status = append(status, "无接收人")
|
||||
case STATUS_CALLBACK:
|
||||
status = append(status, "已回调")
|
||||
case STATUS_MASK:
|
||||
status = append(status, "已屏蔽")
|
||||
case STATUS_CONVERGE:
|
||||
status = append(status, "已收敛")
|
||||
case STATUS_UPGRADE:
|
||||
status = append(status, "已升级")
|
||||
}
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func GetStatus(status string) int {
|
||||
switch status {
|
||||
case STATUS_SEND:
|
||||
return 1 << FLAG_SEND
|
||||
case STATUS_NONEUSER:
|
||||
return 1 << FLAG_NONEUSER
|
||||
case STATUS_CALLBACK:
|
||||
return 1 << FLAG_CALLBACK
|
||||
case STATUS_MASK:
|
||||
return 1 << FLAG_MASK
|
||||
case STATUS_CONVERGE:
|
||||
return 1 << FLAG_CONVERGE
|
||||
case STATUS_UPGRADE:
|
||||
return 1 << FLAG_UPGRADE
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetFlagsByStatus(ss []string) []uint16 {
|
||||
if len(ss) == 0 {
|
||||
return []uint16{}
|
||||
}
|
||||
|
||||
flags := make(map[string][]uint16)
|
||||
for _, s := range ss {
|
||||
switch s {
|
||||
case STATUS_DOING:
|
||||
flags[s] = getDoing()
|
||||
case STATUS_SEND:
|
||||
flags[s] = getSend()
|
||||
case STATUS_NONEUSER:
|
||||
flags[s] = getNoneUser()
|
||||
case STATUS_CALLBACK:
|
||||
flags[s] = getCallback()
|
||||
case STATUS_MASK:
|
||||
flags[s] = getMask()
|
||||
case STATUS_CONVERGE:
|
||||
flags[s] = getConverge()
|
||||
case STATUS_UPGRADE:
|
||||
flags[s] = getUpgrade()
|
||||
}
|
||||
}
|
||||
uss := make([][]uint16, 0)
|
||||
for _, s := range flags {
|
||||
uss = append(uss, s)
|
||||
}
|
||||
return interSection(uss)
|
||||
}
|
||||
|
||||
func GetStatusByFlag(flag uint16) []string {
|
||||
ret := make([]string, 0)
|
||||
|
||||
if flag == 0 {
|
||||
ret = append(ret, STATUS_DOING)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_UPGRADE)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_UPGRADE)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_CONVERGE)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_CONVERGE)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_MASK)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_MASK)
|
||||
return ret
|
||||
}
|
||||
|
||||
if (flag>>FLAG_SEND)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_SEND)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_CALLBACK)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_CALLBACK)
|
||||
}
|
||||
|
||||
if (flag>>FLAG_NONEUSER)&0x01 == 1 {
|
||||
ret = append(ret, STATUS_NONEUSER)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// 0 0 0 0 0 0 正在处理
|
||||
func getDoing() []uint16 {
|
||||
return []uint16{0}
|
||||
}
|
||||
|
||||
// x 0 0 0 x 1 已发送
|
||||
func getSend() []uint16 {
|
||||
return []uint16{1, 3, 33, 35}
|
||||
}
|
||||
|
||||
// x 0 0 0 1 x 已回调
|
||||
func getCallback() []uint16 {
|
||||
return []uint16{2, 3, 34, 35}
|
||||
}
|
||||
|
||||
// 0 0 0 1 0 0 已屏蔽
|
||||
func getMask() []uint16 {
|
||||
return []uint16{4}
|
||||
}
|
||||
|
||||
// x 0 1 0 0 0 被收敛
|
||||
func getConverge() []uint16 {
|
||||
return []uint16{8, 40}
|
||||
}
|
||||
|
||||
// x 1 0 0 x 0 无接收人
|
||||
func getNoneUser() []uint16 {
|
||||
return []uint16{16, 18, 48, 50}
|
||||
}
|
||||
|
||||
// 1 x x 0 x x 已升级
|
||||
func getUpgrade() []uint16 {
|
||||
return []uint16{32, 33, 34, 35, 40, 41, 42, 43, 48, 49, 50, 51, 56, 57, 58, 59}
|
||||
}
|
||||
|
||||
func interSection(ss [][]uint16) []uint16 {
|
||||
if len(ss) == 0 {
|
||||
return []uint16{}
|
||||
}
|
||||
umap := make(map[uint16]int)
|
||||
for _, s := range ss {
|
||||
for _, su := range s {
|
||||
if _, found := umap[su]; found {
|
||||
umap[su] += 1
|
||||
} else {
|
||||
umap[su] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
ret := []uint16{}
|
||||
for su, cnt := range umap {
|
||||
if cnt == len(ss) {
|
||||
ret = append(ret, su)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package model
|
||||
|
||||
import "strings"
|
||||
|
||||
func Paths(longPath string) []string {
|
||||
names := strings.Split(longPath, ".")
|
||||
count := len(names)
|
||||
paths := make([]string, 0, count)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
paths = append(paths, strings.Join(names[:i], "."))
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Instance struct {
|
||||
Id int64 `json:"id"`
|
||||
Module string `json:"module"`
|
||||
Identity string `json:"identity"` //ip 或者 机器名
|
||||
RPCPort string `json:"rpc_port" xorm:"rpc_port"`
|
||||
HTTPPort string `json:"http_port" xorm:"http_port"`
|
||||
TS int64 `json:"ts" xorm:"ts"`
|
||||
Remark string `json:"remark"`
|
||||
Active bool `xorm:"-" json:"active"`
|
||||
}
|
||||
|
||||
func (i *Instance) Add() error {
|
||||
_, err := DB["hbs"].InsertOne(i)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *Instance) Update() error {
|
||||
_, err := DB["hbs"].Where("id=?", i.Id).MustCols("ts", "http_port", "rpc_port").Update(i)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetInstanceBy(mod, identity, rpcPort, httpPort string) (*Instance, error) {
|
||||
var obj Instance
|
||||
has, err := DB["hbs"].Where("module=? and identity=? and rpc_port=? and http_port=?", mod, identity, rpcPort, httpPort).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func GetAllInstances(mod string, alive int) ([]*Instance, error) {
|
||||
objs := make([]*Instance, 0)
|
||||
var err error
|
||||
now := time.Now().Unix()
|
||||
|
||||
ts := now - 60
|
||||
if alive == 1 {
|
||||
err = DB["hbs"].Where("module = ? and ts > ?", mod, ts).OrderBy("id").Find(&objs)
|
||||
} else {
|
||||
err = DB["hbs"].Where("module = ?", mod).OrderBy("id").Find(&objs)
|
||||
}
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
for _, j := range objs {
|
||||
if j.TS > now-60 { //上报心跳时间在1分钟之内
|
||||
j.Active = true
|
||||
}
|
||||
}
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func DelById(id int64) error {
|
||||
_, err := DB["hbs"].Where("id=?", id).Delete(new(Instance))
|
||||
return err
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Invite struct {
|
||||
Id int64
|
||||
Token string
|
||||
Expire int64
|
||||
Creator string
|
||||
}
|
||||
|
||||
func InviteGet(col string, val interface{}) (*Invite, error) {
|
||||
var obj Invite
|
||||
has, err := DB["uic"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func InviteAdd(token, creator string) error {
|
||||
now := time.Now().Unix()
|
||||
obj := Invite{
|
||||
Token: token,
|
||||
Creator: creator,
|
||||
Expire: now + 3600*24*30,
|
||||
}
|
||||
_, err := DB["uic"].Insert(&obj)
|
||||
return err
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||
"gopkg.in/ldap.v3"
|
||||
)
|
||||
|
||||
func genLdapAttributeSearchList() []string {
|
||||
ldapAttributes := []string{}
|
||||
attrs := config.Get().LDAP.Attributes
|
||||
if attrs.Dispname != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Dispname)
|
||||
}
|
||||
if attrs.Email != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Email)
|
||||
}
|
||||
if attrs.Phone != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Phone)
|
||||
}
|
||||
if attrs.Im != "" {
|
||||
ldapAttributes = append(ldapAttributes, attrs.Im)
|
||||
}
|
||||
return ldapAttributes
|
||||
}
|
||||
|
||||
func ldapReq(user, pass string) (*ldap.SearchResult, error) {
|
||||
var conn *ldap.Conn
|
||||
var err error
|
||||
lc := config.Get().LDAP
|
||||
addr := fmt.Sprintf("%s:%d", lc.Host, lc.Port)
|
||||
|
||||
if lc.TLS {
|
||||
conn, err = ldap.DialTLS("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
||||
} else {
|
||||
conn, err = ldap.Dial("tcp", addr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot dial ldap: %v", err)
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if !lc.TLS && lc.StartTLS {
|
||||
if err := conn.StartTLS(&tls.Config{InsecureSkipVerify: true}); err != nil {
|
||||
return nil, fmt.Errorf("ldap.conn startTLS fail: %v", err)
|
||||
}
|
||||
}
|
||||
//if bindUser is empty, anonymousSearch mode
|
||||
if lc.BindUser != "" {
|
||||
//BindSearch mode
|
||||
if err := conn.Bind(lc.BindUser, lc.BindPass); err != nil {
|
||||
return nil, fmt.Errorf("bind ldap fail: %v, use %s", err, lc.BindUser)
|
||||
}
|
||||
}
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
lc.BaseDn, // The base dn to search
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf(lc.AuthFilter, user), // The filter to apply
|
||||
genLdapAttributeSearchList(), // A list attributes to retrieve
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ldap search fail: %v", err)
|
||||
}
|
||||
|
||||
if len(sr.Entries) == 0 {
|
||||
return nil, fmt.Errorf("cannot find such user: %v", user)
|
||||
}
|
||||
|
||||
if len(sr.Entries) > 1 {
|
||||
return nil, fmt.Errorf("multi users is search, query user: %v", user)
|
||||
}
|
||||
|
||||
if err := conn.Bind(sr.Entries[0].DN, pass); err != nil {
|
||||
return nil, fmt.Errorf("password error")
|
||||
}
|
||||
return sr, nil
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Maskconf struct {
|
||||
Id int64 `json:"id"`
|
||||
Nid int64 `json:"nid"`
|
||||
NodePath string `json:"node_path" xorm:"-"`
|
||||
Metric string `json:"metric"`
|
||||
Tags string `json:"tags"`
|
||||
Cause string `json:"cause"`
|
||||
User string `json:"user"`
|
||||
Btime int64 `json:"btime"`
|
||||
Etime int64 `json:"etime"`
|
||||
Endpoints []string `json:"endpoints" xorm:"-"`
|
||||
}
|
||||
|
||||
func (mc *Maskconf) Add(endpoints []string) error {
|
||||
_, err := DB["mon"].Insert(mc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
|
||||
for i := 0; i < len(endpoints); i++ {
|
||||
endpoint := strings.TrimSpace(endpoints[i])
|
||||
if endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&MaskconfEndpoints{
|
||||
MaskId: mc.Id,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
affected++
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
return fmt.Errorf("arg[endpoints] empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) FillEndpoints() error {
|
||||
var objs []MaskconfEndpoints
|
||||
err := DB["mon"].Where("mask_id=?", mc.Id).OrderBy("id").Find(&objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(objs)
|
||||
arr := make([]string, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr[i] = objs[i].Endpoint
|
||||
}
|
||||
|
||||
mc.Endpoints = arr
|
||||
return nil
|
||||
}
|
||||
|
||||
func MaskconfGets(nodeId int64) ([]Maskconf, error) {
|
||||
node, err := NodeGet("id", nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node.Leaf == 1 {
|
||||
var objs []Maskconf
|
||||
err = DB["mon"].Where("nid=?", nodeId).OrderBy("id desc").Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
objs[i].NodePath = node.Path
|
||||
}
|
||||
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
var relatedNodeIds []int64
|
||||
err = DB["mon"].Table("maskconf").Select("nid").Find(&relatedNodeIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(relatedNodeIds) == 0 {
|
||||
return []Maskconf{}, nil
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err = DB["mon"].Where("id in ("+str.IdsString(relatedNodeIds)+")").Where("id="+fmt.Sprint(node.Id)+" or path like ?", node.Path+".%").Find(&nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(nodes)
|
||||
if count == 0 {
|
||||
return []Maskconf{}, nil
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, count)
|
||||
nmap := make(map[int64]Node, count)
|
||||
for i := 0; i < count; i++ {
|
||||
nmap[nodes[i].Id] = nodes[i]
|
||||
ids = append(ids, nodes[i].Id)
|
||||
}
|
||||
|
||||
var objs []Maskconf
|
||||
err = DB["mon"].In("nid", ids).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count = len(objs)
|
||||
for i := 0; i < count; i++ {
|
||||
n, has := nmap[objs[i].Nid]
|
||||
if has {
|
||||
objs[i].NodePath = n.Path
|
||||
}
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return []Maskconf{}, nil
|
||||
}
|
||||
|
||||
sort.Slice(objs, func(i int, j int) bool {
|
||||
if objs[i].NodePath < objs[j].NodePath {
|
||||
return true
|
||||
}
|
||||
|
||||
if objs[i].Id > objs[j].Id {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
func MaskconfDel(id int64) error {
|
||||
_, err := DB["mon"].Where("mask_id=?", id).Delete(new(MaskconfEndpoints))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=?", id).Delete(new(Maskconf))
|
||||
return err
|
||||
}
|
||||
|
||||
func MaskconfGetAll() ([]Maskconf, error) {
|
||||
var objs []Maskconf
|
||||
err := DB["mon"].Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func CleanExpireMask(now int64) error {
|
||||
var objs []Maskconf
|
||||
err := DB["mon"].Where("etime<?", now).Cols("id").Find(&objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(objs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(objs); i++ {
|
||||
if _, err := session.Exec("delete from maskconf where id=?", objs[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_endpoints where mask_id=?", objs[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = session.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
func MaskconfGet(col string, value interface{}) (*Maskconf, error) {
|
||||
var obj Maskconf
|
||||
has, err := DB["mon"].Where(col+"=?", value).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (mc *Maskconf) Update(endpoints []string, cols ...string) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Where("id=?", mc.Id).Cols(cols...).Update(mc); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("delete from maskconf_endpoints where mask_id=?", mc.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected := 0
|
||||
for i := 0; i < len(endpoints); i++ {
|
||||
endpoint := strings.TrimSpace(endpoints[i])
|
||||
if endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := session.Insert(&MaskconfEndpoints{
|
||||
MaskId: mc.Id,
|
||||
Endpoint: endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
affected += 1
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("arg[endpoints] empty")
|
||||
}
|
||||
|
||||
if err := session.Commit(); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package model
|
||||
|
||||
type MaskconfEndpoints struct {
|
||||
Id int64 `json:"id"`
|
||||
MaskId int64 `json:"mask_id"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/runner"
|
||||
)
|
||||
|
||||
type MySQLConf struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Max int `yaml:"max"`
|
||||
Idle int `yaml:"idle"`
|
||||
Debug bool `yaml:"debug"`
|
||||
}
|
||||
|
||||
var DB = map[string]*xorm.Engine{}
|
||||
|
||||
func InitMySQL(names ...string) {
|
||||
confdir := path.Join(runner.Cwd, "etc")
|
||||
|
||||
mysqlYml := path.Join(confdir, "mysql.local.yml")
|
||||
if !file.IsExist(mysqlYml) {
|
||||
mysqlYml = path.Join(confdir, "mysql.yml")
|
||||
}
|
||||
|
||||
confs := make(map[string]MySQLConf)
|
||||
err := file.ReadYaml(mysqlYml, &confs)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot read yml[%s]: %v", mysqlYml, err)
|
||||
}
|
||||
|
||||
count := len(names)
|
||||
for i := 0; i < count; i++ {
|
||||
conf, has := confs[names[i]]
|
||||
if !has {
|
||||
log.Fatalf("no such mysql conf: %s", names[i])
|
||||
}
|
||||
|
||||
db, err := xorm.NewEngine("mysql", conf.Addr)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot connect mysql[%s]: %v", conf.Addr, err)
|
||||
}
|
||||
|
||||
db.SetMaxIdleConns(conf.Idle)
|
||||
db.SetMaxOpenConns(conf.Max)
|
||||
db.SetConnMaxLifetime(time.Hour)
|
||||
db.ShowSQL(conf.Debug)
|
||||
db.Logger().SetLevel(core.LOG_INFO)
|
||||
|
||||
DB[names[i]] = db
|
||||
}
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Id int64 `json:"id"`
|
||||
Pid int64 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Leaf int `json:"leaf"`
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
// InitNode 初始化第一个node节点
|
||||
func InitNode() {
|
||||
num, err := DB["mon"].Where("pid=0").Count(new(Node))
|
||||
if err != nil {
|
||||
log.Fatalln("cannot query first node", err)
|
||||
}
|
||||
|
||||
if num > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
node := Node{
|
||||
Pid: 0,
|
||||
Name: "cop",
|
||||
Path: "cop",
|
||||
Leaf: 0,
|
||||
Note: "公司节点",
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&node)
|
||||
if err != nil {
|
||||
log.Fatalln("cannot insert node[cop]")
|
||||
}
|
||||
|
||||
logger.Info("node cop init done")
|
||||
}
|
||||
|
||||
func NodeGets(where string, args ...interface{}) (nodes []Node, err error) {
|
||||
if where != "" {
|
||||
err = DB["mon"].Where(where, args...).Find(&nodes)
|
||||
} else {
|
||||
err = DB["mon"].Find(&nodes)
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func NodeGetsByPaths(paths []string) ([]Node, error) {
|
||||
if len(paths) == 0 {
|
||||
return []Node{}, nil
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err := DB["mon"].In("path", paths).Find(&nodes)
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func NodeByIds(ids []int64) ([]Node, error) {
|
||||
if len(ids) == 0 {
|
||||
return []Node{}, nil
|
||||
}
|
||||
|
||||
return NodeGets(fmt.Sprintf("id in (%s)", str.IdsString(ids)))
|
||||
}
|
||||
|
||||
func NodeQueryPath(query string, limit int) (nodes []Node, err error) {
|
||||
err = DB["mon"].Where("path like ?", "%"+query+"%").OrderBy("path").Limit(limit).Find(&nodes)
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func TreeSearchByPath(query string) (nodes []Node, err error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if strings.Contains(query, " ") {
|
||||
arr := strings.Fields(query)
|
||||
cnt := len(arr)
|
||||
for i := 0; i < cnt; i++ {
|
||||
session.Where("path like ?", "%"+arr[i]+"%")
|
||||
}
|
||||
err = session.Find(&nodes)
|
||||
} else {
|
||||
err = session.Where("path like ?", "%"+query+"%").Find(&nodes)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cnt := len(nodes)
|
||||
if cnt == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
pathset := make(map[string]struct{})
|
||||
for i := 0; i < cnt; i++ {
|
||||
pathset[nodes[i].Path] = struct{}{}
|
||||
|
||||
paths := Paths(nodes[i].Path)
|
||||
for j := 0; j < len(paths); j++ {
|
||||
pathset[paths[j]] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
var objs []Node
|
||||
err = session.In("path", str.MtoL(pathset)).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func NodeGet(col string, val interface{}) (*Node, error) {
|
||||
var obj Node
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func NodesGetByIds(ids []int64) ([]Node, error) {
|
||||
var objs []Node
|
||||
err := DB["mon"].In("id", ids).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func NodeValid(name, path string) error {
|
||||
if len(name) > 32 {
|
||||
return fmt.Errorf("name too long")
|
||||
}
|
||||
|
||||
if len(path) > 255 {
|
||||
return fmt.Errorf("path too long")
|
||||
}
|
||||
|
||||
if !str.IsMatch(name, `^[a-z0-9\-]+$`) {
|
||||
return fmt.Errorf("name permissible characters: [a-z0-9] and -")
|
||||
}
|
||||
|
||||
arr := strings.Split(path, ".")
|
||||
if name != arr[len(arr)-1] {
|
||||
return fmt.Errorf("name and path not match")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) CreateChild(name string, leaf int, note string) (int64, error) {
|
||||
if n.Leaf == 1 {
|
||||
return 0, fmt.Errorf("parent node is leaf, cannot create child")
|
||||
}
|
||||
|
||||
path := n.Path + "." + name
|
||||
node, err := NodeGet("path", path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if node != nil {
|
||||
return 0, fmt.Errorf("node[%s] already exists", path)
|
||||
}
|
||||
|
||||
child := Node{
|
||||
Pid: n.Id,
|
||||
Name: name,
|
||||
Path: path,
|
||||
Leaf: leaf,
|
||||
Note: note,
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&child)
|
||||
return child.Id, err
|
||||
}
|
||||
|
||||
func (n *Node) Bind(endpointIds []int64, delOld int) error {
|
||||
if delOld == 1 {
|
||||
bindings, err := NodeEndpointGetByEndpointIds(endpointIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(bindings); i++ {
|
||||
err = NodeEndpointUnbind(bindings[i].NodeId, bindings[i].EndpointId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cnt := len(endpointIds)
|
||||
for i := 0; i < cnt; i++ {
|
||||
if err := NodeEndpointBind(n.Id, endpointIds[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) Unbind(hostIds []int64) error {
|
||||
if len(hostIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(hostIds); i++ {
|
||||
if err := NodeEndpointUnbind(n.Id, hostIds[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) LeafIds() ([]int64, error) {
|
||||
if n.Leaf == 1 {
|
||||
return []int64{n.Id}, nil
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err := DB["mon"].Where("path like ? and leaf=1", n.Path+".%").Find(&nodes)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
|
||||
cnt := len(nodes)
|
||||
arr := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr = append(arr, nodes[i].Id)
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func (n *Node) Pids() ([]int64, error) {
|
||||
if n.Pid == 0 {
|
||||
return []int64{n.Pid}, nil
|
||||
}
|
||||
|
||||
var objs []Node
|
||||
arr := []int64{}
|
||||
paths := []string{}
|
||||
|
||||
nodes := strings.Split(n.Path, ".")
|
||||
cnt := len(nodes)
|
||||
|
||||
for i := 1; i < cnt; i++ {
|
||||
path := strings.Join(nodes[:cnt-i], ".")
|
||||
paths = append(paths, path)
|
||||
}
|
||||
|
||||
err := DB["mon"].In("path", paths).Find(&objs)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
|
||||
cnt = len(objs)
|
||||
for i := 0; i < cnt; i++ {
|
||||
arr = append(arr, objs[i].Id)
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func (n *Node) Rename(name string) error {
|
||||
oldprefix := n.Path + "."
|
||||
|
||||
arr := strings.Split(n.Path, ".")
|
||||
arr[len(arr)-1] = name
|
||||
newpath := strings.Join(arr, ".")
|
||||
|
||||
newprefix := newpath + "."
|
||||
|
||||
brother, err := NodeGet("path", newpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if brother != nil {
|
||||
return fmt.Errorf("%s already exists", newpath)
|
||||
}
|
||||
|
||||
var nodes []Node
|
||||
err = DB["mon"].Where("path like ?", oldprefix+"%").Find(&nodes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Exec("UPDATE node SET name=?, path=? WHERE id=?", name, newpath, n.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(nodes)
|
||||
for i := 0; i < cnt; i++ {
|
||||
if _, err = session.Exec("UPDATE node SET path=? WHERE id=?", strings.Replace(nodes[i].Path, oldprefix, newprefix, 1), nodes[i].Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (n *Node) Del() error {
|
||||
if n.Pid == 0 {
|
||||
return fmt.Errorf("cannot delete root node")
|
||||
}
|
||||
|
||||
// 叶子节点下不能有endpoint
|
||||
if n.Leaf == 1 {
|
||||
cnt, err := DB["mon"].Where("node_id=?", n.Id).Count(new(NodeEndpoint))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("there are endpoint binding this node")
|
||||
}
|
||||
}
|
||||
|
||||
// 非叶子节点下不能有子节点
|
||||
if n.Leaf == 0 {
|
||||
cnt, err := DB["mon"].Where("pid=?", n.Id).Count(new(Node))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("node[%s] has children node", n.Path)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := DB["mon"].Where("id=?", n.Id).Delete(new(Node))
|
||||
return err
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type NodeEndpoint struct {
|
||||
NodeId int64 `xorm:"'node_id'"`
|
||||
EndpointId int64 `xorm:"'endpoint_id'"`
|
||||
}
|
||||
|
||||
func (NodeEndpoint) TableName() string {
|
||||
return "node_endpoint"
|
||||
}
|
||||
|
||||
func NodeIdsGetByEndpointId(endpointId int64) ([]int64, error) {
|
||||
if endpointId == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["mon"].Table("node_endpoint").Where("endpoint_id = ?", endpointId).Select("node_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func EndpointIdsByNodeIds(nodeIds []int64) ([]int64, error) {
|
||||
if len(nodeIds) == 0 {
|
||||
return []int64{}, nil
|
||||
}
|
||||
|
||||
var ids []int64
|
||||
err := DB["mon"].Table("node_endpoint").In("node_id", nodeIds).Select("endpoint_id").Find(&ids)
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func NodeEndpointGetByEndpointIds(endpointsIds []int64) ([]NodeEndpoint, error) {
|
||||
if len(endpointsIds) == 0 {
|
||||
return []NodeEndpoint{}, nil
|
||||
}
|
||||
|
||||
var objs []NodeEndpoint
|
||||
err := DB["mon"].In("endpoint_id", endpointsIds).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
// EndpointBindingsForMail 用来发告警邮件的时候带上各个endpoint的挂载信息
|
||||
func EndpointBindingsForMail(endpoints []string) []string {
|
||||
ids, err := EndpointIdsByIdents(endpoints)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("get endpoint ids by idents fail: %v", err)}
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
bindings, err := EndpointBindings(ids)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("get endpoint bindings fail: %v", err)}
|
||||
}
|
||||
|
||||
var ret []string
|
||||
size := len(bindings)
|
||||
for i := 0; i < size; i++ {
|
||||
for j := 0; j < len(bindings[i].Nodes); j++ {
|
||||
ret = append(ret, bindings[i].Ident+" - "+bindings[i].Alias+" - "+bindings[i].Nodes[j].Path)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func NodeEndpointGetByNodeIds(nodeIds []int64) ([]NodeEndpoint, error) {
|
||||
if len(nodeIds) == 0 {
|
||||
return []NodeEndpoint{}, nil
|
||||
}
|
||||
|
||||
var objs []NodeEndpoint
|
||||
err := DB["mon"].In("node_id", nodeIds).Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func NodeEndpointUnbind(nid, eid int64) error {
|
||||
_, err := DB["mon"].Where("node_id=? and endpoint_id=?", nid, eid).Delete(new(NodeEndpoint))
|
||||
return err
|
||||
}
|
||||
|
||||
func NodeEndpointBind(nid, eid int64) error {
|
||||
total, err := DB["mon"].Where("node_id=? and endpoint_id=?", nid, eid).Count(new(NodeEndpoint))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
endpoint, err := EndpointGet("id", eid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if endpoint == nil {
|
||||
return fmt.Errorf("endpoint[id:%d] not found", eid)
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Insert(&NodeEndpoint{
|
||||
NodeId: nid,
|
||||
EndpointId: eid,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Screen struct {
|
||||
Id int64 `json:"id"`
|
||||
NodeId int64 `json:"node_id"`
|
||||
Name string `json:"name"`
|
||||
LastUpdator string `json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
}
|
||||
|
||||
func (s *Screen) Add() error {
|
||||
_, err := DB["mon"].Insert(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func ScreenGets(nodeId int64) ([]Screen, error) {
|
||||
var objs []Screen
|
||||
err := DB["mon"].Where("node_id=?", nodeId).OrderBy("name").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ScreenGet(col string, val interface{}) (*Screen, error) {
|
||||
var obj Screen
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (s *Screen) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", s.Id).Cols(cols...).Update(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Screen) Del() error {
|
||||
subclasses, err := ScreenSubclassGets(s.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(subclasses)
|
||||
for i := 0; i < cnt; i++ {
|
||||
err = subclasses[i].Del()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=?", s.Id).Delete(new(Screen))
|
||||
return err
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package model
|
||||
|
||||
type ScreenSubclass struct {
|
||||
Id int64 `json:"id"`
|
||||
ScreenId int64 `json:"screen_id"`
|
||||
Name string `json:"name"`
|
||||
Weight int `json:"weight"`
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Add() error {
|
||||
_, err := DB["mon"].Insert(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func ScreenSubclassGets(screenId int64) ([]ScreenSubclass, error) {
|
||||
var objs []ScreenSubclass
|
||||
err := DB["mon"].Where("screen_id=?", screenId).OrderBy("weight").Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func ScreenSubclassGet(col string, val interface{}) (*ScreenSubclass, error) {
|
||||
var obj ScreenSubclass
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Update(cols ...string) error {
|
||||
_, err := DB["mon"].Where("id=?", s.Id).Cols(cols...).Update(s)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ScreenSubclass) Del() error {
|
||||
_, err := DB["mon"].Where("subclass_id=?", s.Id).Delete(new(Chart))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = DB["mon"].Where("id=?", s.Id).Delete(new(ScreenSubclass))
|
||||
return err
|
||||
}
|
|
@ -1,545 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type Stra struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Category int `json:"category"` //机器,非机器
|
||||
Nid int64 `json:"nid"` //服务树节点id
|
||||
ExclNidStr string `xorm:"excl_nid" json:"-"` //排除的叶子节点
|
||||
AlertDur int `json:"alert_dur"` //单位秒,持续异常10分钟则产生异常event
|
||||
RecoveryDur int `json:"recovery_dur"` //单位秒,持续正常2分钟则产生恢复event,0表示立即产生恢复event
|
||||
RecoveryNotify int `json:"recovery_notify"` //0 发送恢复通知 1不发送恢复通知
|
||||
ExprsStr string `xorm:"exprs" json:"-"` //多个条件的监控实例需要相同,并且同时满足才产生event
|
||||
TagsStr string `xorm:"tags" json:"-"` //tag过滤条件
|
||||
EnableStime string `json:"enable_stime"` //策略生效开始时间
|
||||
EnableEtime string `json:"enable_etime"` //策略生效终止时间 支持23:00-02:00
|
||||
EnableDaysOfWeekStr string `xorm:"enable_days_of_week" json:"-"` //策略生效日期
|
||||
ConvergeStr string `xorm:"converge" json:"-"` //告警通知收敛,第1个值表示收敛周期,单位秒,第2个值表示周期内允许发送告警次数
|
||||
Priority int `json:"priority"`
|
||||
Callback string `json:"callback"`
|
||||
NotifyGroupStr string `xorm:"notify_group" json:"-"`
|
||||
NotifyUserStr string `xorm:"notify_user" json:"-"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `xorm:"created" json:"created"`
|
||||
LastUpdator string `xorm:"last_updator" json:"last_updator"`
|
||||
LastUpdated time.Time `xorm:"<-" json:"last_updated"`
|
||||
NeedUpgrade int `xorm:"need_upgrade" json:"need_upgrade"`
|
||||
AlertUpgradeStr string `xorm:"alert_upgrade" json:"-"`
|
||||
|
||||
ExclNid []int64 `xorm:"-" json:"excl_nid"`
|
||||
Exprs []Exp `xorm:"-" json:"exprs"`
|
||||
Tags []Tag `xorm:"-" json:"tags"`
|
||||
EnableDaysOfWeek []int `xorm:"-" json:"enable_days_of_week"`
|
||||
Converge []int `xorm:"-" json:"converge"`
|
||||
NotifyGroup []int `xorm:"-" json:"notify_group"`
|
||||
NotifyUser []int `xorm:"-" json:"notify_user"`
|
||||
LeafNids []int64 `xorm:"-" json:"leaf_nids"` //叶子节点id
|
||||
Endpoints []string `xorm:"-" json:"endpoints"`
|
||||
AlertUpgrade AlertUpgrade `xorm:"-" json:"alert_upgrade"`
|
||||
JudgeInstance string `xorm:"-" json:"judge_instance"`
|
||||
}
|
||||
|
||||
type StraLog struct {
|
||||
Id int64 `json:"id"`
|
||||
Sid int64 `json:"sid"`
|
||||
Action string `json:"action"` // update|delete
|
||||
Body string `json:"body"`
|
||||
Creator string `json:"creator"`
|
||||
Created time.Time `json:"created" xorm:"created"`
|
||||
}
|
||||
|
||||
type Exp struct {
|
||||
Eopt string `json:"eopt"`
|
||||
Func string `json:"func"` //all,max,min
|
||||
Metric string `json:"metric"` //metric
|
||||
Params []int `json:"params"` //连续n秒
|
||||
Threshold float64 `json:"threshold"` //阈值
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Tkey string `json:"tkey"`
|
||||
Topt string `json:"topt"`
|
||||
Tval []string `json:"tval"` //修改为数组
|
||||
}
|
||||
|
||||
type AlertUpgrade struct {
|
||||
Users []int64 `json:"users"`
|
||||
Groups []int64 `json:"groups"`
|
||||
Duration int `json:"duration"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
var MathOperators = map[string]bool{
|
||||
">": true,
|
||||
"<": true,
|
||||
">=": true,
|
||||
"<=": true,
|
||||
"!=": true,
|
||||
"=": true,
|
||||
}
|
||||
|
||||
func (s *Stra) Save() error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = session.Insert(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(s.Id, "add", s.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
session.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Update() error {
|
||||
var obj Stra
|
||||
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
err := session.Begin()
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := session.ID(s.Id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", s.Id)
|
||||
}
|
||||
|
||||
_, err = session.ID(s.Id).AllCols().Update(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(s.Id, "update", s.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
session.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func StraGet(col string, val interface{}) (*Stra, error) {
|
||||
var obj Stra
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func StraDel(id int64) error {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
var obj Stra
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := session.ID(id).Get(&obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
session.Rollback()
|
||||
return fmt.Errorf("%d not exists", obj.Id)
|
||||
}
|
||||
|
||||
if _, err := session.ID(id).Delete(new(Stra)); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
straByte, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = SaveStraCommit(obj.Id, "delete", obj.Creator, string(straByte), session)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func StrasList(name string, priority int, nid int64) ([]*Stra, error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
objs := make([]*Stra, 0)
|
||||
|
||||
whereClause := "1 = 1"
|
||||
params := []interface{}{}
|
||||
|
||||
if name != "" {
|
||||
whereClause += " AND name LIKE ?"
|
||||
params = append(params, "%"+name+"%")
|
||||
}
|
||||
|
||||
if priority <= 3 {
|
||||
whereClause += " AND priority = ?"
|
||||
params = append(params, priority)
|
||||
}
|
||||
|
||||
var err error
|
||||
if nid != 0 {
|
||||
err = session.Where(whereClause, params...).Where("nid=?", nid).Find(&objs)
|
||||
} else {
|
||||
err = session.Where(whereClause, params...).Find(&objs)
|
||||
}
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func StrasAll() ([]*Stra, error) {
|
||||
objs := make([]*Stra, 0)
|
||||
|
||||
err := DB["mon"].Find(&objs)
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func EffectiveStrasList() ([]*Stra, error) {
|
||||
session := DB["mon"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
objs := make([]*Stra, 0)
|
||||
t := time.Now()
|
||||
|
||||
now := t.Format("15:04")
|
||||
weekday := strconv.Itoa(int(t.Weekday()))
|
||||
|
||||
err := session.Where("((enable_stime <= ? and enable_etime >= ? or (enable_stime > enable_etime and !(enable_stime > ? and enable_etime < ?))) and enable_days_of_week like ?)", now, now, now, now, "%"+weekday+"%").Find(&objs)
|
||||
if err != nil {
|
||||
return objs, err
|
||||
}
|
||||
|
||||
stras := make([]*Stra, 0)
|
||||
for _, obj := range objs {
|
||||
err = obj.Decode()
|
||||
if err != nil {
|
||||
return stras, err
|
||||
}
|
||||
stras = append(stras, obj)
|
||||
}
|
||||
return stras, err
|
||||
}
|
||||
|
||||
func SaveStraCommit(id int64, action, username, body string, session *xorm.Session) error {
|
||||
strategyLog := StraLog{
|
||||
Sid: id,
|
||||
Action: action,
|
||||
Body: body,
|
||||
Creator: username,
|
||||
}
|
||||
|
||||
if _, err := session.Insert(&strategyLog); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) HasPermssion() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Encode() error {
|
||||
alertUpgrade, err := AlertUpgradeMarshal(s.AlertUpgrade)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode alert_upgrade err:%v", err)
|
||||
}
|
||||
|
||||
if s.NeedUpgrade == 1 {
|
||||
if len(s.AlertUpgrade.Users) == 0 && len(s.AlertUpgrade.Groups) == 0 {
|
||||
return fmt.Errorf("alert upgrade: users and groups is blank")
|
||||
}
|
||||
}
|
||||
|
||||
s.AlertUpgradeStr = alertUpgrade
|
||||
|
||||
exclNid, err := json.Marshal(s.ExclNid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode excl_nid err:%v", err)
|
||||
}
|
||||
s.ExclNidStr = string(exclNid)
|
||||
|
||||
exprs, err := json.Marshal(s.Exprs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode exprs err:%v", err)
|
||||
}
|
||||
s.ExprsStr = string(exprs)
|
||||
|
||||
// 校验 exprs
|
||||
var exprsTmp []Exp
|
||||
err = json.Unmarshal(exprs, &exprsTmp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal exprs err:%v", err)
|
||||
}
|
||||
|
||||
for _, exp := range exprsTmp {
|
||||
if _, found := MathOperators[exp.Eopt]; !found {
|
||||
return fmt.Errorf("unknown exp.eopt:%v", exp)
|
||||
}
|
||||
}
|
||||
|
||||
tags, err := json.Marshal(s.Tags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode Tags err:%v", err)
|
||||
}
|
||||
s.TagsStr = string(tags)
|
||||
|
||||
// 校验 tags
|
||||
var tagsTmp []Tag
|
||||
err = json.Unmarshal(tags, &tagsTmp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal Tags err:%v", err)
|
||||
}
|
||||
|
||||
for _, tag := range tagsTmp {
|
||||
if tag.Topt != "=" && tag.Topt != "!=" {
|
||||
return fmt.Errorf("unknown tag.topt")
|
||||
}
|
||||
}
|
||||
|
||||
//校验时间
|
||||
err = checkDurationString(s.EnableStime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unknown enable_stime: %s", s.EnableStime)
|
||||
}
|
||||
|
||||
err = checkDurationString(s.EnableEtime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unknown enable_etime: %s", s.EnableEtime)
|
||||
}
|
||||
|
||||
for _, day := range s.EnableDaysOfWeek {
|
||||
if day > 7 || day < 0 {
|
||||
return fmt.Errorf("illegal period_days_of_week %v", s.EnableDaysOfWeek)
|
||||
}
|
||||
}
|
||||
enableDaysOfWeek, err := json.Marshal(s.EnableDaysOfWeek)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode EnableDaysOfWeek err:%v", err)
|
||||
}
|
||||
s.EnableDaysOfWeekStr = string(enableDaysOfWeek)
|
||||
|
||||
//校验收敛配置
|
||||
if len(s.Converge) != 2 {
|
||||
return fmt.Errorf("illegal converge %v", s.Converge)
|
||||
}
|
||||
Converge, err := json.Marshal(s.Converge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ConvergeStr = string(Converge)
|
||||
|
||||
notifyGroup, err := json.Marshal(s.NotifyGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.NotifyGroupStr = string(notifyGroup)
|
||||
|
||||
notifyUser, err := json.Marshal(s.NotifyUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.NotifyUserStr = string(notifyUser)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stra) Decode() error {
|
||||
var err error
|
||||
|
||||
s.AlertUpgrade, err = AlertUpgradeUnMarshal(s.AlertUpgradeStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ExclNidStr), &s.ExclNid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ExprsStr), &s.Exprs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.TagsStr), &s.Tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.EnableDaysOfWeekStr), &s.EnableDaysOfWeek)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.ConvergeStr), &s.Converge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.NotifyUserStr), &s.NotifyUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(s.NotifyGroupStr), &s.NotifyGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 00:00-23:59
|
||||
func checkDurationString(str string) error {
|
||||
slice := strings.Split(str, ":")
|
||||
if len(slice) != 2 {
|
||||
return fmt.Errorf("illegal duration: %s", str)
|
||||
}
|
||||
|
||||
hour, err := strconv.Atoi(slice[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("illegal duration: %s", str)
|
||||
}
|
||||
if hour < 0 || hour > 23 {
|
||||
return fmt.Errorf("illegal duration: %s", str)
|
||||
}
|
||||
minute, err := strconv.Atoi(slice[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("illegal duration: %s", str)
|
||||
}
|
||||
if minute < 0 || minute > 59 {
|
||||
return fmt.Errorf("illegal duration: %s", str)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AlertUpgradeMarshal(alterUpgrade AlertUpgrade) (string, error) {
|
||||
dat := AlertUpgrade{
|
||||
Duration: alterUpgrade.Duration,
|
||||
Level: alterUpgrade.Level,
|
||||
}
|
||||
|
||||
if alterUpgrade.Duration == 0 {
|
||||
dat.Duration = 60
|
||||
}
|
||||
|
||||
if alterUpgrade.Level == 0 {
|
||||
dat.Level = 1
|
||||
}
|
||||
|
||||
if alterUpgrade.Groups == nil {
|
||||
dat.Groups = []int64{}
|
||||
} else {
|
||||
dat.Groups = alterUpgrade.Groups
|
||||
}
|
||||
|
||||
if alterUpgrade.Users == nil {
|
||||
dat.Users = []int64{}
|
||||
} else {
|
||||
dat.Users = alterUpgrade.Users
|
||||
}
|
||||
|
||||
data, err := json.Marshal(dat)
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
func AlertUpgradeUnMarshal(str string) (AlertUpgrade, error) {
|
||||
var obj AlertUpgrade
|
||||
if strings.TrimSpace(str) == "" {
|
||||
return AlertUpgrade{
|
||||
Users: []int64{},
|
||||
Groups: []int64{},
|
||||
Duration: 0,
|
||||
Level: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(str), &obj)
|
||||
return obj, err
|
||||
}
|
|
@ -1,334 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/toolkits/pkg/str"
|
||||
)
|
||||
|
||||
type Team struct {
|
||||
Id int64 `json:"id"`
|
||||
Ident string `json:"ident"`
|
||||
Name string `json:"name"`
|
||||
Mgmt int `json:"mgmt"`
|
||||
AdminObjs []User `json:"admin_objs" xorm:"-"`
|
||||
MemberObjs []User `json:"member_objs" xorm:"-"`
|
||||
}
|
||||
|
||||
func (t *Team) Del() error {
|
||||
session := DB["uic"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team_user WHERE team_id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team WHERE id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (t *Team) CheckFields() error {
|
||||
if len(t.Ident) > 255 {
|
||||
return fmt.Errorf("ident too long")
|
||||
}
|
||||
|
||||
if len(t.Name) > 255 {
|
||||
return fmt.Errorf("name too long")
|
||||
}
|
||||
|
||||
if t.Mgmt != 0 && t.Mgmt != 1 {
|
||||
return fmt.Errorf("mgmt invalid")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Ident) {
|
||||
return fmt.Errorf("ident dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(t.Name) {
|
||||
return fmt.Errorf("name dangerous")
|
||||
}
|
||||
|
||||
if !str.IsMatch(t.Ident, `^[a-z0-9\-]+$`) {
|
||||
return fmt.Errorf("ident permissible characters: [a-z0-9] and -")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Team) FillObjs() error {
|
||||
var tus []TeamUser
|
||||
err := DB["uic"].Where("team_id=?", t.Id).Find(&tus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt := len(tus)
|
||||
for i := 0; i < cnt; i++ {
|
||||
user, err := UserGet("id", tus[i].UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if tus[i].IsAdmin == 1 {
|
||||
t.AdminObjs = append(t.AdminObjs, *user)
|
||||
} else {
|
||||
t.MemberObjs = append(t.MemberObjs, *user)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func safeUserIds(ids []int64) ([]int64, error) {
|
||||
cnt := len(ids)
|
||||
ret := make([]int64, 0, cnt)
|
||||
for i := 0; i < cnt; i++ {
|
||||
user, err := UserGet("id", ids[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
ret = append(ret, ids[i])
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (t *Team) Modify(ident, name string, mgmt int, admins, members []int64) error {
|
||||
adminIds, err := safeUserIds(admins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memberIds, err := safeUserIds(members)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(adminIds) == 0 && len(memberIds) == 0 {
|
||||
return fmt.Errorf("no invalid memeber ids")
|
||||
}
|
||||
|
||||
if mgmt == 1 && len(adminIds) == 0 {
|
||||
return fmt.Errorf("arg[admins] is necessary")
|
||||
}
|
||||
|
||||
// 如果ident有变化,就要检查是否有重名
|
||||
if ident != t.Ident {
|
||||
cnt, err := DB["uic"].Where("ident = ? and id <> ?", ident, t.Id).Count(new(Team))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("ident[%s] already exists", ident)
|
||||
}
|
||||
}
|
||||
|
||||
t.Ident = ident
|
||||
t.Name = name
|
||||
t.Mgmt = mgmt
|
||||
|
||||
if err = t.CheckFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["uic"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Where("id=?", t.Id).Cols("ident", "name", "mgmt").Update(t); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Exec("DELETE FROM team_user WHERE team_id=?", t.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(adminIds); i++ {
|
||||
if err = teamUserBind(session, t.Id, adminIds[i], 1); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(memberIds); i++ {
|
||||
if err = teamUserBind(session, t.Id, memberIds[i], 0); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func TeamAdd(ident, name string, mgmt int, admins, members []int64) error {
|
||||
adminIds, err := safeUserIds(admins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memberIds, err := safeUserIds(members)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(adminIds) == 0 && len(memberIds) == 0 {
|
||||
return fmt.Errorf("no invalid memeber ids")
|
||||
}
|
||||
|
||||
if mgmt == 1 && len(adminIds) == 0 {
|
||||
return fmt.Errorf("arg[admins] is necessary")
|
||||
}
|
||||
|
||||
t := Team{
|
||||
Ident: ident,
|
||||
Name: name,
|
||||
Mgmt: mgmt,
|
||||
}
|
||||
|
||||
if err = t.CheckFields(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := DB["uic"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
cnt, err := session.Where("ident=?", ident).Count(new(Team))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("%s already exists", ident)
|
||||
}
|
||||
|
||||
if err = session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = session.Insert(&t); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(adminIds); i++ {
|
||||
if err := teamUserBind(session, t.Id, adminIds[i], 1); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(memberIds); i++ {
|
||||
if err := teamUserBind(session, t.Id, memberIds[i], 0); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func teamUserBind(session *xorm.Session, teamid, userid int64, isadmin int) error {
|
||||
var tu TeamUser
|
||||
has, err := session.Where("team_id=? and user_id=?", teamid, userid).Get(&tu)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has && isadmin != tu.IsAdmin {
|
||||
_, err = session.Exec("UPDATE team_user SET is_admin=? WHERE team_id=? and user_id=?", isadmin, teamid, userid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !has {
|
||||
_, err = session.Insert(&TeamUser{
|
||||
TeamId: teamid,
|
||||
UserId: userid,
|
||||
IsAdmin: isadmin,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TeamGet(col string, val interface{}) (*Team, error) {
|
||||
var obj Team
|
||||
has, err := DB["uic"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func TeamTotal(query string) (int64, error) {
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return DB["uic"].Where("ident like ? or name like ?", q, q).Count(new(Team))
|
||||
}
|
||||
|
||||
return DB["uic"].Count(new(Team))
|
||||
}
|
||||
|
||||
func TeamGets(query string, limit, offset int) ([]Team, error) {
|
||||
session := DB["uic"].Limit(limit, offset).OrderBy("ident")
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("ident like ? or name like ?", q, q)
|
||||
}
|
||||
|
||||
var objs []Team
|
||||
err := session.Find(&objs)
|
||||
return objs, err
|
||||
}
|
||||
|
||||
func TeamNameGetsByIds(ids string) ([]string, error) {
|
||||
var objs []Team
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
var groupIds []int64
|
||||
|
||||
if err := json.Unmarshal([]byte(ids), &groupIds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := DB["uic"].In("id", groupIds).Cols("name").Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := []string{}
|
||||
for i := 0; i < len(objs); i++ {
|
||||
names = append(names, objs[i].Name)
|
||||
}
|
||||
return names, nil
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package model
|
||||
|
||||
type TeamUser struct {
|
||||
TeamId int64 `json:"team_id" xorm:"'team_id'"`
|
||||
UserId int64 `json:"user_id" xorm:"'user_id'"`
|
||||
IsAdmin int `json:"is_admin" xorm:"'is_admin'"`
|
||||
}
|
||||
|
||||
func UserIdGetByTeamIds(teamIds []int64) ([]int64, error) {
|
||||
var objs []TeamUser
|
||||
err := DB["uic"].In("team_id", teamIds).Find(&objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userIds := []int64{}
|
||||
for i := 0; i < len(objs); i++ {
|
||||
userIds = append(userIds, objs[i].UserId)
|
||||
}
|
||||
|
||||
return userIds, nil
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package model
|
||||
|
||||
type TmpChart struct {
|
||||
Id int64 `json:"id"`
|
||||
Configs string `json:"configs"`
|
||||
Creator string `json:"creator"`
|
||||
}
|
||||
|
||||
func (t *TmpChart) Add() error {
|
||||
_, err := DB["mon"].InsertOne(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func TmpChartGet(col string, val interface{}) (*TmpChart, error) {
|
||||
var obj TmpChart
|
||||
has, err := DB["mon"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
|
@ -1,264 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/toolkits/pkg/errors"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/str"
|
||||
"gopkg.in/ldap.v3"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"`
|
||||
Dispname string `json:"dispname"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Im string `json:"im"`
|
||||
IsRoot int `json:"is_root"`
|
||||
}
|
||||
|
||||
func (u *User) CheckFields() {
|
||||
u.Username = strings.TrimSpace(u.Username)
|
||||
if u.Username == "" {
|
||||
errors.Bomb("username is blank")
|
||||
}
|
||||
|
||||
if str.Dangerous(u.Username) {
|
||||
errors.Bomb("username is dangerous")
|
||||
}
|
||||
|
||||
if str.Dangerous(u.Dispname) {
|
||||
errors.Bomb("dispname is dangerous")
|
||||
}
|
||||
/*
|
||||
if u.Phone != "" && !str.IsPhone(u.Phone) {
|
||||
errors.Bomb("%s format error", u.Phone)
|
||||
}
|
||||
|
||||
if u.Email != "" && !str.IsMail(u.Email) {
|
||||
errors.Bomb("%s format error", u.Email)
|
||||
}
|
||||
*/
|
||||
if len(u.Username) > 32 {
|
||||
errors.Bomb("username too long")
|
||||
}
|
||||
|
||||
if len(u.Dispname) > 32 {
|
||||
errors.Bomb("dispname too long")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) Update(cols ...string) error {
|
||||
u.CheckFields()
|
||||
_, err := DB["uic"].Where("id=?", u.Id).Cols(cols...).Update(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *User) Save() error {
|
||||
u.CheckFields()
|
||||
|
||||
if u.Id > 0 {
|
||||
return fmt.Errorf("user.id[%d] not equal 0", u.Id)
|
||||
}
|
||||
|
||||
cnt, err := DB["uic"].Where("username=?", u.Username).Count(new(User))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnt > 0 {
|
||||
return fmt.Errorf("username already exists")
|
||||
}
|
||||
|
||||
_, err = DB["uic"].Insert(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *User) Del() error {
|
||||
session := DB["uic"].NewSession()
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM team_user WHERE user_id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := session.Exec("DELETE FROM user WHERE id=?", u.Id); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (u *User) CanModifyTeam(t *Team) (bool, error) {
|
||||
if u.IsRoot == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
session := DB["uic"].Where("team_id=? and user_id=?", t.Id, u.Id)
|
||||
if t.Mgmt == 1 {
|
||||
session = session.Where("is_admin=1")
|
||||
}
|
||||
|
||||
cnt, err := session.Count(new(TeamUser))
|
||||
return cnt > 0, err
|
||||
}
|
||||
|
||||
func (u *User) CopyLdapAttr(sr *ldap.SearchResult) {
|
||||
attrs := config.Get().LDAP.Attributes
|
||||
if attrs.Dispname != "" {
|
||||
u.Dispname = sr.Entries[0].GetAttributeValue(attrs.Dispname)
|
||||
}
|
||||
if attrs.Email != "" {
|
||||
u.Email = sr.Entries[0].GetAttributeValue(attrs.Email)
|
||||
}
|
||||
if attrs.Phone != "" {
|
||||
u.Phone = sr.Entries[0].GetAttributeValue(attrs.Phone)
|
||||
}
|
||||
if attrs.Im != "" {
|
||||
u.Im = sr.Entries[0].GetAttributeValue(attrs.Im)
|
||||
}
|
||||
}
|
||||
|
||||
func InitRoot() {
|
||||
var u User
|
||||
has, err := DB["uic"].Where("username=?", "root").Get(&u)
|
||||
if err != nil {
|
||||
log.Fatalln("cannot query user[root]", err)
|
||||
}
|
||||
|
||||
if has {
|
||||
return
|
||||
}
|
||||
|
||||
// gen := str.RandLetters(32)
|
||||
|
||||
u = User{
|
||||
Username: "root",
|
||||
Password: config.CryptoPass("root"),
|
||||
Dispname: "超管",
|
||||
IsRoot: 1,
|
||||
}
|
||||
|
||||
_, err = DB["uic"].Insert(&u)
|
||||
if err != nil {
|
||||
log.Fatalln("cannot insert user[root]")
|
||||
}
|
||||
|
||||
logger.Info("user root init done")
|
||||
}
|
||||
|
||||
func LdapLogin(user, pass string) error {
|
||||
sr, err := ldapReq(user, pass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var u User
|
||||
has, err := DB["uic"].Where("username=?", user).Get(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.CopyLdapAttr(sr)
|
||||
if has {
|
||||
if config.Get().LDAP.CoverAttributes {
|
||||
_, err := DB["uic"].Where("id=?", u.Id).Update(u)
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !config.Get().LDAP.AutoRegist {
|
||||
return fmt.Errorf("user has not be created, may be you should enable auto regist: %v", user)
|
||||
}
|
||||
|
||||
u.Username = user
|
||||
u.Password = "******"
|
||||
_, err = DB["uic"].Insert(u)
|
||||
return err
|
||||
}
|
||||
|
||||
func PassLogin(user, pass string) error {
|
||||
var u User
|
||||
has, err := DB["uic"].Where("username=?", user).Cols("password").Get(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return fmt.Errorf("user[%s] not found", user)
|
||||
}
|
||||
|
||||
if config.CryptoPass(pass) != u.Password {
|
||||
return fmt.Errorf("password error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UserGet(col string, val interface{}) (*User, error) {
|
||||
var obj User
|
||||
has, err := DB["uic"].Where(col+"=?", val).Get(&obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func UserTotal(query string) (int64, error) {
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
return DB["uic"].Where("username like ? or dispname like ? or phone like ? or email like ?", q, q, q, q).Count(new(User))
|
||||
}
|
||||
|
||||
return DB["uic"].Count(new(User))
|
||||
}
|
||||
|
||||
func UserGets(query string, limit, offset int) ([]User, error) {
|
||||
session := DB["uic"].Limit(limit, offset).OrderBy("username")
|
||||
if query != "" {
|
||||
q := "%" + query + "%"
|
||||
session = session.Where("username like ? or dispname like ? or phone like ? or email like ?", q, q, q, q)
|
||||
}
|
||||
|
||||
var users []User
|
||||
err := session.Find(&users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func UserNameGetByIds(ids string) ([]string, error) {
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
var userIds []int64
|
||||
if err := json.Unmarshal([]byte(ids), &userIds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var names []string
|
||||
err := DB["uic"].Table("user").In("id", userIds).Select("username").Find(&names)
|
||||
return names, err
|
||||
}
|
||||
|
||||
func UserGetByIds(ids []int64) ([]User, error) {
|
||||
var objs []User
|
||||
err := DB["uic"].In("id", ids).Find(&objs)
|
||||
return objs, err
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
process "github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
var MetricHistory *History
|
||||
var ProcsCache *ProcessCache
|
||||
|
||||
|
||||
func Init() {
|
||||
MetricHistory = NewHistory()
|
||||
ProcsCache = NewProcsCache()
|
||||
}
|
||||
|
||||
func NewHistory() *History {
|
||||
h := History{
|
||||
Data: make(map[string]dataobj.MetricValue),
|
||||
}
|
||||
|
||||
go h.Clean()
|
||||
return &h
|
||||
}
|
||||
|
||||
type History struct {
|
||||
sync.RWMutex
|
||||
Data map[string]dataobj.MetricValue
|
||||
}
|
||||
|
||||
func (h *History) Set(key string, item dataobj.MetricValue) {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
h.Data[key] = item
|
||||
}
|
||||
|
||||
func (h *History) Get(key string) (dataobj.MetricValue, bool) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
|
||||
item, exists := h.Data[key]
|
||||
return item, exists
|
||||
}
|
||||
|
||||
func (h *History) Clean() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *History) clean() {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
now := time.Now().Unix()
|
||||
for key, item := range h.Data {
|
||||
if now-item.Timestamp > 10*item.Step {
|
||||
delete(h.Data, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ProcessCache struct {
|
||||
sync.RWMutex
|
||||
Data map[int32]*process.Process
|
||||
}
|
||||
|
||||
|
||||
func NewProcsCache() *ProcessCache{
|
||||
pc := ProcessCache{
|
||||
Data: make(map[int32]*process.Process),
|
||||
}
|
||||
go pc.Clean()
|
||||
return &pc
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Set(pid int32, p *process.Process){
|
||||
pc.Lock()
|
||||
defer pc.Unlock()
|
||||
pc.Data[pid] = p
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Get(pid int32)(*process.Process, bool){
|
||||
pc.RLock()
|
||||
defer pc.RUnlock()
|
||||
p, exists := pc.Data[pid]
|
||||
return p, exists
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) Clean() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
pc.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *ProcessCache) clean() {
|
||||
pc.Lock()
|
||||
defer pc.Unlock()
|
||||
for pid, procs := range pc.Data {
|
||||
running, _ := procs.IsRunning()
|
||||
if !running{
|
||||
delete(pc.Data, pid)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/collector/cache"
|
||||
"github.com/didi/nightingale/src/modules/collector/config"
|
||||
"github.com/didi/nightingale/src/modules/collector/core"
|
||||
"github.com/didi/nightingale/src/modules/collector/http/routes"
|
||||
"github.com/didi/nightingale/src/modules/collector/log/worker"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys/funcs"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys/plugins"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys/ports"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys/procs"
|
||||
"github.com/didi/nightingale/src/toolkits/http"
|
||||
"github.com/didi/nightingale/src/toolkits/identity"
|
||||
tlogger "github.com/didi/nightingale/src/toolkits/logger"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/runner"
|
||||
)
|
||||
|
||||
var (
|
||||
vers *bool
|
||||
help *bool
|
||||
conf *string
|
||||
|
||||
version = "No Version Provided"
|
||||
gitHash = "No GitHash Provided"
|
||||
buildTime = "No BuildTime Provided"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vers = flag.Bool("v", false, "display the version.")
|
||||
help = flag.Bool("h", false, "print this help.")
|
||||
conf = flag.String("f", "", "specify configuration file.")
|
||||
flag.Parse()
|
||||
|
||||
if *vers {
|
||||
fmt.Println("Version:", version)
|
||||
fmt.Println("Git Commit Hash:", gitHash)
|
||||
fmt.Println("UTC Build Time:", buildTime)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
aconf()
|
||||
pconf()
|
||||
start()
|
||||
cfg := config.Get()
|
||||
|
||||
tlogger.Init(cfg.Logger)
|
||||
|
||||
identity.Init(cfg.Identity)
|
||||
if identity.Identity == "127.0.0.1" {
|
||||
log.Fatalln("endpoint: 127.0.0.1, cannot work")
|
||||
} else {
|
||||
log.Println("endpoint:", identity.Identity)
|
||||
}
|
||||
|
||||
sys.Init(cfg.Sys)
|
||||
stra.Init(cfg.Stra)
|
||||
|
||||
core.InitRpcClients()
|
||||
funcs.BuildMappers()
|
||||
funcs.Collect()
|
||||
|
||||
//插件采集
|
||||
plugins.Detect()
|
||||
|
||||
//进程采集
|
||||
procs.Detect()
|
||||
|
||||
//端口采集
|
||||
ports.Detect()
|
||||
|
||||
//初始化缓存,用作保存COUNTER类型数据
|
||||
cache.Init()
|
||||
|
||||
//日志采集
|
||||
worker.Init(config.Config.Worker)
|
||||
go worker.UpdateConfigsLoop()
|
||||
go worker.PusherStart()
|
||||
go worker.Zeroize()
|
||||
|
||||
if cfg.Logger.Level != "DEBUG" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
r := gin.New()
|
||||
routes.Config(r)
|
||||
http.Start(r, "collector", cfg.Logger.Level)
|
||||
ending()
|
||||
}
|
||||
|
||||
// auto detect configuration file
|
||||
func aconf() {
|
||||
if *conf != "" && file.IsExist(*conf) {
|
||||
return
|
||||
}
|
||||
|
||||
*conf = "etc/collector.local.yml"
|
||||
if file.IsExist(*conf) {
|
||||
return
|
||||
}
|
||||
|
||||
*conf = "etc/collector.yml"
|
||||
if file.IsExist(*conf) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("no configuration file for collector")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// parse configuration file
|
||||
func pconf() {
|
||||
if err := config.Parse(*conf); err != nil {
|
||||
fmt.Println("cannot parse configuration file:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func ending() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
select {
|
||||
case <-c:
|
||||
fmt.Printf("stop signal caught, stopping... pid=%d\n", os.Getpid())
|
||||
}
|
||||
|
||||
logger.Close()
|
||||
http.Shutdown()
|
||||
fmt.Println("sender stopped successfully")
|
||||
}
|
||||
|
||||
func start() {
|
||||
runner.Init()
|
||||
fmt.Println("collector start, use configuration file:", *conf)
|
||||
fmt.Println("runner.cwd:", runner.Cwd)
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/collector/log/worker"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
"github.com/didi/nightingale/src/modules/collector/sys"
|
||||
"github.com/didi/nightingale/src/toolkits/identity"
|
||||
"github.com/didi/nightingale/src/toolkits/logger"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/toolkits/pkg/file"
|
||||
)
|
||||
|
||||
type ConfYaml struct {
|
||||
Identity identity.IdentitySection `yaml:"identity"`
|
||||
Logger logger.LoggerSection `yaml:"logger"`
|
||||
Stra stra.StraSection `yaml:"stra"`
|
||||
Worker worker.WorkerSection `yaml:"worker"`
|
||||
Sys sys.SysSection `yaml:"sys"`
|
||||
}
|
||||
|
||||
var (
|
||||
Config *ConfYaml
|
||||
Endpoint string
|
||||
Cwd string
|
||||
)
|
||||
|
||||
// Get configuration file
|
||||
func Get() *ConfYaml {
|
||||
return Config
|
||||
}
|
||||
|
||||
func Parse(conf string) error {
|
||||
bs, err := file.ReadBytes(conf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read yml[%s]: %v", conf, err)
|
||||
}
|
||||
|
||||
viper.SetConfigType("yaml")
|
||||
err = viper.ReadConfig(bytes.NewBuffer(bs))
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read yml[%s]: %v", conf, err)
|
||||
}
|
||||
|
||||
viper.SetDefault("worker", map[string]interface{}{
|
||||
"workerNum": 10,
|
||||
"queueSize": 1024000,
|
||||
"pushInterval": 5,
|
||||
"waitPush": 0,
|
||||
})
|
||||
|
||||
viper.SetDefault("stra", map[string]interface{}{
|
||||
"enable": true,
|
||||
"timeout": 1000,
|
||||
"interval": 10, //采集策略更新时间
|
||||
"portPath": "./etc/port",
|
||||
"procPath": "./etc/proc",
|
||||
"logPath": "./etc/log",
|
||||
"api": "/api/portal/collects/",
|
||||
})
|
||||
|
||||
viper.SetDefault("sys", map[string]interface{}{
|
||||
"enable": true,
|
||||
"timeout": 1000, //请求超时时间
|
||||
"interval": 10, //基础指标上报周期
|
||||
"pluginRemote": true, //从monapi获取插件采集配置
|
||||
"plugin": "./plugin",
|
||||
})
|
||||
|
||||
err = viper.Unmarshal(&Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal config error:%v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RpcClientContainer struct {
|
||||
M map[string]*rpc.Client
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
var rpcClients *RpcClientContainer
|
||||
|
||||
func InitRpcClients() {
|
||||
rpcClients = &RpcClientContainer{
|
||||
M: make(map[string]*rpc.Client),
|
||||
}
|
||||
}
|
||||
|
||||
func (rcc *RpcClientContainer) Get(addr string) *rpc.Client {
|
||||
rcc.RLock()
|
||||
defer rcc.RUnlock()
|
||||
|
||||
client, has := rcc.M[addr]
|
||||
if !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// Put 返回的bool表示affected,确实把自己塞进去了
|
||||
func (rcc *RpcClientContainer) Put(addr string, client *rpc.Client) bool {
|
||||
rcc.Lock()
|
||||
defer rcc.Unlock()
|
||||
|
||||
oc, has := rcc.M[addr]
|
||||
if has && oc != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rcc.M[addr] = client
|
||||
return true
|
||||
}
|
||||
|
||||
func (rcc *RpcClientContainer) Del(addr string) {
|
||||
rcc.Lock()
|
||||
defer rcc.Unlock()
|
||||
delete(rcc.M, addr)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
)
|
||||
|
||||
func NewMetricValue(metric string, val interface{}, dataType string, tags ...string) *dataobj.MetricValue {
|
||||
mv := dataobj.MetricValue{
|
||||
Metric: metric,
|
||||
ValueUntyped: val,
|
||||
CounterType: dataType,
|
||||
}
|
||||
|
||||
size := len(tags)
|
||||
|
||||
if size > 0 {
|
||||
mv.Tags = strings.Join(tags, ",")
|
||||
}
|
||||
|
||||
return &mv
|
||||
}
|
||||
|
||||
func GaugeValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue {
|
||||
return NewMetricValue(metric, val, "GAUGE", tags...)
|
||||
}
|
||||
|
||||
func CounterValue(metric string, val interface{}, tags ...string) *dataobj.MetricValue {
|
||||
return NewMetricValue(metric, val, "COUNTER", tags...)
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/ugorji/go/codec"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
"github.com/didi/nightingale/src/modules/collector/cache"
|
||||
"github.com/didi/nightingale/src/toolkits/address"
|
||||
"github.com/didi/nightingale/src/toolkits/identity"
|
||||
)
|
||||
|
||||
func Push(metricItems []*dataobj.MetricValue) error {
|
||||
var err error
|
||||
var items []*dataobj.MetricValue
|
||||
now := time.Now().Unix()
|
||||
|
||||
for _, item := range metricItems {
|
||||
logger.Debug("->recv: ", item)
|
||||
if item.Endpoint == "" {
|
||||
item.Endpoint = identity.Identity
|
||||
}
|
||||
err = item.CheckValidity(now)
|
||||
if err != nil {
|
||||
msg := fmt.Errorf("metric:%v err:%v", item, err)
|
||||
logger.Warning(msg)
|
||||
// 如果数据有问题,直接跳过吧,比如mymon采集的到的数据,其实只有一个有问题,剩下的都没问题
|
||||
continue
|
||||
}
|
||||
if item.CounterType == dataobj.COUNTER {
|
||||
item = CounterToGauge(item)
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if item.CounterType == dataobj.SUBTRACT {
|
||||
item = SubtractToGauge(item)
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
logger.Debug("push item: ", item)
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
addrs := address.GetRPCAddresses("transfer")
|
||||
count := len(addrs)
|
||||
retry := 0
|
||||
for {
|
||||
for _, i := range rand.Perm(count) {
|
||||
addr := addrs[i]
|
||||
reply, err := rpcCall(addr, items)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
} else {
|
||||
if reply.Msg != "ok" {
|
||||
err = fmt.Errorf("some item push err: %s", reply.Msg)
|
||||
logger.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
|
||||
retry += 1
|
||||
if retry == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func rpcCall(addr string, items []*dataobj.MetricValue) (dataobj.TransferResp, error) {
|
||||
var reply dataobj.TransferResp
|
||||
var err error
|
||||
|
||||
client := rpcClients.Get(addr)
|
||||
if client == nil {
|
||||
client, err = rpcClient(addr)
|
||||
if err != nil {
|
||||
return reply, err
|
||||
}
|
||||
affected := rpcClients.Put(addr, client)
|
||||
if !affected {
|
||||
defer func() {
|
||||
// 我尝试把自己这个client塞进map失败,说明已经有一个client塞进去了,那我自己用完了就关闭
|
||||
client.Close()
|
||||
}()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
timeout := time.Duration(8) * time.Second
|
||||
done := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
err := client.Call("Transfer.Push", items, &reply)
|
||||
done <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
logger.Warningf("rpc call timeout, transfer addr: %s\n", addr)
|
||||
rpcClients.Put(addr, nil)
|
||||
client.Close()
|
||||
return reply, fmt.Errorf("%s rpc call timeout", addr)
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
rpcClients.Del(addr)
|
||||
client.Close()
|
||||
return reply, fmt.Errorf("%s rpc call done, but fail: %v", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
func rpcClient(addr string) (*rpc.Client, error) {
|
||||
conn, err := net.DialTimeout("tcp", addr, time.Second*3)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("dial transfer %s fail: %v", addr, err)
|
||||
logger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var bufConn = struct {
|
||||
io.Closer
|
||||
*bufio.Reader
|
||||
*bufio.Writer
|
||||
}{conn, bufio.NewReader(conn), bufio.NewWriter(conn)}
|
||||
|
||||
var mh codec.MsgpackHandle
|
||||
mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
|
||||
rpcCodec := codec.MsgpackSpecRpc.ClientCodec(bufConn, &mh)
|
||||
client := rpc.NewClientWithCodec(rpcCodec)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func CounterToGauge(item *dataobj.MetricValue) *dataobj.MetricValue {
|
||||
key := item.PK()
|
||||
|
||||
old, exists := cache.MetricHistory.Get(key)
|
||||
cache.MetricHistory.Set(key, *item)
|
||||
|
||||
if !exists {
|
||||
logger.Debugf("not found old item:%v, maybe this is the first item", item)
|
||||
return nil
|
||||
}
|
||||
|
||||
if old.Value > item.Value {
|
||||
logger.Warningf("item:%v old value:%v greater than new value:%v", item, old.Value, item.Value)
|
||||
return nil
|
||||
}
|
||||
|
||||
if old.Timestamp >= item.Timestamp {
|
||||
logger.Warningf("item:%v old timestamp:%v greater than new timestamp:%v", item, old.Timestamp, item.Timestamp)
|
||||
return nil
|
||||
}
|
||||
|
||||
item.ValueUntyped = (item.Value - old.Value) / float64(item.Timestamp-old.Timestamp)
|
||||
item.CounterType = dataobj.GAUGE
|
||||
return item
|
||||
}
|
||||
|
||||
func SubtractToGauge(item *dataobj.MetricValue) *dataobj.MetricValue {
|
||||
key := item.PK()
|
||||
|
||||
old, exists := cache.MetricHistory.Get(key)
|
||||
cache.MetricHistory.Set(key, *item)
|
||||
|
||||
if !exists {
|
||||
logger.Debugf("not found old item:%v, maybe this is the first item", item)
|
||||
return nil
|
||||
}
|
||||
|
||||
if old.Timestamp >= item.Timestamp {
|
||||
logger.Warningf("item:%v old timestamp:%v greater than new timestamp:%v", item, old.Timestamp, item.Timestamp)
|
||||
return nil
|
||||
}
|
||||
|
||||
if old.Timestamp <= item.Timestamp-2*item.Step {
|
||||
logger.Warningf("item:%v old timestamp:%v too old <= %v = (new timestamp: %v - 2 * step: %v), maybe some point lost", item, old.Timestamp, item.Timestamp-2*item.Step, item.Timestamp, item.Step)
|
||||
return nil
|
||||
}
|
||||
|
||||
item.ValueUntyped = item.Value - old.Value
|
||||
item.CounterType = dataobj.GAUGE
|
||||
return item
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
"github.com/didi/nightingale/src/modules/collector/core"
|
||||
"github.com/didi/nightingale/src/modules/collector/log/strategy"
|
||||
"github.com/didi/nightingale/src/modules/collector/log/worker"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
"github.com/didi/nightingale/src/toolkits/http/render"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/toolkits/pkg/errors"
|
||||
)
|
||||
|
||||
func ping(c *gin.Context) {
|
||||
c.String(200, "pong")
|
||||
}
|
||||
|
||||
func addr(c *gin.Context) {
|
||||
c.String(200, c.Request.RemoteAddr)
|
||||
}
|
||||
|
||||
func pid(c *gin.Context) {
|
||||
c.String(200, fmt.Sprintf("%d", os.Getpid()))
|
||||
}
|
||||
|
||||
func pushData(c *gin.Context) {
|
||||
if c.Request.ContentLength == 0 {
|
||||
render.Message(c, "blank body")
|
||||
return
|
||||
}
|
||||
|
||||
var recvMetricValues []*dataobj.MetricValue
|
||||
errors.Dangerous(c.ShouldBindJSON(&recvMetricValues))
|
||||
|
||||
err := core.Push(recvMetricValues)
|
||||
render.Message(c, err)
|
||||
}
|
||||
|
||||
func getStrategy(c *gin.Context) {
|
||||
var resp []interface{}
|
||||
|
||||
port := stra.GetPortCollects()
|
||||
for _, s := range port {
|
||||
resp = append(resp, s)
|
||||
}
|
||||
|
||||
proc := stra.GetProcCollects()
|
||||
for _, s := range proc {
|
||||
resp = append(resp, s)
|
||||
}
|
||||
|
||||
logStras := strategy.GetListAll()
|
||||
for _, s := range logStras {
|
||||
resp = append(resp, s)
|
||||
}
|
||||
|
||||
render.Data(c, resp, nil)
|
||||
}
|
||||
|
||||
func getLogCached(c *gin.Context) {
|
||||
render.Data(c, worker.GetCachedAll(), nil)
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Config routes
|
||||
func Config(r *gin.Engine) {
|
||||
sys := r.Group("/api/collector")
|
||||
{
|
||||
sys.GET("/ping", ping)
|
||||
sys.GET("/pid", pid)
|
||||
sys.GET("/addr", addr)
|
||||
|
||||
sys.GET("/stra", getStrategy)
|
||||
sys.GET("/cached", getLogCached)
|
||||
sys.POST("/push", pushData)
|
||||
}
|
||||
|
||||
// compatible with open-falcon
|
||||
v1 := r.Group("/v1")
|
||||
{
|
||||
v1.GET("/ping", ping)
|
||||
v1.GET("/pid", pid)
|
||||
v1.GET("/addr", addr)
|
||||
|
||||
v1.GET("/stra", getStrategy)
|
||||
v1.GET("/cached", getLogCached)
|
||||
v1.POST("/push", pushData)
|
||||
}
|
||||
|
||||
pprof.Register(r, "/api/collector/debug/pprof")
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
package reader
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
|
||||
"github.com/hpcloud/tail"
|
||||
)
|
||||
|
||||
type Reader struct {
|
||||
FilePath string //配置的路径 正则路径
|
||||
t *tail.Tail
|
||||
Stream chan string
|
||||
CurrentPath string //当前的路径
|
||||
Close chan struct{}
|
||||
FD uint64 // 文件的inode
|
||||
}
|
||||
|
||||
func NewReader(filepath string, stream chan string) (*Reader, error) {
|
||||
r := &Reader{
|
||||
FilePath: filepath,
|
||||
Stream: stream,
|
||||
Close: make(chan struct{}),
|
||||
}
|
||||
path := GetCurrentPath(filepath)
|
||||
err := r.openFile(io.SeekEnd, path) //默认打开SeekEnd
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (r *Reader) openFile(whence int, filepath string) error {
|
||||
seekinfo := &tail.SeekInfo{
|
||||
Offset: 0,
|
||||
Whence: whence,
|
||||
}
|
||||
config := tail.Config{
|
||||
Location: seekinfo,
|
||||
ReOpen: true,
|
||||
Poll: true,
|
||||
Follow: true,
|
||||
}
|
||||
|
||||
t, err := tail.TailFile(filepath, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.t = t
|
||||
r.CurrentPath = filepath
|
||||
r.FD = GetFileInodeNum(r.CurrentPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reader) StartRead() {
|
||||
var readCnt, readSwp int64
|
||||
var dropCnt, dropSwp int64
|
||||
|
||||
analysClose := make(chan int)
|
||||
go func() {
|
||||
for {
|
||||
// 十秒钟统计一次
|
||||
select {
|
||||
case <-analysClose:
|
||||
return
|
||||
case <-time.After(time.Second * 10):
|
||||
}
|
||||
a := readCnt
|
||||
b := dropCnt
|
||||
logger.Debugf("read [%d] line in last 10s\n", a-readSwp)
|
||||
logger.Debugf("drop [%d] line in last 10s\n", b-dropSwp)
|
||||
readSwp = a
|
||||
dropSwp = b
|
||||
}
|
||||
}()
|
||||
|
||||
for line := range r.t.Lines {
|
||||
readCnt = readCnt + 1
|
||||
select {
|
||||
case r.Stream <- line.Text:
|
||||
default:
|
||||
dropCnt = dropCnt + 1
|
||||
//TODO 数据丢失处理,从现时间戳开始截断上报5周期
|
||||
// 是否真的要做?
|
||||
// 首先,5 周期也是拍脑袋的,只能拍脑袋丢数据,并不能保证准确性
|
||||
// 其次,是当前时间推五周期,并不知道日志是什么时候,这个地方有待斟酌
|
||||
// 结论,暂且不做,后人注意
|
||||
}
|
||||
}
|
||||
analysClose <- 0
|
||||
}
|
||||
|
||||
func (r *Reader) StopRead() error {
|
||||
return r.t.Stop()
|
||||
}
|
||||
|
||||
func (r *Reader) Stop() {
|
||||
r.StopRead()
|
||||
close(r.Close)
|
||||
|
||||
}
|
||||
func (r *Reader) Start() {
|
||||
go r.StartRead()
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
r.check()
|
||||
case <-r.Close:
|
||||
close(r.Stream)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func (r *Reader) check() {
|
||||
nextpath := GetCurrentPath(r.FilePath)
|
||||
|
||||
// 文件名发生变化, 一般发生在配置了动态日志场景
|
||||
if r.CurrentPath != nextpath {
|
||||
if _, err := os.Stat(nextpath); err != nil {
|
||||
logger.Warningf("stat nextpath err: %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
r.t.StopAtEOF()
|
||||
if err := r.openFile(io.SeekStart, nextpath); err == nil { //从文件开始打开
|
||||
go r.StartRead()
|
||||
} else {
|
||||
logger.Warningf("openFile err @check, err: %v\n", err.Error())
|
||||
}
|
||||
|
||||
// 执行到这里, 动态日志已经reopen, 无需再进行下面同名文件的inode变化check
|
||||
return
|
||||
}
|
||||
|
||||
// 同名文件inode变化check
|
||||
// 重新打开文件, 从头开始读取
|
||||
// TODO hpcloud/tail 应该感知到这种场景
|
||||
newFD := GetFileInodeNum(r.CurrentPath)
|
||||
if r.FD == newFD {
|
||||
return
|
||||
}
|
||||
r.FD = newFD
|
||||
logger.Warningf("inode changed, reopen file %v\n", r.CurrentPath)
|
||||
|
||||
r.t.StopAtEOF()
|
||||
if err := r.openFile(io.SeekStart, nextpath); err == nil { //从文件开始打开
|
||||
go r.StartRead()
|
||||
} else {
|
||||
logger.Warningf("openFile err @check, err: %v\n", err.Error())
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package reader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
//当新文件出现时,是否自动读取
|
||||
func TestCheck(t *testing.T) {
|
||||
util(true)
|
||||
}
|
||||
|
||||
//测试文件打开关闭
|
||||
func TestStartAndStop(t *testing.T) {
|
||||
util(false)
|
||||
}
|
||||
|
||||
func util(isnext bool) {
|
||||
stream := make(chan string, 100)
|
||||
rj, err := NewReader("/test/aby.${%Y-%m-%d-%H}", stream)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go rj.Start()
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second) //2秒后创建文件
|
||||
now := time.Now()
|
||||
if isnext {
|
||||
now = now.Add(time.Hour)
|
||||
}
|
||||
suffix := now.Format("2006-01-02-15")
|
||||
filepath := fmt.Sprintf("/test/aby.%s", suffix)
|
||||
|
||||
{
|
||||
f, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 250) //因为tail 的巡检周期是250ms
|
||||
defer f.Close()
|
||||
|
||||
fmt.Fprint(f, "this is a test\n")
|
||||
|
||||
}
|
||||
time.Sleep(250 * time.Millisecond) //延迟关闭
|
||||
rj.Stop()
|
||||
|
||||
}()
|
||||
|
||||
for line := range stream {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package reader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetCurrentPath(path string) string {
|
||||
return getLogPath(path)
|
||||
}
|
||||
|
||||
func getLogPath(path string) string {
|
||||
pat := `(\$\{(%[YmdH][^\/]*)+\})`
|
||||
reg := regexp.MustCompile(pat)
|
||||
return reg.ReplaceAllStringFunc(path, func(s string) string {
|
||||
stringv := strings.TrimFunc(s, func(r rune) bool {
|
||||
if r == '$' || r == '{' || r == '}' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
name := strings.Split(strings.TrimLeft(stringv, "%"), "%")
|
||||
now := time.Now()
|
||||
for k, v := range name {
|
||||
if strings.Contains(v, "Y") {
|
||||
if strings.HasPrefix(v, "Y") {
|
||||
year := fmt.Sprintf("%d", now.Year())
|
||||
name[k] = strings.Replace(v, "Y", year, 1)
|
||||
}
|
||||
} else if strings.Contains(v, "m") {
|
||||
if strings.HasPrefix(v, "m") {
|
||||
month := fmt.Sprintf("%02d", now.Month())
|
||||
name[k] = strings.Replace(v, "m", month, 1)
|
||||
}
|
||||
} else if strings.Contains(v, "d") {
|
||||
if strings.HasPrefix(v, "d") {
|
||||
day := fmt.Sprintf("%02d", now.Day())
|
||||
name[k] = strings.Replace(v, "d", day, 1)
|
||||
}
|
||||
} else if strings.Contains(v, "H") {
|
||||
if strings.HasPrefix(v, "H") {
|
||||
hour := fmt.Sprintf("%02d", now.Hour())
|
||||
name[k] = strings.Replace(v, "H", hour, 1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return strings.Join(name, "")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func GetFileInodeNum(path string) uint64 {
|
||||
s, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
stat, ok := s.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return stat.Ino
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package reader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
path = "/home/${%Y%m}/log/${%Y%m%d}/application.log.${%Y-%m-%d-%H}"
|
||||
)
|
||||
|
||||
func TestGetCurrentPath(t *testing.T) {
|
||||
now := time.Now()
|
||||
dir1 := now.Format("200601")
|
||||
dir2 := now.Format("20060102")
|
||||
suffix := now.Format("2006-01-02-15")
|
||||
expected := fmt.Sprintf("/home/%s/log/%s/application.log.%s", dir1, dir2, suffix)
|
||||
assert.Equal(t, expected, GetCurrentPath(path))
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package strategy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
// 后续开发者切记 : 没有锁,不能修改globalStrategy,更新的时候直接替换,否则会panic
|
||||
var (
|
||||
globalStrategy map[int64]*stra.Strategy
|
||||
)
|
||||
|
||||
func init() {
|
||||
globalStrategy = make(map[int64]*stra.Strategy)
|
||||
}
|
||||
|
||||
func Update() error {
|
||||
strategies := stra.GetLogCollects()
|
||||
|
||||
err := UpdateGlobalStrategy(strategies)
|
||||
if err != nil {
|
||||
logger.Errorf("Update Strategy cache error:%v\n", err)
|
||||
return err
|
||||
}
|
||||
logger.Infof("Update Strategy end")
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateGlobalStrategy(sts []*stra.Strategy) error {
|
||||
tmpStrategyMap := make(map[int64]*stra.Strategy)
|
||||
for _, st := range sts {
|
||||
if st.Degree == 0 {
|
||||
st.Degree = 6
|
||||
}
|
||||
tmpStrategyMap[st.ID] = st
|
||||
}
|
||||
globalStrategy = tmpStrategyMap
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetListAll() []*stra.Strategy {
|
||||
stmap := GetDeepCopyAll()
|
||||
var ret []*stra.Strategy
|
||||
for _, st := range stmap {
|
||||
ret = append(ret, st)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetDeepCopyAll() map[int64]*stra.Strategy {
|
||||
ret := make(map[int64]*stra.Strategy, len(globalStrategy))
|
||||
for k, v := range globalStrategy {
|
||||
ret[k] = DeepCopyStrategy(v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetAll() map[int64]*stra.Strategy {
|
||||
return globalStrategy
|
||||
}
|
||||
|
||||
func GetByID(id int64) (*stra.Strategy, error) {
|
||||
st, ok := globalStrategy[id]
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("ID : %d is not exists in global Cache", id)
|
||||
}
|
||||
return st, nil
|
||||
|
||||
}
|
||||
|
||||
func DeepCopyStrategy(p *stra.Strategy) *stra.Strategy {
|
||||
s := stra.Strategy{}
|
||||
s.ID = p.ID
|
||||
s.Name = p.Name
|
||||
s.FilePath = p.FilePath
|
||||
s.TimeFormat = p.TimeFormat
|
||||
s.Pattern = p.Pattern
|
||||
s.MeasurementType = p.MeasurementType
|
||||
s.Interval = p.Interval
|
||||
s.Tags = stra.DeepCopyStringMap(p.Tags)
|
||||
s.Func = p.Func
|
||||
s.Degree = p.Degree
|
||||
s.Unit = p.Unit
|
||||
s.Comment = p.Comment
|
||||
s.Creator = p.Creator
|
||||
s.SrvUpdated = p.SrvUpdated
|
||||
s.LocalUpdated = p.LocalUpdated
|
||||
|
||||
return &s
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
)
|
||||
|
||||
// cached时间周期
|
||||
const cachedDuration = 60
|
||||
|
||||
type counterCache struct {
|
||||
sync.RWMutex
|
||||
Points map[string]float64 `json:"points"`
|
||||
}
|
||||
|
||||
type pushPointsCache struct {
|
||||
sync.RWMutex
|
||||
Counters map[string]*counterCache `json:"counters"`
|
||||
}
|
||||
|
||||
var globalPushPoints = pushPointsCache{Counters: make(map[string]*counterCache)}
|
||||
|
||||
func init() {
|
||||
go CleanLoop()
|
||||
}
|
||||
|
||||
func PostToCache(paramPoints []*dataobj.MetricValue) {
|
||||
for _, point := range paramPoints {
|
||||
globalPushPoints.AddPoint(point)
|
||||
}
|
||||
}
|
||||
|
||||
func CleanLoop() {
|
||||
for {
|
||||
// 遍历,删掉过期的cache
|
||||
globalPushPoints.CleanOld()
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func GetCachedAll() string {
|
||||
globalPushPoints.Lock()
|
||||
str, err := json.Marshal(globalPushPoints)
|
||||
globalPushPoints.Unlock()
|
||||
if err != nil {
|
||||
logger.Errorf("err when get cached all : [%s]", err.Error())
|
||||
}
|
||||
return string(str)
|
||||
}
|
||||
|
||||
func (cc *counterCache) AddPoint(tms int64, value float64) {
|
||||
cc.Lock()
|
||||
tmsStr := fmt.Sprintf("%d", tms)
|
||||
cc.Points[tmsStr] = value
|
||||
cc.Unlock()
|
||||
}
|
||||
|
||||
func (cc *counterCache) GetKeys() []string {
|
||||
cc.RLock()
|
||||
retList := make([]string, 0)
|
||||
for k := range cc.Points {
|
||||
retList = append(retList, k)
|
||||
}
|
||||
cc.RUnlock()
|
||||
return retList
|
||||
}
|
||||
|
||||
func (cc *counterCache) RemoveTms(tms string) {
|
||||
cc.Lock()
|
||||
delete(cc.Points, tms)
|
||||
cc.Unlock()
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) AddCounter(counter string) {
|
||||
pc.Lock()
|
||||
tmp := new(counterCache)
|
||||
tmp.Points = make(map[string]float64)
|
||||
pc.Counters[counter] = tmp
|
||||
pc.Unlock()
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) GetCounters() []string {
|
||||
ret := make([]string, 0)
|
||||
pc.RLock()
|
||||
for k := range pc.Counters {
|
||||
ret = append(ret, k)
|
||||
}
|
||||
pc.RUnlock()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) RemoveCounter(counter string) {
|
||||
pc.Lock()
|
||||
delete(pc.Counters, counter)
|
||||
pc.Unlock()
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) GetCounterObj(key string) (*counterCache, bool) {
|
||||
pc.RLock()
|
||||
Points, ok := pc.Counters[key]
|
||||
pc.RUnlock()
|
||||
|
||||
return Points, ok
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) AddPoint(point *dataobj.MetricValue) {
|
||||
counter := calcCounter(point)
|
||||
if _, ok := pc.GetCounterObj(counter); !ok {
|
||||
pc.AddCounter(counter)
|
||||
}
|
||||
counterPoints, exists := pc.GetCounterObj(counter)
|
||||
if exists {
|
||||
counterPoints.AddPoint(point.Timestamp, point.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *pushPointsCache) CleanOld() {
|
||||
counters := pc.GetCounters()
|
||||
for _, counter := range counters {
|
||||
counterObj, exists := pc.GetCounterObj(counter)
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
tmsList := counterObj.GetKeys()
|
||||
|
||||
//如果列表为空,清理掉这个counter
|
||||
if len(tmsList) == 0 {
|
||||
pc.RemoveCounter(counter)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, tmsStr := range tmsList {
|
||||
tms, err := strconv.Atoi(tmsStr)
|
||||
if err != nil {
|
||||
logger.Errorf("clean cached point, atoi error : [%v]", err)
|
||||
counterObj.RemoveTms(tmsStr)
|
||||
} else if (time.Now().Unix() - int64(tms)) > cachedDuration {
|
||||
counterObj.RemoveTms(tmsStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calcCounter(point *dataobj.MetricValue) string {
|
||||
tagstring := dataobj.SortedTags(point.TagsMap)
|
||||
counter := fmt.Sprintf("%s/%s", point.Metric, tagstring)
|
||||
return counter
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package worker
|
||||
|
||||
type WorkerSection struct {
|
||||
WorkerNum int `yaml:"workerNum"`
|
||||
QueueSize int `yaml:"queueSize"`
|
||||
PushInterval int `yaml:"pushInterval"`
|
||||
WaitPush int `yaml:"waitPush"`
|
||||
}
|
||||
|
||||
var WorkerConfig WorkerSection
|
||||
|
||||
func Init(cfg WorkerSection) {
|
||||
WorkerConfig = cfg
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/collector/log/reader"
|
||||
"github.com/didi/nightingale/src/modules/collector/log/strategy"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
type ConfigInfo struct {
|
||||
Id int64
|
||||
FilePath string
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
r *reader.Reader
|
||||
w *WorkerGroup
|
||||
}
|
||||
|
||||
var ManagerJob map[string]*Job //管理job,文件路径为key
|
||||
var ManagerJobLock *sync.RWMutex
|
||||
var ManagerConfig map[int64]*ConfigInfo
|
||||
|
||||
func init() {
|
||||
ManagerJob = make(map[string]*Job)
|
||||
ManagerJobLock = new(sync.RWMutex)
|
||||
ManagerConfig = make(map[int64]*ConfigInfo)
|
||||
}
|
||||
|
||||
func UpdateConfigsLoop() {
|
||||
for {
|
||||
strategy.Update()
|
||||
strategyMap := strategy.GetAll() //最新策略
|
||||
|
||||
ManagerJobLock.Lock()
|
||||
//metric.MetricJobNum(len(ManagerJob))
|
||||
for id, st := range strategyMap {
|
||||
cfg := &ConfigInfo{
|
||||
Id: id,
|
||||
FilePath: st.FilePath,
|
||||
}
|
||||
cache := make(chan string, WorkerConfig.QueueSize)
|
||||
if err := createJob(cfg, cache); err != nil {
|
||||
logger.Errorf("create job fail [id:%d][filePath:%s][err:%v]", cfg.Id, cfg.FilePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
for id := range ManagerConfig {
|
||||
if _, ok := strategyMap[id]; !ok { //如果策略中不存在,说明用户已删除
|
||||
cfg := &ConfigInfo{
|
||||
Id: id,
|
||||
FilePath: ManagerConfig[id].FilePath,
|
||||
}
|
||||
deleteJob(cfg)
|
||||
}
|
||||
}
|
||||
ManagerJobLock.Unlock()
|
||||
|
||||
//更新counter
|
||||
GlobalCount.UpdateByStrategy(strategyMap)
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func GetLatestTmsAndDelay(filepath string) (int64, int64, bool) {
|
||||
ManagerJobLock.RLock()
|
||||
job, ok := ManagerJob[filepath]
|
||||
ManagerJobLock.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return 0, 0, false
|
||||
}
|
||||
latest, delay := job.w.GetLatestTmsAndDelay()
|
||||
return latest, delay, true
|
||||
}
|
||||
|
||||
//添加任务到管理map( managerjob managerconfig) 启动reader和worker
|
||||
func createJob(config *ConfigInfo, cache chan string) error {
|
||||
if _, ok := ManagerJob[config.FilePath]; ok {
|
||||
if _, ok := ManagerConfig[config.Id]; !ok {
|
||||
ManagerConfig[config.Id] = config
|
||||
}
|
||||
//依赖策略的周期更新, 触发文件乱序时间戳的重置
|
||||
ManagerJob[config.FilePath].w.ResetMaxDelay()
|
||||
return nil
|
||||
}
|
||||
|
||||
ManagerConfig[config.Id] = config
|
||||
//启动reader
|
||||
r, err := reader.NewReader(config.FilePath, cache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//metric.MetricReadAddReaderNum(config.FilePath)
|
||||
//启动worker
|
||||
w := NewWorkerGroup(config.FilePath, cache)
|
||||
ManagerJob[config.FilePath] = &Job{
|
||||
r: r,
|
||||
w: w,
|
||||
}
|
||||
w.Start()
|
||||
//启动reader
|
||||
go r.Start()
|
||||
|
||||
logger.Infof("Create job success [filePath:%s][sid:%d]", config.FilePath, config.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
//先stop worker reader再从管理map中删除
|
||||
func deleteJob(config *ConfigInfo) {
|
||||
//删除jobs
|
||||
tag := 0
|
||||
for _, cg := range ManagerConfig {
|
||||
if config.FilePath == cg.FilePath {
|
||||
tag++
|
||||
}
|
||||
}
|
||||
if tag <= 1 {
|
||||
//metric.MetricReadDelReaderNum(config.FilePath)
|
||||
if job, ok := ManagerJob[config.FilePath]; ok {
|
||||
job.w.Stop() //先stop worker
|
||||
job.r.Stop()
|
||||
delete(ManagerJob, config.FilePath)
|
||||
}
|
||||
}
|
||||
logger.Infof("Stop reader & worker success [filePath:%s][sid:%d]", config.FilePath, config.Id)
|
||||
|
||||
//删除config
|
||||
if _, ok := ManagerConfig[config.Id]; ok {
|
||||
delete(ManagerConfig, config.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func Zeroize() {
|
||||
|
||||
t1 := time.NewTicker(time.Duration(10) * time.Second)
|
||||
for {
|
||||
<-t1.C
|
||||
stras := strategy.GetListAll()
|
||||
for _, stra := range stras {
|
||||
if stra.Func == "cnt" && len(stra.Tags) < 1 {
|
||||
point := &AnalysPoint{
|
||||
StrategyID: stra.ID,
|
||||
Value: -1,
|
||||
Tms: time.Now().Unix(),
|
||||
Tags: map[string]string{},
|
||||
}
|
||||
if err := PushToCount(point); err != nil {
|
||||
logger.Errorf("push to counter error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCreatejobAndDeletejob(t *testing.T) {
|
||||
config := &ConfigInfo{
|
||||
Id: 1,
|
||||
FilePath: "a.log.${%Y-%m-%d-%H}",
|
||||
}
|
||||
cache := make(chan string, 100)
|
||||
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
deleteJob(config)
|
||||
}()
|
||||
if err := createJob(config, cache); err == nil {
|
||||
for line := range cache {
|
||||
fmt.Println(line)
|
||||
}
|
||||
} else {
|
||||
log.Printf("create job failed : %v", err)
|
||||
}
|
||||
}
|
|
@ -1,363 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
"github.com/didi/nightingale/src/modules/collector/log/strategy"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
//从worker往计算部分推的Point
|
||||
type AnalysPoint struct {
|
||||
StrategyID int64
|
||||
Value float64
|
||||
Tms int64
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
//统计的实体
|
||||
type PointCounter struct {
|
||||
sync.RWMutex
|
||||
Count int64
|
||||
Sum float64
|
||||
Max float64
|
||||
Min float64
|
||||
}
|
||||
|
||||
// 单策略下,单step的统计对象
|
||||
// 以Sorted的tagkv的字符串来做索引
|
||||
type PointsCounter struct {
|
||||
sync.RWMutex
|
||||
TagstringMap map[string]*PointCounter
|
||||
}
|
||||
|
||||
// 单策略下的对象, 以step为索引, 索引每一个Step的统计
|
||||
// 单step统计, 推送完则删
|
||||
type StrategyCounter struct {
|
||||
sync.RWMutex
|
||||
Strategy *stra.Strategy //Strategy结构体扔这里,以备不时之需
|
||||
TmsPoints map[int64]*PointsCounter //按照时间戳分类的分别的counter
|
||||
}
|
||||
|
||||
// 全局counter对象, 以key为索引,索引每个策略的统计
|
||||
// key : Strategy ID
|
||||
type GlobalCounter struct {
|
||||
sync.RWMutex
|
||||
StrategyCounts map[int64]*StrategyCounter
|
||||
}
|
||||
|
||||
var GlobalCount *GlobalCounter
|
||||
|
||||
func init() {
|
||||
GlobalCount = new(GlobalCounter)
|
||||
GlobalCount.StrategyCounts = make(map[int64]*StrategyCounter)
|
||||
}
|
||||
|
||||
// 提供给Worker用来Push计算后的信息
|
||||
// 需保证线程安全
|
||||
func PushToCount(Point *AnalysPoint) error {
|
||||
stCount, err := GlobalCount.GetStrategyCountByID(Point.StrategyID)
|
||||
|
||||
// 更新strategyCounts
|
||||
if err != nil {
|
||||
strategy, err := strategy.GetByID(Point.StrategyID)
|
||||
if err != nil {
|
||||
logger.Errorf("GetByID ERROR when count:[%v]", err)
|
||||
return err
|
||||
}
|
||||
|
||||
GlobalCount.AddStrategyCount(strategy)
|
||||
|
||||
stCount, err = GlobalCount.GetStrategyCountByID(Point.StrategyID)
|
||||
// 还拿不到,就出错返回吧
|
||||
if err != nil {
|
||||
logger.Errorf("Get strategyCount Failed after addition: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 拿到stCount,更新StepCounts
|
||||
stepTms := AlignStepTms(stCount.Strategy.Interval, Point.Tms)
|
||||
tmsCount, err := stCount.GetByTms(stepTms)
|
||||
if err != nil {
|
||||
err := stCount.AddTms(stepTms)
|
||||
if err != nil {
|
||||
logger.Errorf("Add tms to strategy error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
tmsCount, err = stCount.GetByTms(stepTms)
|
||||
// 还拿不到,就出错返回吧
|
||||
if err != nil {
|
||||
logger.Errorf("Get tmsCount Failed By Twice Add: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//拿到tmsCount, 更新TagstringMap
|
||||
tagstring := dataobj.SortedTags(Point.Tags)
|
||||
return tmsCount.Update(tagstring, Point.Value)
|
||||
}
|
||||
|
||||
//时间戳向前对齐
|
||||
func AlignStepTms(step, tms int64) int64 {
|
||||
if step <= 0 {
|
||||
return tms
|
||||
}
|
||||
newTms := tms - (tms % step)
|
||||
return newTms
|
||||
}
|
||||
|
||||
func (pc *PointCounter) UpdateCnt() {
|
||||
atomic.AddInt64(&pc.Count, 1)
|
||||
}
|
||||
|
||||
func (pc *PointCounter) UpdateSum(value float64) {
|
||||
addFloat64(&pc.Sum, value)
|
||||
}
|
||||
|
||||
func (pc *PointCounter) UpdateMaxMin(value float64) {
|
||||
// 这里要用到结构体的小锁
|
||||
// sum和cnt可以不用锁,但是最大最小没办法做到原子操作
|
||||
// 只能引入锁
|
||||
pc.RLock()
|
||||
if math.IsNaN(pc.Max) || value > pc.Max {
|
||||
pc.RUnlock()
|
||||
pc.Lock()
|
||||
if math.IsNaN(pc.Max) || value > pc.Max {
|
||||
pc.Max = value
|
||||
}
|
||||
pc.Unlock()
|
||||
} else {
|
||||
pc.RUnlock()
|
||||
}
|
||||
|
||||
pc.RLock()
|
||||
if math.IsNaN(pc.Min) || value < pc.Min {
|
||||
pc.RUnlock()
|
||||
pc.Lock()
|
||||
if math.IsNaN(pc.Min) || value < pc.Min {
|
||||
pc.Min = value
|
||||
}
|
||||
pc.Unlock()
|
||||
} else {
|
||||
pc.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (psc *PointsCounter) GetBytagstring(tagstring string) (*PointCounter, error) {
|
||||
psc.RLock()
|
||||
point, ok := psc.TagstringMap[tagstring]
|
||||
psc.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tagstring [%s] not exists", tagstring)
|
||||
}
|
||||
return point, nil
|
||||
}
|
||||
|
||||
func (psc *PointsCounter) Update(tagstring string, value float64) error {
|
||||
pointCount, err := psc.GetBytagstring(tagstring)
|
||||
if err != nil {
|
||||
psc.Lock()
|
||||
tmp := new(PointCounter)
|
||||
tmp.Count = 0
|
||||
tmp.Sum = 0
|
||||
|
||||
if value == -1 {
|
||||
tmp.Sum = math.NaN() //补零逻辑,不处理Sum
|
||||
}
|
||||
tmp.Max = math.NaN()
|
||||
tmp.Min = math.NaN()
|
||||
psc.TagstringMap[tagstring] = tmp
|
||||
psc.Unlock()
|
||||
|
||||
pointCount, err = psc.GetBytagstring(tagstring)
|
||||
// 如果还是拿不到,就出错返回吧
|
||||
if err != nil {
|
||||
return fmt.Errorf("when update, cannot get pointCount after add [tagstring:%s]", tagstring)
|
||||
}
|
||||
}
|
||||
|
||||
pointCount.Lock()
|
||||
|
||||
if value != -1 { //value=-1,是补零逻辑,不做特殊处理
|
||||
pointCount.Sum = pointCount.Sum + value
|
||||
if math.IsNaN(pointCount.Max) || value > pointCount.Max {
|
||||
pointCount.Max = value
|
||||
}
|
||||
if math.IsNaN(pointCount.Min) || value < pointCount.Min {
|
||||
pointCount.Min = value
|
||||
}
|
||||
|
||||
pointCount.Count = pointCount.Count + 1
|
||||
}
|
||||
|
||||
pointCount.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFloat64(val *float64, delta float64) (new float64) {
|
||||
for {
|
||||
old := *val
|
||||
new = old + delta
|
||||
if atomic.CompareAndSwapUint64(
|
||||
(*uint64)(unsafe.Pointer(val)),
|
||||
math.Float64bits(old),
|
||||
math.Float64bits(new),
|
||||
) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (sc *StrategyCounter) GetTmsList() []int64 {
|
||||
var tmsList []int64
|
||||
sc.RLock()
|
||||
for tms := range sc.TmsPoints {
|
||||
tmsList = append(tmsList, tms)
|
||||
}
|
||||
sc.RUnlock()
|
||||
return tmsList
|
||||
}
|
||||
|
||||
func (sc *StrategyCounter) DeleteTms(tms int64) {
|
||||
sc.Lock()
|
||||
delete(sc.TmsPoints, tms)
|
||||
sc.Unlock()
|
||||
}
|
||||
|
||||
func (sc *StrategyCounter) GetByTms(tms int64) (*PointsCounter, error) {
|
||||
sc.RLock()
|
||||
psCount, ok := sc.TmsPoints[tms]
|
||||
if !ok {
|
||||
sc.RUnlock()
|
||||
return nil, fmt.Errorf("no this tms:%v", tms)
|
||||
}
|
||||
sc.RUnlock()
|
||||
return psCount, nil
|
||||
}
|
||||
|
||||
func (sc *StrategyCounter) AddTms(tms int64) error {
|
||||
sc.Lock()
|
||||
_, ok := sc.TmsPoints[tms]
|
||||
if !ok {
|
||||
tmp := new(PointsCounter)
|
||||
tmp.TagstringMap = make(map[string]*PointCounter)
|
||||
sc.TmsPoints[tms] = tmp
|
||||
}
|
||||
sc.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 只做更新和删除,添加 由数据驱动
|
||||
func (gc *GlobalCounter) UpdateByStrategy(globalStras map[int64]*stra.Strategy) {
|
||||
var delCount, upCount int
|
||||
// 先以count的ID为准,更新count
|
||||
// 若ID没有了, 那就删掉
|
||||
for _, id := range gc.GetIDs() {
|
||||
gc.RLock()
|
||||
sCount, ok := gc.StrategyCounts[id]
|
||||
gc.RUnlock()
|
||||
|
||||
if !ok || sCount.Strategy == nil {
|
||||
//证明此策略无效,或已被删除
|
||||
//删一下
|
||||
delCount = delCount + 1
|
||||
gc.deleteByID(id)
|
||||
continue
|
||||
}
|
||||
|
||||
newStrategy := globalStras[id]
|
||||
|
||||
// 一个是sCount.Strategy, 一个是newStrategy
|
||||
// 开始比较
|
||||
if !countEqual(newStrategy, sCount.Strategy) {
|
||||
//需要清空缓存
|
||||
upCount = upCount + 1
|
||||
logger.Infof("strategy [%d] changed, clean data", id)
|
||||
gc.cleanStrategyData(id)
|
||||
sCount.Strategy = newStrategy
|
||||
} else {
|
||||
gc.upStrategy(newStrategy)
|
||||
}
|
||||
}
|
||||
logger.Infof("Update global count done, [del:%d][update:%d]", delCount, upCount)
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) AddStrategyCount(st *stra.Strategy) {
|
||||
gc.Lock()
|
||||
if _, ok := gc.StrategyCounts[st.ID]; !ok {
|
||||
tmp := new(StrategyCounter)
|
||||
tmp.Strategy = st
|
||||
tmp.TmsPoints = make(map[int64]*PointsCounter)
|
||||
gc.StrategyCounts[st.ID] = tmp
|
||||
}
|
||||
gc.Unlock()
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) upStrategy(st *stra.Strategy) {
|
||||
gc.Lock()
|
||||
if _, ok := gc.StrategyCounts[st.ID]; ok {
|
||||
gc.StrategyCounts[st.ID].Strategy = st
|
||||
}
|
||||
gc.Unlock()
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) GetStrategyCountByID(id int64) (*StrategyCounter, error) {
|
||||
gc.RLock()
|
||||
stCount, ok := gc.StrategyCounts[id]
|
||||
if !ok {
|
||||
gc.RUnlock()
|
||||
return nil, fmt.Errorf("No this ID")
|
||||
}
|
||||
gc.RUnlock()
|
||||
return stCount, nil
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) GetIDs() []int64 {
|
||||
gc.RLock()
|
||||
rList := make([]int64, 0)
|
||||
for k := range gc.StrategyCounts {
|
||||
rList = append(rList, k)
|
||||
}
|
||||
gc.RUnlock()
|
||||
return rList
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) deleteByID(id int64) {
|
||||
gc.Lock()
|
||||
delete(gc.StrategyCounts, id)
|
||||
gc.Unlock()
|
||||
}
|
||||
|
||||
func (gc *GlobalCounter) cleanStrategyData(id int64) {
|
||||
gc.RLock()
|
||||
sCount, ok := gc.StrategyCounts[id]
|
||||
gc.RUnlock()
|
||||
if !ok || sCount == nil {
|
||||
return
|
||||
}
|
||||
sCount.TmsPoints = make(map[int64]*PointsCounter)
|
||||
}
|
||||
|
||||
// countEqual意味着不会对统计的结构产生影响
|
||||
func countEqual(A *stra.Strategy, B *stra.Strategy) bool {
|
||||
if A == nil || B == nil {
|
||||
return false
|
||||
}
|
||||
if A.Pattern == B.Pattern && A.Interval == B.Interval && A.Func == B.Func && reflect.DeepEqual(A.Tags, B.Tags) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/dataobj"
|
||||
"github.com/didi/nightingale/src/modules/collector/core"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
"github.com/didi/nightingale/src/toolkits/identity"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
var pushQueue chan *dataobj.MetricValue
|
||||
|
||||
type SortByTms []*dataobj.MetricValue
|
||||
|
||||
func (p SortByTms) Len() int { return len(p) }
|
||||
func (p SortByTms) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
func (p SortByTms) Less(i, j int) bool { return p[i].Timestamp < p[j].Timestamp }
|
||||
|
||||
func init() {
|
||||
//拍一个队列大小,10s一清,理论上肯定够用
|
||||
pushQueue = make(chan *dataobj.MetricValue, 1024*100)
|
||||
}
|
||||
|
||||
func PusherStart() {
|
||||
PosterLoop() //归类,批量发送给collector
|
||||
PusherLoop() //计算,推送给发送队列
|
||||
}
|
||||
|
||||
//循环推送,10s一次
|
||||
func PosterLoop() {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case p := <-pushQueue:
|
||||
points := make([]*dataobj.MetricValue, 0)
|
||||
points = append(points, p)
|
||||
DONE:
|
||||
for {
|
||||
select {
|
||||
case tmp := <-pushQueue:
|
||||
points = append(points, tmp)
|
||||
continue
|
||||
default:
|
||||
break DONE
|
||||
}
|
||||
}
|
||||
//先推到cache中
|
||||
PostToCache(points)
|
||||
//开一个协程,异步发送至collector
|
||||
go postToCollector(points)
|
||||
}
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func PusherLoop() {
|
||||
for {
|
||||
gIds := GlobalCount.GetIDs()
|
||||
for _, id := range gIds {
|
||||
stCount, err := GlobalCount.GetStrategyCountByID(id)
|
||||
if err != nil {
|
||||
logger.Errorf("get strategy count by id %v error: %v\n", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if stCount.Strategy == nil {
|
||||
logger.Errorf("strategy id %v is nil\n", id)
|
||||
continue
|
||||
}
|
||||
|
||||
step := stCount.Strategy.Interval
|
||||
filePath := stCount.Strategy.FilePath
|
||||
tmsList := stCount.GetTmsList()
|
||||
for _, tms := range tmsList {
|
||||
if tmsNeedPush(tms, filePath, step, WorkerConfig.WaitPush) {
|
||||
pointsCount, err := stCount.GetByTms(tms)
|
||||
if err == nil {
|
||||
ToPushQueue(stCount.Strategy, tms, pointsCount.TagstringMap)
|
||||
} else {
|
||||
logger.Errorf("get by tms [%d] error : %v", tms, err)
|
||||
}
|
||||
stCount.DeleteTms(tms)
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * time.Duration(WorkerConfig.PushInterval))
|
||||
}
|
||||
}
|
||||
|
||||
func tmsNeedPush(tms int64, filePath string, step int64, waitPush int) bool {
|
||||
|
||||
latest, delay, found := GetLatestTmsAndDelay(filePath)
|
||||
logger.Debugf("filepath:%s tms:%d latest tms:%d delay:%d", filePath, tms, latest, delay)
|
||||
|
||||
if !found {
|
||||
return true
|
||||
}
|
||||
|
||||
// 为解决日志时间戳乱序的最大等待时间, hard code
|
||||
// delay == 0时, 不用额外等待, 进而提高时效性
|
||||
if delay > 0 {
|
||||
var maxDelay int64
|
||||
if step <= 10 {
|
||||
maxDelay = step * 3
|
||||
} else if step > 10 && step <= 30 {
|
||||
maxDelay = step * 2
|
||||
} else {
|
||||
maxDelay = step
|
||||
}
|
||||
if delay > maxDelay {
|
||||
delay = maxDelay
|
||||
}
|
||||
}
|
||||
|
||||
waitTime := step
|
||||
if waitPush != 0 {
|
||||
waitTime = int64(waitPush)
|
||||
}
|
||||
|
||||
//如果日志文件更新时间晚于一个采集周期,则进行补零
|
||||
if latest < time.Now().Unix()-waitTime {
|
||||
return true
|
||||
}
|
||||
|
||||
if tms < AlignStepTms(step, latest-delay) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 这个参数是为了最大限度的对接
|
||||
// pointMap的key,是打平了的tagkv
|
||||
func ToPushQueue(strategy *stra.Strategy, tms int64, pointMap map[string]*PointCounter) error {
|
||||
for tagstring, PointCounter := range pointMap {
|
||||
var value float64 = 0
|
||||
switch strategy.Func {
|
||||
case "cnt":
|
||||
value = float64(PointCounter.Count)
|
||||
case "avg":
|
||||
if PointCounter.Count == 0 {
|
||||
//这种就不用往监控推了
|
||||
continue
|
||||
} else {
|
||||
avg := PointCounter.Sum / float64(PointCounter.Count)
|
||||
value = getPrecision(avg, strategy.Degree)
|
||||
}
|
||||
case "sum":
|
||||
value = PointCounter.Sum
|
||||
case "max":
|
||||
value = PointCounter.Max
|
||||
case "min":
|
||||
value = PointCounter.Min
|
||||
default:
|
||||
logger.Errorf("Strategy Func Error: %s ", strategy.Func)
|
||||
return fmt.Errorf("Strategy Func Error: %s ", strategy.Func)
|
||||
}
|
||||
|
||||
var tags map[string]string
|
||||
if tagstring == "null" {
|
||||
tags = make(map[string]string)
|
||||
} else {
|
||||
tags = dataobj.DictedTagstring(tagstring)
|
||||
}
|
||||
|
||||
if math.IsNaN(value) {
|
||||
continue
|
||||
}
|
||||
|
||||
tmpPoint := &dataobj.MetricValue{
|
||||
Metric: strategy.Name,
|
||||
Endpoint: identity.Identity,
|
||||
ValueUntyped: value,
|
||||
Timestamp: tms,
|
||||
Step: strategy.Interval,
|
||||
TagsMap: tags,
|
||||
CounterType: "GAUGE",
|
||||
}
|
||||
//metric.MetricPushDelay(tms)
|
||||
pushQueue <- tmpPoint
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func postToCollector(paramPoints []*dataobj.MetricValue) {
|
||||
// 按照时间戳分组发送
|
||||
tsPsMap := make(map[int64][]*dataobj.MetricValue)
|
||||
for _, p := range paramPoints {
|
||||
if _, exist := tsPsMap[p.Timestamp]; !exist {
|
||||
tsPsMap[p.Timestamp] = make([]*dataobj.MetricValue, 0)
|
||||
}
|
||||
|
||||
tsPsMap[p.Timestamp] = append(tsPsMap[p.Timestamp], p)
|
||||
}
|
||||
|
||||
var tsps tsPs
|
||||
for ts, ps := range tsPsMap {
|
||||
tsps = append(tsps, _tsPs{ts: ts, ps: ps})
|
||||
}
|
||||
sort.Sort(tsps)
|
||||
|
||||
for _, ps := range tsps {
|
||||
core.Push(ps.ps)
|
||||
|
||||
// 1000ms是经验值
|
||||
// 对于10G/小时的数据量+异步落盘的场景, 产生的结果友好一些
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
}
|
||||
}
|
||||
|
||||
func getPrecision(num float64, degree int64) float64 {
|
||||
tmpFloat := num * float64(math.Pow10(int(degree)))
|
||||
tmpInt := int(tmpFloat + 0.5)
|
||||
return float64(tmpInt) / float64(math.Pow10(int(degree)))
|
||||
}
|
||||
|
||||
type _tsPs struct {
|
||||
ts int64
|
||||
ps []*dataobj.MetricValue
|
||||
}
|
||||
|
||||
type tsPs []_tsPs
|
||||
|
||||
func (tp tsPs) Len() int { return len(tp) }
|
||||
func (tp tsPs) Swap(i, j int) { tp[i], tp[j] = tp[j], tp[i] }
|
||||
func (tp tsPs) Less(i, j int) bool { return tp[i].ts < tp[j].ts }
|
|
@ -1,327 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/didi/nightingale/src/modules/collector/log/strategy"
|
||||
"github.com/didi/nightingale/src/modules/collector/stra"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
type callbackHandler func(int64, int64)
|
||||
|
||||
//单个worker对象
|
||||
type Worker struct {
|
||||
FilePath string
|
||||
Counter int64
|
||||
LatestTms int64 //正在处理的单条日志时间
|
||||
Delay int64 //时间戳乱序差值, 每个worker独立更新
|
||||
Close chan struct{}
|
||||
Stream chan string
|
||||
Mark string //标记该worker信息,方便打log及上报自监控指标, 追查问题
|
||||
Analyzing bool //标记当前Worker状态是否在分析中,还是空闲状态
|
||||
Callback callbackHandler
|
||||
}
|
||||
|
||||
//worker组
|
||||
type WorkerGroup struct {
|
||||
WorkerNum int
|
||||
LatestTms int64 //日志文件最新处理的时间戳
|
||||
MaxDelay int64 //日志文件存在的时间戳乱序最大差值
|
||||
ResetTms int64 //maxDelay上次重置的时间
|
||||
Workers []*Worker
|
||||
TimeFormatStrategy string
|
||||
}
|
||||
|
||||
/*
|
||||
* filepath和stream依赖外部,其他的都自己创建
|
||||
*/
|
||||
func NewWorkerGroup(filePath string, stream chan string) *WorkerGroup {
|
||||
wokerNum := WorkerConfig.WorkerNum
|
||||
wg := &WorkerGroup{
|
||||
WorkerNum: wokerNum,
|
||||
Workers: make([]*Worker, 0),
|
||||
}
|
||||
|
||||
logger.Infof("new worker group, [file:%s][worker_num:%d]", filePath, wokerNum)
|
||||
|
||||
for i := 0; i < wg.WorkerNum; i++ {
|
||||
mark := fmt.Sprintf("[worker][file:%s][num:%d][id:%d]", filePath, wokerNum, i)
|
||||
w := Worker{}
|
||||
w.Close = make(chan struct{})
|
||||
w.FilePath = filePath
|
||||
w.Stream = stream
|
||||
w.Mark = mark
|
||||
w.Analyzing = false
|
||||
w.Counter = 0
|
||||
w.LatestTms = 0
|
||||
w.Delay = 0
|
||||
w.Callback = wg.SetLatestTmsAndDelay
|
||||
wg.Workers = append(wg.Workers, &w)
|
||||
}
|
||||
|
||||
return wg
|
||||
}
|
||||
|
||||
func (wg WorkerGroup) GetLatestTmsAndDelay() (tms int64, delay int64) {
|
||||
return wg.LatestTms, wg.MaxDelay
|
||||
}
|
||||
|
||||
func (wg *WorkerGroup) SetLatestTmsAndDelay(tms int64, delay int64) {
|
||||
latest := atomic.LoadInt64(&wg.LatestTms)
|
||||
|
||||
if latest < tms {
|
||||
swapped := atomic.CompareAndSwapInt64(&wg.LatestTms, latest, tms)
|
||||
if swapped {
|
||||
logger.Debugf("[work group:%s][set latestTms:%d]", wg.Workers[0].Mark, tms)
|
||||
}
|
||||
}
|
||||
|
||||
if delay == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
newest := atomic.LoadInt64(&wg.MaxDelay)
|
||||
if newest < delay {
|
||||
atomic.CompareAndSwapInt64(&wg.MaxDelay, newest, delay)
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WorkerGroup) Start() {
|
||||
for _, worker := range wg.Workers {
|
||||
worker.Start()
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WorkerGroup) Stop() {
|
||||
for _, worker := range wg.Workers {
|
||||
worker.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WorkerGroup) ResetMaxDelay() {
|
||||
// 默认1天重置一次
|
||||
ts := time.Now().Unix()
|
||||
if ts-wg.ResetTms > 86400 {
|
||||
wg.ResetTms = ts
|
||||
atomic.StoreInt64(&wg.MaxDelay, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Worker) Start() {
|
||||
go func() {
|
||||
w.Work()
|
||||
}()
|
||||
}
|
||||
|
||||
func (w *Worker) Stop() {
|
||||
close(w.Close)
|
||||
}
|
||||
|
||||
func (w *Worker) Work() {
|
||||
defer func() {
|
||||
if reason := recover(); reason != nil {
|
||||
logger.Infof("%s -- worker quit: panic reason: %v", w.Mark, reason)
|
||||
} else {
|
||||
logger.Infof("%s -- worker quit: normally", w.Mark)
|
||||
}
|
||||
}()
|
||||
logger.Infof("worker starting...[%s]", w.Mark)
|
||||
|
||||
var anaCnt, anaSwp int64
|
||||
analysClose := make(chan int)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
//休眠10s
|
||||
select {
|
||||
case <-analysClose:
|
||||
return
|
||||
case <-time.After(time.Second * 10):
|
||||
}
|
||||
a := anaCnt
|
||||
//metric.MetricWorkerAnalysisNum(int(a - anaSwp))
|
||||
logger.Debugf("analysis %d line in last 10s", a-anaSwp)
|
||||
anaSwp = a
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case line := <-w.Stream:
|
||||
w.Analyzing = true
|
||||
anaCnt = anaCnt + 1
|
||||
w.analysis(line)
|
||||
w.Analyzing = false
|
||||
case <-w.Close:
|
||||
analysClose <- 0
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//内部的分析方法
|
||||
//轮全局的规则列表
|
||||
//单次遍历
|
||||
func (w *Worker) analysis(line string) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger.Infof("%s[analysis panic] : %v", w.Mark, err)
|
||||
}
|
||||
}()
|
||||
|
||||
sts := strategy.GetAll()
|
||||
for _, strategy := range sts {
|
||||
if strategy.FilePath == w.FilePath && strategy.ParseSucc {
|
||||
analyspoint, err := w.producer(line, strategy)
|
||||
|
||||
if err != nil {
|
||||
log := fmt.Sprintf("%s[producer error][sid:%d] : %v", w.Mark, strategy.ID, err)
|
||||
//sample_log.Error(log)
|
||||
logger.Error(log)
|
||||
continue
|
||||
} else {
|
||||
if analyspoint != nil {
|
||||
toCounter(analyspoint, w.Mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Worker) producer(line string, strategy *stra.Strategy) (*AnalysPoint, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger.Errorf("%s[producer panic] : %v", w.Mark, err)
|
||||
}
|
||||
}()
|
||||
|
||||
var reg *regexp.Regexp
|
||||
_, timeFormat := stra.GetPatAndTimeFormat(strategy.TimeFormat)
|
||||
|
||||
reg = strategy.TimeReg
|
||||
|
||||
t := reg.FindString(line)
|
||||
if len(t) <= 0 {
|
||||
return nil, fmt.Errorf("cannot get timestamp:[sname:%s][sid:%d][timeFormat:%v]", strategy.Name, strategy.ID, timeFormat)
|
||||
}
|
||||
|
||||
// 如果没有年,需添加当前年
|
||||
// 需干掉内部的多于空格, 如Dec 7,有的有一个空格,有的有两个,这里统一替换成一个
|
||||
if timeFormat == "Jan 2 15:04:05" || timeFormat == "0102 15:04:05" {
|
||||
timeFormat = fmt.Sprintf("2006 %s", timeFormat)
|
||||
t = fmt.Sprintf("%d %s", time.Now().Year(), t)
|
||||
reg := regexp.MustCompile(`\s+`)
|
||||
rep := " "
|
||||
t = reg.ReplaceAllString(t, rep)
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation("Local")
|
||||
tms, err := time.ParseInLocation(timeFormat, t, loc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmsUnix := tms.Unix()
|
||||
if tmsUnix > time.Now().Unix() {
|
||||
logger.Debugf("%s[illegal timestamp][id:%d][tmsUnix:%d][current:%d]",
|
||||
w.Mark, strategy.ID, tmsUnix, time.Now().Unix())
|
||||
return nil, errors.New("illegal timestamp, greater than current")
|
||||
}
|
||||
|
||||
// 更新worker的时间戳和乱序差值
|
||||
// 如有必要, 更新上层group的时间戳和乱序差值
|
||||
updateLatest := false
|
||||
delay := int64(0)
|
||||
if w.LatestTms < tmsUnix {
|
||||
updateLatest = true
|
||||
w.LatestTms = tmsUnix
|
||||
|
||||
} else if w.LatestTms > tmsUnix {
|
||||
logger.Debugf("%s[timestamp disorder][id:%d][latest:%d][producing:%d]",
|
||||
w.Mark, strategy.ID, w.LatestTms, tmsUnix)
|
||||
|
||||
delay = w.LatestTms - tmsUnix
|
||||
}
|
||||
if updateLatest || delay > 0 {
|
||||
w.Callback(tmsUnix, delay)
|
||||
}
|
||||
|
||||
//处理用户正则
|
||||
var patternReg, excludeReg *regexp.Regexp
|
||||
var value float64
|
||||
patternReg = strategy.PatternReg
|
||||
if patternReg != nil {
|
||||
v := patternReg.FindStringSubmatch(line)
|
||||
var vString string
|
||||
if v != nil && len(v) != 0 {
|
||||
if len(v) > 1 {
|
||||
vString = v[1]
|
||||
} else {
|
||||
vString = ""
|
||||
}
|
||||
value, err = strconv.ParseFloat(vString, 64)
|
||||
if err != nil {
|
||||
value = math.NaN()
|
||||
}
|
||||
} else {
|
||||
//外边匹配err之后,要确保返回值不是nil再推送至counter
|
||||
//正则有表达式,没匹配到,直接返回
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
} else {
|
||||
value = math.NaN()
|
||||
}
|
||||
|
||||
//处理exclude
|
||||
excludeReg = strategy.ExcludeReg
|
||||
if excludeReg != nil {
|
||||
v := excludeReg.FindStringSubmatch(line)
|
||||
if v != nil && len(v) != 0 {
|
||||
//匹配到exclude了,需要返回
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
//处理tag 正则
|
||||
tag := map[string]string{}
|
||||
for tagk, tagv := range strategy.Tags {
|
||||
var regTag *regexp.Regexp
|
||||
regTag, ok := strategy.TagRegs[tagk]
|
||||
if !ok {
|
||||
logger.Errorf("%s[get tag reg error][sid:%d][tagk:%s][tagv:%s]", w.Mark, strategy.ID, tagk, tagv)
|
||||
return nil, nil
|
||||
}
|
||||
t := regTag.FindStringSubmatch(line)
|
||||
if t != nil && len(t) > 1 {
|
||||
tag[tagk] = t[1]
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
ret := &AnalysPoint{
|
||||
StrategyID: strategy.ID,
|
||||
Value: value,
|
||||
Tms: tms.Unix(),
|
||||
Tags: tag,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
//将解析数据给counter
|
||||
func toCounter(analyspoint *AnalysPoint, mark string) {
|
||||
if err := PushToCount(analyspoint); err != nil {
|
||||
logger.Errorf("%s push to counter error: %v", mark, err)
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWorkerStart(t *testing.T) {
|
||||
c := make(chan string, 10)
|
||||
go func() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
c <- fmt.Sprintf("test--%d--%d", i, j)
|
||||
}
|
||||
fmt.Println()
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
}()
|
||||
|
||||
wg := NewWorkerGroup("test", c)
|
||||
wg.Start()
|
||||
time.Sleep(10 * time.Second)
|
||||
wg.Stop()
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
linux 服务器基础资源采集agent
|
||||
|
||||
## 功能
|
||||
系统指标采集
|
||||
|
||||
|
||||
## 接口
|
||||
|
||||
#### 上报数据
|
||||
|
||||
```
|
||||
POST /api/collector/push
|
||||
|
||||
request body:
|
||||
// endpoint 可以填ip或者hostname, 如果ip是在运维平台是唯一表示, 那就填ip, hostname类同
|
||||
// step 为监控指标的采集周期
|
||||
// tags 监控指标的额外描述, a=b的形式, 可以填多个, 多个用逗号隔开, 比如 group=devops,module=api
|
||||
[
|
||||
{
|
||||
"metric":"qps",
|
||||
"endpoint":"hostname",
|
||||
"timestamp":1559733442,
|
||||
"step":10,
|
||||
"value":1,
|
||||
"tags":""
|
||||
}
|
||||
]
|
||||
|
||||
response body:
|
||||
{
|
||||
|
||||
"dat": "ok"
|
||||
"err": "",
|
||||
}
|
||||
```
|
||||
|
||||
-------
|
||||
#### 获取已生效的采集策略
|
||||
|
||||
```
|
||||
GET /api/collector/stra
|
||||
|
||||
response body:
|
||||
{
|
||||
"dat": [
|
||||
{
|
||||
"collect_type": "port",
|
||||
"comment": "test",
|
||||
"created": "2019-06-05T18:52:58+08:00",
|
||||
"creator": "root",
|
||||
"id": 1,
|
||||
"last_updated": "2019-06-17T15:46:06+08:00",
|
||||
"last_updator": "root",
|
||||
"name": "test",
|
||||
"nid": 2,
|
||||
"port": 8047,
|
||||
"step": 10,
|
||||
"tags": "port=8047,service=tsdb",
|
||||
"timeout": 3
|
||||
}
|
||||
],
|
||||
"err": ""
|
||||
}
|
||||
```
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
package stra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/toolkits/pkg/logger"
|
||||
"github.com/toolkits/pkg/net/httplib"
|
||||
|
||||
"github.com/didi/nightingale/src/model"
|
||||
"github.com/didi/nightingale/src/toolkits/address"
|
||||
"github.com/didi/nightingale/src/toolkits/identity"
|
||||
)
|
||||
|
||||
func GetCollects() {
|
||||
if !StraConfig.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
detect()
|
||||
go loopDetect()
|
||||
}
|
||||
|
||||
func loopDetect() {
|
||||
t1 := time.NewTicker(time.Duration(StraConfig.Interval) * time.Second)
|
||||
for {
|
||||
<-t1.C
|
||||
detect()
|
||||
}
|
||||
}
|
||||
|
||||
func detect() {
|
||||
c, err := GetCollectsRetry()
|
||||
if err != nil {
|
||||
logger.Errorf("get collect err:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Collect.Update(&c)
|
||||
}
|
||||
|
||||
type CollectResp struct {
|
||||
Dat model.Collect `json:"dat"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
func GetCollectsRetry() (model.Collect, error) {
|
||||
count := len(address.GetHTTPAddresses("monapi"))
|
||||
var resp CollectResp
|
||||
var err error
|
||||
for i := 0; i < count; i++ {
|
||||
resp, err = getCollects()
|
||||
if err == nil {
|
||||
if resp.Err != "" {
|
||||
err = fmt.Errorf(resp.Err)
|
||||
continue
|
||||
}
|
||||
return resp.Dat, err
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Dat, err
|
||||
}
|
||||
|
||||
func getCollects() (CollectResp, error) {
|
||||
addrs := address.GetHTTPAddresses("monapi")
|
||||
i := rand.Intn(len(addrs))
|
||||
addr := addrs[i]
|
||||
|
||||
var res CollectResp
|
||||
var err error
|
||||
|
||||
url := fmt.Sprintf("http://%s%s%s", addr, StraConfig.Api, identity.Identity)
|
||||
err = httplib.Get(url).SetTimeout(time.Duration(StraConfig.Timeout) * time.Millisecond).ToJSON(&res)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("get collects from remote:%s failed, error:%v", url, err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package stra
|
||||
|
||||
import "github.com/didi/nightingale/src/model"
|
||||
|
||||
var StraConfig StraSection
|
||||
var Collect model.Collect
|
||||
|
||||
type StraSection struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
Interval int `yaml:"interval"`
|
||||
Api string `yaml:"api"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
PortPath string `yaml:"portPath"`
|
||||
ProcPath string `yaml:"procPath"`
|
||||
LogPath string `yaml:"logPath"`
|
||||
}
|
||||
|
||||
///api/portal/collects/%s
|
||||
|
||||
func Init(stra StraSection) {
|
||||
StraConfig = stra
|
||||
|
||||
GetCollects()
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
package stra
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/didi/nightingale/src/model"
|
||||
|
||||
"github.com/toolkits/pkg/file"
|
||||
"github.com/toolkits/pkg/logger"
|
||||
)
|
||||
|
||||
type Strategy struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"` //监控策略名
|
||||
FilePath string `json:"file_path"` //文件路径
|
||||
TimeFormat string `json:"time_format"` //时间格式
|
||||
Pattern string `json:"pattern"` //表达式
|
||||
Exclude string `json:"-"`
|
||||
MeasurementType string `json:"measurement_type"`
|
||||
Interval int64 `json:"interval"` //采集周期
|
||||
Tags map[string]string `json:"tags"`
|
||||
Func string `json:"func"` //采集方式(max/min/avg/cnt)
|
||||
Degree int64 `json:"degree"`
|
||||
Unit string `json:"unit"`
|
||||
Comment string `json:"comment"`
|
||||
Creator string `json:"creator"`
|
||||
SrvUpdated string `json:"updated"`
|
||||
LocalUpdated int64 `json:"-"`
|
||||
TimeReg *regexp.Regexp `json:"-"`
|
||||
PatternReg *regexp.Regexp `json:"-"`
|
||||
ExcludeReg *regexp.Regexp `json:"-"`
|
||||
TagRegs map[string]*regexp.Regexp `json:"-"`
|
||||
ParseSucc bool `json:"parse_succ"`
|
||||
}
|
||||
|
||||
func GetLogCollects() []*Strategy {
|
||||
var stras []*Strategy
|
||||
if StraConfig.Enable {
|
||||
strasMap := Collect.GetLogConfig()
|
||||
|
||||
for _, s := range strasMap {
|
||||
stra := ToStrategy(s)
|
||||
stras = append(stras, stra)
|
||||
}
|
||||
}
|
||||
|
||||
//从文件中读取
|
||||
stras = append(stras, GetCollectFromFile(StraConfig.LogPath)...)
|
||||
|
||||
parsePattern(stras)
|
||||
updateRegs(stras)
|
||||
|
||||
return stras
|
||||
}
|
||||
|
||||
func GetCollectFromFile(logPath string) []*Strategy {
|
||||
logger.Info("get collects from local file")
|
||||
var stras []*Strategy
|
||||
|
||||
files, err := file.FilesUnder(logPath)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return stras
|
||||
}
|
||||
|
||||
//扫描文件采集配置
|
||||
for _, f := range files {
|
||||
err := checkName(f)
|
||||
if err != nil {
|
||||
logger.Warningf("read file name err:%s %v", f, err)
|
||||
continue
|
||||
}
|
||||
|
||||
stra := Strategy{}
|
||||
|
||||
b, err := file.ToBytes(logPath + "/" + f)
|
||||
if err != nil {
|
||||
logger.Warningf("read file name err:%s %v", f, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &stra)
|
||||
if err != nil {
|
||||
logger.Warningf("read file name err:%s %v", f, err)
|
||||
continue
|
||||
}
|
||||
|
||||
//todo 配置校验
|
||||
|
||||
stra.ID = genStraID(stra.Name, string(b))
|
||||
stras = append(stras, &stra)
|
||||
}
|
||||
|
||||
return stras
|
||||
}
|
||||
|
||||
func genStraID(name, body string) int64 {
|
||||
var id int64
|
||||
all := name + body
|
||||
if len(all) < 1 {
|
||||
return id
|
||||
}
|
||||
|
||||
id = int64(all[0])
|
||||
|
||||
for i := 1; i < len(all); i++ {
|
||||
id += int64(all[i])
|
||||
id += int64(all[i] - all[i-1])
|
||||
}
|
||||
|
||||
id += 1000000 //避免与web端配置的id冲突
|
||||
return id
|
||||
}
|
||||
|
||||
func ToStrategy(p *model.LogCollect) *Strategy {
|
||||
s := Strategy{}
|
||||
s.ID = p.Id
|
||||
s.Name = p.Name
|
||||
s.FilePath = p.FilePath
|
||||
s.TimeFormat = p.TimeFormat
|
||||
s.Pattern = p.Pattern
|
||||
s.MeasurementType = p.CollectType
|
||||
s.Interval = int64(p.Step)
|
||||
s.Tags = DeepCopyStringMap(p.Tags)
|
||||
s.Func = p.Func
|
||||
s.Degree = int64(p.Degree)
|
||||
s.Unit = p.Unit
|
||||
s.Comment = p.Comment
|
||||
s.Creator = p.Creator
|
||||
s.SrvUpdated = p.LastUpdated.String()
|
||||
s.LocalUpdated = p.LocalUpdated
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
func DeepCopyStringMap(p map[string]string) map[string]string {
|
||||
r := make(map[string]string, len(p))
|
||||
for k, v := range p {
|
||||
r[k] = v
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
const PATTERN_EXCLUDE_PARTITION = "```EXCLUDE```"
|
||||
|
||||
func parsePattern(strategies []*Strategy) {
|
||||
for _, st := range strategies {
|
||||
patList := strings.Split(st.Pattern, PATTERN_EXCLUDE_PARTITION)
|
||||
|
||||
if len(patList) == 1 {
|
||||
st.Pattern = strings.TrimSpace(st.Pattern)
|
||||
continue
|
||||
} else if len(patList) >= 2 {
|
||||
st.Pattern = strings.TrimSpace(patList[0])
|
||||
st.Exclude = strings.TrimSpace(patList[1])
|
||||
continue
|
||||
} else {
|
||||
logger.Errorf("bad pattern to parse : [%s]", st.Pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateRegs(strategies []*Strategy) {
|
||||
for _, st := range strategies {
|
||||
st.TagRegs = make(map[string]*regexp.Regexp)
|
||||
st.ParseSucc = false
|
||||
|
||||
//更新时间正则
|
||||
pat, _ := GetPatAndTimeFormat(st.TimeFormat)
|
||||
reg, err := regexp.Compile(pat)
|
||||
if err != nil {
|
||||
logger.Errorf("compile time regexp failed:[sid:%d][format:%s][pat:%s][err:%v]", st.ID, st.TimeFormat, pat, err)
|
||||
continue
|
||||
}
|
||||
st.TimeReg = reg //拿到时间正则
|
||||
|
||||
if len(st.Pattern) == 0 && len(st.Exclude) == 0 {
|
||||
logger.Errorf("pattern and exclude are all empty, sid:[%d]", st.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
//更新pattern
|
||||
if len(st.Pattern) != 0 {
|
||||
reg, err = regexp.Compile(st.Pattern)
|
||||
if err != nil {
|
||||
logger.Errorf("compile pattern regexp failed:[sid:%d][pat:%s][err:%v]", st.ID, st.Pattern, err)
|
||||
continue
|
||||
}
|
||||
st.PatternReg = reg
|
||||
}
|
||||
|
||||
//更新exclude
|
||||
if len(st.Exclude) != 0 {
|
||||
reg, err = regexp.Compile(st.Exclude)
|
||||
if err != nil {
|
||||
logger.Errorf("compile exclude regexp failed:[sid:%d][pat:%s][err:%v]", st.ID, st.Exclude, err)
|
||||
continue
|
||||
}
|
||||
st.ExcludeReg = reg
|
||||
}
|
||||
|
||||
//更新tags
|
||||
for tagk, tagv := range st.Tags {
|
||||
reg, err = regexp.Compile(tagv)
|
||||
if err != nil {
|
||||
logger.Errorf("compile tag failed:[sid:%d][pat:%s][err:%v]", st.ID, st.Exclude, err)
|
||||
continue
|
||||
}
|
||||
st.TagRegs[tagk] = reg
|
||||
}
|
||||
st.ParseSucc = true
|
||||
}
|
||||
}
|
||||
|
||||
func checkName(f string) (err error) {
|
||||
if !strings.Contains(f, "log.") {
|
||||
err = fmt.Errorf("name illege not contain log. %s", f)
|
||||
return
|
||||
}
|
||||
|
||||
arr := strings.Split(f, ".")
|
||||
if len(arr) < 3 {
|
||||
err = fmt.Errorf("name illege %s len:%d len < 3 ", f, len(arr))
|
||||
return
|
||||
}
|
||||
|
||||
if arr[len(arr)-1] != "json" {
|
||||
err = fmt.Errorf("name illege %s not json file", f)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetPatAndTimeFormat(tf string) (string, string) {
|
||||
var pat, timeFormat string
|
||||
switch tf {
|
||||
case "dd/mmm/yyyy:HH:MM:SS":
|
||||
pat = `([012][0-9]|3[01])/[JFMASONDjfmasond][a-zA-Z]{2}/(2[0-9]{3}):([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "02/Jan/2006:15:04:05"
|
||||
case "dd/mmm/yyyy HH:MM:SS":
|
||||
pat = `([012][0-9]|3[01])/[JFMASONDjfmasond][a-zA-Z]{2}/(2[0-9]{3})\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "02/Jan/2006 15:04:05"
|
||||
case "yyyy-mm-ddTHH:MM:SS":
|
||||
pat = `(2[0-9]{3})-(0[1-9]|1[012])-([012][0-9]|3[01])T([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "2006-01-02T15:04:05"
|
||||
case "dd-mmm-yyyy HH:MM:SS":
|
||||
pat = `([012][0-9]|3[01])-[JFMASONDjfmasond][a-zA-Z]{2}-(2[0-9]{3})\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "02-Jan-2006 15:04:05"
|
||||
case "yyyy-mm-dd HH:MM:SS":
|
||||
pat = `(2[0-9]{3})-(0[1-9]|1[012])-([012][0-9]|3[01])\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "2006-01-02 15:04:05"
|
||||
case "yyyy/mm/dd HH:MM:SS":
|
||||
pat = `(2[0-9]{3})/(0[1-9]|1[012])/([012][0-9]|3[01])\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "2006/01/02 15:04:05"
|
||||
case "yyyymmdd HH:MM:SS":
|
||||
pat = `(2[0-9]{3})(0[1-9]|1[012])([012][0-9]|3[01])\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "20060102 15:04:05"
|
||||
case "mmm dd HH:MM:SS":
|
||||
pat = `[JFMASONDjfmasond][a-zA-Z]{2}\s+([1-9]|[1-2][0-9]|3[01])\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "Jan 2 15:04:05"
|
||||
case "mmdd HH:MM:SS":
|
||||
pat = `(0[1-9]|1[012])([012][0-9]|3[01])\s([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "0102 15:04:05"
|
||||
case "dd/mm/yyyy:HH:MM:SS":
|
||||
pat = `([012][0-9]|3[01])/(0[1-9]|1[012])/(2[0-9]{3}):([01][0-9]|2[0-4])(:[012345][0-9]){2}`
|
||||
timeFormat = "02/01/2006:15:04:05"
|
||||
default:
|
||||
logger.Errorf("match time pac failed : [timeFormat:%s]", tf)
|
||||
return "", ""
|
||||
}
|
||||
return pat, timeFormat
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package stra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPatternParse(t *testing.T) {
|
||||
fmt.Println("Now Test PatternParse:")
|
||||
var a Strategy
|
||||
a.Pattern = "test"
|
||||
parsePattern([]*Strategy{&a})
|
||||
fmt.Printf("a.pat:[%s], a.ex[%s]\n", a.Pattern, a.Exclude)
|
||||
a.Pattern = "```EXCLUDE```test"
|
||||
parsePattern([]*Strategy{&a})
|
||||
fmt.Printf("a.pat:[%s], a.ex[%s]\n", a.Pattern, a.Exclude)
|
||||
a.Pattern = "test```EXCLUDE```"
|
||||
parsePattern([]*Strategy{&a})
|
||||
fmt.Printf("a.pat:[%s], a.ex[%s]\n", a.Pattern, a.Exclude)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue