Skip to content

Commit

Permalink
Logstation now has two tailing methods: filesystem or polling
Browse files Browse the repository at this point in the history
  • Loading branch information
jdrews committed Jul 3, 2023
1 parent 05b2771 commit f984ddd
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 21 deletions.
2 changes: 2 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func HandleConfigFile(configFilePath string) {
viper.SetDefault("logs", []string{`test\logfile.log`, `test\logfile2.log`})
viper.SetDefault("server_settings.webserveraddress", "0.0.0.0")
viper.SetDefault("server_settings.disablecors", false)
viper.SetDefault("tailingMethod", "filesystem")
viper.SetDefault("pollingTimeMS", 10)

viper.SetConfigFile(configFilePath)
if err := viper.ReadInConfig(); err != nil {
Expand Down
42 changes: 27 additions & 15 deletions logstation.default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ logs = [
]
# Unix example of setting up logs
#logs = [
# '/home/jdrews/git/logstation/logfile.log',
# '/home/jdrews/git/logstation/*.log'
# '/home/jdrews/git/logstation/logfile.log',
# '/home/jdrews/git/logstation/*.log'
#]

# Unique name for logstation instance
# This name will be prepended to the browser tab
# Can be useful when connecting to multiple logstations
# This name will be prepended to the browser tab
# Can be useful when connecting to multiple logstations
logStationName = "logstation"

# Setup your syntax highlighting below
# matching gives priority to the top most
# if the regular experssion passes, the entire log line will be colored
# matching gives priority to the top most
# if the regular experssion passes, the entire log line will be colored
#
# "color" can be any of of the following
# red, green, yellow, blue, magenta, cyan
# hired, higreen, hiyellow, hiblue, himagenta, hicyan
# NOTE: these are ANSI colors.
# The "hi" colors above are recommended as they show up much better on black backgrounds
# "color" can be any of of the following
# red, green, yellow, blue, magenta, cyan
# hired, higreen, hiyellow, hiblue, himagenta, hicyan
# NOTE: these are ANSI colors.
# The "hi" colors above are recommended as they show up much better on black backgrounds
#
# "regex" is a regular expression matched against a log line
# syntax in particular follows https://github.com/google/re2/wiki/Syntax
# "regex" is a regular expression matched against a log line
# syntax in particular follows https://github.com/google/re2/wiki/Syntax
syntaxColors = [
{ color="hired", regex=".*ERROR.*" }, # red
{ color="hiyellow", regex=".*WARN.*" }, # yellow
Expand All @@ -48,11 +48,23 @@ syntaxColors = [
{ color="hicyan", regex=".*TRACE.*" }, # cyan
]

# Select the method for tailing log files
# - "filesystem": listens for filesystem notifications that the log file has changed, then reads the file
# - "polling": polls the log file for updates at a regular cadence
#
# Defaults to "filesystem"
# If you find that you're not picking up log lines, try out "polling"
tailingMethod = "filesystem"

# Specity the polling time in milliseconds to check for log file updates
# Only applies when tailingMethod is set to "polling"
pollingTimeMS = 10

[server_settings]
webServerPort = 8884 # Webserver port to listen on
webServerAddress = "0.0.0.0" # Webserver address to listen on

# Disable CORS checking on the server
# This is a security vulnerability if you disable CORS. Please be careful!
# Read more here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
# This is a security vulnerability if you disable CORS. Please be careful!
# Read more here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
disableCORS = false
10 changes: 9 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,19 @@ func main() {
// setup message broker
pubSub := pubsub.New(1)

// collect settings for tailingMethod
tailingMethod := viper.GetString("tailingMethod")
polling := false
if tailingMethod == "polling" {
polling = true
}
pollingTimeMS := viper.GetInt("pollingTimeMS")

// process all log files to watch
logFiles := viper.GetStringSlice("logs")
for _, logFile := range logFiles {
//begin watching the file in a goroutine for concurrency
go Follow(logFile, pubSub, patterns)
go Follow(logFile, pubSub, patterns, polling, pollingTimeMS)
}

// startup the web server
Expand Down
12 changes: 10 additions & 2 deletions tailer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@ import (
"github.com/cskr/pubsub"
"github.com/jdrews/go-tailer/fswatcher"
"github.com/jdrews/go-tailer/glob"
"time"
)

// Follow begins a tailer for the specified logFilePath and publishes log lines to the given pubSub message broker
// When Follow picks up a log line, it also runs the line through regex via func Colorize
// to determine if it matches a color pattern
func Follow(logFilePath string, pubSub *pubsub.PubSub, patterns []CompiledRegexColors) {
func Follow(logFilePath string, pubSub *pubsub.PubSub, patterns []CompiledRegexColors, polling bool, pollingRateMS int) {

var tailer fswatcher.FileTailer

parsedGlob, err := glob.Parse(logFilePath)
if err != nil {
panic(fmt.Sprintf("%q: failed to parse glob: %q", parsedGlob, err))
}

tailer, err := fswatcher.RunFileTailer([]glob.Glob{parsedGlob}, false, true, logger)
if polling {
tailer, err = fswatcher.RunPollingFileTailer([]glob.Glob{parsedGlob}, false, true, time.Duration(pollingRateMS)*time.Millisecond, logger)
} else {
tailer, err = fswatcher.RunFileTailer([]glob.Glob{parsedGlob}, false, true, logger)
}

for line := range tailer.Lines() {
logger.Debug(line.Line)
logMessage := Colorize(line.Line, line.File, patterns)
Expand Down
16 changes: 13 additions & 3 deletions tailer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,23 @@ func writeALine(t *testing.T, logFilePath string, logString string) {
}
}

// TestFollow is an integration test for the entire backend tailing system
// TestFollowFilesystem executes the testFollow integration test with the filesystem tailing method
func TestFollowFilesystem(t *testing.T) {
testFollow(t, false, 10)
}

// TestFollowPolling executes the testFollow integration test with the polling tailing method
func TestFollowPolling(t *testing.T) {
testFollow(t, true, 10)
}

// testFollow is an integration test for the entire backend tailing system
//
// This test starts up the Follow function, which watches a specified log file,
// writes a line to the log file,
// and listens for a response on the pubsub topic.
// This test also verifies the message was correctly colored.
func TestFollow(t *testing.T) {
func testFollow(t *testing.T, polling bool, pollingTimeMS int) {
// Enable ANSI colors regardless of terminal state
color.NoColor = false

Expand All @@ -68,7 +78,7 @@ func TestFollow(t *testing.T) {
defer pubSub.Unsub(linesChannel, "lines")

// Run Follow
go Follow(logFilePath, pubSub, compiledRegexColors)
go Follow(logFilePath, pubSub, compiledRegexColors, polling, pollingTimeMS)

// Give the fswatcher.RunFileTailer enough time to startup
time.Sleep(time.Duration(2000) * time.Millisecond)
Expand Down

0 comments on commit f984ddd

Please sign in to comment.