记录 golang 读取打日志文件(27G)

package log

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	filepath  = "./d.log"
	insertNum = 0
)

type Commands struct {
	LogFile string
	Ip      string
	LogType string
	LogDate string
}

func Run() {
	getFile(0)
}

func getFile(step int) {
	if step == 0 {
		fmt.Print("请输入包含全路径的文件:")
	} else {
		fmt.Print("请重新输入:")
	}
	step++
	var c = &Commands{}
	var _, _ = fmt.Scanln(&c.LogFile)
	if ok := Exists(c.LogFile); !ok {
		fmt.Printf("文件不存在:%s\n", c.LogFile)
		getFile(step)
	} else {
		fmt.Print("请输入要重写的日期[格式:20210808]:")
		getLogDate(c)
	}
}

func getLogDate(c *Commands) {
	var _, _ = fmt.Scanln(&c.LogDate)
	if ok, _ := regexp.MatchString("^(20)[0-9]{6}$", c.LogDate); !ok {
		fmt.Print("日期输入有误,请重新输入:")

		getLogDate(c)
	} else {
		fmt.Print("请输入请求的IP:")
		getIp(c)
	}
}

func getIp(c *Commands) {
	var _, _ = fmt.Scanln(&c.Ip)
	if ok, _ := regexp.MatchString("^[0-9]{2,3}(.)[0-9]{1,3}(.)[0-9]{1,3}(.)[0-9]{1,3}$", c.Ip); !ok {
		fmt.Print("IP 有误,请重新输入:")

		getIp(c)
	} else {
		fmt.Print("请输入日志类型,默认[AdClient]:")
		getLogType(c)
	}
}

func getLogType(c *Commands) {
	var _, _ = fmt.Scanln(&c.LogType)
	if ok, _ := regexp.MatchString("^[A-Za-z0-9_]+$", c.LogType); !ok {
		fmt.Print("类型输入有误,请重新输入:")

		getLogType(c)
	} else {
		fmt.Println()
		fmt.Println("日志日期:", c.LogDate)
		fmt.Println("日志文件:", c.LogFile)
		fmt.Println("IP:", c.Ip)
		fmt.Println("日志类型:", c.LogType)
		fmt.Println("开始扫描文件中的日志并重写...")

		RedoLog(c)
	}
}

func RedoLog(c *Commands) {
	f, err := os.Open(c.LogFile)
	if err != nil {
		fmt.Println("文件打开失败")
		return
	}
	defer f.Close()

	buf := bufio.NewReader(f)
	x := 0
	for {
		x++
		line, _, err := buf.ReadLine()
		if err == io.EOF {
			// 文件读取结束
			break
		}
		dataLine := strings.TrimSpace(string(line))
		ok := handleLog(dataLine, c)
		if !ok {
			fmt.Println("当前行重写失败", dataLine)
		}
	}
}

// 处理读取出来的日志信息
func handleLog(logMessage string, c *Commands) bool {
	// 有效数据出现的位置
	//idx := strings.Index(logMessage, "AdClient")
	l := strings.SplitAfter(logMessage, c.LogType)
	lens := len(l)
	if lens == 0 {
		return false
	}
	//l := strings.SplitAfterN(logMessage, "AdClient", 5)
	//fmt.Println(l)
	logs := make([]string, 0)

	for i := 1; i < lens; i++ {
		d := strings.TrimRight(l[i], "\\n"+c.LogType)
		dataFields := strings.Split(d, "|")
		// 长度不为 51 是错误数据,字段共 51 个
		if dl := len(dataFields); dl != 51 {
			// 舍弃
			continue
		}
		t, err := strconv.Atoi(dataFields[26])
		if err != nil {
			fmt.Println("时间格式转化 int 失败,行字段排列有误")
			continue
		}
		dateHour := time.Unix(int64(t), 0)
		if h := dateHour.Format("20060102"); h != c.LogDate {
			fmt.Println("时间格式有误")
			continue
		}
		filename := dateHour.Format("2006010215")
		insertLine := make([]string, 0, 53)
		insertLine = append(insertLine, c.Ip)
		insertLine = append(insertLine, dataFields[26])
		insertLine = append(insertLine, c.LogType)
		insertLine = append(insertLine, dataFields...)
		// 重组后的字符串再放入切片
		reLog := strings.Join(insertLine, "|")
		logs = append(logs, reLog)

		filepath = "./d_" + filename + ".log"
	}

	writeLog(filepath, logs)

	return true
}

func writeLog(filepath string, logMessage []string) {
	o, err := os.OpenFile(filepath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 755)
	if err != nil {
		fmt.Println("文件打开失败")
		return
	}
	defer o.Close()

	for _, log := range logMessage {
		o.WriteString(log + "\r\n")
		insertNum++
		fmt.Printf("写入成功 %d 行...\n", insertNum)
	}
}

// 判断文件是否存在
func Exists(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}
posted @ 2021-08-16 10:25  Silent-Cxl  阅读(497)  评论(0)    收藏  举报