【Go】go-es统计接口被刷数和ip访问来源

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。所以需要进行编程的处理

环境

go-elasticsearch 模块

eql

  • 实现统计数据分析的核心就是eql(es查询语言),通过go-elasticsearch模块进行eql的发送,再接收es返回的回复体
  • 以下是使用go-es发送eql后,es的回复体的struct源码
  • 可以看到type Response struct 中,我们想要的json数据在Body中,但是注意Body的类型为 io.ReadCloser , 因此是需要用go的io模块进行获取json数据
    • 这边解决读取问题的代码如下。该函数接收es响应体,并返回未序列化的byte切片
go 复制代码
// 处理es的响应,获取响应体里的Body
func getResponseBody(result *esapi.Response, context *gin.Context) []byte {
	// 接收es回复体里返回的数据,这里返回io流,需要用对应方法接收
	var bodyBytes []byte
	bodyBytes, err := io.ReadAll(result.Body)
	if err != nil {
		panic(err)
	}
	return bodyBytes
}

es客户端建立连接

go 复制代码
package esinit

import (
	"github.com/elastic/go-elasticsearch/v7"
	"io/ioutil"
	"log"
)

var EsClient *elasticsearch.Client

func 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"聚合统计
go 复制代码
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字段数据
go 复制代码
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条记录
go 复制代码
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的模块进行处理,就能够得到数据。然后便可进行渲染
相关推荐
研究是为了理解1 小时前
Git Bash 常用命令
git·elasticsearch·bash
杜杜的man4 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*4 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
半桶水专家4 小时前
go语言中package详解
开发语言·golang·xcode
llllinuuu4 小时前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s4 小时前
Golang--协程和管道
开发语言·后端·golang
王大锤43914 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
产幻少年4 小时前
golang函数
golang
为什么这亚子4 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
半桶水专家4 小时前
用go实现创建WebSocket服务器
服务器·websocket·golang