Merge pull request #5263 from baude/logsize

implement reverse reader for log reads
This commit is contained in:
OpenShift Merge Robot 2020-02-21 13:12:21 -05:00 committed by GitHub
commit 5bdf5aeb71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 24 deletions

View file

@ -97,7 +97,7 @@ keys=[k for k in env if "ENCRYPTED" not in str(env[k])]
for k,v in env.items():
v=str(v)
if "ENCRYPTED" not in v:
print "{0}=\"{1}\"".format(k, v),
print("{0}=\"{1}\"".format(k, v)),
'
}

View file

@ -2,13 +2,16 @@ package logs
import (
"fmt"
"io/ioutil"
"io"
"os"
"strings"
"sync"
"time"
"github.com/containers/libpod/libpod/logs/reversereader"
"github.com/hpcloud/tail"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
@ -74,43 +77,84 @@ func GetLogFile(path string, options *LogOptions) (*tail.Tail, []*LogLine, error
func getTailLog(path string, tail int) ([]*LogLine, error) {
var (
tailLog []*LogLine
nlls []*LogLine
tailCounter int
partial string
nlls []*LogLine
nllCounter int
leftover string
partial string
tailLog []*LogLine
)
content, err := ioutil.ReadFile(path)
f, err := os.Open(path)
if err != nil {
return nil, err
}
splitContent := strings.Split(string(content), "\n")
// We read the content in reverse and add each nll until we have the same
// number of F type messages as the desired tail
for i := len(splitContent) - 1; i >= 0; i-- {
if len(splitContent[i]) == 0 {
continue
rr, err := reversereader.NewReverseReader(f)
if err != nil {
return nil, err
}
inputs := make(chan []string)
go func() {
for {
s, err := rr.Read()
if err != nil {
if errors.Cause(err) == io.EOF {
inputs <- []string{leftover}
close(inputs)
break
}
logrus.Error(err)
close(inputs)
}
line := strings.Split(s+leftover, "\n")
if len(line) > 1 {
inputs <- line[1:]
}
leftover = line[0]
}
nll, err := NewLogLine(splitContent[i])
if err != nil {
return nil, err
}()
for i := range inputs {
// the incoming array is FIFO; we want FIFO so
// reverse the slice read order
for j := len(i) - 1; j >= 0; j-- {
// lines that are "" are junk
if len(i[j]) < 1 {
continue
}
// read the content in reverse and add each nll until we have the same
// number of F type messages as the desired tail
nll, err := NewLogLine(i[j])
if err != nil {
return nil, err
}
nlls = append(nlls, nll)
if !nll.Partial() {
nllCounter++
}
}
nlls = append(nlls, nll)
if !nll.Partial() {
tailCounter++
}
if tailCounter == tail {
// if we have enough loglines, we can hangup
if nllCounter >= tail {
if err := f.Close(); err != nil {
logrus.Error(err)
}
break
}
}
// Now we iterate the results and assemble partial messages to become full messages
// re-assemble the log lines and trim (if needed) to the
// tail length
for _, nll := range nlls {
if nll.Partial() {
partial += nll.Msg
} else {
nll.Msg += partial
tailLog = append(tailLog, nll)
// prepend because we need to reverse the order again to FIFO
tailLog = append([]*LogLine{nll}, tailLog...)
partial = ""
}
if len(tailLog) == tail {
break
}
}
return tailLog, nil
}

View file

@ -0,0 +1,66 @@
package reversereader
import (
"io"
"os"
"github.com/pkg/errors"
)
// ReverseReader structure for reading a file backwards
type ReverseReader struct {
reader *os.File
offset int64
readSize int64
}
// NewReverseReader returns a reader that reads from the end of a file
// rather than the beginning. It sets the readsize to pagesize and determines
// the first offset using using modulus.
func NewReverseReader(reader *os.File) (*ReverseReader, error) {
// pagesize should be safe for memory use and file reads should be on page
// boundaries as well
pageSize := int64(os.Getpagesize())
stat, err := reader.Stat()
if err != nil {
return nil, err
}
// figure out the last page boundary
remainder := stat.Size() % pageSize
end, err := reader.Seek(0, 2)
if err != nil {
return nil, err
}
// set offset (starting position) to the last page boundary or
// zero if fits in one page
startOffset := end - remainder
if startOffset < 0 {
startOffset = 0
}
rr := ReverseReader{
reader: reader,
offset: startOffset,
readSize: pageSize,
}
return &rr, nil
}
// ReverseReader reads from a given offset to the previous offset and
// then sets the newoff set one pagesize less than the previous read.
func (r *ReverseReader) Read() (string, error) {
if r.offset < 0 {
return "", errors.Wrap(io.EOF, "at beginning of file")
}
// Read from given offset
b := make([]byte, r.readSize)
n, err := r.reader.ReadAt(b, r.offset)
if err != nil && errors.Cause(err) != io.EOF {
return "", err
}
if int64(n) < r.readSize {
b = b[0:n]
}
// Set to the next page boundary
r.offset = -r.readSize
return string(b), nil
}

View file

@ -338,7 +338,11 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *logs.LogOptions) er
if tailLen < 0 {
tailLen = 0
}
logChannel := make(chan *logs.LogLine, tailLen*len(c.InputArgs)+1)
numContainers := len(c.InputArgs)
if numContainers == 0 {
numContainers = 1
}
logChannel := make(chan *logs.LogLine, tailLen*numContainers+1)
containers, err := shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
if err != nil {
return err