Skip to content

Instantly share code, notes, and snippets.

@k8scat
Last active May 6, 2021 10:44
Show Gist options
  • Save k8scat/c5e41f3f011e176e08a4b76999011235 to your computer and use it in GitHub Desktop.
Save k8scat/c5e41f3f011e176e08a4b76999011235 to your computer and use it in GitHub Desktop.
Filter content by date range or read only last N lines of a file.
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"io"
"os"
"regexp"
"time"
)
var (
logFile string
afterLines int
startDate string
endDate string
mode string
lineNum int
)
const (
modeDate = "date"
modeLine = "line"
)
type DateRange struct {
Start int64
End int64
}
func (dr *DateRange) MatchDate(b []byte) bool {
ly := "2006-01-02"
f := time.Unix(dr.Start, 0)
ts := time.Unix(dr.End, 0).Format(ly)
for {
fs := f.Format(ly)
r := regexp.MustCompile(fmt.Sprintf(".*%s.*", fs))
if r.Match(b) {
return true
}
if fs == ts {
return false
}
f = f.AddDate(0, 0, 1)
}
}
func GetLogByLine(r io.Reader, n int) []byte {
buf := bufio.NewReader(r)
lines := make([][]byte, 0)
var pre bool
for {
line, isPrefix, err := buf.ReadLine()
if err != nil {
break
}
if !pre {
lines = append(lines, line)
} else if len(lines) > 0 {
lines[len(lines)-1] = append(lines[len(lines)-1], line...)
}
if !isPrefix && len(lines) > n {
lines = lines[1:]
}
pre = isPrefix
}
result := bytes.Join(lines, []byte("\r\n"))
return result
}
// param `al` means "After Lines"
func GetLogByDateRange(r io.Reader, dr *DateRange, al int) []byte {
buf := bufio.NewReader(r)
lines := make([][]byte, 0)
var pre bool
var c int
for {
line, isPrefix, err := buf.ReadLine()
if err != nil {
break
}
m := dr.MatchDate(line)
if m || (c > 0 && c <= al) {
if pre {
lines[len(lines)-1] = append(lines[len(lines)-1], line...)
} else {
lines = append(lines, line)
// Reset c if line matched, or increase c
if m {
c = 1
} else {
c++
}
}
} else if c != 0 {
c = 0
}
pre = isPrefix
}
return bytes.Join(lines, []byte("\r\n"))
}
func main() {
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Filter content by date range or read only last N lines of a file.\n")
fmt.Fprintf(flag.CommandLine.Output(), "Created by K8sCat <[email protected]>\n\n")
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0])
flag.PrintDefaults()
}
flag.StringVar(&logFile, "f", "", "Log file")
flag.StringVar(&startDate, "start-date", "", "Start date, layout `2006-01-02`")
flag.StringVar(&endDate, "end-date", "", "End date, layout `2006-01-02`")
flag.IntVar(&afterLines, "a", 0, "After lines")
flag.IntVar(&lineNum, "n", 10, "Line count")
flag.StringVar(&mode, "m", modeLine, "Mode, date or line")
flag.Parse()
f, _ := time.Parse("2006-01-02", startDate)
t, _ := time.Parse("2006-01-02", endDate)
dr := &DateRange{
Start: f.Unix(),
End: t.Unix(),
}
file, err := os.Open(logFile)
if err != nil {
panic(err)
}
var result []byte
switch mode {
case modeLine:
result = GetLogByLine(file, lineNum)
case modeDate:
result = GetLogByDateRange(file, dr, afterLines)
default:
panic("mode not support")
}
fmt.Println(string(result))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment