前端代码
一. 代码结构
- config: 开发 & 构建配置
- proxy.config.js:代理配置
- theme.js:antd 主题配置
- webpack.config.js:webpack 开发环境补充配置,覆盖默认配置
- webpack.build.config.js:webpack 构建补充配置,覆盖默认配置
- webpack.build.config.js:webpack dll补充配置,覆盖默认配置
- webpackConfigResolveAlias.js 文件路径别名配置
- src:源代码所在目录
- assets:全局资源 img、css
- common: 全局配置、通用方法
- components:公共组件
- pages:路由匹配的页面组件
- app.jsx 菜单、路由配置组件
- index.html:单页
- index.jsx:入口文件
- fetk.config.js 开发工具配置页面
二. 修改内容
1.添加接口查询功能
2.修改页面图标和公司名称
3.添加报警提示音
三. 代码修改记录
- common/request.tsx
//新增
if (!data) {
return data;
}
if(data.notify_type){
return data;
}
- components/Layout/index.tsx
//新增定时任务 提示报警信息
this.timerID =self.setInterval(()=>{
request("/api/alarm").then((res: any) => {
console.log(res);
console.log("查询");
if(res){
if(res.event.endpoint){
message.warn(res.event.sname);
var url= "http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=5&text=" + encodeURI("创林监控系统报警, ip为"+res.event.endpoint+" 错误为"+res.event.sname);
new Audio(url).play()
}
}
});
},60000)
- interface/index.tsx
//interface返回参数新增notify_type属性
notify_type:any | ResponseDat,
- locales/zh.ts
//新增接口页面属性名
'collect.api': '接口',
'collect.api.name': '接口',
'collect.api.name.placeholder': 'http://xxx.xxxx.xxx/xxx',
'collect.api.ip': '主机ip',
'collect.api.ip.placeholder': '192.168.0.1',
- pages/Monitor
- Collect
- CollectForm
- APIForm.tsx
//整页新增
- index.tsx
//新增页面 export default { log: LOGForm, port: PORTForm, proc: PROCForm, plugin: PLUGINForm, api:APIForm, //新增 };
- config.tsx
//typeMap新增api接口属性 export const typeMap: any = { log: '日志', port: '端口', proc: '进程', plugin: '插件', api:'接口'//新增属性 };
- CollectForm
- Dashboard
- config.tsx
//metricMap新增redis,nginx,pgsql分类 nginx: { key: 'nginx', alias: 'nginx', dynamic: true, filter: { type: 'prefix', value: 'nginx.,NGINX.' }, }, pgsql: { key: 'pgsql', alias: 'pgsql', dynamic: true, filter: { type: 'prefix', value: 'pgsql.,PGSQL.' }, }, redis: { key: 'redis', alias: 'redis', dynamic: true, filter: { type: 'prefix', value: 'redis.,Redis.' }, },
- MetricSelect.tsx
//新增采集数据信息提示 title={() => { const currentMetricMeta = getCurrentMetricMeta(metric); if (currentMetricMeta) { return ( <div> <p>含义:{currentMetricMeta.meaning}</p> <p>单位:{currentMetricMeta.unit}</p> </div> ); } return ''; }}
- Collect
邮件服务
一. 代码结构
- mail-sender
- config //配置
- cron //发送数据
- dataobj //警报结构体
- etc //配置文件
- redisc //redis操作方法
二. 修改内容
1.在报警邮件发送前向Redis存储报警信息
2.对外暴露一个报警信息查询接口,接口用成功后删除当前报警信息
三. 修改记录
- cron/sender.go
//sendMail方法中新增
redisc.AddMessage(message)
- redisc/poper.go
//新增两个数据
/**
添加报警数据
*/
func AddMessage(message *dataobj.Message) (string,error) {
var lst []*dataobj.Message
rc := RedisConnPool.Get()
defer rc.Close()
reply, err := redis.String(rc.Do("GET", "alarm-message"))
if err != nil {
if err != redis.ErrNil {
logger.Errorf("rpop queue:%s failed, err: %v", "alarm-message", err)
}
}
if reply == "" || reply == "nil" {
//读取到的是空 新增alarm-message数据
lst=append(lst,message)
}else{
err = json.Unmarshal([]byte(reply), &lst)
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return "json转换失败", err
}
lst=append(lst,message)
}
jsonArr,err:=json.Marshal(lst)
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return "json转换失败", err
}
setres,err:=redis.String(rc.Do("SET","alarm-message",jsonArr))
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return "json转换失败", err
}
if(setres=="" || setres=="nil"){
logger.Errorf("返回空")
}
return "ok", nil
}
/**
查找报警数据
*/
func FindMessage() (*dataobj.Message,error){
var lst []*dataobj.Message
rc := RedisConnPool.Get()
defer rc.Close()
reply, err := redis.String(rc.Do("GET", "alarm-message"))
if err != nil {
if err != redis.ErrNil {
logger.Errorf("rpop queue:%s failed, err: %v", "alarm-message", err)
}
return nil, err
}
if reply == "" || reply == "nil" {
//读取到的是空 新增alarm-message数据
return nil, err
} else{
err = json.Unmarshal([]byte(reply), &lst)
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return nil, err
}
if(len(lst)<=0){
return nil, err
}
res :=lst[0]
lst=lst[1:len(lst)]
jsonArr,err:=json.Marshal(lst)
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return nil, err
}
//删除
del,err := redis.Bool(rc.Do("DEL","alarm-message"))
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return nil, err
}
fmt.Println(del)
//设置message
setres,err:=redis.String(rc.Do("SET","alarm-message",jsonArr))
if err != nil {
logger.Errorf("unmarshal message failed, err: %v, redis reply: %v", err, reply)
return nil, err
}
if(setres=="" || setres=="nil"){
logger.Errorf("返回空")
}
return res, nil
}
}
- main.go
//main函数下新增端口监听
http.HandleFunc("/", indexHandler)
port := os.Getenv("PORT")
if port == "" {
port = "8082"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
log.Printf("Open http://localhost:%s in the browser", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
//新增接口路由
func indexHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
_, err := fmt.Fprint(w, "Hello, World!````````` ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
if r.URL.Path == "/api/alarm" {
res,err:=redisc.FindMessage()
b,err:=json.Marshal(res)
if err != nil {
fmt.Println("失败")
}
w.Header().Set("Content-Type","application/json; charset=utf-8")
w.Header().Set("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
}else {
http.NotFound(w, r)
return
}
客户端collector
一. 代码结构
- collector
- cache
- config //结构体配置文件
- http //api接口配置
- log
- nginxInfo //获取nginx实例数据
- pgsqlInfo //获取pgsql实例数据
- redisInfo //获取redis实例数据
- stra //采集配置结构体
- sys //采集配置实现
- util //网络请求工具包
- collector.go //入口
二. 修改内容
1.添加Redis数据监控
2.添加Pgsql数据监控
3.添加nginx数据监控
4.rpc数据交互改为http数据交互
三. 代码修改记录
- config
- data.go
//新增data.go文件 //夜莺插件提交规范结构体
- log.go
//新增自定义插件运行日志
- yaml.go
//新增自定义插件配置文件 //文件位置 etc/configuration.yml
- nginxInfo
//新增nginx.go文件
//采集nginx实例
- pgsqlInfo
//新增pgsql.go文件
//采集pgsql实例
- redisInfo
//新增redis.go文件
//采集redis实例
- sys
-fengjiePlugins//新增cron.go //1.读取自定义插件配置内容 //2.调用自定义插件采集方法
- funcs
- cron.go
//该文件主要负责收集程序采集的数据并push到服务器 //rpc 改用http 并发太高导致连接超时 //修改方案:赋予每个并发请求一个随机延迟 //动态判断 进行休眠 b := rand.Intn(6000) //取随机数 time.Sleep(time.Duration(b/100) * time.Second) //睡眠相应时间
- push.go
//新增 接口返回参数结构体 type reportRes struct { Err string `json:"err"` Dat string `json:"dat"` } //当前方法先读取配置文件中的openRpc属性判断是否启用rpc openRpc:=address.GetOpenRpc("transfer") if(openRpc){ //开启openrpc fmt.Println("openrpc") count := len(addrs) retry := 0 for { for _, i := range rand.Perm(count) { addr := addrs[i] logger.Error("Push"+addr) 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 } } }else { //http提交数据 url:=address.GetApi("transfer") var res reportRes err := httplib.Post(url).JSONBodyQuiet(items).SetTimeout(2000 * time.Millisecond).ToJSON(&res) if err != nil { logger.Errorf("curl %s fail: %v", url, err) fmt.Println("curl %s fail: %v", url, err) fmt.Println(items[0].Metric) } if res.Err != "" { logger.Error(res.Err) } }
- plugins | ports | procs
//修改scheduler.go //给一个随机延迟 b := rand.Intn(10000) time.Sleep(time.Duration(b/1000) * time.Second)
- funcs
-collector.go
//调用自定义插件采集方法
//自定义插件采集
fengjiePlugins.Detect()
服务端collector
一. 代码结构
- collector
- cache
- config //结构体配置文件
- http //api接口配置
- log
- nginxInfo //获取nginx实例数据
- pgsqlInfo //获取pgsql实例数据
- redisInfo //获取redis实例数据
- stra //采集配置结构体
- sys //采集配置实现
- util //网络请求工具包
- collector.go //入口
二. 修改内容
1.新增接口定时查询功能
2.接口返回是否正常使用原rpc数据上报功能
三. 修改记录
- stra/api.go
//新增api.go文件
//新增api结构体和获取用户配置的接口列表
- sys/apiTest
//新增api.go,cron.go,scheduler.go文件
//所有关于接口的函数都在这里
- collector.go
//启动接口数据采集
apiTest.Detect()
服务端monapi
一. 代码结构
- monapi
- config
- cron
- http
- mcache
- notify
- redisc
- scache
二. 修改内容
1.新增查询所有采集配置为api的数据列表
2.修改采集配置创建接囗,新增api分类属性
3.mode 包下collet文件新增结构体ApiCollect,并新增添加,删除,更新,查询方法
三. 修改记录
- http/routes
- collect.go
//collectPost方法下新增 api分类 case "api": collect := new(model.ApiCollect) b, err := json.Marshal(obj.Data) if err != nil { errors.Bomb("marshal body %s err:%v", obj, err) } err = json.Unmarshal(b, collect) if err != nil { errors.Bomb("unmarshal body %s err:%v", string(b), err) } collect.Creator = creator collect.LastUpdator = creator nid := collect.Nid name := collect.Name old, _ := model.GetCollectByName(obj.Type, name) if old != nil && int64(old.(map[string]interface{})["nid"].(float64)) == nid { errors.Bomb("同节点下策略名称 %s 已存在", name) } errors.Dangerous(model.CreateCollect(obj.Type, creator, collect)) //给types数组新增api属性 types := []string{"port", "proc", "log", "plugin","api"} //新增获取所有api的方法 func collectsGetApiAll(c *gin.Context) { collects, err := model.GetApiCollect() if err != nil { logger.Warning("api", err) } if err == nil { c.JSON(200, gin.H{"dat": collects, "err": ""}) return } renderMessage(c, err.Error()) } //collectPut方法下新增 case "api": collect := new(model.ApiCollect) b, err := json.Marshal(recv.Data) if err != nil { errors.Bomb("marshal body %s err:%v", recv, err) } err = json.Unmarshal(b, collect) if err != nil { errors.Bomb("unmarshal body %s err:%v", string(b), err) } nid := collect.Nid name := collect.Name //校验采集是否存在 obj, err := model.GetCollectById(recv.Type, collect.Id) //id找不到的情况 if err != nil { errors.Bomb("采集不存在 type:%s id:%d", recv.Type, collect.Id) } tmpId := obj.(*model.ApiCollect).Id if tmpId == 0 { errors.Bomb("采集不存在 type:%s id:%d", recv.Type, collect.Id) } collect.Creator = creator collect.LastUpdator = creator old, _ := model.GetCollectByName(recv.Type, name) if old != nil && int64(old.(map[string]interface{})["nid"].(float64)) == nid && tmpId != collect.Id { errors.Bomb("同节点下策略名称 %s 已存在", name) } errors.Dangerous(collect.Update()) renderData(c, "ok", nil) return
- routes.go
//新增不需要鉴权的接口 api := r.Group("/api/portal") { api.GET("/collect/apiAllList", collectsGetApiAll) }