mirror of https://github.com/perkeep/perkeep.git
buildbot: use ringBuffer to store last 1MB of logs
Change-Id: I689ca82c64b9c7f89913551c5138a78718377c0d
This commit is contained in:
parent
72021e4516
commit
0712432e1f
|
@ -40,9 +40,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
interval = 60 * time.Second // polling frequency
|
||||
warmup = 60 * time.Second // duration before we test if devcam server has started properly
|
||||
historySize = 30
|
||||
interval = 60 * time.Second // polling frequency
|
||||
warmup = 60 * time.Second // duration before we test if devcam server has started properly
|
||||
historySize = 30
|
||||
maxStderrSize = 1 << 20 // Keep last 1 MB of logging.
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -89,21 +90,67 @@ var (
|
|||
|
||||
// Override the os.Stderr used by the default logger so we can provide
|
||||
// more debug info on status page.
|
||||
logStderr = new(lockedBuffer)
|
||||
logStderr = newLockedBuffer()
|
||||
)
|
||||
|
||||
// lockedBuffer protects all Write calls with a mutex. Users of lockedBuffer
|
||||
// must wrap any calls to Bytes, and use of the resulting slice with calls to
|
||||
// Lock/Unlock.
|
||||
type lockedBuffer struct {
|
||||
sync.Mutex // guards Buffer
|
||||
bytes.Buffer
|
||||
sync.Mutex // guards ringBuffer
|
||||
*ringBuffer
|
||||
}
|
||||
|
||||
func newLockedBuffer() *lockedBuffer {
|
||||
return &lockedBuffer{ringBuffer: newRingBuffer(maxStderrSize)}
|
||||
}
|
||||
|
||||
func (lb *lockedBuffer) Write(b []byte) (int, error) {
|
||||
lb.Lock()
|
||||
defer lb.Unlock()
|
||||
return lb.Buffer.Write(b)
|
||||
return lb.ringBuffer.Write(b)
|
||||
}
|
||||
|
||||
type ringBuffer struct {
|
||||
buf []byte
|
||||
off int // End of ring buffer.
|
||||
l int // Length of ring buffer filled.
|
||||
}
|
||||
|
||||
func newRingBuffer(maxSize int) *ringBuffer {
|
||||
return &ringBuffer{
|
||||
buf: make([]byte, maxSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (rb *ringBuffer) Bytes() []byte {
|
||||
if (rb.off - rb.l) >= 0 {
|
||||
// Partially full buffer with no wrap.
|
||||
return rb.buf[rb.off-rb.l : rb.off]
|
||||
}
|
||||
|
||||
// Buffer has been wrapped, copy second half then first half.
|
||||
start := rb.off - rb.l
|
||||
if start < 0 {
|
||||
start = rb.off
|
||||
}
|
||||
b := make([]byte, 0, cap(rb.buf))
|
||||
b = append(b, rb.buf[start:]...)
|
||||
b = append(b, rb.buf[:start]...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (rb *ringBuffer) Write(buf []byte) (int, error) {
|
||||
ringLen := cap(rb.buf)
|
||||
for i, b := range buf {
|
||||
rb.buf[(rb.off+i)%ringLen] = b
|
||||
}
|
||||
rb.off = (rb.off + len(buf)) % ringLen
|
||||
rb.l = rb.l + len(buf)
|
||||
if rb.l > ringLen {
|
||||
rb.l = ringLen
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
var NameToCmd = map[string]string{
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRingBuffer(t *testing.T) {
|
||||
rb := newRingBuffer(4)
|
||||
data := []struct {
|
||||
in, want string
|
||||
}{
|
||||
{in: "a", want: "a"},
|
||||
{in: "b", want: "ab"},
|
||||
{in: "c", want: "abc"},
|
||||
{in: "d", want: "abcd"},
|
||||
{in: "e", want: "bcde"},
|
||||
{in: "f", want: "cdef"},
|
||||
// Multibyte writes that wrap the ring buffer.
|
||||
{in: "ghi", want: "fghi"},
|
||||
{in: "jkl", want: "ijkl"},
|
||||
{in: "mno", want: "lmno"},
|
||||
// Write larger than ring buffer.
|
||||
{in: "pqrstuv", want: "stuv"},
|
||||
}
|
||||
for i, d := range data {
|
||||
in := []byte(d.in)
|
||||
n, err := rb.Write(in)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if n != len(in) {
|
||||
t.Error(i, "Wrote", n, "bytes, want", len(in))
|
||||
}
|
||||
got := rb.Bytes()
|
||||
want := []byte(d.want)
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("%d Got %q want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue