chore(go.d/pkgs/logs): validation fixes, resource safety, and cleanup (#20931)
Ilya Mashchenko committed
Sep 8, 2025 at 15:46 UTC
1ba65ff83ca2644d6ef2f3a0d2ec197bd2af6e24
5 files changed
+12
-110
src/go/plugin/go.d/pkg/logs/csv.go
+3
@@ -186,6 +186,9 @@ func parseCSVDelimiter(s string) (rune, error) {
186
if err != nil {
187
return 0, fmt.Errorf("invalid CSV delimiter: %v", err)
188
}
189
+ if d < 0 {
190
+ return 0, errors.New("invalid CSV delimiter: must be a non-negative integer")
191
+ }
192
return rune(d), nil
193
}
194
if len(s) != 1 {
src/go/plugin/go.d/pkg/logs/lastline.go
-54
@@ -3,63 +3,9 @@
3
package logs
4
5
import (
6
- "errors"
7
- "os"
8
-
6
"github.com/clbanning/rfile/v2"
7
)
8
12
-const DefaultMaxLineWidth = 4 * 1024 // assume disk block size is 4K
13
-
14
-var ErrTooLongLine = errors.New("too long line")
15
-
16
-// ReadLastLine returns the last line of the file and any read error encountered.
17
-// It expects last line width <= maxLineWidth.
18
-// If maxLineWidth <= 0, it defaults to DefaultMaxLineWidth.
19
-func ReadLastLine(filename string, maxLineWidth int64) ([]byte, error) {
20
- if maxLineWidth <= 0 {
21
- maxLineWidth = DefaultMaxLineWidth
22
- }
23
- f, err := os.Open(filename)
24
- if err != nil {
25
- return nil, err
26
- }
27
- defer func() { _ = f.Close() }()
28
-
29
- stat, _ := f.Stat()
30
- endPos := stat.Size()
31
- if endPos == 0 {
32
- return []byte{}, nil
33
- }
34
- startPos := endPos - maxLineWidth
35
- if startPos < 0 {
36
- startPos = 0
37
- }
38
- buf := make([]byte, endPos-startPos)
39
- n, err := f.ReadAt(buf, startPos)
40
- if err != nil {
41
- return nil, err
42
- }
43
- lnPos := 0
44
- foundLn := false
45
- for i := n - 2; i >= 0; i-- {
46
- ch := buf[i]
47
- if ch == '\n' {
48
- foundLn = true
49
- lnPos = i
50
- break
51
- }
52
- }
53
- if foundLn {
54
- return buf[lnPos+1 : n], nil
55
- }
56
- if startPos == 0 {
57
- return buf[0:n], nil
58
- }
59
-
60
- return nil, ErrTooLongLine
61
-}
62
-
9
func ReadLastLines(filename string, n uint) ([]string, error) {
10
return rfile.Tail(filename, int(n))
11
}
src/go/plugin/go.d/pkg/logs/lastline_test.go
deleted
-54
@@ -1,54 +0,0 @@
1
-// SPDX-License-Identifier: GPL-3.0-or-later
2
-
3
-package logs
4
-
5
-import (
6
- "os"
7
- "testing"
8
-
9
- "github.com/stretchr/testify/assert"
10
- "github.com/stretchr/testify/require"
11
-)
12
-
13
-func TestReadLastLine(t *testing.T) {
14
- tests := []struct {
15
- name string
16
- content string
17
- expected string
18
- err error
19
- }{
20
- {"empty", "", "", nil},
21
- {"empty-ln", "\n", "\n", nil},
22
- {"one-line", "hello", "hello", nil},
23
- {"one-line-ln", "hello\n", "hello\n", nil},
24
- {"multi-line", "hello\nworld", "world", nil},
25
- {"multi-line-ln", "hello\nworld\n", "world\n", nil},
26
- {"long-line", "hello hello hello", "", ErrTooLongLine},
27
- {"long-line-ln", "hello hello hello\n", "", ErrTooLongLine},
28
- }
29
- for _, test := range tests {
30
- t.Run(test.name, func(t *testing.T) {
31
- filename := prepareFile(t, test.content)
32
- defer func() { _ = os.Remove(filename) }()
33
-
34
- line, err := ReadLastLine(filename, 10)
35
-
36
- if test.err != nil {
37
- require.NotNil(t, err)
38
- assert.Contains(t, err.Error(), test.err.Error())
39
- } else {
40
- assert.Equal(t, test.expected, string(line))
41
- }
42
- })
43
- }
44
-}
45
-
46
-func prepareFile(t *testing.T, content string) string {
47
- t.Helper()
48
- file, err := os.CreateTemp("", "go-test")
49
- require.NoError(t, err)
50
- defer func() { _ = file.Close() }()
51
-
52
- _, _ = file.WriteString(content)
53
- return file.Name()
54
-}
src/go/plugin/go.d/pkg/logs/reader.go
+7
-1
@@ -45,7 +45,7 @@ func Open(path string, excludePath string, log *logger.Logger) (*Reader, error)
45
return nil, fmt.Errorf("bad path syntax: %q", path)
46
}
47
if _, err = filepath.Match(excludePath, "/"); err != nil {
48
- return nil, fmt.Errorf("bad exclude_path syntax: %q", path)
48
+ return nil, fmt.Errorf("bad exclude_path syntax: %q", excludePath)
49
}
50
r := &Reader{
51
path: path,
@@ -61,6 +61,9 @@ func Open(path string, excludePath string, log *logger.Logger) (*Reader, error)
61
62
// CurrentFilename get current opened file name
63
func (r *Reader) CurrentFilename() string {
64
+ if r.file == nil {
65
+ return ""
66
+ }
67
return r.file.Name()
68
}
69
@@ -77,9 +80,11 @@ func (r *Reader) open() error {
80
}
81
stat, err := file.Stat()
82
if err != nil {
83
+ _ = file.Close()
84
return err
85
}
86
if _, err = file.Seek(stat.Size(), io.SeekStart); err != nil {
87
+ _ = file.Close()
88
return err
89
}
90
r.file = file
@@ -129,6 +134,7 @@ func (r *Reader) Close() (err error) {
134
r.log.Debug("close log file: ", r.file.Name())
135
err = r.file.Close()
136
r.file = nil
137
+ r.continuousEOF = 0
138
r.eofCounter = 0
139
return
140
}
src/go/plugin/go.d/pkg/logs/regexp.go
+2
-1
@@ -8,6 +8,7 @@ import (
8
"fmt"
9
"io"
10
"regexp"
11
+ "slices"
12
)
13
14
type (
@@ -31,7 +32,7 @@ func NewRegExpParser(config RegExpConfig, in io.Reader) (*RegExpParser, error) {
32
return nil, fmt.Errorf("compile: %w", err)
33
}
34
34
- if pattern.NumSubexp() == 0 {
35
+ if hasNamed := slices.ContainsFunc(pattern.SubexpNames(), func(s string) bool { return s != "" }); !hasNamed {
36
return nil, errors.New("pattern has no named subgroups")
37
}
38