Skip to content

Commit 7825f11

Browse files
authored
Merge pull request #325 from young-0/master
Fix the bug that multi-level directory /a/*/c/*.log wildcard cannot be matched dynamically
2 parents a342bbe + 3074ca8 commit 7825f11

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed

internal/mtail/mtail.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"net/http/pprof"
1616
"os"
1717
"os/signal"
18+
"path/filepath"
1819
"runtime"
1920
"sync"
2021
"syscall"
@@ -104,6 +105,25 @@ func (m *Server) StartTailing() error {
104105
return nil
105106
}
106107

108+
// Scan the wildcard directory address regularly and add to the wildcard address scanning
109+
func (m *Server) PollLogPathPatterns() error {
110+
for _, pattern := range m.logPathPatterns {
111+
absPath, err := filepath.Abs(pattern)
112+
if err != nil {
113+
return err
114+
}
115+
d := filepath.Dir(absPath)
116+
if !m.t.HasMeta(d) {
117+
continue
118+
}
119+
glog.V(1).Infof("Tail pattern %q", pattern)
120+
if err = m.t.TailPattern(pattern); err != nil {
121+
glog.Warning(err)
122+
}
123+
}
124+
return nil
125+
}
126+
107127
// initLoader constructs a new program loader and performs the initial load of program files in the program directory.
108128
func (m *Server) initLoader() error {
109129
opts := []func(*vm.Loader) error{
@@ -326,7 +346,20 @@ func (m *Server) Serve() error {
326346
}
327347
errc <- err
328348
}()
349+
pollQuit := make(chan int, 1) // Channel to stop PollLogPathPatterns.
350+
go func(chan int) {
351+
ticker := time.NewTicker(time.Second)
352+
for {
353+
select {
354+
case <-ticker.C:
355+
m.PollLogPathPatterns()
356+
case <-pollQuit:
357+
return
358+
}
359+
}
360+
}(pollQuit)
329361
m.WaitForShutdown()
362+
pollQuit <- 1
330363
return <-errc
331364
}
332365

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2019 Google Inc. All Rights Reserved.
2+
// This file is available under the Apache license.
3+
// +build integration
4+
5+
package mtail_test
6+
7+
import (
8+
"os"
9+
"path"
10+
"testing"
11+
"time"
12+
13+
"github.com/golang/glog"
14+
"github.com/google/mtail/internal/mtail"
15+
"github.com/google/mtail/internal/testutil"
16+
)
17+
18+
func TestPollLogPathPatterns(t *testing.T) {
19+
tmpDir, rmTmpDir := testutil.TestTempDir(t)
20+
defer rmTmpDir()
21+
22+
logDir := path.Join(tmpDir, "logs")
23+
progDir := path.Join(tmpDir, "progs")
24+
testutil.FatalIfErr(t, os.Mkdir(logDir, 0700))
25+
testutil.FatalIfErr(t, os.Mkdir(progDir, 0700))
26+
defer testutil.TestChdir(t, logDir)()
27+
28+
m, stopM := mtail.TestStartServer(t, 10*time.Millisecond, false, mtail.ProgramPath(progDir), mtail.LogPathPatterns(logDir+"/files/*/log/*log"))
29+
defer stopM()
30+
31+
startLogCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
32+
startLineCount := mtail.TestGetMetric(t, m.Addr(), "lines_total")
33+
34+
logFile := path.Join(logDir, "files", "a", "log", "a.log")
35+
testutil.FatalIfErr(t, os.MkdirAll(path.Dir(logFile), 0700))
36+
f := testutil.TestOpenFile(t, logFile)
37+
n, err := f.WriteString("")
38+
testutil.FatalIfErr(t, err)
39+
time.Sleep(time.Second)
40+
f.WriteString("line 1\n")
41+
glog.Infof("Wrote %d bytes", n)
42+
time.Sleep(time.Second)
43+
44+
logCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
45+
lineCount := mtail.TestGetMetric(t, m.Addr(), "lines_total")
46+
47+
if logCount.(float64)-startLogCount.(float64) != 1. {
48+
t.Errorf("Unexpected log count: got %g, want 1", logCount.(float64)-startLogCount.(float64))
49+
}
50+
if lineCount.(float64)-startLineCount.(float64) != 1. {
51+
t.Errorf("Unexpected line count: got %g, want 1", lineCount.(float64)-startLineCount.(float64))
52+
}
53+
time.Sleep(time.Second)
54+
55+
}

internal/tailer/tail.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"os"
2020
"path/filepath"
2121
"regexp"
22+
"runtime"
23+
"strings"
2224
"sync"
2325
"time"
2426

@@ -263,9 +265,20 @@ func (t *Tailer) watchDirname(pathname string) error {
263265
return err
264266
}
265267
d := filepath.Dir(absPath)
268+
if t.HasMeta(d) {
269+
return nil
270+
}
266271
return t.w.Observe(d, t)
267272
}
268273

274+
func (t *Tailer) HasMeta(path string) bool {
275+
magicChars := `*?[`
276+
if runtime.GOOS != "windows" {
277+
magicChars = `*?[\`
278+
}
279+
return strings.ContainsAny(path, magicChars)
280+
}
281+
269282
// openLogPath opens a log file named by pathname.
270283
func (t *Tailer) openLogPath(pathname string, seekToStart bool) error {
271284
glog.V(2).Infof("openlogPath %s %v", pathname, seekToStart)

0 commit comments

Comments
 (0)