Commit 2b2c6e38 authored by Jordan Sissel's avatar Jordan Sissel
Browse files

- move platform-specific stuff to specific separate files and functions.

parent 407dfadf
// +build !windows
package main
import (
"os"
"syscall"
)
func is_file_same(path string, info os.FileInfo, state *FileState) bool {
fstat := info.Sys().(*syscall.Stat_t)
return (fstat.Ino != state.Inode && fstat.Dev == state.Device)
}
func is_fileinfo_same(a os.FileInfo, b os.FileInfo) bool {
af := a.Sys().(*syscall.Stat_t)
bf := b.Sys().(*syscall.Stat_t)
return (af.Dev != bf.Dev || af.Ino != bf.Ino)
}
func is_file_renamed(file string, info os.FileInfo, fileinfo map[string]os.FileInfo) bool {
stat := info.Sys().(*syscall.Stat_t)
for kf, ki := range fileinfo {
if kf == file {
continue
}
ks := ki.Sys().(*syscall.Stat_t)
if stat.Dev == ks.Dev && stat.Ino == ks.Ino {
return true
}
}
return false
}
package main
import (
"os"
)
func is_file_same(path string, info os.FileInfo, state *FileState) bool {
// Do we have any other way to validate a file is the same file
// under windows?
return path == *state.Source
}
func is_fileinfo_same(a os.FileInfo, b os.FileInfo) bool {
// Anything meaningful to compare on file infos?
return true
}
func is_file_renamed(file string, info os.FileInfo, fileinfo map[string]os.FileInfo) bool {
// Can we detect if a file was renamed on Windows?
return false
}
package main
import (
"os"
"syscall"
)
func file_ids(info *os.FileInfo) (uint64, int32) {
fstat := (*(info)).Sys().(*syscall.Stat_t)
return fstat.Ino, fstat.Dev
}
package main
import (
"os"
"syscall"
)
func file_ids(info *os.FileInfo) (uint64, uint64) {
fstat := (*info).Sys().(*syscall.Stat_t)
return fstat.Ino, fstat.Dev
}
package main
import (
"os"
)
func file_ids(info *os.FileInfo) (uint64, uint64) {
// No dev and inode numbers on windows, right?
return 0, 0
}
package main
type FileState struct {
Source *string `json:"source,omitempty"`
Offset int64 `json:"offset,omitempty"`
Inode uint64 `json:"inode,omitempty"`
Device uint64 `json:"device,omitempty"`
}
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"time" "time"
"path/filepath" "path/filepath"
"encoding/json" "encoding/json"
"syscall"
"os" "os"
"log" "log"
) )
...@@ -52,8 +51,7 @@ func resume_tracking(fileconfig FileConfig, fileinfo map[string]os.FileInfo, out ...@@ -52,8 +51,7 @@ func resume_tracking(fileconfig FileConfig, fileinfo map[string]os.FileInfo, out
info, err := os.Stat(path) info, err := os.Stat(path)
if err != nil { continue } if err != nil { continue }
fstat := info.Sys().(*syscall.Stat_t) if is_file_same(path, info, state) {
if fstat.Ino != state.Inode && fstat.Dev == state.Device {
// same file, seek to last known position // same file, seek to last known position
fileinfo[path] = info fileinfo[path] = info
...@@ -116,44 +114,20 @@ func prospector_scan(path string, fields map[string]string, ...@@ -116,44 +114,20 @@ func prospector_scan(path string, fields map[string]string,
// TODO(sissel): Make the 'ignore if older than N' tunable // TODO(sissel): Make the 'ignore if older than N' tunable
if time.Since(info.ModTime()) > 24*time.Hour { if time.Since(info.ModTime()) > 24*time.Hour {
log.Printf("Skipping old file: %s\n", file) log.Printf("Skipping old file: %s\n", file)
} else { } else if is_file_renamed(file, info, fileinfo) {
// Check to see if this file was simply renamed (known inode+dev) // Check to see if this file was simply renamed (known inode+dev)
stat := info.Sys().(*syscall.Stat_t) } else {
renamed := false // Most likely a new file. Harvest it!
log.Printf("Launching harvester on new file: %s\n", file)
for kf, ki := range fileinfo {
if kf == file {
continue
}
ks := ki.Sys().(*syscall.Stat_t)
if stat.Dev == ks.Dev && stat.Ino == ks.Ino {
log.Printf("Skipping %s (old known name: %s)\n", file, kf)
renamed = true
// Delete the old entry
delete(fileinfo, kf)
break
}
}
if !renamed {
log.Printf("Launching harvester on new file: %s\n", file)
harvester := Harvester{Path: file, Fields: fields}
go harvester.Harvest(output)
}
}
} else {
// TODO(sissel): FileInfo.Sys() can be nil on unsupported platforms.
laststat := lastinfo.Sys().(*syscall.Stat_t)
stat := info.Sys().(*syscall.Stat_t)
// Compare inode and device; it's a 'new file' if either have changed.
// aka, the file was rotated/renamed/whatever
if stat.Dev != laststat.Dev || stat.Ino != laststat.Ino {
log.Printf("Launching harvester on rotated file: %s\n", file)
// TODO(sissel): log 'file rotated' or osmething
// Start a harvester on the path; a new file appeared with the same name.
harvester := Harvester{Path: file, Fields: fields} harvester := Harvester{Path: file, Fields: fields}
go harvester.Harvest(output) go harvester.Harvest(output)
} }
} else if !is_fileinfo_same(lastinfo, info) {
log.Printf("Launching harvester on rotated file: %s\n", file)
// TODO(sissel): log 'file rotated' or osmething
// Start a harvester on the path; a new file appeared with the same name.
harvester := Harvester{Path: file, Fields: fields}
go harvester.Harvest(output)
} }
} // for each file matched by the glob } // for each file matched by the glob
} }
...@@ -3,7 +3,6 @@ package main ...@@ -3,7 +3,6 @@ package main
import ( import (
"log" "log"
"os" "os"
"syscall"
"encoding/json" "encoding/json"
) )
...@@ -20,14 +19,14 @@ func Registrar(input chan []*FileEvent) { ...@@ -20,14 +19,14 @@ func Registrar(input chan []*FileEvent) {
// have to dereference the FileInfo here because os.FileInfo is an // have to dereference the FileInfo here because os.FileInfo is an
// interface, not a struct, so Go doesn't have smarts to call the Sys() // interface, not a struct, so Go doesn't have smarts to call the Sys()
// method on a pointer to os.FileInfo. :( // method on a pointer to os.FileInfo. :(
fstat := (*(event.fileinfo)).Sys().(*syscall.Stat_t) ino, dev := file_ids(event.fileinfo)
state[*event.Source] = &FileState{ state[*event.Source] = &FileState{
Source: event.Source, Source: event.Source,
// take the offset + length of the line + newline char and // take the offset + length of the line + newline char and
// save it as the new starting offset. // save it as the new starting offset.
Offset: event.Offset + int64(len(*event.Text)) + 1, Offset: event.Offset + int64(len(*event.Text)) + 1,
Inode: fstat.Ino, Inode: ino,
Device: fstat.Dev, Device: dev,
} }
} }
......
...@@ -3,5 +3,5 @@ package main ...@@ -3,5 +3,5 @@ package main
import "log" import "log"
func configureSyslog() { func configureSyslog() {
log.Logf("Logging to syslog not supported on this platform\n"); log.Printf("Logging to syslog not supported on this platform\n");
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment