blob: 00a1b3e6cd560569b34f8876f86c49ef6d8c54be [file] [log] [blame]
package impl
import (
"io"
"math"
"os"
"path/filepath"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/services/mgmt/logreader/types"
"veyron.io/veyron/veyron2/vlog"
)
// logFileInvoker holds the state of a logfile invocation.
type logFileInvoker struct {
// root is the root directory from which the object names are based.
root string
// suffix is the suffix of the current invocation that is assumed to
// be used as a relative object name to identify a log file.
suffix string
}
// NewLogFileInvoker is the invoker factory.
func NewLogFileInvoker(root, suffix string) ipc.Invoker {
return ipc.ReflectInvoker(&logFileInvoker{filepath.Clean(root), suffix})
}
// Size returns the size of the log file, in bytes.
func (i *logFileInvoker) Size(call ipc.ServerCall) (int64, error) {
vlog.VI(1).Infof("%v.Size()", i.suffix)
fname, err := translateNameToFilename(i.root, i.suffix)
if err != nil {
return 0, err
}
fi, err := os.Stat(fname)
if err != nil {
if os.IsNotExist(err) {
return 0, errNotFound
}
vlog.Errorf("Stat(%v) failed: %v", fname, err)
return 0, errOperationFailed
}
if fi.IsDir() {
return 0, errOperationFailed
}
return fi.Size(), nil
}
// ReadLog returns log entries from the log file.
func (i *logFileInvoker) ReadLog(call ipc.ServerCall, startpos int64, numEntries int32, follow bool) (int64, error) {
vlog.VI(1).Infof("%v.ReadLog(%v, %v, %v)", i.suffix, startpos, numEntries, follow)
fname, err := translateNameToFilename(i.root, i.suffix)
if err != nil {
return 0, err
}
f, err := os.Open(fname)
if err != nil {
if os.IsNotExist(err) {
return 0, errNotFound
}
return 0, errOperationFailed
}
reader := newFollowReader(call, f, startpos, follow)
if numEntries == types.AllEntries {
numEntries = int32(math.MaxInt32)
}
for n := int32(0); n < numEntries; n++ {
line, offset, err := reader.readLine()
if err == io.EOF && n > 0 {
return reader.tell(), nil
}
if err == io.EOF {
return reader.tell(), errEOF
}
if err != nil {
return reader.tell(), errOperationFailed
}
if err := call.Send(types.LogEntry{Position: offset, Line: line}); err != nil {
return reader.tell(), err
}
}
return reader.tell(), nil
}