Last active
          May 6, 2021 10:44 
        
      - 
      
 - 
        
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.
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | 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