Skip to content

Commit 09f8320

Browse files
committed
Merge branch 'main' into feature/windows-eventId-filtering
2 parents f96d9d7 + 6fc3a58 commit 09f8320

File tree

15 files changed

+288
-131
lines changed

15 files changed

+288
-131
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package constants
5+
6+
const (
7+
// DefaultMaxEventSize is the default maximum size for log events (1MB)
8+
DefaultMaxEventSize = 1024 * 1024
9+
10+
// PerEventHeaderBytes is the bytes required for metadata for each log event
11+
PerEventHeaderBytes = 200
12+
)

plugins/inputs/logfile/fileconfig.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,10 @@ import (
1818

1919
"github.com/aws/amazon-cloudwatch-agent/internal/logscommon"
2020
"github.com/aws/amazon-cloudwatch-agent/logs"
21+
"github.com/aws/amazon-cloudwatch-agent/plugins/inputs/logfile/constants"
2122
"github.com/aws/amazon-cloudwatch-agent/profiler"
2223
)
2324

24-
const (
25-
defaultMaxEventSize = 1024 * 256 //256KB
26-
defaultTruncateSuffix = "[Truncated...]"
27-
)
28-
2925
// The file config presents the structure of configuration for a file to be tailed.
3026
type FileConfig struct {
3127
//The file path for input log file.
@@ -154,11 +150,7 @@ func (config *FileConfig) init() error {
154150
}
155151

156152
if config.MaxEventSize == 0 {
157-
config.MaxEventSize = defaultMaxEventSize
158-
}
159-
160-
if config.TruncateSuffix == "" {
161-
config.TruncateSuffix = defaultTruncateSuffix
153+
config.MaxEventSize = constants.DefaultMaxEventSize - constants.PerEventHeaderBytes
162154
}
163155
if config.RetentionInDays == 0 {
164156
config.RetentionInDays = -1

plugins/inputs/logfile/logfile.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ const sampleConfig = `
8686
## Whether file is a named pipe
8787
pipe = false
8888
destination = "cloudwatchlogs"
89-
## Max size of each log event, defaults to 262144 (256KB)
90-
max_event_size = 262144
89+
## Max size of each log event, defaults to 1048576 (1MB)
90+
max_event_size = 1048576
9191
## Suffix to be added to truncated logline to indicate its truncation, defaults to "[Truncated...]"
9292
truncate_suffix = "[Truncated...]"
9393
@@ -266,7 +266,6 @@ func (t *LogFile) FindLogSrc() []logs.LogSrc {
266266
fileconfig.timestampFromLogLine,
267267
fileconfig.Enc,
268268
fileconfig.MaxEventSize,
269-
fileconfig.TruncateSuffix,
270269
fileconfig.RetentionInDays,
271270
fileconfig.BackpressureMode,
272271
)

plugins/inputs/logfile/tail/tail.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"gopkg.in/tomb.v1"
1919

2020
"github.com/aws/amazon-cloudwatch-agent/internal/state"
21+
"github.com/aws/amazon-cloudwatch-agent/plugins/inputs/logfile/constants"
2122
"github.com/aws/amazon-cloudwatch-agent/plugins/inputs/logfile/tail/watch"
2223
)
2324

@@ -306,8 +307,12 @@ func (tail *Tail) readlineUtf16() (string, error) {
306307
}
307308
cur = append(cur, nextByte)
308309
}
309-
// 262144 => 256KB
310-
if resSize+len(cur) >= 262144 {
310+
// Use MaxLineSize if configured, otherwise use DefaultMaxEventSize
311+
maxSize := constants.DefaultMaxEventSize // Use the constant defined in constants package
312+
if tail.MaxLineSize > 0 {
313+
maxSize = tail.MaxLineSize
314+
}
315+
if resSize+len(cur) >= maxSize {
311316
break
312317
}
313318
buf := make([]byte, len(cur))
@@ -534,8 +539,7 @@ func (tail *Tail) waitForChanges() error {
534539
func (tail *Tail) openReader() {
535540
tail.lk.Lock()
536541
if tail.MaxLineSize > 0 {
537-
// add 2 to account for newline characters
538-
tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize+2)
542+
tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize)
539543
} else {
540544
tail.reader = bufio.NewReader(tail.file)
541545
}

plugins/inputs/logfile/tail/tail_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import (
77
"fmt"
88
"log"
99
"os"
10+
"path/filepath"
1011
"strings"
1112
"testing"
1213
"time"
1314

1415
"github.com/stretchr/testify/assert"
16+
"github.com/stretchr/testify/require"
1517
)
1618

1719
const linesWrittenToFile int = 10
@@ -197,3 +199,100 @@ func tearDown(tmpfile *os.File) {
197199
exitOnDeletionCheckDuration = time.Minute
198200
exitOnDeletionWaitDuration = 5 * time.Minute
199201
}
202+
203+
func TestUtf16LineSize(t *testing.T) {
204+
tmpfile, err := os.CreateTemp("", "")
205+
require.NoError(t, err)
206+
defer os.Remove(tmpfile.Name())
207+
208+
// Create a UTF-16 BOM
209+
_, err = tmpfile.Write([]byte{0xFE, 0xFF})
210+
require.NoError(t, err)
211+
212+
// Create a tail with a small MaxLineSize
213+
maxLineSize := 100
214+
tail, err := TailFile(tmpfile.Name(), Config{
215+
MaxLineSize: maxLineSize,
216+
Follow: true,
217+
ReOpen: false,
218+
Poll: true,
219+
})
220+
require.NoError(t, err)
221+
defer tail.Stop()
222+
223+
// Write a UTF-16 encoded line that exceeds MaxLineSize when decoded
224+
// Each 'a' will be 2 bytes in UTF-16
225+
utf16Line := make([]byte, 0, maxLineSize*4)
226+
for i := 0; i < maxLineSize*2; i++ {
227+
utf16Line = append(utf16Line, 0x00, 'a')
228+
}
229+
utf16Line = append(utf16Line, 0x00, '\n')
230+
231+
_, err = tmpfile.Write(utf16Line)
232+
require.NoError(t, err)
233+
err = tmpfile.Sync()
234+
require.NoError(t, err)
235+
236+
// Read the line and verify it's truncated
237+
select {
238+
case line := <-tail.Lines:
239+
// The line should be truncated to maxLineSize
240+
assert.LessOrEqual(t, len(line.Text), maxLineSize)
241+
case <-time.After(1 * time.Second):
242+
t.Fatal("timeout waiting for line")
243+
}
244+
}
245+
246+
func TestTail_DefaultBuffer(t *testing.T) {
247+
// Test that default buffer works with normal-sized log lines
248+
tempDir := t.TempDir()
249+
filename := filepath.Join(tempDir, "test.log")
250+
251+
// Create a file with a normal-sized line (1KB - well within default buffer)
252+
normalContent := strings.Repeat("b", 1024) // 1KB
253+
err := os.WriteFile(filename, []byte(normalContent+"\n"), 0600)
254+
require.NoError(t, err)
255+
256+
tail, err := TailFile(filename, Config{
257+
Follow: false,
258+
MustExist: true,
259+
// MaxLineSize not set - should use default buffer
260+
})
261+
require.NoError(t, err)
262+
defer tail.Stop()
263+
264+
select {
265+
case line := <-tail.Lines:
266+
assert.NoError(t, line.Err)
267+
assert.Equal(t, normalContent, line.Text)
268+
case <-time.After(time.Second):
269+
t.Fatal("Timeout waiting for line")
270+
}
271+
}
272+
273+
func TestTail_1MBWithExplicitMaxLineSize(t *testing.T) {
274+
// Test that large lines work when MaxLineSize is explicitly set
275+
tempDir := t.TempDir()
276+
filename := filepath.Join(tempDir, "test.log")
277+
278+
// Create a file with a 512KB line
279+
largeContent := strings.Repeat("b", 512*1024) // 512KB
280+
err := os.WriteFile(filename, []byte(largeContent+"\n"), 0600)
281+
require.NoError(t, err)
282+
283+
tail, err := TailFile(filename, Config{
284+
Follow: false,
285+
MustExist: true,
286+
MaxLineSize: 1024 * 1024, // Explicitly set 1MB buffer
287+
})
288+
require.NoError(t, err)
289+
defer tail.Stop()
290+
291+
select {
292+
case line := <-tail.Lines:
293+
assert.NoError(t, line.Err)
294+
assert.Equal(t, largeContent, line.Text)
295+
case <-time.After(time.Second):
296+
t.Fatal("Timeout waiting for line")
297+
}
298+
}

plugins/inputs/logfile/tailersrc.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ type tailerSrc struct {
7070
timestampFn func(string) (time.Time, string)
7171
enc encoding.Encoding
7272
maxEventSize int
73-
truncateSuffix string
7473
retentionInDays int
7574

7675
outputFn func(logs.LogEvent)
@@ -98,7 +97,6 @@ func NewTailerSrc(
9897
timestampFn func(string) (time.Time, string),
9998
enc encoding.Encoding,
10099
maxEventSize int,
101-
truncateSuffix string,
102100
retentionInDays int,
103101
backpressureMode logscommon.BackpressureMode,
104102
) *tailerSrc {
@@ -116,7 +114,6 @@ func NewTailerSrc(
116114
timestampFn: timestampFn,
117115
enc: enc,
118116
maxEventSize: maxEventSize,
119-
truncateSuffix: truncateSuffix,
120117
retentionInDays: retentionInDays,
121118
backpressureFdDrop: !autoRemoval && backpressureMode == logscommon.LogBackpressureModeFDRelease,
122119
done: make(chan struct{}),
@@ -238,10 +235,6 @@ func (ts *tailerSrc) runTail() {
238235
} else {
239236
msgBuf.WriteString("\n")
240237
msgBuf.WriteString(text)
241-
if msgBuf.Len() > ts.maxEventSize {
242-
msgBuf.Truncate(ts.maxEventSize - len(ts.truncateSuffix))
243-
msgBuf.WriteString(ts.truncateSuffix)
244-
}
245238
fo.ShiftInt64(line.Offset)
246239
continue
247240
}

0 commit comments

Comments
 (0)