commit
0fd6176ac6
|
@ -0,0 +1 @@
|
||||||
|
web
|
|
@ -0,0 +1,28 @@
|
||||||
|
FROM golang AS builder
|
||||||
|
# RUN apk add --no-cache git gcc
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# comment this if using vendor
|
||||||
|
# ENV GOPROXY=https://mod.gokit.info
|
||||||
|
# COPY go.mod go.sum ./
|
||||||
|
# RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
ENV GOPROXY=https://mod.gokit.info
|
||||||
|
RUN ./control build docker
|
||||||
|
|
||||||
|
FROM buildpack-deps:buster-curl
|
||||||
|
LABEL maintainer="llitfkitfk@gmail.com"
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/docker/scripts /app/scripts
|
||||||
|
COPY --from=builder /app/etc /app/etc
|
||||||
|
# Change default address (hard code)
|
||||||
|
RUN ./scripts/sed.sh
|
||||||
|
|
||||||
|
COPY --from=builder /app/bin /usr/local/bin
|
||||||
|
|
||||||
|
|
||||||
|
# ENTRYPOINT []
|
||||||
|
# CMD []
|
12
README.md
12
README.md
|
@ -15,7 +15,17 @@ Nightingale user manual: [https://n9e.didiyun.com/](https://n9e.didiyun.com/)
|
||||||
mkdir -p $GOPATH/src/github.com/didi
|
mkdir -p $GOPATH/src/github.com/didi
|
||||||
cd $GOPATH/src/github.com/didi
|
cd $GOPATH/src/github.com/didi
|
||||||
git clone https://github.com/didi/nightingale.git
|
git clone https://github.com/didi/nightingale.git
|
||||||
cd nightingale && ./control build
|
cd nightingale
|
||||||
|
# export env[GOPROXY] if your network is not good
|
||||||
|
# export GOPROXY=https://mirrors.aliyun.com/goproxy/
|
||||||
|
./control build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start (need install docker for [mac](https://docs.docker.com/docker-for-mac/install/)/[win](https://docs.docker.com/docker-for-windows/install/))
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
# open http://localhost in web browser
|
||||||
```
|
```
|
||||||
|
|
||||||
## Team
|
## Team
|
||||||
|
|
|
@ -15,7 +15,10 @@ Nightingale是一套衍生自Open-Falcon的互联网监控解决方案,融入
|
||||||
mkdir -p $GOPATH/src/github.com/didi
|
mkdir -p $GOPATH/src/github.com/didi
|
||||||
cd $GOPATH/src/github.com/didi
|
cd $GOPATH/src/github.com/didi
|
||||||
git clone https://github.com/didi/nightingale.git
|
git clone https://github.com/didi/nightingale.git
|
||||||
cd nightingale && ./control build
|
cd nightingale
|
||||||
|
# 如果网络环境不好可以尝试aliyun的mirror
|
||||||
|
# export GOPROXY=https://mirrors.aliyun.com/goproxy/
|
||||||
|
./control build
|
||||||
```
|
```
|
||||||
|
|
||||||
## 团队
|
## 团队
|
||||||
|
|
18
control
18
control
|
@ -139,8 +139,16 @@ build_one()
|
||||||
go build -o n9e-${mod} --tags "md5" src/modules/${mod}/${mod}.go
|
go build -o n9e-${mod} --tags "md5" src/modules/${mod}/${mod}.go
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_docker()
|
||||||
|
{
|
||||||
|
mod=$1
|
||||||
|
go build -o bin/n9e-${mod} --tags "md5" src/modules/${mod}/${mod}.go
|
||||||
|
}
|
||||||
|
|
||||||
build()
|
build()
|
||||||
{
|
{
|
||||||
|
export GO111MODULE=on
|
||||||
|
|
||||||
mod=$1
|
mod=$1
|
||||||
if [ "x${mod}" = "x" ]; then
|
if [ "x${mod}" = "x" ]; then
|
||||||
build_one monapi
|
build_one monapi
|
||||||
|
@ -152,6 +160,16 @@ build()
|
||||||
return
|
return
|
||||||
fi
|
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
|
build_one $mod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
version: "3"
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:stable-alpine
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
volumes:
|
||||||
|
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ./docker/nginx/conf.d:/etc/nginx/conf.d
|
||||||
|
- ./pub:/home/n9e/pub
|
||||||
|
api:
|
||||||
|
build: .
|
||||||
|
image: api
|
||||||
|
|
||||||
|
monapi:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-monapi
|
||||||
|
ports:
|
||||||
|
- 5800:5800
|
||||||
|
|
||||||
|
transfer:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-transfer
|
||||||
|
ports:
|
||||||
|
- 5810:5810
|
||||||
|
- 5811:5811
|
||||||
|
|
||||||
|
tsdb:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-tsdb
|
||||||
|
ports:
|
||||||
|
- 5820:5820
|
||||||
|
- 5821:5821
|
||||||
|
|
||||||
|
index:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-index
|
||||||
|
ports:
|
||||||
|
- 5830:5830
|
||||||
|
- 5831:5831
|
||||||
|
|
||||||
|
judge:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-judge
|
||||||
|
ports:
|
||||||
|
- 5840:5840
|
||||||
|
- 5841:5841
|
||||||
|
|
||||||
|
collector:
|
||||||
|
image: api
|
||||||
|
restart: always
|
||||||
|
command: n9e-collector
|
||||||
|
ports:
|
||||||
|
- 2058:2058
|
||||||
|
|
||||||
|
# web:
|
||||||
|
# build:
|
||||||
|
# context: web
|
||||||
|
# restart: always
|
||||||
|
# command: npm run dev
|
||||||
|
# ports:
|
||||||
|
# - 8010:8010
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:5.7
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=1234
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
volumes:
|
||||||
|
- ./sql:/docker-entrypoint-initdb.d
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
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 monapi:5800;
|
||||||
|
keepalive 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream n9e.index {
|
||||||
|
server index:5830;
|
||||||
|
keepalive 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream n9e.transfer {
|
||||||
|
server transfer: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
sed -i 's/127.0.0.1:6379/redis:6379/g' /app/etc/judge.yml
|
||||||
|
sed -i 's/127.0.0.1:6379/redis:6379/g' /app/etc/monapi.yml
|
||||||
|
sed -i 's/127.0.0.1:3306/mysql:3306/g' /app/etc/mysql.yml
|
||||||
|
sed -i 's/127.0.0.1:5821/tsdb:5821/g' /app/etc/transfer.yml
|
|
@ -1,11 +1,10 @@
|
||||||
# use shell if specify is blank
|
|
||||||
logger:
|
logger:
|
||||||
dir: logs/collector
|
dir: logs/collector
|
||||||
level: WARNING
|
level: WARNING
|
||||||
keepHours: 2
|
keepHours: 2
|
||||||
identity:
|
identity:
|
||||||
specify: ""
|
specify: ""
|
||||||
shell: /usr/sbin/ifconfig `/usr/sbin/route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1
|
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||||
sys:
|
sys:
|
||||||
# timeout in ms
|
# timeout in ms
|
||||||
# interval in second
|
# interval in second
|
||||||
|
|
|
@ -4,4 +4,4 @@ logger:
|
||||||
keepHours: 2
|
keepHours: 2
|
||||||
identity:
|
identity:
|
||||||
specify: ""
|
specify: ""
|
||||||
shell: /usr/sbin/ifconfig `/usr/sbin/route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1
|
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||||
|
|
|
@ -6,6 +6,7 @@ query:
|
||||||
redis:
|
redis:
|
||||||
addrs:
|
addrs:
|
||||||
- 127.0.0.1:6379
|
- 127.0.0.1:6379
|
||||||
|
db: 0
|
||||||
pass: ""
|
pass: ""
|
||||||
# timeout:
|
# timeout:
|
||||||
# conn: 500
|
# conn: 500
|
||||||
|
@ -14,7 +15,7 @@ redis:
|
||||||
|
|
||||||
identity:
|
identity:
|
||||||
specify: ""
|
specify: ""
|
||||||
shell: /usr/sbin/ifconfig `/usr/sbin/route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|head -n 1
|
shell: ifconfig `route|grep '^default'|awk '{print $NF}'`|grep inet|awk '{print $2}'|awk -F ':' '{print $NF}'|head -n 1
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
dir: logs/judge
|
dir: logs/judge
|
||||||
|
|
|
@ -14,11 +14,19 @@ ldap:
|
||||||
host: "ldap.example.org"
|
host: "ldap.example.org"
|
||||||
port: 389
|
port: 389
|
||||||
baseDn: "dc=example,dc=org"
|
baseDn: "dc=example,dc=org"
|
||||||
|
# AD: manange@example.org
|
||||||
bindUser: "cn=manager,dc=example,dc=org"
|
bindUser: "cn=manager,dc=example,dc=org"
|
||||||
bindPass: "*******"
|
bindPass: "*******"
|
||||||
# openldap: (&(uid=%s))
|
# openldap: (&(uid=%s))
|
||||||
# AD: (&(sAMAccountName=%s))
|
# AD: (&(sAMAccountName=%s))
|
||||||
authFilter: "(&(uid=%s))"
|
authFilter: "(&(uid=%s))"
|
||||||
|
attributes:
|
||||||
|
dispname: "cn"
|
||||||
|
email: "mail"
|
||||||
|
phone: "mobile"
|
||||||
|
im: ""
|
||||||
|
coverAttributes: false
|
||||||
|
autoRegist: false
|
||||||
tls: false
|
tls: false
|
||||||
startTLS: false
|
startTLS: false
|
||||||
|
|
||||||
|
@ -44,6 +52,7 @@ link:
|
||||||
# for alarm event and message queue
|
# for alarm event and message queue
|
||||||
redis:
|
redis:
|
||||||
addr: "127.0.0.1:6379"
|
addr: "127.0.0.1:6379"
|
||||||
|
db: 0
|
||||||
pass: ""
|
pass: ""
|
||||||
# in ms
|
# in ms
|
||||||
# timeout:
|
# timeout:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
user nginx;
|
user root;
|
||||||
|
|
||||||
worker_processes auto;
|
worker_processes auto;
|
||||||
worker_cpu_affinity auto;
|
worker_cpu_affinity auto;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-collector
|
|
@ -1 +0,0 @@
|
||||||
sshd
|
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-monapi
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-transfer
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-tsdb
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-index
|
|
@ -0,0 +1 @@
|
||||||
|
n9e-judge
|
|
@ -1 +0,0 @@
|
||||||
{"version":3,"file":"index-3eb7c9ca4d88e3ad5c58.js","sources":["webpack:///index-3eb7c9ca4d88e3ad5c58.js"],"mappings":"AAAA;;;;;;;AAmsYA","sourceRoot":""}
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"index-5c8cbf958683e20086f5.js","sources":["webpack:///index-5c8cbf958683e20086f5.js"],"mappings":"AAAA;;;;;;;AAmsYA","sourceRoot":""}
|
|
@ -1 +1 @@
|
||||||
<!doctype html><html><head><meta charset="UTF-8"><title>Nightingale</title><link rel="shortcut icon" href="/favicon.ico"><link href="/index-3eb7c9ca4d88e3ad5c58.css" rel="stylesheet"></head><body><div id="react-content"></div><script src="/lib-033bee8514de110e36ef.dll.js"></script><script src="/index-3eb7c9ca4d88e3ad5c58.js"></script></body></html>
|
<!doctype html><html><head><meta charset="UTF-8"><title>Nightingale</title><link rel="shortcut icon" href="/favicon.ico"><link href="/index-5c8cbf958683e20086f5.css" rel="stylesheet"></head><body><div id="react-content"></div><script src="/lib-033bee8514de110e36ef.dll.js"></script><script src="/index-5c8cbf958683e20086f5.js"></script></body></html>
|
|
@ -91,8 +91,8 @@ create table `tmp_chart` (
|
||||||
create table `event_cur` (
|
create table `event_cur` (
|
||||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||||
`sname` varchar(256) not null default '' comment 'name, 报警通知名称',
|
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||||
`node_path` varchar(256) not null default '' comment 'node path',
|
`node_path` varchar(255) not null default '' comment 'node path',
|
||||||
`nid` int unsigned not null default '0' comment 'node id',
|
`nid` int unsigned not null default '0' comment 'node id',
|
||||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||||
|
@ -103,7 +103,7 @@ create table `event_cur` (
|
||||||
`detail` text comment 'counter points pred_points 详情',
|
`detail` text comment 'counter points pred_points 详情',
|
||||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||||
`value` varchar(256) not null default '' comment '当前值',
|
`value` varchar(255) not null default '' comment '当前值',
|
||||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||||
`info` varchar(512) not null default '' comment 'strategy info',
|
`info` varchar(512) not null default '' comment 'strategy info',
|
||||||
|
@ -122,8 +122,8 @@ create table `event_cur` (
|
||||||
create table `event` (
|
create table `event` (
|
||||||
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
`id` bigint(20) unsigned not null AUTO_INCREMENT comment 'id',
|
||||||
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
`sid` bigint(20) unsigned not null default 0 comment 'sid',
|
||||||
`sname` varchar(256) not null default '' comment 'name, 报警通知名称',
|
`sname` varchar(255) not null default '' comment 'name, 报警通知名称',
|
||||||
`node_path` varchar(256) not null default '' comment 'node path',
|
`node_path` varchar(255) not null default '' comment 'node path',
|
||||||
`nid` int unsigned not null default '0' comment 'node id',
|
`nid` int unsigned not null default '0' comment 'node id',
|
||||||
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
`endpoint` varchar(255) not null default '' comment 'endpoint',
|
||||||
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
`endpoint_alias` varchar(255) not null default '' comment 'endpoint alias',
|
||||||
|
@ -134,7 +134,7 @@ create table `event` (
|
||||||
`detail` text comment 'counter points pred_points 详情',
|
`detail` text comment 'counter points pred_points 详情',
|
||||||
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
`hashid` varchar(128) not null default '' comment 'sid+counter hash',
|
||||||
`etime` bigint(20) not null default 0 comment 'event ts',
|
`etime` bigint(20) not null default 0 comment 'event ts',
|
||||||
`value` varchar(256) not null default '' comment '当前值',
|
`value` varchar(255) not null default '' comment '当前值',
|
||||||
`users` varchar(512) not null default '[]' comment 'notify users',
|
`users` varchar(512) not null default '[]' comment 'notify users',
|
||||||
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
`groups` varchar(512) not null default '[]' comment 'notify groups',
|
||||||
`info` varchar(512) not null default '' comment 'strategy info',
|
`info` varchar(512) not null default '' comment 'strategy info',
|
||||||
|
@ -167,8 +167,8 @@ CREATE TABLE `stra` (
|
||||||
`converge` varchar(45) NOT NULL DEFAULT '' COMMENT 'n秒最多报m次警',
|
`converge` varchar(45) NOT NULL DEFAULT '' COMMENT 'n秒最多报m次警',
|
||||||
`recovery_notify` int(1) NOT NULL DEFAULT 1 COMMENT '1 发送恢复通知 0不发送恢复通知',
|
`recovery_notify` int(1) NOT NULL DEFAULT 1 COMMENT '1 发送恢复通知 0不发送恢复通知',
|
||||||
`priority` int(1) NOT NULL DEFAULT 3 COMMENT '告警等级',
|
`priority` int(1) NOT NULL DEFAULT 3 COMMENT '告警等级',
|
||||||
`notify_group` varchar(256) NOT NULL DEFAULT '' COMMENT '告警通知组',
|
`notify_group` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知组',
|
||||||
`notify_user` varchar(256) NOT NULL DEFAULT '' COMMENT '告警通知人',
|
`notify_user` varchar(255) NOT NULL DEFAULT '' COMMENT '告警通知人',
|
||||||
`callback` varchar(1024) NOT NULL DEFAULT '' COMMENT 'callback url',
|
`callback` varchar(1024) NOT NULL DEFAULT '' COMMENT 'callback url',
|
||||||
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
`creator` varchar(64) NOT NULL COMMENT '创建者',
|
||||||
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
`created` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' COMMENT 'created',
|
||||||
|
|
|
@ -63,17 +63,14 @@ func (m *MetricValue) CheckValidity() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//将保留字替换
|
//检测保留字
|
||||||
var illegal bool
|
if HasReservedWords(m.Metric) {
|
||||||
m.Metric, illegal = ReplaceReservedWords(m.Metric)
|
err = fmt.Errorf("metric:%s contains reserved words:[\\t] [\\r] [\\n] [,] [ ] [=]", m.Metric)
|
||||||
if illegal {
|
|
||||||
err = fmt.Errorf("Metric contains reserved word")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Endpoint, illegal = ReplaceReservedWords(m.Endpoint)
|
if HasReservedWords(m.Endpoint) {
|
||||||
if illegal {
|
err = fmt.Errorf("endpoint:%s contains reserved words:[\\t] [\\r] [\\n] [,] [ ] [=]", m.Endpoint)
|
||||||
err = fmt.Errorf("Endpoint contains reserved word:%s", m.Endpoint)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +148,7 @@ func (m *MetricValue) CheckValidity() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReplaceReservedWords(str string) (string, bool) {
|
func HasReservedWords(str string) bool {
|
||||||
if -1 == strings.IndexFunc(str,
|
if -1 == strings.IndexFunc(str,
|
||||||
func(r rune) bool {
|
func(r rune) bool {
|
||||||
return r == '\t' ||
|
return r == '\t' ||
|
||||||
|
@ -159,27 +156,13 @@ func ReplaceReservedWords(str string) (string, bool) {
|
||||||
r == '\n' ||
|
r == '\n' ||
|
||||||
r == ',' ||
|
r == ',' ||
|
||||||
r == ' ' ||
|
r == ' ' ||
|
||||||
r == ':' ||
|
|
||||||
r == '='
|
r == '='
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
return str, false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Map(func(r rune) rune {
|
return true
|
||||||
if r == '\t' ||
|
|
||||||
r == '\r' ||
|
|
||||||
r == '\n' ||
|
|
||||||
r == ',' ||
|
|
||||||
r == ' ' ||
|
|
||||||
r == ':' ||
|
|
||||||
r == '=' {
|
|
||||||
return '_'
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}, str), true
|
|
||||||
|
|
||||||
return str, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SortedTags(tags map[string]string) string {
|
func SortedTags(tags map[string]string) string {
|
||||||
|
|
|
@ -24,6 +24,17 @@ type QueryDataForUI struct {
|
||||||
Comparisons []int64 `json:"comparisons"` //环比多少时间
|
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 {
|
type QueryDataResp struct {
|
||||||
Data []*TsdbQueryResponse
|
Data []*TsdbQueryResponse
|
||||||
Msg string
|
Msg string
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -79,7 +79,7 @@ func NodeQueryPath(query string, limit int) (nodes []Node, err error) {
|
||||||
|
|
||||||
func TreeSearchByPath(query string) (nodes []Node, err error) {
|
func TreeSearchByPath(query string) (nodes []Node, err error) {
|
||||||
session := DB["mon"].NewSession()
|
session := DB["mon"].NewSession()
|
||||||
defer session.Clone()
|
defer session.Close()
|
||||||
|
|
||||||
if strings.Contains(query, " ") {
|
if strings.Contains(query, " ") {
|
||||||
arr := strings.Fields(query)
|
arr := strings.Fields(query)
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Team struct {
|
||||||
|
|
||||||
func (t *Team) Del() error {
|
func (t *Team) Del() error {
|
||||||
session := DB["uic"].NewSession()
|
session := DB["uic"].NewSession()
|
||||||
defer session.Clone()
|
defer session.Close()
|
||||||
|
|
||||||
if err := session.Begin(); err != nil {
|
if err := session.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -118,6 +117,23 @@ func (u *User) CanModifyTeam(t *Team) (bool, error) {
|
||||||
return cnt > 0, err
|
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)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func InitRoot() {
|
func InitRoot() {
|
||||||
var u User
|
var u User
|
||||||
has, err := DB["uic"].Where("username=?", "root").Get(&u)
|
has, err := DB["uic"].Where("username=?", "root").Get(&u)
|
||||||
|
@ -147,78 +163,31 @@ func InitRoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func LdapLogin(user, pass string) error {
|
func LdapLogin(user, pass string) error {
|
||||||
var conn *ldap.Conn
|
sr, err := ldapReq(user, pass)
|
||||||
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 fmt.Errorf("cannot dial ldap: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
if !lc.TLS && lc.StartTLS {
|
|
||||||
err = conn.StartTLS(&tls.Config{InsecureSkipVerify: true})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ldap.conn startTLS fail: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.Bind(lc.BindUser, lc.BindPass)
|
|
||||||
if err != nil {
|
|
||||||
return 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
|
|
||||||
[]string{}, // A list attributes to retrieve
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
sr, err := conn.Search(searchRequest)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ldap search fail: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sr.Entries) == 0 {
|
|
||||||
return fmt.Errorf("cannot find such user: %v", user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sr.Entries) > 1 {
|
|
||||||
return fmt.Errorf("multi users is search, query user: %v", user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.Bind(sr.Entries[0].DN, pass)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("password error")
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt, err := DB["uic"].Where("username=?", user).Count(new(User))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cnt > 0 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
u := &User{
|
if !config.Get().LDAP.AutoRegist {
|
||||||
Username: user,
|
return fmt.Errorf("user has not be created, may be you should enable auto regist: %v", user)
|
||||||
Password: "******",
|
|
||||||
Dispname: "",
|
|
||||||
Email: "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.Username = user
|
||||||
|
u.Password = "******"
|
||||||
_, err = DB["uic"].Insert(u)
|
_, err = DB["uic"].Insert(u)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@ func main() {
|
||||||
identity.Init(cfg.Identity)
|
identity.Init(cfg.Identity)
|
||||||
if identity.Identity == "127.0.0.1" {
|
if identity.Identity == "127.0.0.1" {
|
||||||
log.Fatalln("endpoint: 127.0.0.1, cannot work")
|
log.Fatalln("endpoint: 127.0.0.1, cannot work")
|
||||||
|
} else {
|
||||||
|
log.Println("endpoint:", identity.Identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.Init(cfg.Sys)
|
sys.Init(cfg.Sys)
|
||||||
|
@ -70,7 +72,6 @@ func main() {
|
||||||
|
|
||||||
funcs.BuildMappers()
|
funcs.BuildMappers()
|
||||||
funcs.Collect()
|
funcs.Collect()
|
||||||
stra.GetCollects()
|
|
||||||
|
|
||||||
//插件采集
|
//插件采集
|
||||||
plugins.Detect()
|
plugins.Detect()
|
||||||
|
@ -137,6 +138,5 @@ func ending() {
|
||||||
func start() {
|
func start() {
|
||||||
runner.Init()
|
runner.Init()
|
||||||
fmt.Println("collector start, use configuration file:", *conf)
|
fmt.Println("collector start, use configuration file:", *conf)
|
||||||
fmt.Println("runner.Cwd:", runner.Cwd)
|
fmt.Println("runner.cwd:", runner.Cwd)
|
||||||
fmt.Println("runner.Endpoint:", runner.Hostname)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,16 +62,16 @@ func Parse(conf string) error {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"timeout": 1000,
|
"timeout": 1000,
|
||||||
"interval": 10, //采集策略更新时间
|
"interval": 10, //采集策略更新时间
|
||||||
"portPath": "/home/n9e/etc/port",
|
"portPath": "./etc/port",
|
||||||
"procPath": "/home/n9e/etc/proc",
|
"procPath": "./etc/proc",
|
||||||
"logPath": "/home/n9e/etc/log",
|
"logPath": "./etc/log",
|
||||||
"api": "/api/portal/collects/",
|
"api": "/api/portal/collects/",
|
||||||
})
|
})
|
||||||
|
|
||||||
viper.SetDefault("sys", map[string]interface{}{
|
viper.SetDefault("sys", map[string]interface{}{
|
||||||
"timeout": 1000, //请求超时时间
|
"timeout": 1000, //请求超时时间
|
||||||
"interval": 10, //基础指标上报周期
|
"interval": 10, //基础指标上报周期
|
||||||
"plugin": "/home/n9e/plugin",
|
"plugin": "./plugin",
|
||||||
})
|
})
|
||||||
|
|
||||||
err = viper.Unmarshal(&Config)
|
err = viper.Unmarshal(&Config)
|
||||||
|
|
|
@ -18,9 +18,9 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Update() error {
|
func Update() error {
|
||||||
strategys := stra.GetLogCollects()
|
strategies := stra.GetLogCollects()
|
||||||
|
|
||||||
err := UpdateGlobalStrategy(strategys)
|
err := UpdateGlobalStrategy(strategies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Update Strategy cache error ! [msg:%v]", err)
|
logger.Errorf("Update Strategy cache error ! [msg:%v]", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -74,7 +74,7 @@ func getCollects() (CollectResp, error) {
|
||||||
url := fmt.Sprintf("http://%s%s%s", addr, StraConfig.Api, identity.Identity)
|
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)
|
err = httplib.Get(url).SetTimeout(time.Duration(StraConfig.Timeout) * time.Millisecond).ToJSON(&res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("get collects from remote failed, error:%v", err)
|
err = fmt.Errorf("get collects from remote:%s failed, error:%v", url, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -146,8 +146,8 @@ func DeepCopyStringMap(p map[string]string) map[string]string {
|
||||||
|
|
||||||
const PATTERN_EXCLUDE_PARTITION = "```EXCLUDE```"
|
const PATTERN_EXCLUDE_PARTITION = "```EXCLUDE```"
|
||||||
|
|
||||||
func parsePattern(strategys []*Strategy) {
|
func parsePattern(strategies []*Strategy) {
|
||||||
for _, st := range strategys {
|
for _, st := range strategies {
|
||||||
patList := strings.Split(st.Pattern, PATTERN_EXCLUDE_PARTITION)
|
patList := strings.Split(st.Pattern, PATTERN_EXCLUDE_PARTITION)
|
||||||
|
|
||||||
if len(patList) == 1 {
|
if len(patList) == 1 {
|
||||||
|
@ -163,8 +163,8 @@ func parsePattern(strategys []*Strategy) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRegs(strategys []*Strategy) {
|
func updateRegs(strategies []*Strategy) {
|
||||||
for _, st := range strategys {
|
for _, st := range strategies {
|
||||||
st.TagRegs = make(map[string]*regexp.Regexp, 0)
|
st.TagRegs = make(map[string]*regexp.Regexp, 0)
|
||||||
st.ParseSucc = false
|
st.ParseSucc = false
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,9 @@ func Push(items []*dataobj.MetricValue) {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
logger.Info("push succ, reply: ", reply)
|
if reply.Msg != "ok" {
|
||||||
|
logger.Error("some item push err", reply)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ func ListPlugins(dir string) map[string]*Plugin {
|
||||||
filename := f.Name()
|
filename := f.Name()
|
||||||
arr := strings.Split(filename, "_")
|
arr := strings.Split(filename, "_")
|
||||||
if len(arr) < 2 {
|
if len(arr) < 2 {
|
||||||
|
logger.Warningf("plugin:%s name illegal, should be: $cycle_$xx", filename)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +40,16 @@ func ListPlugins(dir string) map[string]*Plugin {
|
||||||
var cycle int
|
var cycle int
|
||||||
cycle, err = strconv.Atoi(arr[0])
|
cycle, err = strconv.Atoi(arr[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Warningf("plugin:%s name illegal, should be: $cycle_$xx %v", filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fpath, err := filepath.Abs(filepath.Join(dir, filename))
|
||||||
|
if err != nil {
|
||||||
|
logger.Warningf("plugin:%s absolute path get err:%v", filename, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fpath := filepath.Join(dir, filename)
|
|
||||||
plugin := &Plugin{FilePath: fpath, MTime: f.ModTime().Unix(), Cycle: cycle}
|
plugin := &Plugin{FilePath: fpath, MTime: f.ModTime().Unix(), Cycle: cycle}
|
||||||
ret[fpath] = plugin
|
ret[fpath] = plugin
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,7 @@ func PluginRun(plugin *Plugin) {
|
||||||
|
|
||||||
timeout := plugin.Cycle*1000 - 500 //比运行周期少500毫秒
|
timeout := plugin.Cycle*1000 - 500 //比运行周期少500毫秒
|
||||||
|
|
||||||
fpath := filepath.Join(plugin.FilePath)
|
fpath := plugin.FilePath
|
||||||
|
|
||||||
if !file.IsExist(fpath) {
|
if !file.IsExist(fpath) {
|
||||||
logger.Error("no such plugin:", fpath)
|
logger.Error("no such plugin:", fpath)
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,6 +20,6 @@ func loopDetect() {
|
||||||
|
|
||||||
func detect() {
|
func detect() {
|
||||||
ps := stra.GetProcCollects()
|
ps := stra.GetProcCollects()
|
||||||
DelNoPorcCollect(ps)
|
DelNoProcCollect(ps)
|
||||||
AddNewPorcCollect(ps)
|
AddNewProcCollect(ps)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ var (
|
||||||
ProcsWithScheduler = make(map[string]*ProcScheduler)
|
ProcsWithScheduler = make(map[string]*ProcScheduler)
|
||||||
)
|
)
|
||||||
|
|
||||||
func DelNoPorcCollect(newCollect map[string]*model.ProcCollect) {
|
func DelNoProcCollect(newCollect map[string]*model.ProcCollect) {
|
||||||
for currKey, currProc := range Procs {
|
for currKey, currProc := range Procs {
|
||||||
newProc, ok := newCollect[currKey]
|
newProc, ok := newCollect[currKey]
|
||||||
if !ok || currProc.LastUpdated != newProc.LastUpdated {
|
if !ok || currProc.LastUpdated != newProc.LastUpdated {
|
||||||
|
@ -18,7 +18,7 @@ func DelNoPorcCollect(newCollect map[string]*model.ProcCollect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddNewPorcCollect(newCollect map[string]*model.ProcCollect) {
|
func AddNewProcCollect(newCollect map[string]*model.ProcCollect) {
|
||||||
for target, newProc := range newCollect {
|
for target, newProc := range newCollect {
|
||||||
if _, ok := Procs[target]; ok && newProc.LastUpdated == Procs[target].LastUpdated {
|
if _, ok := Procs[target]; ok && newProc.LastUpdated == Procs[target].LastUpdated {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/didi/nightingale/src/toolkits/address"
|
"github.com/didi/nightingale/src/toolkits/address"
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
|
|
||||||
"github.com/toolkits/pkg/concurrent/semaphore"
|
"github.com/toolkits/pkg/concurrent/semaphore"
|
||||||
"github.com/toolkits/pkg/logger"
|
"github.com/toolkits/pkg/logger"
|
||||||
|
@ -49,11 +50,12 @@ func reportEndpoint(endpoints []interface{}) {
|
||||||
err := httplib.Post(url).JSONBodyQuiet(m).SetTimeout(3*time.Second).Header("x-srv-token", "monapi-builtin-token").ToJSON(&body)
|
err := httplib.Post(url).JSONBodyQuiet(m).SetTimeout(3*time.Second).Header("x-srv-token", "monapi-builtin-token").ToJSON(&body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warningf("curl %s fail: %v. retry", url, err)
|
logger.Warningf("curl %s fail: %v. retry", url, err)
|
||||||
|
stats.Counter.Set("report.endpoint.err", 1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if body.Err != "" { //数据库连接出错会出现此情况
|
||||||
if body.Err != "" {
|
|
||||||
logger.Warningf("curl %s fail: %s. retry", url, body.Err)
|
logger.Warningf("curl %s fail: %s. retry", url, body.Err)
|
||||||
|
stats.Counter.Set("report.endpoint.err", 1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/didi/nightingale/src/toolkits/compress"
|
"github.com/didi/nightingale/src/toolkits/compress"
|
||||||
"github.com/didi/nightingale/src/toolkits/identity"
|
"github.com/didi/nightingale/src/toolkits/identity"
|
||||||
"github.com/didi/nightingale/src/toolkits/report"
|
"github.com/didi/nightingale/src/toolkits/report"
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CacheSection struct {
|
type CacheSection struct {
|
||||||
|
@ -72,8 +73,8 @@ func StartPersist(interval int) {
|
||||||
err := Persist("normal")
|
err := Persist("normal")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Persist err:", err)
|
logger.Error("Persist err:", err)
|
||||||
|
stats.Counter.Set("persist.err", 1)
|
||||||
}
|
}
|
||||||
//logger.Infof("clean %+v, took %.2f ms\n", cleanRet, float64(time.Since(start).Nanoseconds())*1e-6)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,9 @@ func (t *TagkvIndex) GetTagkv() []*TagPair {
|
||||||
t.RLock()
|
t.RLock()
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
tagkvs := []*TagPair{}
|
tagkvs := []*TagPair{}
|
||||||
var vs []string
|
|
||||||
for k, vm := range t.Tagkv {
|
for k, vm := range t.Tagkv {
|
||||||
|
var vs []string
|
||||||
for v, _ := range vm {
|
for v, _ := range vm {
|
||||||
vs = append(vs, v)
|
vs = append(vs, v)
|
||||||
}
|
}
|
||||||
|
@ -50,8 +51,8 @@ func (t *TagkvIndex) GetTagkvMap() map[string][]string {
|
||||||
defer t.RUnlock()
|
defer t.RUnlock()
|
||||||
tagkvs := make(map[string][]string)
|
tagkvs := make(map[string][]string)
|
||||||
|
|
||||||
var vs []string
|
|
||||||
for k, vm := range t.Tagkv {
|
for k, vm := range t.Tagkv {
|
||||||
|
var vs []string
|
||||||
for v, _ := range vm {
|
for v, _ := range vm {
|
||||||
vs = append(vs, v)
|
vs = append(vs, v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,9 +93,8 @@ func GetTagPairs(c *gin.Context) {
|
||||||
|
|
||||||
resp := []*IndexTagkvResp{}
|
resp := []*IndexTagkvResp{}
|
||||||
|
|
||||||
tagkvFilter := make(map[string]map[string]struct{})
|
|
||||||
|
|
||||||
for _, metric := range recv.Metrics {
|
for _, metric := range recv.Metrics {
|
||||||
|
tagkvFilter := make(map[string]map[string]struct{})
|
||||||
tagkvs := []*cache.TagPair{}
|
tagkvs := []*cache.TagPair{}
|
||||||
|
|
||||||
for _, endpoint := range recv.Endpoints {
|
for _, endpoint := range recv.Endpoints {
|
||||||
|
@ -107,6 +106,7 @@ func GetTagPairs(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tagkvMap := metricIndex.TagkvMap.GetTagkvMap()
|
tagkvMap := metricIndex.TagkvMap.GetTagkvMap()
|
||||||
|
|
||||||
for tagk, tagvs := range tagkvMap {
|
for tagk, tagvs := range tagkvMap {
|
||||||
tagvFilter, exists := tagkvFilter[tagk]
|
tagvFilter, exists := tagkvFilter[tagk]
|
||||||
if !exists {
|
if !exists {
|
||||||
|
|
|
@ -42,6 +42,5 @@ func Push(event *dataobj.Event) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.Counter.Set("redis.failed", 1)
|
|
||||||
return fmt.Errorf("redis publish failed finally:%v", err)
|
return fmt.Errorf("redis publish failed finally:%v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
"github.com/garyburd/redigo/redis"
|
"github.com/garyburd/redigo/redis"
|
||||||
"github.com/toolkits/pkg/logger"
|
"github.com/toolkits/pkg/logger"
|
||||||
)
|
)
|
||||||
|
@ -14,6 +15,7 @@ var Config RedisSection
|
||||||
type RedisSection struct {
|
type RedisSection struct {
|
||||||
Addrs []string `yaml:"addrs"`
|
Addrs []string `yaml:"addrs"`
|
||||||
Pass string `yaml:"pass"`
|
Pass string `yaml:"pass"`
|
||||||
|
DB int `yaml:"db"`
|
||||||
Idle int `yaml:"idle"`
|
Idle int `yaml:"idle"`
|
||||||
Timeout TimeoutSection `yaml:"timeout"`
|
Timeout TimeoutSection `yaml:"timeout"`
|
||||||
Prefix string `yaml:"prefix"`
|
Prefix string `yaml:"prefix"`
|
||||||
|
@ -30,6 +32,7 @@ func Init(cfg RedisSection) {
|
||||||
|
|
||||||
addrs := cfg.Addrs
|
addrs := cfg.Addrs
|
||||||
pass := cfg.Pass
|
pass := cfg.Pass
|
||||||
|
db := cfg.DB
|
||||||
maxIdle := cfg.Idle
|
maxIdle := cfg.Idle
|
||||||
idleTimeout := 240 * time.Second
|
idleTimeout := 240 * time.Second
|
||||||
|
|
||||||
|
@ -44,6 +47,7 @@ func Init(cfg RedisSection) {
|
||||||
c, err := redis.Dial("tcp", addr, redis.DialConnectTimeout(connTimeout), redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
|
c, err := redis.Dial("tcp", addr, redis.DialConnectTimeout(connTimeout), redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("conn redis err:%v", err)
|
logger.Errorf("conn redis err:%v", err)
|
||||||
|
stats.Counter.Set("redis.conn.failed", 1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +55,17 @@ func Init(cfg RedisSection) {
|
||||||
if _, err := c.Do("AUTH", pass); err != nil {
|
if _, err := c.Do("AUTH", pass); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
logger.Errorf("ERR: redis auth fail:%v", err)
|
logger.Errorf("ERR: redis auth fail:%v", err)
|
||||||
|
stats.Counter.Set("redis.conn.failed", 1)
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if db != 0 {
|
||||||
|
if _, err := c.Do("SELECT", db); err != nil {
|
||||||
|
c.Close()
|
||||||
|
logger.Error("redis select db fail, db: ", db)
|
||||||
|
stats.Counter.Set("redis.conn.failed", 1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ func Judge(stra *model.Stra, exps []model.Exp, historyData []*dataobj.RRDData, f
|
||||||
stats.Counter.Set("running", 1)
|
stats.Counter.Set("running", 1)
|
||||||
|
|
||||||
if len(exps) < 1 {
|
if len(exps) < 1 {
|
||||||
stats.Counter.Set("stra.err", 1)
|
stats.Counter.Set("stra.illegal", 1)
|
||||||
logger.Warningf("stra:%v exp is null", stra)
|
logger.Warningf("stra:%v exp is null", stra)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -105,21 +105,21 @@ func Judge(stra *model.Stra, exps []model.Exp, historyData []*dataobj.RRDData, f
|
||||||
Hashid: getHashId(stra.Id, firstItem),
|
Hashid: getHashId(stra.Id, firstItem),
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEventIfNeed(historyData, isTriggered, now, event)
|
sendEventIfNeed(historyData, isTriggered, event)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
leftValue, isTriggered = judgeItemWithStrategy(stra, historyData, exps[0], firstItem, now)
|
leftValue, isTriggered = judgeItemWithStrategy(stra, historyData, exps[0], firstItem, now)
|
||||||
if !isTriggered {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if value == "" {
|
if value == "" {
|
||||||
value = fmt.Sprintf("%s: %v", exp.Metric, leftValue)
|
value = fmt.Sprintf("%s: %v", exp.Metric, leftValue)
|
||||||
} else {
|
} else {
|
||||||
value += fmt.Sprintf("; %s: %v", exp.Metric, leftValue)
|
value += fmt.Sprintf("; %s: %v", exp.Metric, leftValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isTriggered {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//与条件情况下执行
|
//与条件情况下执行
|
||||||
if len(exps) > 1 {
|
if len(exps) > 1 {
|
||||||
if exps[1].Func == "nodata" { //nodata重新查询索引来进行告警判断
|
if exps[1].Func == "nodata" { //nodata重新查询索引来进行告警判断
|
||||||
|
@ -387,7 +387,7 @@ func GetReqs(stra *model.Stra, metric string, endpoints []string, now int64) ([]
|
||||||
return reqs, nil
|
return reqs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendEventIfNeed(historyData []*dataobj.RRDData, isTriggered bool, now int64, event *dataobj.Event) {
|
func sendEventIfNeed(historyData []*dataobj.RRDData, isTriggered bool, event *dataobj.Event) {
|
||||||
lastEvent, exists := cache.LastEvents.Get(event.ID)
|
lastEvent, exists := cache.LastEvents.Get(event.ID)
|
||||||
if isTriggered {
|
if isTriggered {
|
||||||
event.EventType = EVENT_ALERT
|
event.EventType = EVENT_ALERT
|
||||||
|
@ -421,6 +421,7 @@ func sendEvent(event *dataobj.Event) {
|
||||||
|
|
||||||
err := redi.Push(event)
|
err := redi.Push(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
stats.Counter.Set("redis.push.failed", 1)
|
||||||
logger.Errorf("push event:%v err:%v", event, err)
|
logger.Errorf("push event:%v err:%v", event, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,11 +56,13 @@ func getStrategy(opts StrategySection) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warningf("get strategy from remote failed, error:%v", err)
|
logger.Warningf("get strategy from remote failed, error:%v", err)
|
||||||
|
stats.Counter.Set("stra.get.err", 1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Err != "" {
|
if resp.Err != "" {
|
||||||
logger.Warningf("get strategy from remote failed, error:%v", resp.Err)
|
logger.Warningf("get strategy from remote failed, error:%v", resp.Err)
|
||||||
|
stats.Counter.Set("stra.get.err", 1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ type cleanerSection struct {
|
||||||
type redisSection struct {
|
type redisSection struct {
|
||||||
Addr string `yaml:"addr"`
|
Addr string `yaml:"addr"`
|
||||||
Pass string `yaml:"pass"`
|
Pass string `yaml:"pass"`
|
||||||
|
DB int `yaml:"db"`
|
||||||
Idle int `yaml:"idle"`
|
Idle int `yaml:"idle"`
|
||||||
Timeout timeoutSection `yaml:"timeout"`
|
Timeout timeoutSection `yaml:"timeout"`
|
||||||
}
|
}
|
||||||
|
@ -70,10 +71,20 @@ type ldapSection struct {
|
||||||
BindUser string `yaml:"bindUser"`
|
BindUser string `yaml:"bindUser"`
|
||||||
BindPass string `yaml:"bindPass"`
|
BindPass string `yaml:"bindPass"`
|
||||||
AuthFilter string `yaml:"authFilter"`
|
AuthFilter string `yaml:"authFilter"`
|
||||||
|
Attributes ldapAttributes `yaml:"attributes"`
|
||||||
|
CoverAttributes bool `yaml:"coverAttributes"`
|
||||||
|
AutoRegist bool `yaml:"autoRegist"`
|
||||||
TLS bool `yaml:"tls"`
|
TLS bool `yaml:"tls"`
|
||||||
StartTLS bool `yaml:"startTLS"`
|
StartTLS bool `yaml:"startTLS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ldapAttributes struct {
|
||||||
|
Dispname string `yaml:"dispname"`
|
||||||
|
Phone string `yaml:"phone"`
|
||||||
|
Email string `yaml:"email"`
|
||||||
|
Im string `yaml:"im"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
yaml *Config
|
yaml *Config
|
||||||
lock = new(sync.RWMutex)
|
lock = new(sync.RWMutex)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/didi/nightingale/src/model"
|
"github.com/didi/nightingale/src/model"
|
||||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||||
"github.com/didi/nightingale/src/modules/monapi/scache"
|
"github.com/didi/nightingale/src/modules/monapi/scache"
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckJudgeLoop() {
|
func CheckJudgeLoop() {
|
||||||
|
@ -19,6 +20,7 @@ func CheckJudgeLoop() {
|
||||||
time.Sleep(duration)
|
time.Sleep(duration)
|
||||||
err := CheckJudge()
|
err := CheckJudge()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
stats.Counter.Set("get.judge.err", 1)
|
||||||
logger.Error("check judge fail: ", err)
|
logger.Error("check judge fail: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ func consume(event *model.Event) {
|
||||||
SetEventStatus(event, model.STATUS_UPGRADE)
|
SetEventStatus(event, model.STATUS_UPGRADE)
|
||||||
|
|
||||||
if needNotify {
|
if needNotify {
|
||||||
if event.EventType == config.ALERT && NeedCallback(event.Sid) {
|
if NeedCallback(event.Sid) {
|
||||||
if err := PushCallbackEvent(event); err != nil {
|
if err := PushCallbackEvent(event); err != nil {
|
||||||
logger.Errorf("push event to callback queue failed, callbackEvent: %+v", event)
|
logger.Errorf("push event to callback queue failed, callbackEvent: %+v", event)
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ func consume(event *model.Event) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.EventType == config.ALERT && NeedCallback(event.Sid) {
|
if NeedCallback(event.Sid) {
|
||||||
if err := PushCallbackEvent(event); err != nil {
|
if err := PushCallbackEvent(event); err != nil {
|
||||||
logger.Errorf("push event to callback queue failed, callbackEvent: %+v", event)
|
logger.Errorf("push event to callback queue failed, callbackEvent: %+v", event)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/toolkits/pkg/logger"
|
"github.com/toolkits/pkg/logger"
|
||||||
|
|
||||||
"github.com/didi/nightingale/src/modules/monapi/config"
|
"github.com/didi/nightingale/src/modules/monapi/config"
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
var RedisConnPool *redis.Pool
|
var RedisConnPool *redis.Pool
|
||||||
|
@ -16,6 +17,7 @@ func InitRedis() {
|
||||||
|
|
||||||
addr := cfg.Redis.Addr
|
addr := cfg.Redis.Addr
|
||||||
pass := cfg.Redis.Pass
|
pass := cfg.Redis.Pass
|
||||||
|
db := cfg.Redis.DB
|
||||||
maxIdle := cfg.Redis.Idle
|
maxIdle := cfg.Redis.Idle
|
||||||
idleTimeout := 240 * time.Second
|
idleTimeout := 240 * time.Second
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ func InitRedis() {
|
||||||
Dial: func() (redis.Conn, error) {
|
Dial: func() (redis.Conn, error) {
|
||||||
c, err := redis.Dial("tcp", addr, redis.DialConnectTimeout(connTimeout), redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
|
c, err := redis.Dial("tcp", addr, redis.DialConnectTimeout(connTimeout), redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorf("conn redis err:%v", err)
|
||||||
|
stats.Counter.Set("redis.conn.failed", 1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +40,16 @@ func InitRedis() {
|
||||||
if _, err := c.Do("AUTH", pass); err != nil {
|
if _, err := c.Do("AUTH", pass); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
logger.Error("redis auth fail, pass: ", pass)
|
logger.Error("redis auth fail, pass: ", pass)
|
||||||
|
stats.Counter.Set("redis.conn.failed", 1)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if db != 0 {
|
||||||
|
if _, err := c.Do("SELECT", db); err != nil {
|
||||||
|
c.Close()
|
||||||
|
logger.Error("redis select db fail, db: ", db)
|
||||||
|
stats.Counter.Set("redis.select.failed", 1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/didi/nightingale/src/dataobj"
|
"github.com/didi/nightingale/src/dataobj"
|
||||||
"github.com/didi/nightingale/src/modules/transfer/calc"
|
"github.com/didi/nightingale/src/modules/transfer/calc"
|
||||||
"github.com/didi/nightingale/src/toolkits/address"
|
"github.com/didi/nightingale/src/toolkits/address"
|
||||||
|
"github.com/didi/nightingale/src/toolkits/stats"
|
||||||
|
|
||||||
"github.com/toolkits/pkg/logger"
|
"github.com/toolkits/pkg/logger"
|
||||||
"github.com/toolkits/pkg/net/httplib"
|
"github.com/toolkits/pkg/net/httplib"
|
||||||
|
@ -95,15 +96,15 @@ func FetchDataForUI(input dataobj.QueryDataForUI) []*dataobj.TsdbQueryResponse {
|
||||||
//进行数据计算
|
//进行数据计算
|
||||||
aggrDatas := []*dataobj.TsdbQueryResponse{}
|
aggrDatas := []*dataobj.TsdbQueryResponse{}
|
||||||
if input.AggrFunc != "" && len(resp) > 1 {
|
if input.AggrFunc != "" && len(resp) > 1 {
|
||||||
aggrData := &dataobj.TsdbQueryResponse{
|
|
||||||
Start: input.Start,
|
|
||||||
End: input.End,
|
|
||||||
}
|
|
||||||
|
|
||||||
aggrCounter := make(map[string][]*dataobj.TsdbQueryResponse)
|
aggrCounter := make(map[string][]*dataobj.TsdbQueryResponse)
|
||||||
if len(input.GroupKey) == 0 || getTags(resp[0].Counter) == "" {
|
if len(input.GroupKey) == 0 || getTags(resp[0].Counter) == "" {
|
||||||
|
aggrData := &dataobj.TsdbQueryResponse{
|
||||||
|
Start: input.Start,
|
||||||
|
End: input.End,
|
||||||
|
Values: calc.Compute(input.AggrFunc, resp),
|
||||||
|
}
|
||||||
//没有聚合 tag, 或者曲线没有其他 tags, 直接所有曲线进行计算
|
//没有聚合 tag, 或者曲线没有其他 tags, 直接所有曲线进行计算
|
||||||
aggrData.Values = calc.Compute(input.AggrFunc, resp)
|
|
||||||
aggrDatas = append(aggrDatas, aggrData)
|
aggrDatas = append(aggrDatas, aggrData)
|
||||||
} else {
|
} else {
|
||||||
for _, data := range resp {
|
for _, data := range resp {
|
||||||
|
@ -132,9 +133,12 @@ func FetchDataForUI(input dataobj.QueryDataForUI) []*dataobj.TsdbQueryResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
for counter, datas := range aggrCounter {
|
for counter, datas := range aggrCounter {
|
||||||
aggrData.Counter = counter
|
aggrData := &dataobj.TsdbQueryResponse{
|
||||||
aggrData.Values = calc.Compute(input.AggrFunc, datas)
|
Start: input.Start,
|
||||||
|
End: input.End,
|
||||||
|
Counter: counter,
|
||||||
|
Values: calc.Compute(input.AggrFunc, datas),
|
||||||
|
}
|
||||||
aggrDatas = append(aggrDatas, aggrData)
|
aggrDatas = append(aggrDatas, aggrData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,10 +165,12 @@ func fetchDataSync(start, end int64, consolFun, endpoint, counter string, step i
|
||||||
defer func() {
|
defer func() {
|
||||||
<-worker
|
<-worker
|
||||||
}()
|
}()
|
||||||
|
stats.Counter.Set("query.tsdb", 1)
|
||||||
|
|
||||||
data, err := fetchData(start, end, consolFun, endpoint, counter, step)
|
data, err := fetchData(start, end, consolFun, endpoint, counter, step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning(err)
|
logger.Warning(err)
|
||||||
|
stats.Counter.Set("query.data.err", 1)
|
||||||
}
|
}
|
||||||
dataChan <- data
|
dataChan <- data
|
||||||
return
|
return
|
||||||
|
|
|
@ -107,6 +107,7 @@ func Send2TsdbTask(Q *list.SafeListLimited, node string, addr string, concurrent
|
||||||
|
|
||||||
// 将数据 打入 某个Tsdb的发送缓存队列, 具体是哪一个Tsdb 由一致性哈希 决定
|
// 将数据 打入 某个Tsdb的发送缓存队列, 具体是哪一个Tsdb 由一致性哈希 决定
|
||||||
func Push2TsdbSendQueue(items []*dataobj.MetricValue) {
|
func Push2TsdbSendQueue(items []*dataobj.MetricValue) {
|
||||||
|
errCnt := 0
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
tsdbItem := convert2TsdbItem(item)
|
tsdbItem := convert2TsdbItem(item)
|
||||||
stats.Counter.Set("tsdb.queue.push", 1)
|
stats.Counter.Set("tsdb.queue.push", 1)
|
||||||
|
@ -118,13 +119,13 @@ func Push2TsdbSendQueue(items []*dataobj.MetricValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cnode := Config.ClusterList[node]
|
cnode := Config.ClusterList[node]
|
||||||
errCnt := 0
|
|
||||||
for _, addr := range cnode.Addrs {
|
for _, addr := range cnode.Addrs {
|
||||||
Q := TsdbQueues[node+addr]
|
Q := TsdbQueues[node+addr]
|
||||||
if !Q.PushFront(tsdbItem) {
|
if !Q.PushFront(tsdbItem) {
|
||||||
errCnt += 1
|
errCnt += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// statistics
|
// statistics
|
||||||
if errCnt > 0 {
|
if errCnt > 0 {
|
||||||
|
@ -132,7 +133,6 @@ func Push2TsdbSendQueue(items []*dataobj.MetricValue) {
|
||||||
logger.Error("Push2TsdbSendQueue err num: ", errCnt)
|
logger.Error("Push2TsdbSendQueue err num: ", errCnt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func Send2JudgeTask(Q *list.SafeListLimited, addr string, concurrent int) {
|
func Send2JudgeTask(Q *list.SafeListLimited, addr string, concurrent int) {
|
||||||
batch := Config.Batch
|
batch := Config.Batch
|
||||||
|
@ -172,7 +172,7 @@ func Send2JudgeTask(Q *list.SafeListLimited, addr string, concurrent int) {
|
||||||
|
|
||||||
if !sendOk {
|
if !sendOk {
|
||||||
stats.Counter.Set("points.out.judge.err", 1)
|
stats.Counter.Set("points.out.judge.err", 1)
|
||||||
logger.Errorf("send judge %s fail: %v", addr, err)
|
logger.Errorf("send %v to judge %s fail: %v", judgeItems, addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}(addr, judgeItems, count)
|
}(addr, judgeItems, count)
|
||||||
|
@ -180,6 +180,7 @@ func Send2JudgeTask(Q *list.SafeListLimited, addr string, concurrent int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Push2JudgeSendQueue(items []*dataobj.MetricValue) {
|
func Push2JudgeSendQueue(items []*dataobj.MetricValue) {
|
||||||
|
errCnt := 0
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
key := str.PK(item.Metric, item.Endpoint)
|
key := str.PK(item.Metric, item.Endpoint)
|
||||||
stras := cache.StraMap.GetByKey(key)
|
stras := cache.StraMap.GetByKey(key)
|
||||||
|
@ -203,12 +204,14 @@ func Push2JudgeSendQueue(items []*dataobj.MetricValue) {
|
||||||
|
|
||||||
q, exists := JudgeQueues.Get(stra.JudgeInstance)
|
q, exists := JudgeQueues.Get(stra.JudgeInstance)
|
||||||
if exists {
|
if exists {
|
||||||
q.PushFront(judgeItem)
|
if !q.PushFront(judgeItem) {
|
||||||
|
errCnt += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stats.Counter.Set("judge.queue.err", errCnt)
|
||||||
|
}
|
||||||
|
|
||||||
// 打到Tsdb的数据,要根据rrdtool的特定 来限制 step、counterType、timestamp
|
// 打到Tsdb的数据,要根据rrdtool的特定 来限制 step、counterType、timestamp
|
||||||
func convert2TsdbItem(d *dataobj.MetricValue) *dataobj.TsdbItem {
|
func convert2TsdbItem(d *dataobj.MetricValue) *dataobj.TsdbItem {
|
||||||
|
|
|
@ -46,18 +46,50 @@ func QueryData(c *gin.Context) {
|
||||||
func QueryDataForUI(c *gin.Context) {
|
func QueryDataForUI(c *gin.Context) {
|
||||||
stats.Counter.Set("data.ui.qp10s", 1)
|
stats.Counter.Set("data.ui.qp10s", 1)
|
||||||
var input dataobj.QueryDataForUI
|
var input dataobj.QueryDataForUI
|
||||||
|
var respData []*dataobj.QueryDataForUIResp
|
||||||
errors.Dangerous(c.ShouldBindJSON(&input))
|
errors.Dangerous(c.ShouldBindJSON(&input))
|
||||||
|
start := input.Start
|
||||||
|
end := input.End
|
||||||
|
|
||||||
resp := backend.FetchDataForUI(input)
|
resp := backend.FetchDataForUI(input)
|
||||||
|
for _, d := range resp {
|
||||||
|
data := &dataobj.QueryDataForUIResp{
|
||||||
|
Start: d.Start,
|
||||||
|
End: d.End,
|
||||||
|
Endpoint: d.Endpoint,
|
||||||
|
Counter: d.Counter,
|
||||||
|
DsType: d.DsType,
|
||||||
|
Step: d.Step,
|
||||||
|
Values: d.Values,
|
||||||
|
}
|
||||||
|
respData = append(respData, data)
|
||||||
|
}
|
||||||
|
|
||||||
if len(input.Comparisons) > 1 {
|
if len(input.Comparisons) > 1 {
|
||||||
for i := 1; i < len(input.Comparisons); i++ {
|
for i := 1; i < len(input.Comparisons); i++ {
|
||||||
input.Start = input.Start - input.Comparisons[i]
|
comparison := input.Comparisons[i]
|
||||||
input.End = input.End - input.Comparisons[i]
|
input.Start = start - comparison
|
||||||
|
input.End = end - comparison
|
||||||
res := backend.FetchDataForUI(input)
|
res := backend.FetchDataForUI(input)
|
||||||
resp = append(resp, res...)
|
for _, d := range res {
|
||||||
|
for j := range d.Values {
|
||||||
|
d.Values[j].Timestamp += comparison
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &dataobj.QueryDataForUIResp{
|
||||||
|
Start: d.Start,
|
||||||
|
End: d.End,
|
||||||
|
Endpoint: d.Endpoint,
|
||||||
|
Counter: d.Counter,
|
||||||
|
DsType: d.DsType,
|
||||||
|
Step: d.Step,
|
||||||
|
Values: d.Values,
|
||||||
|
Comparison: comparison,
|
||||||
|
}
|
||||||
|
respData = append(respData, data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render.Data(c, resp, nil)
|
render.Data(c, respData, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func Config(r *gin.Engine) {
|
||||||
sys.GET("/alive-judges", judges)
|
sys.GET("/alive-judges", judges)
|
||||||
|
|
||||||
sys.POST("/push", PushData)
|
sys.POST("/push", PushData)
|
||||||
sys.POST("/data", QueryDataForJudge)
|
sys.POST("/data", QueryData)
|
||||||
sys.POST("/data/ui", QueryDataForUI)
|
sys.POST("/data/ui", QueryDataForUI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,10 @@ func (t *Transfer) Push(args []*dataobj.MetricValue, reply *dataobj.TransferResp
|
||||||
err := v.CheckValidity()
|
err := v.CheckValidity()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stats.Counter.Set("points.in.err", 1)
|
stats.Counter.Set("points.in.err", 1)
|
||||||
logger.Warningf("item is illegal item:%s err:%v", v, err)
|
msg := fmt.Sprintf("item is illegal item:%s err:%v", v, err)
|
||||||
|
logger.Warningf(msg)
|
||||||
reply.Invalid += 1
|
reply.Invalid += 1
|
||||||
reply.Msg += fmt.Sprintf("%v\n", err)
|
reply.Msg += msg
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ func GetIndexLoop() {
|
||||||
func GetIndex() {
|
func GetIndex() {
|
||||||
instances, err := report.GetAlive("index", Config.HbsMod)
|
instances, err := report.GetAlive("index", Config.HbsMod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stats.Counter.Set("index.get.err", 1)
|
stats.Counter.Set("get.index.err", 1)
|
||||||
logger.Warningf("get index list err:%v", err)
|
logger.Warningf("get index list err:%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@ func handleItems(items []*dataobj.TsdbItem) {
|
||||||
//todo hash冲突问题需要解决
|
//todo hash冲突问题需要解决
|
||||||
if err := cache.Caches.Push(item.Key, item.Timestamp, item.Value); err != nil {
|
if err := cache.Caches.Push(item.Key, item.Timestamp, item.Value); err != nil {
|
||||||
stats.Counter.Set("points.in.err", 1)
|
stats.Counter.Set("points.in.err", 1)
|
||||||
|
|
||||||
logger.Warningf("push obj error, obj: %v, error: %v\n", items[i], err)
|
logger.Warningf("push obj error, obj: %v, error: %v\n", items[i], err)
|
||||||
fail++
|
fail++
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,7 @@ func FlushRRD(flushChunks map[interface{}][]*cache.Chunk) {
|
||||||
|
|
||||||
err := FlushFile(seriesID, items)
|
err := FlushFile(seriesID, items)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
stats.Counter.Set("flush.rrd.err", 1)
|
||||||
logger.Errorf("flush %v data to rrd err:%v", seriesID, err)
|
logger.Errorf("flush %v data to rrd err:%v", seriesID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,12 @@ type IdentitySection struct {
|
||||||
func Init(identity IdentitySection) {
|
func Init(identity IdentitySection) {
|
||||||
if identity.Specify != "" {
|
if identity.Specify != "" {
|
||||||
Identity = identity.Specify
|
Identity = identity.Specify
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
Identity, err = sys.CmdOutTrim("bash", "-c", identity.Shell)
|
Identity, err = sys.CmdOutTrim("bash", "-c", identity.Shell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("[F] cannot get hostname")
|
log.Fatalln("[F] cannot get identity")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,17 @@ package stats
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/didi/nightingale/src/dataobj"
|
"github.com/didi/nightingale/src/dataobj"
|
||||||
"github.com/didi/nightingale/src/toolkits/identity"
|
"github.com/didi/nightingale/src/toolkits/address"
|
||||||
|
|
||||||
|
"github.com/toolkits/pkg/file"
|
||||||
"github.com/toolkits/pkg/logger"
|
"github.com/toolkits/pkg/logger"
|
||||||
|
"github.com/toolkits/pkg/runner"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -17,8 +21,14 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init(prefix string, addr ...string) {
|
func Init(prefix string, addr ...string) {
|
||||||
if len(addr) > 0 {
|
if len(addr) > 0 && addr[0] != "" {
|
||||||
|
//如果配置了 addr,使用 addr 参数
|
||||||
PushUrl = addr[0]
|
PushUrl = addr[0]
|
||||||
|
|
||||||
|
} else if file.IsExist(path.Join(runner.Cwd, "etc", "address.yml")) {
|
||||||
|
//address.yml 存在,则使用配置文件的地址
|
||||||
|
port := address.GetHTTPPort("collector")
|
||||||
|
PushUrl = fmt.Sprintf("http://127.0.0.1:%d/api/collector/push", port)
|
||||||
}
|
}
|
||||||
|
|
||||||
Counter = NewCounter(prefix)
|
Counter = NewCounter(prefix)
|
||||||
|
@ -42,7 +52,6 @@ func Push() {
|
||||||
func NewMetricValue(metric string, value int64) *dataobj.MetricValue {
|
func NewMetricValue(metric string, value int64) *dataobj.MetricValue {
|
||||||
item := &dataobj.MetricValue{
|
item := &dataobj.MetricValue{
|
||||||
Metric: metric,
|
Metric: metric,
|
||||||
Endpoint: identity.Identity,
|
|
||||||
Timestamp: time.Now().Unix(),
|
Timestamp: time.Now().Unix(),
|
||||||
ValueUntyped: value,
|
ValueUntyped: value,
|
||||||
CounterType: "GAUGE",
|
CounterType: "GAUGE",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1,7 @@
|
||||||
|
FROM node:lts-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm install
|
|
@ -76,7 +76,10 @@ class index extends Component<Props, State> {
|
||||||
processData = async (endpoints: Endpoint[]) => {
|
processData = async (endpoints: Endpoint[]) => {
|
||||||
if (this.state.displayBindNode && endpoints) {
|
if (this.state.displayBindNode && endpoints) {
|
||||||
const idents = _.map(endpoints, item => item.ident);
|
const idents = _.map(endpoints, item => item.ident);
|
||||||
const endpointNodes = await request(`${api.endpoint}s/bindings?idents=${_.join(idents, ',')}`);
|
let endpointNodes: any[] = [];
|
||||||
|
if (idents.length) {
|
||||||
|
endpointNodes = await request(`${api.endpoint}s/bindings?idents=${_.join(idents, ',')}`);
|
||||||
|
}
|
||||||
const newEndpoints = _.map(endpoints, (item) => {
|
const newEndpoints = _.map(endpoints, (item) => {
|
||||||
const current = _.find(endpointNodes, { ident: item.ident });
|
const current = _.find(endpointNodes, { ident: item.ident });
|
||||||
const nodes = _.get(current, 'nodes', []);
|
const nodes = _.get(current, 'nodes', []);
|
||||||
|
|
|
@ -184,7 +184,7 @@ class index extends Component<null, State> {
|
||||||
<div className="mt10 mb10" style={{ wordBreak: 'break-word' }}>
|
<div className="mt10 mb10" style={{ wordBreak: 'break-word' }}>
|
||||||
{_.get(selectedNode, 'path')}
|
{_.get(selectedNode, 'path')}
|
||||||
</div>
|
</div>
|
||||||
<Popconfirm title="确定要删除这个节点吗?" onConfirm={this.handleDelNode}>
|
<Popconfirm disabled={isPdlNode} title="确定要删除这个节点吗?" onConfirm={this.handleDelNode}>
|
||||||
<Button disabled={isPdlNode}>删除</Button>
|
<Button disabled={isPdlNode}>删除</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue