日志统计系统的整体思路就是监控各个文件夹下的日志,实时获取日志写入内容并写入kafka队列,写入kafka队列可以在高并发时排队,而且达到了逻辑解耦合的目的。然后从kafka队列中读出数据,根据实际需求显示网页上或者控制台等。

前情提要

上一节我们完成了如下目标
1 配置kafka,并启动消息队列。
2 编写代码向kafka录入消息,并且从kafka读取消息。

本节目标

1 写代码从kafka中读取消息,保证kafka消息读写功能无误。
2 借助tailf实现文件监控,并模拟测试事实写文件以及文件备份时功能无误。
3 本系列文章开发语言使用Go

从kafka中读取消息

func main(){
fmt.Println("consumer begin...")
config := sarama.NewConfig()
config.Consumer.Return.Errors = true
wg :=sync.WaitGroup{}
//创建消费者
consumer, err := sarama.NewConsumer([]string{"localhost:9092"},config)
if err != nil {
fmt.Println("consumer create failed, error is ", err.Error())
return
}
defer consumer.Close() //Partitions(topic):该方法返回了该topic的所有分区id
partitionList, err := consumer.Partitions("test")
if err != nil {
fmt.Println("get consumer partitions failed")
fmt.Println("error is ", err.Error())
return
} for partition := range partitionList {
//ConsumePartition方法根据主题,
//分区和给定的偏移量创建创建了相应的分区消费者
//如果该分区消费者已经消费了该信息将会返回error
//OffsetNewest消费最新数据
pc, err := consumer.ConsumePartition("test", int32(partition), sarama.OffsetNewest)
if err != nil {
panic(err)
}
//异步关闭,保证数据落盘
defer pc.AsyncClose()
wg.Add(1)
go func(sarama.PartitionConsumer) {
defer wg.Done()
//Messages()该方法返回一个消费消息类型的只读通道,由代理产生
for msg := range pc.Messages() {
fmt.Printf("%s---Partition:%d, Offset:%d, Key:%s, Value:%s\n",
msg.Topic,msg.Partition, msg.Offset, string(msg.Key), string(msg.Value))
}
}(pc)
}
wg.Wait()
consumer.Close() }

  

这样我们启动zookeeper和kafka后,分别运行前文实现的向kafka中写入数据的代码,以及现在的从kafka中消费的代码,看到如下效果

实现文件监控

实现文件监控,主要是在文件中有内容写入时,程序可以及时获取写入的内容,类似于Linux命令中的tailf -f 某个文件的功能。
golang 中提供了tail库,我们借助这个库完成指定文件的监控,我的文件组织如下

logdir文件夹下的log.txt记录的是不断增加的日志文件
tailf文件夹下logtailf.go实现log.txt监控功能。
writefile文件夹下writefile.go实现的是向log.txt文件写日志并备份的功能。

func main() {
logrelative := `../logdir/log.txt`
_, filename, _, _ := runtime.Caller(0)
fmt.Println(filename)
datapath := path.Join(path.Dir(filename), logrelative)
fmt.Println(datapath)
tailFile, err := tail.TailFile(datapath, tail.Config{
//文件被移除或被打包,需要重新打开
ReOpen: true,
//实时跟踪
Follow: true,
//如果程序出现异常,保存上次读取的位置,避免重新读取
Location: &tail.SeekInfo{Offset: 0, Whence: 2},
//支持文件不存在
MustExist: false,
Poll: true,
}) if err != nil {
fmt.Println("tail file err:", err)
return
} for true {
msg, ok := <-tailFile.Lines
if !ok {
fmt.Printf("tail file close reopen, filename: %s\n", tailFile.Filename)
time.Sleep(100 * time.Millisecond)
continue
}
//fmt.Println("msg:", msg)
//只打印text
fmt.Println("msg:", msg.Text)
}
}

为了测试监控的功能。我们实现向log.txt中每隔0.1s写入一行”Hello+时间戳”的日志。当写入20条内容后我们将log.txt备份重命名。
然后创建新的log.txt继续写入。
在writefile.go实现一个函数定时写入,并且备份功能

func writeLog(datapath string) {
filew, err := os.OpenFile(datapath, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
fmt.Println("open file error ", err.Error())
return
} w := bufio.NewWriter(filew)
for i := 0; i < 20; i++ {
timeStr := time.Now().Format("2006-01-02 15:04:05")
fmt.Fprintln(w, "Hello current time is "+timeStr)
time.Sleep(time.Millisecond * 100)
w.Flush()
}
logBak := time.Now().Format("20060102150405") + ".txt"
logBak = path.Join(path.Dir(datapath), logBak)
filew.Close()
err = os.Rename(datapath, logBak)
if err != nil {
fmt.Println("Rename error ", err.Error())
return
}
}

  然后我们实现main函数,调用三次writeLog,这样会产生三个备份文件

func main() {
logrelative := `../logdir/log.txt`
_, filename, _, _ := runtime.Caller(0)
fmt.Println(filename)
datapath := path.Join(path.Dir(filename), logrelative)
for i := 0; i < 3; i++ {
writeLog(datapath)
}
}

 

我们分别启动文件监控和文件写入程序,效果如下

可以看到,当log.txt有内容写入时,logtailf.go实现了动态监控,而且当文件备份时,logtailf.go提示了文件被重命名备份。
最终我们看到产生三个备份文件

总结

目前我们已经完成了kafka消息读写,文件监控,动态写入和备份等功能,接下来我们实现项目的配置化和统筹代码。
源码下载
https://github.com/secondtonone1/golang-
感谢关注我的公众号

Go项目实战:打造高并发日志采集系统(二)的更多相关文章

  1. Go项目实战:打造高并发日志采集系统(一)

    项目结构 本系列文章意在记录如何搭建一个高可用的日志采集系统,实际项目中会有多个日志文件分布在服务器各个文件夹,这些日志记录了不同的功能.随着业务的增多,日志文件也再增多,企业中常常需要实现一个独立的 ...

  2. Go项目实战:打造高并发日志采集系统(六)

    前情回顾 前文我们完成了日志采集系统的日志文件监控,配置文件热更新,协程异常检测和保活机制. 本节目标 本节加入kafka消息队列,kafka前文也介绍过了,可以对消息进行排队,解耦合和流量控制的作用 ...

  3. Go项目实战:打造高并发日志采集系统(三)

    前文中已经完成了文件的监控,kafka信息读写,今天主要完成配置文件的读写以及热更新.并且规划一下系统的整体结构,然后将之前的功能串起来形成一套完整的日志采集系统. 前情提要 上一节我们完成了如下目标 ...

  4. Go项目实战:打造高并发日志采集系统(四)

    前情回顾 前文我们完成了如下目标1 项目架构整体编写2 使框架支持热更新 本节目标 在前文的框架基础上,我们1 将之前实现的日志监控功能整合到框架中.2 一个日志对应一个监控协程,当配置热更新后根据新 ...

  5. Go项目实战:打造高并发日志采集系统(五)

    前情回顾 前文我们完成了如下功能1 根据配置文件启动多个协程监控日志,并启动协程监听配置文件.2 根据配置文件热更新,动态协调日志监控.3 编写测试代码,向文件中不断写入日志并备份日志,验证系统健壮性 ...

  6. 《实战java高并发程序设计》源码整理及读书笔记

    日常啰嗦 不要被标题吓到,虽然书籍是<实战java高并发程序设计>,但是这篇文章不会讲高并发.线程安全.锁啊这些比较恼人的知识点,甚至都不会谈相关的技术,只是写一写本人的一点读书感受,顺便 ...

  7. 《实战Java高并发程序设计》读书笔记

    文章目录 第二章 Java并行程序基础 2.1 线程的基本操作 2.1.1 线程中断 2.1.2 等待(wait)和通知(notify) 2.1.3 等待线程结束(join)和谦让(yield) 2. ...

  8. 【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  9. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

随机推荐

  1. 使用php实现javascript的escape和unescape函数

    javascript有编码函数escape()和对应的解码函数unescape(),而php中只有个urlencode和urldecode,这个编码和解码函数对encodeURI和encodeURIC ...

  2. Appium Desired Capabilities-Android Only

    Android Only These Capabilities are available only on Android-baseddrivers (like UiAutomator2for exa ...

  3. 平衡树treap 0基础详解

    刚开始学treap..同学在台上给我们讲,貌似除我之外的机房dalao们都听懂了就我发呆...(滑稽) 于是,事后的窝只能自己上网翻书研究了.... treap: treap=tree+heap,树+ ...

  4. Java笔记(基础第二篇)

    声明数组 数组元素类型 数组名字[]; 数组元素类型[] 数组名字; 分配内存空间 数组名字 = new 数组元素类型[数组元素的个数] 其中使用new关键字为数组分配内存时,数组中各个元素的初始化值 ...

  5. [React] Reduce Code Redundancy with Custom React Hooks

    In this lesson, we'll cover how to create a custom React hook for managing the state of any input. T ...

  6. Codeforces Round #453 (Div. 1) 901C C. Bipartite Segments

    题 http://codeforces.com/contest/901/problem/C codeforces 901C 解 首先因为图中没有偶数长度的环,所以: 1.图中的环长度全是奇数,也就是说 ...

  7. yarn是什么?

    yarn是个包管理器.你可以通过它使用全世界开发者的代码, 或者分享自己的代码. 从 npm 安装软件包并保持相同的包管理流程. 优点:         1.速度超快. Yarn 缓存了每个下载过的包 ...

  8. 第四届西安邮电大学acm-icpc校赛 热狗树

    题目描述  “我是番茄酱!”“我是黄芥末酱!”“合在一起就是——美式热狗上加的,那个!“热狗树上的每个节点都涂有番茄酱或者黄芥末酱中的一种,这样热狗树就变得美味了~LiMn2O4构造了一颗热狗树,他想 ...

  9. 秒的换算:ms(毫秒),μs(微秒),ns(纳秒),ps(皮秒)

    皮秒 皮秒,符号ps(英语:picosecond ).1皮秒等于一万亿分之一秒(10-12秒) 1,000 皮秒 = 1纳秒 1,000,000 皮秒 = 1微秒 1,000,000,000 皮秒 = ...

  10. CDQ分治的嵌套

    CDQ的嵌套 上一篇博客介绍了一下CDQ的入门思想.这里再介绍一下它的进阶,CDQ套CDQ.其实如果对入门思想掌握的透彻,嵌套也是很容易掌握的,思想是一样的. 什么是嵌套 简单地说,有的问题,如果用一 ...