func (i *Tail) translateConfig(original *TailConfig) tail.Config { config := tail.Config{Follow: true, ReOpen: true} if original.MustExist { config.MustExist = true } if original.Poll { config.Poll = true } if original.LimitRate > 0 { config.RateLimiter = ratelimiter.NewLeakyBucket( uint16(original.LimitRate), time.Second, ) } position := i.readPosition() if position > 0 { config.Location = &tail.SeekInfo{Offset: position, Whence: 0} } return config }
func args2config() (tail.Config, int64) { config := tail.Config{Follow: true} n := int64(0) maxlinesize := int(0) flag.Int64Var(&n, "n", 0, "tail from the last Nth location") flag.IntVar(&maxlinesize, "max", 0, "max line size") flag.BoolVar(&config.Follow, "f", false, "wait for additional data to be appended to the file") flag.BoolVar(&config.ReOpen, "F", false, "follow, and track file rename/rotation") flag.BoolVar(&config.Poll, "p", false, "use polling, instead of inotify") flag.Parse() if config.ReOpen { config.Follow = true } config.MaxLineSize = maxlinesize return config, n }
func tailOptionsToConfig(tailOptions TailOptions) tail.Config { config := tail.Config{ ReOpen: tailOptions.ReOpen, MustExist: tailOptions.MustExist, Poll: tailOptions.Poll, Pipe: tailOptions.Pipe, Follow: tailOptions.Follow, } if tailOptions.Location != nil { config.Location = &tail.SeekInfo{ Offset: tailOptions.Location.Offset, Whence: tailOptions.Location.Whence, } } return config }
func (v *FileTail) watcher() { log.Printf("[INFO] [%s] File watcher started", v.tag) for { for file, _ := range v.files { select { case <-v.files[file].Dying(): log.Printf("[DEBUG] [%s] File \"%s\" closed", v.tag, file) delete(v.files, file) default: continue } } //Search for new files for _, path := range v.paths { f, _ := filepath.Glob(path) for _, file := range f { if _, ok := v.files[file]; !ok { log.Printf("[DEBUG] [%s] Found file \"%s\"", v.tag, file) tc := tail.Config{Follow: true, ReOpen: false, MustExist: true, Poll: true, Logger: tail.DiscardingLogger} if s, err := ioutil.ReadFile(file + ".pos"); err == nil { s := strings.Split(string(s), "\n") if len(s) == 2 { if ctime, err := strconv.Atoi(s[0]); err == nil && int64(ctime) == ctimeFile(file) { if pos, err := strconv.Atoi(s[1]); err == nil { tc.Location = &tail.SeekInfo{Whence: os.SEEK_CUR, Offset: int64(pos)} log.Printf("[DEBUG] [%s] Restoring position %d in file \"%s\"", v.tag, pos, file) } } } } t, err := tail.TailFile(file, tc) if err == nil { go v.worker(t) v.files[file] = t } } } } time.Sleep(time.Second) } }
func (c config) parseFile(ac map[int]Event, f string) map[int]Event { tc := tail.Config{} if *c.TailFile { tc.Follow = true tc.ReOpen = true } //open file for parsing t, err := tail.TailFile(f, tc) check(err) //loop through file contents for line := range t.Lines { var lineMap map[string]string var ok bool if lineMap, ok = matchLine(lineRe, line.Text); !ok { continue } connum, err := strconv.Atoi(lineMap["conn_num"]) if err != nil { fmt.Printf("failed to parse '%s' into int\n", lineMap["conn_num"]) } if connectionMap, ok := matchLine(connectionOpenRe, lineMap["event"]); ok { //new connection made ssl := false if connectionMap["ssl"] == "SSL" { ssl = true } ac[connum] = Event{ Client: connectionMap["client_ip"], Server: connectionMap["server_ip"], Connection: connum, Operation: -2, //number that shouldn't exist in logs ConnTime: lineMap["time"], SSL: ssl, } continue } if _, exists := ac[connum]; !exists { //skip operation if no connection exists // this is caused by connections that were created before we started // parsing the log file. continue } conn := ac[connum] if sslMap, ok := matchLine(sslCipherRe, lineMap["event"]); ok { conn.SSLCipher = sslMap["cipher"] conn.SSLStrength = sslMap["strength"] ac[connum] = conn } if operationMap, ok := matchLine(operationRe, lineMap["event"]); ok { //new operation opnum, err := strconv.Atoi(operationMap["opnum"]) if err != nil { fmt.Printf("failed to parse '%s' into int\n", operationMap["opnum"]) } if opnum != conn.Operation { if conn.Operation != -2 { c.printEvent(conn) } if operationMap["operation"] == "BIND" { if bindDN, ok := matchLine(bindDNRe, lineMap["event"]); ok { conn.AuthenticatedDN = bindDN["dn"] } else { conn.AuthenticatedDN = "__anonymous__" } } conn.OppTime = lineMap["time"] conn.Operation = opnum conn.Action = operationMap["operation"] conn.Requests = make([]string, 0) conn.Responses = make([]string, 0) conn.Requests = append(conn.Requests, operationMap["operation"]+operationMap["details"]) } else { if operationMap["operation"] == "SORT" || operationMap["operation"] == "VLV" { conn.Requests = append(conn.Requests, operationMap["operation"]+operationMap["details"]) } else { conn.Responses = append(conn.Responses, operationMap["operation"]+operationMap["details"]) c.printEvent(conn) conn.Operation = -2 } } ac[connum] = conn } if connectionClosedRe.MatchString(lineMap["event"]) { delete(ac, connum) } } return ac }