本想说从头开始做一个日志采集工具,emmm... 但是发现自己实现的主要功能都是无关紧要的,我就是一个技艺不精的缝衣匠,谈何而来的从头开始,哈哈哈 自我吐槽一番
使用的技术栈:
后端的开发语言: golang
前端框架: vue3
主要功能
-
日志采集
实现日志采集的功能,
golang中实现找到了github.com/hpcloud/tail这个库,我fork了一下然后升级成了go mod模式, 库的地址github.com/issueye/tail使用简单的几句代码就能够实现对日志文件的监听
cfg := tail.Config{
ReOpen: true, // 重新打开
Follow: true, // 是否跟随
Location: &tail.SeekInfo{Offset: 0, Whence: 2}, // 从文件的哪个地方开始读
MustExist: false, // 文件不存在不报错
Poll: true,
}
tails, err := tail.TailFile("server.log", cfg)
if err != nil {
fmt.Println("tail file failed, err:", err)
return
}
fmt.Println("开启监听:", a.Path)
// 开始监听文件
for {
select {
case line, ok := <-tails.Lines: // 读内容
{
//遍历chan,读取日志内容
if !ok {
fmt.Printf("tail file close reopen, filename:%s\n", tails.Filename)
time.Sleep(time.Second)
continue
}
fmt.Printf("content:%s\n", line.Text)
}
}
}
-
扩展性
通过使用动态脚本语言来增加动态扩展性,使用库
github.com/issueye/lichee-js使golang运行javascript脚本,库内部使用了github.com/dop251/goja这个库
src := `
console.log('你好')
`
c := licheejs.NewCore()
err := c.RunString("test", src)
if err != nil {
panic(fmt.Errorf("运行代码失败,失败原因:%s", err.Error()))
}
-
动态添加
添加前端管理页面,动态的添加监听的路径日志,实现对多个日志的同时监听,使用
vue3前端框架开发一个简单的管理页面 -
本地保存记录
使用
sqlite存储数据,为了避免使用gcc所以使用的是用golang实现的sqlie库github.com/glebarez/sqlite
项目搭建
代码主要目录 internal
公共包目录 pkg
├─internal // 主要的内部代码
│ ├─agent // 对日志文件的处理
│ ├─controller // 控制器
│ ├─config // 配置
│ ├─global // 内部的全局内容
│ ├─initialize // 初始化
│ ├─middleware // 中间件
│ ├─model // 数据模型
│ ├─router // 路由
│ └─service // service
├─pkg
│ ├─db // 数据库
│ ├─logger // 日志
│ ├─middleware // 中间件
│ ├─res // 返回
│ ├─utils // 工具方法
│ ├─validator // 表单验证
│ └─ws // websocket
首先完成 main.go
主要是调用初始化单元的初始化方法进行初始化
func main() {
initialize.Initialize()
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
}
在包 initialize 中添加文件 initialize.go 并且添加方法 Initialize()
// 对项目初始化,并且启动服务
func Initialize() {
// ...
}
程序所生成的文件都要存放在一个固定的文件夹下,我们规定生成的文件都放在 runtime 文件夹下,生成的数据库文件存放到 data 文件夹下,日志存放到 logs 文件夹下,静态文件存放当在 static 文件夹下
在包 initialize 添加文件 init_runtime.go 添加方法 isExistsCreatePath
func isExistsCreatePath(path, name string) string {
p := filepath.Join(path, name)
exists, err := utils.PathExists(p)
if err != nil {
panic(err.Error())
}
if !exists {
panic(fmt.Errorf("创建【%s】文件夹失败", name))
}
return p
}
PathExists :判断文件夹是否存在
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
// 创建文件夹
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return false, err
} else {
return true, nil
}
}
return false, err
}
添加方法 InitRuntime 用来初始化创建对应的文件夹
func InitRuntime() {
// 检查本地是否存在runtime文件夹
// 获取当前程序的路径
path := utils.GetWorkDir()
rtPath := isExistsCreatePath(path, "runtime")
isExistsCreatePath(rtPath, "data")
isExistsCreatePath(rtPath, "logs")
staticPath := isExistsCreatePath(rtPath, "static")
}
GetWorkDir :获取程序当前运行目录
// 获取程序运行目录
func GetWorkDir() string {
pwd, _ := os.Getwd()
return pwd
}