云南建设人才网站首页,湘潭网站优化公司,跟我一起做网站pdf电驴,wordpress 查看文章go-es模块统计日志中接口被刷数和ip访问来源
以下是使用go的web框架gin作为后端#xff0c;展示的统计页面
背景
上面的数据来自elk日志统计。因为elk通过kibana进行展示#xff0c;但是kibana有一定学习成本且不太能满足定制化的需求#xff0c;所以考虑用编程的方式…go-es模块统计日志中接口被刷数和ip访问来源
以下是使用go的web框架gin作为后端展示的统计页面
背景
上面的数据来自elk日志统计。因为elk通过kibana进行展示但是kibana有一定学习成本且不太能满足定制化的需求所以考虑用编程的方式对数据进行处理首先是接口统计kibana的页面只会在 字段uri 的 top500 进行百分比统计展示前5条数据统计不够充分 其次是网关日志ip来源的采集字段是通过x_forward_for这记录了各级的代理来源ip。并不能直接对用户的ip进行数据聚合的统计 举例这里面 “223.104.195.51,192.168.29.135” 这种数据我需要拿到223.104.195.51因为这才是用户的ip。所以需要进行编程的处理
环境
elk 7.9
https://www.elastic.co/downloads/past-releases/elasticsearch-7-9-3go 1.17 gin 1.6.3go-elasticsearch 7.9.0
# go1.17下载地址
https://go.dev/dl/# 模块下载
go env -w GOPROXYhttps://goproxy.cn,direct
go mod init go-ops # 本项目的go mod 名字
go get github.com/elastic/go-elasticsearch/v7v7.9.0
go get github.com/gin-gonic/ginv1.6.3前端layui 和 echarts
# layui下载
http://layui.dotnetcms.cn/res/static/download/layui/layui-v2.6.8.zip?v1
# layui框架代码
http://layui.dotnetcms.cn/web/demo/admin.html
# layui数据表格
http://layui.dotnetcms.cn/web/demo/table.html
# echarts下载需魔法
https://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js
# echarts直方图
https://echarts.apache.org/handbook/zh/get-started/
# echarts 饼图
https://echarts.apache.org/handbook/zh/how-to/chart-types/pie/basic-pie/后端
# gin静态文件服务(导入js、css、图片用的)
https://learnku.com/docs/gin-gonic/1.7/examples-serving-static-files/11402
# gin模板引擎前后端不分离后端数据渲染前端
https://learnku.com/docs/gin-gonic/1.7/examples-html-rendering/11363
# gin绑定Uri动态获取二级路由
https://learnku.com/docs/gin-gonic/1.7/examples-bind-uri/11391go-elasticsearch 模块
顾名思义此模块作用是充当es的客户端往es索引中读取数据其原理和kibana上的dev tools一样都是对es的restful api调用
# 以下是go-elasticsearch 的增删查改文档
https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/getting-started-go.htmleql
实现统计数据分析的核心就是eqles查询语言通过go-elasticsearch模块进行eql的发送再接收es返回的回复体 以下是使用go-es发送eql后es的回复体的struct源码 可以看到type Response struct 中我们想要的json数据在Body中但是注意Body的类型为 io.ReadCloser 因此是需要用go的io模块进行获取json数据 这边解决读取问题的代码如下。该函数接收es响应体并返回未序列化的byte切片
// 处理es的响应获取响应体里的Body
func getResponseBody(result *esapi.Response, context *gin.Context) []byte {// 接收es回复体里返回的数据这里返回io流需要用对应方法接收var bodyBytes []bytebodyBytes, err : io.ReadAll(result.Body)if err ! nil {panic(err)}return bodyBytes
}es客户端建立连接
文档地址
https://www.elastic.co/guide/en/elasticsearch/client/go-api/current/connecting.html这边给的是https连接 用户名密码认证 不受信任证书的解决方法
package esinitimport (github.com/elastic/go-elasticsearch/v7io/ioutillog
)var EsClient *elasticsearch.Clientfunc init() {EsClient newEsClient()
}func newEsClient() *elasticsearch.Client {cert, certErr : ioutil.ReadFile(esinit/es.crt) // 你的不受信任的https证书if certErr ! nil {log.Println(certErr)}EsClient, error : elasticsearch.NewClient(elasticsearch.Config{Username: 你的用户名,Password: 你的密码,Addresses: []string{https://es-cluster1:9200,https://es-cluster2:9200,https://es-cluster3:9200,},CACert: cert,})if error ! nil {panic(error)}return EsClient
}
实现统计的三段eql
这里eql使用 fmt.Sprintf() 方法进行参数传递第一段eql是统计PV 这里注意的是我们在东八区所以统计pv从16:00开始。这里根据timestamp字段进行“aggs”聚合统计
func getPvResponse(startYear int, startMonth int, startDay int, endYear, endMonth int, endDay int) *esapi.Response {query : fmt.Sprintf(
{query: {bool: {must: [{range: {timestamp: {gte: %d-%02d-%02dT16:00:00,lte: %d-%02d-%02dT16:00:00}}}]}},aggs: {log_count: {value_count: {field: timestamp}}}
}
, startYear, startMonth, startDay, endYear, endMonth, endDay)result, _ : esinit.EsClient.Search(esinit.EsClient.Search.WithIndex(k8s-istio-ingress*), // 索引名esinit.EsClient.Search.WithBody(strings.NewReader(query)), // eql)return result
}第二段是对微服务java的接口uri字段的聚合统计 这里用的 sortUri 是gin的绑定uri功能动态获取二级路由的名字这里返回前1天10000条es文档的uri字段数据
func getSortResponse(context *gin.Context) *esapi.Response {if err : context.ShouldBindUri(sortUri); err ! nil { // sortUri二级路由传递索引名context.JSON(400, gin.H{msg: err})}//搜索文档// eql 搜索时间范围内10000条记录并只展示uri字段的内容query : fmt.Sprintf({_source: [uri],query: {bool: {filter: [{range: {timestamp: {gte: now-1d/d,lte: now/d}}}]}},size: 10000})// 对应索引进行搜索result, _ : esinit.EsClient.Search(esinit.EsClient.Search.WithIndex(sortUri.Name*),esinit.EsClient.Search.WithBody(strings.NewReader(query)),)return result
}第三段是对istio前一小时的ip请求统计返回2000条记录
func getIstioDataResponse() *esapi.Response {query :
{_source: [x_forwarded_for,timestamp,path,user_agent_a,response_code,method,upstream_cluster],query: {bool: {filter: [{range: {timestamp: {gte: now-1h/h,lte: now/d}}}]}},size: 2000
}
result, _ : esinit.EsClient.Search(esinit.EsClient.Search.WithIndex(k8s-istio-ingress*),esinit.EsClient.Search.WithBody(strings.NewReader(query)),)return result
}上面的eql函数会return 一个 []byte切片可以进行 json.Unmarshal 或其他struct转json的模块进行处理就能够得到数据。然后便可进行渲染