golang+influxdb+grafana 实现 nginx 日志流量、响应时间等监控系统

本贴最后更新于 2375 天前,其中的信息可能已经时过境迁

先看下具体效果图
imagepng

主要是对自己博客服务器的流量的监控
imagepng

主要思路

读取日志-> 正则解析-> 写入 influxdb->grafana 获取数据渲染

首先我们需要先将 influxdb 和 grafana 安装部署好 以便于后面使用

centos7 安装 influxdb

wget https://dl.influxdata.com/influxdb/releases/influxdb-0.13.0.x86_64.rpm sudo yum localinstall influxdb-0.13.0.x86_64.rpm service influxdb restart 如果遇到influxdb 8083端口访问不到web管理页面则需要到/etc/influxdb/influxdb.conf 修改参数 vim 命令模式下:/admin搜索到对应部分去掉注释#[admin] #enabled=true [admin] # Determines whether the admin service is enabled. enabled =true # The default bind address used by the admin service. bind-address = ":8083" # Whether the admin service should use HTTPS. # https-enabled = false # The SSL certificate used when HTTPS is enabled. # https-certificate = "/etc/ssl/influxdb.pem" 然后具体操作添加用户,建库什么均在百度,和mysql大同小异

centos7 下安装 grafana
官方文档中有很多办法
我是通过配置 yum 然后 install 的

Add the following to a new file at /etc/yum.repos.d/grafana.repo [grafana] name=grafana baseurl=https://packagecloud.io/grafana/stable/el/7/$basearch repo_gpgcheck=1 enabled=1 gpgcheck=1 gpgkey=https://packagecloud.io/gpg.key https://grafanarel.s3.amazonaws.com/RPM-GPG-KEY-grafana sslverify=1 sslcacert=/etc/pki/tls/certs/ca-bundle.crt sudo yum install grafana service grafana-server restart 默认跑在3000端口 账号密码为 admin admin

代码实现

type Reader interface { Read(rc chan []byte) } type Writer interface { Write(rc chan *Message) } //存入db的基本数据 type Message struct { Host string TimeLocal time.Time Method, Resource, Protocol string Status string BytesSent int Scheme string Url string UpstreamTime, RequestTime float64 } //扩展性实现接口的struct type ReadFromFile struct { path string } type WriteToInfluxDB struct { influxDBDsn string } //日志解析中转 type LogProcess struct { rc chan []byte wc chan *Message read Reader write Writer }

从文件中读取数据(注释中的数据为我 nginx 日志中的一条数据)

/*14.215.176.15 - - [23/APR/2018:21:43:39 +0800] "GET /CONSOLE/DIST/LAYOUTS/DEFAULT.F5E6C608DE637CAC3F50.JS HTTP/1.1" 200 5665 "HTTPS://WWW.XHXBLOG.CN/?B3ID=H9OXZSYM" "MOZILLA/5.0 (WINDOWS NT 6.1; WOW64; RV:43.0) GECKO/20100101 FIREFOX/43.0" "-"*/ func (r *ReadFromFile) Read(rc chan []byte) { //读取数据 f, err := os.Open(r.path) if err != nil { panic(fmt.Sprintf("open file fail:%s", err.Error())) } //跳到文件末尾 f.Seek(0, 2) rd := bufio.NewReader(f) //循环读取数据将每行数据送入rc channel for { line, err := rd.ReadBytes('\n') if err == io.EOF { time.Sleep(500 * time.Millisecond) continue } else if err != nil { panic(fmt.Sprintf("ReadBytes error: %s", err.Error())) } TypeMonitorChan <- TypeHandleLine rc <- line[:len(line)-1] } }

正则解析数据(参考正则表达解析,使用该工具调试)

正则测试模块没有单独写出来了,放在如下函数的注释中测试

其中 method,resource,protocol 等是通过正则解析后的字符串再次通过空格 split 分割获取的

func (l *LogProcess) Process() { //解析数据 r := regexp.MustCompile(`([\d\.]+)\s+([^\[]+)\s+([^\[]+)\s+\[([^\]]+)\]\s+\"([^"]+)\"\s+(\d{3})\s+(\d+)\s+\"([^"]+)\"\s+\"([^"]+)\"\s+`) /** 测试flag */ //flag := 0 loc, _ := time.LoadLocation("Asia/Shanghai") for v := range l.rc { ret := r.FindStringSubmatch(string(v)) /*测试**/ /* if flag != 2 { sp := strings.Split(ret[5], " ") fmt.Println(ret) fmt.Println("Host:", ret[1]) fmt.Println("LocalTime:", ret[4]) fmt.Println("Method:", sp[0]) uu, _ := url.Parse(sp[1]) fmt.Println(uu.Path) fmt.Println("Path:", sp[1]) fmt.Println("Protocol:", sp[2]) fmt.Println("Status:", ret[6]) fmt.Println("BytesSent:", ret[7]) fmt.Println("Scheme:", ret[9]) fmt.Println(ret[8]) flag++ } */ if len(ret) != 10 { TypeMonitorChan <- TypeErrNum log.Println("FindStringSubmatch fail:", string(v)) continue } t, err := time.ParseInLocation("02/Jan/2006:15:04:05 +0800", ret[4], loc) if err != nil { log.Println("ParseInLocation fail:", err.Error(), ret[4]) } message := &Message{} //14.215.176.15 message.Host = ret[1] //23/APR/2018:21:43:39 +0800 message.TimeLocal = t //MOZILLA/5.0 (WINDOWS NT 6.1; WOW64; RV:43.0) GECKO/20100101 FIREFOX/43.0 message.Scheme = ret[9] //GET /CONSOLE/DIST/LAYOUTS/DEFAULT.F5E6C608DE637CAC3F50.JS HTTP/1.1 sp := strings.Split(ret[5], " ") if len(sp) != 3 { TypeMonitorChan <- TypeErrNum log.Println("strings.Split fail:", ret[5]) continue } //请求方法 message.Method = sp[0] //请求路径 u, err := url.Parse(sp[1]) if err != nil { TypeMonitorChan <- TypeErrNum log.Println("url parse fail:", err) continue } message.Resource = u.Path //请求协议 message.Protocol = sp[2] //200 message.Status = ret[7] //HTTPS://WWW.XHXBLOG.CN/?B3ID=H9OXZSYM message.Url = ret[8] //5665 message.BytesSent, _ = strconv.Atoi(ret[7]) l.wc <- message } }

写入 influxdb 客户端是用 golang 写的 influxdb gay 地址为:InfluxDB Client

func (w *WriteToInfluxDB) Write(wc chan *Message) { sp := strings.Split(w.influxDBDsn, "@") // Create a new HTTPClient c, err := client.NewHTTPClient(client.HTTPConfig{ Addr: sp[0], Username: sp[1], Password: sp[2], }) if err != nil { log.Fatal(err) } defer c.Close() for v := range wc { // Create a new point batch bp, err := client.NewBatchPoints(client.BatchPointsConfig{ Database: sp[3], Precision: sp[4], }) if err != nil { log.Fatal(err) } // Create a point and add to batch tags := map[string]string{"Path": v.Resource, "Method": v.Method, "Scheme": v.Scheme, "Status": v.Status, "Protocol": v.Protocol} fields := map[string]interface{}{ "RequestTime": 2.0, "BytesSent": v.BytesSent, } pt, err := client.NewPoint("nginx_log", tags, fields, v.TimeLocal) if err != nil { log.Fatal(err) } bp.AddPoint(pt) // Write the batch if err := c.Write(bp); err != nil { log.Fatal(err) } // Close client resources if err := c.Close(); err != nil { log.Fatal(err) } log.Println("write success") } }
type SystemInfo struct { HandleLine int `json:"handleLine"` Tps float64 `json:"tps"` ReadChanLen int `json:"readChanLen"` WriteChanLen int `json:"writeChanLen"` RunTime string `json:"runTime"` ErrNum int `json:"errNum"` } type Monitor struct { startTime time.Time data SystemInfo tpsSli []int }

此处主要监控运行时间,channel 阻塞数量,处理条数监听一个端口在 8999 上
其次该监听将阻塞在 main 函数上

//专门接收内容的channel,错误数量和处理条数 var TypeMonitorChan = make(chan int, 200) func (m *Monitor) start(lp *LogProcess) { go func() { for n := range TypeMonitorChan { switch n { case TypeErrNum: m.data.ErrNum += 1 case TypeHandleLine: m.data.HandleLine += 1 } } }() ticker := time.NewTicker(time.Second * 5) go func() { <-ticker.C m.tpsSli = append(m.tpsSli, m.data.HandleLine) //目的是为了通过两次读取的行数除以单位时间就能得到大概的吞吐量 if len(m.tpsSli) > 2 { m.tpsSli = m.tpsSli[1:] } }() http.HandleFunc("/monitor", func(writer http.ResponseWriter, request *http.Request) { m.data.RunTime = time.Now().Sub(m.startTime).String() m.data.ReadChanLen = len(lp.rc) m.data.WriteChanLen = len(lp.wc) if len(m.tpsSli) >= 2 { m.data.Tps = float64(m.tpsSli[1]-m.tpsSli[0]) / 5 } ret, _ := json.MarshalIndent(m.data, "", "\t") io.WriteString(writer, string(ret)) }) http.ListenAndServe(":8999", nil) }
func main() { //通过命令行模式输入参数简单化,不输则为默认值 var path, influxDsn string flag.StringVar(&path, "path", "/var/log/nginx/access.log", "read file path") flag.StringVar(&influxDsn, "influxDsn", "http://127.0.0.1:8086@haoxiong@8080@nginx_log@s", "influx data source") flag.Parse() r := &ReadFromFile{ path: path, } w := &WriteToInfluxDB{ influxDBDsn: influxDsn, } lp := &LogProcess{ rc: make(chan []byte, 200), wc: make(chan *Message), read: r, write: w, } go lp.read.Read(lp.rc) for i := 0; i < 2; i++ { go lp.Process() } for i := 0; i < 4; i++ { go lp.write.Write(lp.wc) } m := &Monitor{ startTime: time.Now(), data: SystemInfo{}, } //监听一个端口阻塞main m.start(lp) }
具体代码
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 248 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
xhaoxiong
站在巨人的肩膀上学习与创新

推荐标签 标签

  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    556 引用 • 675 回帖
  • 招聘

    哪里都缺人,哪里都不缺人。

    188 引用 • 1057 回帖
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • 印象笔记
    3 引用 • 16 回帖 • 3 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    12 引用 • 5 回帖 • 631 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 508 关注
  • gRpc
    11 引用 • 9 回帖 • 92 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 615 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    24 引用 • 241 回帖
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    133 引用 • 796 回帖
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 248 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    89 引用 • 122 回帖 • 618 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 31 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25344 引用 • 104675 回帖 • 1 关注
  • abitmean

    有点意思就行了

    36 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 691 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 3 关注
  • 996
    13 引用 • 200 回帖 • 5 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 650 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 164 关注
  • 自由行
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 93 关注
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 812 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖