*: Use structured logging

Implements structured logging via Logrus. This gives us a logger per
boundry that we care about, allowing for easier parsing of logs if users
have more than one log option enabled. Also, cleans up a lot of
conditionals in the code by simply silencing the logger at creation as
opposed to conditionally logging everywhere.
This commit is contained in:
Derek Parker 2018-06-14 11:12:11 -07:00 committed by Alessandro Arzilli
parent 774b5c7ce2
commit a208c89719
13 changed files with 123 additions and 153 deletions

@ -364,7 +364,7 @@ func traceCmd(cmd *cobra.Command, args []string) {
APIVersion: 2,
WorkingDir: WorkingDir,
Backend: Backend,
}, logflags.RPC())
})
if err := server.Run(); err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
@ -510,7 +510,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
Foreground: Headless,
DisconnectChan: disconnectChan,
}, logflags.RPC())
})
default:
fmt.Printf("Unknown API version: %d\n", APIVersion)
return 1
@ -535,8 +535,6 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
var status int
if Headless {
// Print listener address
fmt.Printf("API server listening at: %s\n", listener.Addr())
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT)
select {

@ -80,13 +80,13 @@ func TestBuild(t *testing.T) {
buildtestdir := filepath.Join(fixtures, "buildtest")
cmd := exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2", "--backend="+testBackend)
cmd := exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2", "--backend="+testBackend, "--log", "--log-output=debugger,rpc")
cmd.Dir = buildtestdir
stdout, err := cmd.StdoutPipe()
assertNoError(err, t, "stdout pipe")
stderr, err := cmd.StderrPipe()
assertNoError(err, t, "stderr pipe")
cmd.Start()
scan := bufio.NewScanner(stdout)
scan := bufio.NewScanner(stderr)
// wait for the debugger to start
scan.Scan()
go func() {

@ -27,14 +27,13 @@ type DebugLineInfo struct {
Instructions []byte
Lookup map[string]*FileEntry
Logf func(string, ...interface{})
// stateMachineCache[pc] is a state machine stopped at pc
stateMachineCache map[uint64]*StateMachine
// lastMachineCache[pc] is a state machine stopped at an address after pc
lastMachineCache map[uint64]*StateMachine
// logSuppressedErrors enables logging of otherwise suppressed errors
logSuppressedErrors bool
}
type FileEntry struct {
@ -47,7 +46,7 @@ type FileEntry struct {
type DebugLines []*DebugLineInfo
// ParseAll parses all debug_line segments found in data
func ParseAll(data []byte) DebugLines {
func ParseAll(data []byte, logfn func(string, ...interface{})) DebugLines {
var (
lines = make(DebugLines, 0)
buf = bytes.NewBuffer(data)
@ -55,7 +54,7 @@ func ParseAll(data []byte) DebugLines {
// We have to parse multiple file name tables here.
for buf.Len() > 0 {
lines = append(lines, Parse("", buf))
lines = append(lines, Parse("", buf, logfn))
}
return lines
@ -63,8 +62,9 @@ func ParseAll(data []byte) DebugLines {
// Parse parses a single debug_line segment from buf. Compdir is the
// DW_AT_comp_dir attribute of the associated compile unit.
func Parse(compdir string, buf *bytes.Buffer) *DebugLineInfo {
func Parse(compdir string, buf *bytes.Buffer, logfn func(string, ...interface{})) *DebugLineInfo {
dbl := new(DebugLineInfo)
dbl.Logf = logfn
dbl.Lookup = make(map[string]*FileEntry)
if compdir != "" {
dbl.IncludeDirs = append(dbl.IncludeDirs, compdir)
@ -146,8 +146,3 @@ func readFileEntry(info *DebugLineInfo, buf *bytes.Buffer, exitOnEmptyPath bool)
return entry
}
// LogSuppressedErrors enables or disables logging of suppressed errors
func (dbl *DebugLineInfo) LogSuppressedErrors(v bool) {
dbl.logSuppressedErrors = v
}

@ -67,7 +67,7 @@ const (
func testDebugLinePrologueParser(p string, t *testing.T) {
data := grabDebugLineSection(p, t)
debugLines := ParseAll(data)
debugLines := ParseAll(data, nil)
mainFileFound := false
@ -164,7 +164,7 @@ func BenchmarkLineParser(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ParseAll(data)
_ = ParseAll(data, nil)
}
}
@ -179,7 +179,7 @@ func loadBenchmarkData(tb testing.TB) DebugLines {
tb.Fatal("Could not read test data", err)
}
return ParseAll(data)
return ParseAll(data, nil)
}
func BenchmarkStateMachine(b *testing.B) {

@ -5,7 +5,6 @@ import (
"encoding/binary"
"errors"
"fmt"
"log"
"github.com/derekparker/delve/pkg/dwarf/util"
)
@ -125,8 +124,8 @@ func (lineInfo *DebugLineInfo) AllPCsForFileLine(f string, l int) (pcs []uint64)
for {
if err := sm.next(); err != nil {
if lineInfo.logSuppressedErrors {
log.Printf("AllPCsForFileLine error: %v", err)
if lineInfo.Logf != nil {
lineInfo.Logf("AllPCsForFileLine error: %v", err)
}
break
}
@ -154,8 +153,8 @@ func (lineInfo *DebugLineInfo) AllPCsBetween(begin, end uint64, excludeFile stri
for {
if err := sm.next(); err != nil {
if lineInfo.logSuppressedErrors {
log.Printf("AllPCsBetween error: %v", err)
if lineInfo.Logf != nil {
lineInfo.Logf("AllPCsBetween error: %v", err)
}
break
}
@ -228,8 +227,8 @@ func (lineInfo *DebugLineInfo) PCToLine(basePC, pc uint64) (string, int) {
func (sm *StateMachine) PCToLine(pc uint64) (string, int, bool) {
if !sm.started {
if err := sm.next(); err != nil {
if sm.dbl.logSuppressedErrors {
log.Printf("PCToLine error: %v", err)
if sm.dbl.Logf != nil {
sm.dbl.Logf("PCToLine error: %v", err)
}
return "", 0, false
}
@ -247,8 +246,8 @@ func (sm *StateMachine) PCToLine(pc uint64) (string, int, bool) {
}
}
if err := sm.next(); err != nil {
if sm.dbl.logSuppressedErrors {
log.Printf("PCToLine error: %v", err)
if sm.dbl.Logf != nil {
sm.dbl.Logf("PCToLine error: %v", err)
}
break
}
@ -276,8 +275,8 @@ func (lineInfo *DebugLineInfo) LineToPC(filename string, lineno int) uint64 {
for {
if err := sm.next(); err != nil {
if lineInfo.logSuppressedErrors {
log.Printf("LineToPC error: %v", err)
if lineInfo.Logf != nil {
lineInfo.Logf("LineToPC error: %v", err)
}
break
}
@ -311,8 +310,8 @@ func (lineInfo *DebugLineInfo) PrologueEndPC(start, end uint64) (pc uint64, file
}
}
if err := sm.next(); err != nil {
if lineInfo.logSuppressedErrors {
log.Printf("PrologueEnd error: %v", err)
if lineInfo.Logf != nil {
lineInfo.Logf("PrologueEnd error: %v", err)
}
return 0, "", 0, false
}

@ -68,6 +68,7 @@ import (
"errors"
"fmt"
"go/ast"
"io/ioutil"
"net"
"os"
"os/exec"
@ -81,6 +82,7 @@ import (
"github.com/derekparker/delve/pkg/logflags"
"github.com/derekparker/delve/pkg/proc"
"github.com/sirupsen/logrus"
)
const (
@ -166,11 +168,17 @@ type gdbRegister struct {
// Detach.
// Use Listen, Dial or Connect to complete connection.
func New(process *os.Process) *Process {
logger := logrus.New().WithFields(logrus.Fields{"layer": "gdbconn"})
logger.Level = logrus.DebugLevel
if !logflags.GdbWire() {
logger.Logger.Out = ioutil.Discard
}
p := &Process{
conn: gdbConn{
maxTransmitAttempts: maxTransmitAttempts,
inbuf: make([]byte, 0, initialInputBufferSize),
direction: proc.Forward,
log: logger,
},
threads: make(map[int]*Thread),
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),

@ -18,6 +18,7 @@ import (
"github.com/derekparker/delve/pkg/logflags"
"github.com/derekparker/delve/pkg/proc"
"github.com/sirupsen/logrus"
)
type gdbConn struct {
@ -43,6 +44,8 @@ type gdbConn struct {
maxTransmitAttempts int // maximum number of transmit or receive attempts when bad checksums are read
threadSuffixSupported bool // thread suffix supported by stub
isDebugserver bool // true if the stub is debugserver
log *logrus.Entry
}
const (
@ -634,7 +637,7 @@ func (conn *gdbConn) parseStopPacket(resp []byte, threadID string, tu *threadUpd
sp.sig = uint8(sig)
if logflags.GdbWire() && gdbWireFullStopPacket {
fmt.Fprintf(os.Stderr, "full stop packet: %s\n", string(resp))
conn.log.Debug("full stop packet: %s\n", string(resp))
}
buf := resp[3:]
@ -705,9 +708,7 @@ const ctrlC = 0x03 // the ASCII character for ^C
// executes a ctrl-C on the line
func (conn *gdbConn) sendCtrlC() error {
if logflags.GdbWire() {
fmt.Println("<- interrupt")
}
conn.log.Debug("<- interrupt")
_, err := conn.conn.Write([]byte{ctrlC})
return err
}
@ -994,9 +995,9 @@ func (conn *gdbConn) send(cmd []byte) error {
for {
if logflags.GdbWire() {
if len(cmd) > gdbWireMaxLen {
fmt.Printf("<- %s...\n", string(cmd[:gdbWireMaxLen]))
conn.log.Debugf("<- %s...\n", string(cmd[:gdbWireMaxLen]))
} else {
fmt.Printf("<- %s\n", string(cmd))
conn.log.Debugf("<- %s\n", string(cmd))
}
}
_, err := conn.conn.Write(cmd)
@ -1045,9 +1046,9 @@ func (conn *gdbConn) recv(cmd []byte, context string, binary bool) (resp []byte,
partial = true
}
if !partial {
fmt.Printf("-> %s%s\n", string(resp), string(conn.inbuf[:2]))
conn.log.Debugf("-> %s%s\n", string(resp), string(conn.inbuf[:2]))
} else {
fmt.Printf("-> %s...\n", string(out))
conn.log.Debugf("-> %s...\n", string(out))
}
}
@ -1098,9 +1099,7 @@ func (conn *gdbConn) readack() bool {
if err != nil {
return false
}
if logflags.GdbWire() {
fmt.Printf("-> %s\n", string(b))
}
conn.log.Debugf("-> %s\n", string(b))
return b == '+'
}
@ -1110,9 +1109,7 @@ func (conn *gdbConn) sendack(c byte) {
panic(fmt.Errorf("sendack(%c)", c))
}
conn.conn.Write([]byte{c})
if logflags.GdbWire() {
fmt.Printf("<- %s\n", string(c))
}
conn.log.Debugf("<- %s\n", string(c))
}
// escapeXor is the value mandated by the specification to escape characters

@ -24,6 +24,7 @@ import (
"github.com/derekparker/delve/pkg/dwarf/reader"
"github.com/derekparker/delve/pkg/goversion"
"github.com/derekparker/delve/pkg/logflags"
"github.com/sirupsen/logrus"
)
// The kind field in runtime._type is a reflect.Kind value plus
@ -220,8 +221,15 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou
}
lineInfoOffset, _ := entry.Val(dwarf.AttrStmtList).(int64)
if lineInfoOffset >= 0 && lineInfoOffset < int64(len(debugLineBytes)) {
cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:]))
cu.lineInfo.LogSuppressedErrors(logflags.DebugLineErrors())
var logfn func(string, ...interface{})
if logflags.DebugLineErrors() {
logger := logrus.New().WithFields(logrus.Fields{"layer": "dwarf-line"})
logger.Level = logrus.DebugLevel
logfn = func(fmt string, args ...interface{}) {
logger.Printf(fmt, args)
}
}
cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:]), logfn)
}
cu.producer, _ = entry.Val(dwarf.AttrProducer).(string)
if cu.isgo && cu.producer != "" {

@ -113,7 +113,7 @@ func withTestTerminalBuildFlags(name string, t testing.TB, buildFlags test.Build
Listener: listener,
ProcessArgs: []string{test.BuildFixture(name, buildFlags).Path},
Backend: testBackend,
}, false)
})
if err := server.Run(); err != nil {
t.Fatal(err)
}

@ -4,7 +4,7 @@ import (
"errors"
"fmt"
"go/parser"
"log"
"io/ioutil"
"path/filepath"
"regexp"
"runtime"
@ -18,6 +18,7 @@ import (
"github.com/derekparker/delve/pkg/proc/gdbserial"
"github.com/derekparker/delve/pkg/proc/native"
"github.com/derekparker/delve/service/api"
"github.com/sirupsen/logrus"
)
// Debugger service.
@ -35,6 +36,7 @@ type Debugger struct {
// TODO(DO NOT MERGE WITHOUT) rename to targetMutex
processMutex sync.Mutex
target proc.Process
log *logrus.Entry
}
// Config provides the configuration to start a Debugger.
@ -63,17 +65,21 @@ type Config struct {
// New creates a new Debugger. ProcessArgs specify the commandline arguments for the
// new process.
func New(config *Config, processArgs []string) (*Debugger, error) {
logger := logrus.New().WithFields(logrus.Fields{"layer": "debugger"})
logger.Level = logrus.DebugLevel
if !logflags.Debugger() {
logger.Logger.Out = ioutil.Discard
}
d := &Debugger{
config: config,
processArgs: processArgs,
log: logger,
}
// Create the process by either attaching or launching.
switch {
case d.config.AttachPid > 0:
if logflags.Debugger() {
log.Printf("attaching to pid %d", d.config.AttachPid)
}
d.log.Infof("attaching to pid %d", d.config.AttachPid)
path := ""
if len(d.processArgs) > 0 {
path = d.processArgs[0]
@ -89,14 +95,10 @@ func New(config *Config, processArgs []string) (*Debugger, error) {
var err error
switch d.config.Backend {
case "rr":
if logflags.Debugger() {
log.Printf("opening trace %s", d.config.CoreFile)
}
d.log.Infof("opening trace %s", d.config.CoreFile)
p, err = gdbserial.Replay(d.config.CoreFile, false)
default:
if logflags.Debugger() {
log.Printf("opening core file %s (executable %s)", d.config.CoreFile, d.processArgs[0])
}
d.log.Infof("opening core file %s (executable %s)", d.config.CoreFile, d.processArgs[0])
p, err = core.OpenCore(d.config.CoreFile, d.processArgs[0])
}
if err != nil {
@ -105,9 +107,7 @@ func New(config *Config, processArgs []string) (*Debugger, error) {
d.target = p
default:
if logflags.Debugger() {
log.Printf("launching process with args: %v", d.processArgs)
}
d.log.Infof("launching process with args: %v", d.processArgs)
p, err := d.Launch(d.processArgs, d.config.WorkingDir)
if err != nil {
if err != proc.NotExecutableErr && err != proc.UnsupportedLinuxArchErr && err != proc.UnsupportedWindowsArchErr && err != proc.UnsupportedDarwinArchErr {
@ -367,9 +367,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin
return nil, err
}
createdBp = api.ConvertBreakpoint(bp)
if logflags.Debugger() {
log.Printf("created breakpoint: %#v", createdBp)
}
d.log.Infof("created breakpoint: %#v", createdBp)
return createdBp, nil
}
@ -417,9 +415,7 @@ func (d *Debugger) ClearBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint
return nil, fmt.Errorf("Can't clear breakpoint @%x: %s", requestedBp.Addr, err)
}
clearedBp = api.ConvertBreakpoint(bp)
if logflags.Debugger() {
log.Printf("cleared breakpoint: %#v", clearedBp)
}
d.log.Infof("cleared breakpoint: %#v", clearedBp)
return clearedBp, err
}
@ -517,9 +513,7 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
if command.Name == api.Halt {
// RequestManualStop does not invoke any ptrace syscalls, so it's safe to
// access the process directly.
if logflags.Debugger() {
log.Print("halting")
}
d.log.Debug("halting")
err = d.target.RequestManualStop()
}
@ -530,14 +524,10 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
switch command.Name {
case api.Continue:
if logflags.Debugger() {
log.Print("continuing")
}
d.log.Debug("continuing")
err = proc.Continue(d.target)
case api.Rewind:
if logflags.Debugger() {
log.Print("rewinding")
}
d.log.Debug("rewinding")
if err := d.target.Direction(proc.Backward); err != nil {
return nil, err
}
@ -546,35 +536,23 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
}()
err = proc.Continue(d.target)
case api.Next:
if logflags.Debugger() {
log.Print("nexting")
}
d.log.Debug("nexting")
err = proc.Next(d.target)
case api.Step:
if logflags.Debugger() {
log.Print("stepping")
}
d.log.Debug("stepping")
err = proc.Step(d.target)
case api.StepInstruction:
if logflags.Debugger() {
log.Print("single stepping")
}
d.log.Debug("single stepping")
err = d.target.StepInstruction()
case api.StepOut:
if logflags.Debugger() {
log.Print("step out")
}
d.log.Debug("step out")
err = proc.StepOut(d.target)
case api.SwitchThread:
if logflags.Debugger() {
log.Printf("switching to thread %d", command.ThreadID)
}
d.log.Debugf("switching to thread %d", command.ThreadID)
err = d.target.SwitchThread(command.ThreadID)
withBreakpointInfo = false
case api.SwitchGoroutine:
if logflags.Debugger() {
log.Printf("switching to goroutine %d", command.GoroutineID)
}
d.log.Debugf("switching to goroutine %d", command.GoroutineID)
err = d.target.SwitchGoroutine(command.GoroutineID)
withBreakpointInfo = false
case api.Halt:

@ -6,7 +6,7 @@ import (
"errors"
"fmt"
"io"
"log"
"io/ioutil"
"net"
"net/rpc"
"net/rpc/jsonrpc"
@ -16,12 +16,14 @@ import (
"unicode"
"unicode/utf8"
"github.com/derekparker/delve/pkg/logflags"
"github.com/derekparker/delve/pkg/version"
"github.com/derekparker/delve/service"
"github.com/derekparker/delve/service/api"
"github.com/derekparker/delve/service/debugger"
"github.com/derekparker/delve/service/rpc1"
"github.com/derekparker/delve/service/rpc2"
"github.com/sirupsen/logrus"
)
// ServerImpl implements a JSON-RPC server that can switch between two
@ -41,7 +43,7 @@ type ServerImpl struct {
s2 *rpc2.RPCServer
// maps of served methods, one for each supported API.
methodMaps []map[string]*methodType
log bool
log *logrus.Entry
}
type RPCCallback struct {
@ -65,17 +67,24 @@ type methodType struct {
}
// NewServer creates a new RPCServer.
func NewServer(config *service.Config, logEnabled bool) *ServerImpl {
func NewServer(config *service.Config) *ServerImpl {
logger := logrus.New().WithFields(logrus.Fields{"layer": "rpc"})
logger.Level = logrus.DebugLevel
if !logflags.RPC() {
logger.Logger.Out = ioutil.Discard
}
if config.APIVersion < 2 {
if logEnabled {
log.Printf("Using API v1")
}
logger.Info("Using API v1")
}
if config.Foreground {
// Print listener address
logger.Infof("API server listening at: %s", config.Listener.Addr())
}
return &ServerImpl{
config: config,
listener: config.Listener,
stopChan: make(chan struct{}),
log: logEnabled,
log: logger,
}
}
@ -183,14 +192,12 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// two signatures:
// func (rcvr ReceiverType) Method(in InputType, out *ReplyType) error
// func (rcvr ReceiverType) Method(in InputType, cb service.RPCCallback)
func suitableMethods(rcvr interface{}, methods map[string]*methodType, logEnabled bool) {
func suitableMethods(rcvr interface{}, methods map[string]*methodType, log *logrus.Entry) {
typ := reflect.TypeOf(rcvr)
rcvrv := reflect.ValueOf(rcvr)
sname := reflect.Indirect(rcvrv).Type().Name()
if sname == "" {
if logEnabled {
log.Printf("rpc.Register: no service name for type %s", typ)
}
log.Debugf("rpc.Register: no service name for type %s", typ)
return
}
for m := 0; m < typ.NumMethod(); m++ {
@ -203,17 +210,13 @@ func suitableMethods(rcvr interface{}, methods map[string]*methodType, logEnable
}
// Method needs three ins: (receive, *args, *reply) or (receiver, *args, *RPCCallback)
if mtype.NumIn() != 3 {
if logEnabled {
log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
}
log.Warn("method", mname, "has wrong number of ins:", mtype.NumIn())
continue
}
// First arg need not be a pointer.
argType := mtype.In(1)
if !isExportedOrBuiltinType(argType) {
if logEnabled {
log.Println(mname, "argument type not exported:", argType)
}
log.Warn(mname, "argument type not exported:", argType)
continue
}
@ -223,39 +226,29 @@ func suitableMethods(rcvr interface{}, methods map[string]*methodType, logEnable
if synchronous {
// Second arg must be a pointer.
if replyType.Kind() != reflect.Ptr {
if logEnabled {
log.Println("method", mname, "reply type not a pointer:", replyType)
}
log.Warn("method", mname, "reply type not a pointer:", replyType)
continue
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
if logEnabled {
log.Println("method", mname, "reply type not exported:", replyType)
}
log.Warn("method", mname, "reply type not exported:", replyType)
continue
}
// Method needs one out.
if mtype.NumOut() != 1 {
if logEnabled {
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
}
log.Warn("method", mname, "has wrong number of outs:", mtype.NumOut())
continue
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
if logEnabled {
log.Println("method", mname, "returns", returnType.String(), "not error")
}
log.Warn("method", mname, "returns", returnType.String(), "not error")
continue
}
} else {
// Method needs zero outs.
if mtype.NumOut() != 0 {
if logEnabled {
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
}
log.Warn("method", mname, "has wrong number of outs:", mtype.NumOut())
continue
}
}
@ -273,18 +266,14 @@ func (s *ServerImpl) serveJSONCodec(conn io.ReadWriteCloser) {
err := codec.ReadRequestHeader(&req)
if err != nil {
if err != io.EOF {
if s.log {
log.Println("rpc:", err)
}
s.log.Error("rpc:", err)
}
break
}
mtype, ok := s.methodMaps[s.config.APIVersion-1][req.ServiceMethod]
if !ok {
if s.log {
log.Printf("rpc: can't find method %s", req.ServiceMethod)
}
s.log.Errorf("rpc: can't find method %s", req.ServiceMethod)
continue
}
@ -307,9 +296,9 @@ func (s *ServerImpl) serveJSONCodec(conn io.ReadWriteCloser) {
}
if mtype.Synchronous {
if s.log {
if logflags.RPC() {
argvbytes, _ := json.Marshal(argv.Interface())
log.Printf("-> %s(%T%s)\n", req.ServiceMethod, argv.Interface(), argvbytes)
s.log.Debugf("-> %s(%T%s)\n", req.ServiceMethod, argv.Interface(), argvbytes)
}
replyv = reflect.New(mtype.ReplyType.Elem())
function := mtype.method.Func
@ -330,15 +319,15 @@ func (s *ServerImpl) serveJSONCodec(conn io.ReadWriteCloser) {
errmsg = errInter.(error).Error()
}
resp = rpc.Response{}
if s.log {
if logflags.RPC() {
replyvbytes, _ := json.Marshal(replyv.Interface())
log.Printf("<- %T%s error: %q\n", replyv.Interface(), replyvbytes, errmsg)
s.log.Debugf("<- %T%s error: %q\n", replyv.Interface(), replyvbytes, errmsg)
}
s.sendResponse(sending, &req, &resp, replyv.Interface(), codec, errmsg)
} else {
if s.log {
if logflags.RPC() {
argvbytes, _ := json.Marshal(argv.Interface())
log.Printf("(async %d) -> %s(%T%s)\n", req.Seq, req.ServiceMethod, argv.Interface(), argvbytes)
s.log.Debugf("(async %d) -> %s(%T%s)\n", req.Seq, req.ServiceMethod, argv.Interface(), argvbytes)
}
function := mtype.method.Func
ctl := &RPCCallback{s, sending, codec, req}
@ -374,9 +363,7 @@ func (s *ServerImpl) sendResponse(sending *sync.Mutex, req *rpc.Request, resp *r
defer sending.Unlock()
err := codec.WriteResponse(resp, reply)
if err != nil {
if s.log {
log.Println("rpc: writing response:", err)
}
s.log.Error("writing response:", err)
}
}
@ -386,9 +373,9 @@ func (cb *RPCCallback) Return(out interface{}, err error) {
errmsg = err.Error()
}
var resp rpc.Response
if cb.s.log {
if logflags.RPC() {
outbytes, _ := json.Marshal(out)
log.Printf("(async %d) <- %T%s error: %q", cb.req.Seq, out, outbytes, errmsg)
cb.s.log.Debugf("(async %d) <- %T%s error: %q", cb.req.Seq, out, outbytes, errmsg)
}
cb.s.sendResponse(cb.sending, &cb.req, &resp, out, cb.codec, errmsg)
}

@ -33,7 +33,7 @@ func withTestClient1(name string, t *testing.T, fn func(c *rpc1.RPCClient)) {
Listener: listener,
ProcessArgs: []string{protest.BuildFixture(name, 0).Path},
Backend: testBackend,
}, false)
})
if err := server.Run(); err != nil {
t.Fatal(err)
}
@ -61,7 +61,7 @@ func Test1RunWithInvalidPath(t *testing.T) {
Listener: listener,
ProcessArgs: []string{"invalid_path"},
Backend: testBackend,
}, false)
})
if err := server.Run(); err == nil {
t.Fatal("Expected Run to return error for invalid program path")
}
@ -150,7 +150,7 @@ func Test1Restart_attachPid(t *testing.T) {
Listener: nil,
AttachPid: 999,
Backend: testBackend,
}, false)
})
if err := server.Restart(); err == nil {
t.Fatal("expected error on restart after attaching to pid but got none")
}

@ -51,7 +51,7 @@ func withTestClient2(name string, t *testing.T, fn func(c service.Client)) {
Listener: listener,
ProcessArgs: []string{protest.BuildFixture(name, 0).Path},
Backend: testBackend,
}, false)
})
if err := server.Run(); err != nil {
t.Fatal(err)
}
@ -84,7 +84,7 @@ func TestRunWithInvalidPath(t *testing.T) {
ProcessArgs: []string{"invalid_path"},
APIVersion: 2,
Backend: testBackend,
}, false)
})
if err := server.Run(); err == nil {
t.Fatal("Expected Run to return error for invalid program path")
}
@ -175,7 +175,7 @@ func TestRestart_attachPid(t *testing.T) {
AttachPid: 999,
APIVersion: 2,
Backend: testBackend,
}, false)
})
if err := server.Restart(); err == nil {
t.Fatal("expected error on restart after attaching to pid but got none")
}