diff --git a/plugin/input/file/worker.go b/plugin/input/file/worker.go index 18bb6738d..f27f62c47 100644 --- a/plugin/input/file/worker.go +++ b/plugin/input/file/worker.go @@ -204,6 +204,14 @@ func (w *worker) work(controller inputer, jobProvider *jobProvider, readBufferSi // check if file was truncated. if isEOFReached { + // Flush remaining data when EOF is reached and there's no trailing newline. + // Without this, the last line of a file that doesn't end with '\n' is silently dropped. + if len(accumBuf) > 0 { + job.lastEventSeq = controller.In(sourceID, sourceName, pipeline.NewOffsets(lastOffset+scanned, offsets), accumBuf, isVirgin, metadataInfo) + accumBuf = accumBuf[:0] + job.tail = job.tail[:0] + } + err := w.processEOF(file, job, jobProvider, lastOffset+readTotal) if err != nil { logger.Fatalf("file %d:%s stat error: %s", sourceID, sourceName, err.Error()) diff --git a/plugin/input/file/worker_test.go b/plugin/input/file/worker_test.go index e3defc21a..17ed2af49 100644 --- a/plugin/input/file/worker_test.go +++ b/plugin/input/file/worker_test.go @@ -58,13 +58,6 @@ func TestWorkerWork(t *testing.T) { readBufferSize: 1024, expData: "abc\n", }, - { - name: "should_ok_and_empty_when_read_not_ready_line", - maxEventSize: 1024, - inFile: "abc", - readBufferSize: 1024, - expData: "", - }, { name: "should_ok_and_not_read_long_line", maxEventSize: 2, @@ -81,11 +74,18 @@ func TestWorkerWork(t *testing.T) { expData: "abc\n", }, { - name: "should_ok_when_read_1_line_without_newline", + name: "should_emit_last_line_without_trailing_newline", maxEventSize: 1024, inFile: "abc", readBufferSize: 1024, - expData: "", + expData: "abc", + }, + { + name: "should_emit_last_line_among_multiple_without_trailing_newline", + maxEventSize: 1024, + inFile: "line1\nline2\nline3", + readBufferSize: 1024, + expData: "line3", }, } for _, tt := range tests { @@ -264,7 +264,7 @@ func TestWorkerWorkMultiData(t *testing.T) { readBufferSize: 1024, inData: `{"a":"a"}`, - outData: nil, // we don't send an event if we don't find a newline + outData: []string{`{"a":"a"}`}, }, }