Skip to content

Commit de8f0fc

Browse files
resolve links on start file watcher (#733)
* resolve links on start file watcher * fix resolve links in watcher
1 parent 08d933e commit de8f0fc

File tree

2 files changed

+117
-14
lines changed

2 files changed

+117
-14
lines changed

plugin/input/file/watcher.go

+74-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,25 @@ func NewWatcher(
4444
}
4545

4646
func (w *watcher) start() {
47-
for _, pattern := range w.paths.Include {
47+
for i, pattern := range w.paths.Include {
4848
// /var/lib/docker/containers/**/*-json.log -> /var/lib/docker/containers
4949
basePattern, _ := doublestar.SplitPattern(pattern)
50-
w.basePaths = append(w.basePaths, basePattern)
50+
allLinksResolvedPath, err := resolvePathLinks(basePattern)
51+
if err != nil {
52+
panic(err)
53+
}
54+
w.paths.Include[i] = strings.Replace(w.paths.Include[i], basePattern, allLinksResolvedPath, 1)
55+
w.basePaths = append(w.basePaths, allLinksResolvedPath)
56+
}
57+
58+
for i, pattern := range w.paths.Exclude {
59+
// /var/lib/docker/containers/**/*-json.log -> /var/lib/docker/containers
60+
basePattern, _ := doublestar.SplitPattern(pattern)
61+
allLinksResolvedPath, err := resolvePathLinks(basePattern)
62+
if err != nil {
63+
panic(err)
64+
}
65+
w.paths.Exclude[i] = strings.Replace(w.paths.Exclude[i], basePattern, allLinksResolvedPath, 1)
5166
}
5267
w.commonPath = commonPathPrefix(w.basePaths)
5368

@@ -215,3 +230,60 @@ func (w *watcher) watch() {
215230
w.notify(event.Event(), event.Path())
216231
}
217232
}
233+
234+
func resolvePathLinks(basePath string) (string, error) {
235+
resolvedPath := basePath
236+
components := filepath.SplitList(resolvedPath)
237+
238+
var finalPath string
239+
for _, component := range components {
240+
if component == "" {
241+
continue
242+
}
243+
244+
finalPath = filepath.Join(finalPath, component)
245+
246+
info, err := os.Lstat(finalPath)
247+
if err != nil {
248+
upDir := filepath.Dir(basePath)
249+
resolvedPath, err := resolvePathLinks(upDir)
250+
return filepath.Join(
251+
resolvedPath,
252+
filepath.Base(basePath),
253+
), err
254+
}
255+
256+
if info.Mode()&os.ModeSymlink != 0 {
257+
target, err := os.Readlink(finalPath)
258+
if err != nil {
259+
return "", err
260+
}
261+
262+
if !filepath.IsAbs(target) {
263+
finalPath = filepath.Join(filepath.Dir(finalPath), target)
264+
} else {
265+
finalPath = target
266+
}
267+
}
268+
}
269+
270+
getParentDir := func(path string) string {
271+
normalizedPath := strings.TrimSuffix(path, string(os.PathSeparator))
272+
parentDir := filepath.Dir(normalizedPath)
273+
if parentDir == "" || parentDir == string(os.PathSeparator) {
274+
return string(os.PathSeparator)
275+
}
276+
return parentDir
277+
}
278+
279+
upDir := getParentDir(finalPath)
280+
if upDir == string(os.PathSeparator) || upDir == filepath.VolumeName(finalPath)+string(os.PathSeparator) {
281+
return finalPath, nil
282+
} else {
283+
resolvedPath, err := resolvePathLinks(upDir)
284+
return filepath.Join(
285+
resolvedPath,
286+
filepath.Base(finalPath),
287+
), err
288+
}
289+
}

plugin/input/file/watcher_test.go

+43-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"strings"
78
"testing"
89
"time"
910

@@ -90,7 +91,15 @@ func TestWatcher(t *testing.T) {
9091

9192
// nolint:gocritic
9293
func TestWatcherPaths(t *testing.T) {
93-
dir := t.TempDir()
94+
originalDir := t.TempDir()
95+
96+
dirWithLink := t.TempDir()
97+
dir := filepath.Join(dirWithLink, "symlink")
98+
err := os.Symlink(originalDir, dir)
99+
if err != nil {
100+
t.Fatalf("Failed to create symlink: %v", err)
101+
}
102+
94103
shouldCreate := atomic.Int64{}
95104
notifyFn := func(_ notify.Event, _ string, _ os.FileInfo) {
96105
shouldCreate.Inc()
@@ -124,47 +133,47 @@ func TestWatcherPaths(t *testing.T) {
124133
shouldNotify bool
125134
}{
126135
{
127-
filename: filepath.Join(dir, "nginx-ingress-0/error.log"),
136+
filename: filepath.Join(originalDir, "nginx-ingress-0/error.log"),
128137
shouldNotify: true,
129138
},
130139
{
131-
filename: filepath.Join(dir, "log/errors.log"),
140+
filename: filepath.Join(originalDir, "log/errors.log"),
132141
shouldNotify: true,
133142
},
134143
{
135-
filename: filepath.Join(dir, "log/0/errors.log"),
144+
filename: filepath.Join(originalDir, "log/0/errors.log"),
136145
shouldNotify: true,
137146
},
138147
{
139-
filename: filepath.Join(dir, "log/0/0/errors.log"),
148+
filename: filepath.Join(originalDir, "log/0/0/errors.log"),
140149
shouldNotify: true,
141150
},
142151
{
143-
filename: filepath.Join(dir, "access.log"),
152+
filename: filepath.Join(originalDir, "access.log"),
144153
shouldNotify: true,
145154
},
146155
{
147-
filename: filepath.Join(dir, "sub_access.log"),
156+
filename: filepath.Join(originalDir, "sub_access.log"),
148157
shouldNotify: true,
149158
},
150159
{
151-
filename: filepath.Join(dir, "access1.log"),
160+
filename: filepath.Join(originalDir, "access1.log"),
152161
shouldNotify: false,
153162
},
154163
{
155-
filename: filepath.Join(dir, "nginx/errors.log"),
164+
filename: filepath.Join(originalDir, "nginx/errors.log"),
156165
shouldNotify: false,
157166
},
158167
{
159-
filename: filepath.Join(dir, "log/payments/errors.log"),
168+
filename: filepath.Join(originalDir, "log/payments/errors.log"),
160169
shouldNotify: false,
161170
},
162171
{
163-
filename: filepath.Join(dir, "log/payments/nginx-ingress-0/errors.log"),
172+
filename: filepath.Join(originalDir, "log/payments/nginx-ingress-0/errors.log"),
164173
shouldNotify: false,
165174
},
166175
{
167-
filename: filepath.Join(dir, "nginx-ingress-payments/error.log"),
176+
filename: filepath.Join(originalDir, "nginx-ingress-payments/error.log"),
168177
shouldNotify: false,
169178
},
170179
}
@@ -204,3 +213,25 @@ func TestCommonPathPrefix(t *testing.T) {
204213
result := commonPathPrefix(paths)
205214
a.Equal("/var", result)
206215
}
216+
217+
func TestResolvePathLinks(t *testing.T) {
218+
a := assert.New(t)
219+
originalDir := t.TempDir()
220+
221+
dirWithLink := t.TempDir()
222+
dirLink := filepath.Join(dirWithLink, "symlink")
223+
err := os.Symlink(originalDir, dirLink)
224+
if err != nil {
225+
t.Fatalf("Failed to create symlink: %v", err)
226+
}
227+
linkSubDir := filepath.Join(dirLink, "dir")
228+
os.Mkdir(linkSubDir, os.FileMode(0o755))
229+
230+
resultDir := filepath.Join(linkSubDir, "dir")
231+
result, err := resolvePathLinks(resultDir)
232+
a.Equal(
233+
strings.Replace(resultDir, dirLink, originalDir, 1),
234+
result,
235+
)
236+
a.Equal(nil, err)
237+
}

0 commit comments

Comments
 (0)