-
Notifications
You must be signed in to change notification settings - Fork 41
Add possibility to force flush logs after certain period of time #216
Changes from 11 commits
644475a
e2399ad
b9ece36
d16d0ee
5d3f482
6b3c0b5
f64b057
5682458
c9bb6cd
a1bf062
1503414
c6557fd
bced39d
6c72b19
b2faa2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,7 +117,8 @@ func (c InputConfig) Build(context operator.BuildContext) ([]operator.Operator, | |
return nil, err | ||
} | ||
|
||
splitFunc, err := c.Multiline.Build(context, encoding.Encoding, false) | ||
// Ensure that multiline is buildable | ||
_, err = c.Multiline.Build(encoding.Encoding, false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -156,7 +157,7 @@ func (c InputConfig) Build(context operator.BuildContext) ([]operator.Operator, | |
InputOperator: inputOperator, | ||
Include: c.Include, | ||
Exclude: c.Exclude, | ||
SplitFunc: splitFunc, | ||
Multiline: c.Multiline, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps this is just a naming issue, but I'll have a difficult time accepting that the splitfunc is being delegated to a I suspect that we can accomplish the same functionality as you are implementing, but by composing things in a better way. Would it make sense to create a new struct which would pair the concept of a split func with the concept of a flush? Maybe something like: type Splitter struct {
splitFunc // can be simple like '\n' or multiline config
flusher // forces a flush based on timing
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After looking at this further, I'm not convinced we even need to do what I've suggested here. Please see my related comment on |
||
PollInterval: c.PollInterval.Raw(), | ||
FilePathField: filePathField, | ||
FileNameField: fileNameField, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ import ( | |
"golang.org/x/text/transform" | ||
|
||
"github.com/open-telemetry/opentelemetry-log-collection/errors" | ||
"github.com/open-telemetry/opentelemetry-log-collection/operator/helper" | ||
) | ||
|
||
// File attributes contains information about file paths | ||
|
@@ -70,11 +71,13 @@ type Reader struct { | |
decoder *encoding.Decoder | ||
decodeBuffer []byte | ||
|
||
multiline *helper.Multiline | ||
|
||
*zap.SugaredLogger `json:"-"` | ||
} | ||
|
||
// NewReader creates a new file reader | ||
func (f *InputOperator) NewReader(path string, file *os.File, fp *Fingerprint) (*Reader, error) { | ||
func (f *InputOperator) NewReader(path string, file *os.File, fp *Fingerprint, multiline *helper.Multiline) (*Reader, error) { | ||
r := &Reader{ | ||
Fingerprint: fp, | ||
file: file, | ||
|
@@ -83,13 +86,14 @@ func (f *InputOperator) NewReader(path string, file *os.File, fp *Fingerprint) ( | |
decoder: f.encoding.Encoding.NewDecoder(), | ||
decodeBuffer: make([]byte, 1<<12), | ||
fileAttributes: f.resolveFileAttributes(path), | ||
multiline: multiline, | ||
} | ||
return r, nil | ||
} | ||
|
||
// Copy creates a deep copy of a Reader | ||
func (r *Reader) Copy(file *os.File) (*Reader, error) { | ||
reader, err := r.fileInput.NewReader(r.fileAttributes.Path, file, r.Fingerprint.Copy()) | ||
reader, err := r.fileInput.NewReader(r.fileAttributes.Path, file, r.Fingerprint.Copy(), r.multiline) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -116,7 +120,7 @@ func (r *Reader) ReadToEnd(ctx context.Context) { | |
return | ||
} | ||
|
||
scanner := NewPositionalScanner(r, r.fileInput.MaxLogSize, r.Offset, r.fileInput.SplitFunc) | ||
scanner := NewPositionalScanner(r, r.fileInput.MaxLogSize, r.Offset, r.multiline.SplitFunc) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this is the only place we are using the split func, so I'm not sure why it needs to be part of the multiline config. We have two concepts here:
I'm not convinced these are dependent on each other, or that either is necessarily a concern of multiline behavior. (Of course a split func may implement multiline splitting, but it does not always.) Can we leave splitFunc as it was and just add a new config that controls flushing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is some relations I was unsure how to resolve, so I put both functionality into one struct:
Regarding line splitting. Of course it is not always a multiline behavior, but looking at it from user perspective it is intuitive to use I will exclude force a flush to separate config, as logic of it is mostly out of the splitFunc, but not sure how to resolve other dependencies in nice way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made some changes in requested direction, but after all I think You can see current implementation without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think consolidating into one struct makes sense There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the latest code, please |
||
|
||
// Iterate over the tokenized file, emitting entries as we go | ||
for { | ||
|
@@ -131,8 +135,13 @@ func (r *Reader) ReadToEnd(ctx context.Context) { | |
if err := getScannerError(scanner); err != nil { | ||
r.Errorw("Failed during scan", zap.Error(err)) | ||
} | ||
|
||
// Force flush eventually in next iteration | ||
r.multiline.CheckAndFlush() | ||
break | ||
} | ||
// Update information about last flush time | ||
r.multiline.Flushed() | ||
|
||
if err := r.emit(ctx, scanner.Bytes()); err != nil { | ||
r.Error("Failed to emit entry", zap.Error(err)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, I think we should use
helper.Duration
instead oftime.Duration
. We can then link tohttps://github.com/open-telemetry/opentelemetry-log-collection/blob/main/docs/types/duration.md
, which explains formatting sufficiently.This is basically the same thing, but with a default unit of seconds, since nanoseconds is basically never reasonable in this context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated documentation