Initial changes to provide configurable logging options

This commit is contained in:
Kenneth Shaw 2017-02-13 16:00:25 +07:00
parent f55e04bb7a
commit 7326b390a0
3 changed files with 114 additions and 29 deletions

View File

@ -34,6 +34,9 @@ type CDP struct {
// handlerMap is the map of target IDs to its active handler. // handlerMap is the map of target IDs to its active handler.
handlerMap map[string]int handlerMap map[string]int
// logging funcs
logf, debugf, errorf LogFunc
sync.RWMutex sync.RWMutex
} }
@ -44,6 +47,9 @@ func New(ctxt context.Context, opts ...Option) (*CDP, error) {
c := &CDP{ c := &CDP{
handlers: make([]*TargetHandler, 0), handlers: make([]*TargetHandler, 0),
handlerMap: make(map[string]int), handlerMap: make(map[string]int),
logf: log.Printf,
debugf: func(string, ...interface{}) {},
errorf: func(s string, v ...interface{}) { log.Printf("error: "+s, v...) },
} }
// apply options // apply options
@ -108,16 +114,16 @@ func (c *CDP) AddTarget(ctxt context.Context, t client.Target) {
defer c.Unlock() defer c.Unlock()
// create target manager // create target manager
h, err := NewTargetHandler(t) h, err := NewTargetHandler(t, c.logf, c.debugf, c.errorf)
if err != nil { if err != nil {
log.Printf("error: could not create handler for %s, got: %v", t, err) c.errorf("could not create handler for %s, got: %v", t, err)
return return
} }
// run // run
err = h.Run(ctxt) err = h.Run(ctxt)
if err != nil { if err != nil {
log.Printf("error: could not start handler for %s, got: %v", t, err) c.errorf("could not start handler for %s, got: %v", t, err)
return return
} }
@ -344,8 +350,8 @@ func (c *CDP) Run(ctxt context.Context, a Action) error {
// Option is a Chrome Debugging Protocol option. // Option is a Chrome Debugging Protocol option.
type Option func(*CDP) error type Option func(*CDP) error
// WithRunner is a option to specify the underlying Chrome runner to monitor // WithRunner is a CDP option to specify the underlying Chrome runner to
// for page handlers. // monitor for page handlers.
func WithRunner(r *runner.Runner) Option { func WithRunner(r *runner.Runner) Option {
return func(c *CDP) error { return func(c *CDP) error {
c.r = r c.r = r
@ -353,8 +359,8 @@ func WithRunner(r *runner.Runner) Option {
} }
} }
// WithTargets is an option to specify the incoming targets to monitor for page // WithTargets is a CDP option to specify the incoming targets to monitor for
// handlers. // page handlers.
func WithTargets(watch <-chan client.Target) Option { func WithTargets(watch <-chan client.Target) Option {
return func(c *CDP) error { return func(c *CDP) error {
c.watch = watch c.watch = watch
@ -362,7 +368,7 @@ func WithTargets(watch <-chan client.Target) Option {
} }
} }
// WithRunnerOptions is a option to specify the options to pass to a newly // WithRunnerOptions is a CDP option to specify the options to pass to a newly
// created Chrome process runner. // created Chrome process runner.
func WithRunnerOptions(opts ...runner.CommandLineOption) Option { func WithRunnerOptions(opts ...runner.CommandLineOption) Option {
return func(c *CDP) error { return func(c *CDP) error {
@ -370,3 +376,51 @@ func WithRunnerOptions(opts ...runner.CommandLineOption) Option {
return nil return nil
} }
} }
// LogFunc is the common logging func type.
type LogFunc func(string, ...interface{})
// WithLogf is a CDP option to specify a func to receive general logging.
func WithLogf(f LogFunc) Option {
return func(c *CDP) error {
c.logf = f
return nil
}
}
// WithDebugf is a CDP option to specify a func to receive debug logging (ie,
// protocol information).
func WithDebugf(f LogFunc) Option {
return func(c *CDP) error {
c.debugf = f
return nil
}
}
// WithErrorf is a CDP option to specify a func to receive error logging.
func WithErrorf(f LogFunc) Option {
return func(c *CDP) error {
c.errorf = f
return nil
}
}
// WithLog is a CDP option that sets the logging, debugging, and error funcs to
// f.
func WithLog(f LogFunc) Option {
return func(c *CDP) error {
c.logf = f
c.debugf = f
c.errorf = f
return nil
}
}
// WithConsolef is a CDP option to specify a func to receive chrome log events.
//
// Note: NOT YET IMPLEMENTED.
func WithConsolef(f LogFunc) Option {
return func(c *CDP) error {
return nil
}
}

View File

@ -3,7 +3,6 @@ package chromedp
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
@ -54,17 +53,25 @@ type TargetHandler struct {
res map[int64]chan interface{} res map[int64]chan interface{}
resrw sync.RWMutex resrw sync.RWMutex
// logging funcs
logf, debugf, errorf LogFunc
sync.RWMutex sync.RWMutex
} }
// NewTargetHandler creates a new handler for the specified client target. // NewTargetHandler creates a new handler for the specified client target.
func NewTargetHandler(t client.Target) (*TargetHandler, error) { func NewTargetHandler(t client.Target, logf, debugf, errorf LogFunc) (*TargetHandler, error) {
conn, err := client.Dial(t) conn, err := client.Dial(t)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &TargetHandler{conn: conn}, nil return &TargetHandler{
conn: conn,
logf: logf,
debugf: debugf,
errorf: errorf,
}, nil
} }
// Run starts the processing of commands and events of the client target // Run starts the processing of commands and events of the client target
@ -154,7 +161,7 @@ func (h *TargetHandler) run(ctxt context.Context) {
h.qres <- msg h.qres <- msg
default: default:
log.Printf("ignoring malformed incoming message (missing id or method): %#v", msg) h.errorf("ignoring malformed incoming message (missing id or method): %#v", msg)
} }
case <-h.detached: case <-h.detached:
@ -175,19 +182,19 @@ func (h *TargetHandler) run(ctxt context.Context) {
case ev := <-h.qevents: case ev := <-h.qevents:
err = h.processEvent(ctxt, ev) err = h.processEvent(ctxt, ev)
if err != nil { if err != nil {
log.Printf("could not process event, got: %v", err) h.errorf("could not process event, got: %v", err)
} }
case res := <-h.qres: case res := <-h.qres:
err = h.processResult(res) err = h.processResult(res)
if err != nil { if err != nil {
log.Printf("could not process command result, got: %v", err) h.errorf("could not process command result, got: %v", err)
} }
case cmd := <-h.qcmd: case cmd := <-h.qcmd:
err = h.processCommand(cmd) err = h.processCommand(cmd)
if err != nil { if err != nil {
log.Printf("could not process command, got: %v", err) h.errorf("could not process command, got: %v", err)
} }
case <-ctxt.Done(): case <-ctxt.Done():
@ -204,7 +211,7 @@ func (h *TargetHandler) read() (*cdp.Message, error) {
return nil, err return nil, err
} }
log.Printf("-> %s", string(buf)) h.debugf("-> %s", string(buf))
// unmarshal // unmarshal
msg := new(cdp.Message) msg := new(cdp.Message)
@ -264,7 +271,7 @@ func (h *TargetHandler) processEvent(ctxt context.Context, msg *cdp.Message) err
func (h *TargetHandler) documentUpdated(ctxt context.Context) { func (h *TargetHandler) documentUpdated(ctxt context.Context) {
f, err := h.WaitFrame(ctxt, EmptyFrameID) f, err := h.WaitFrame(ctxt, EmptyFrameID)
if err != nil { if err != nil {
log.Printf("could not get current frame, got: %v", err) h.errorf("could not get current frame, got: %v", err)
return return
} }
@ -279,7 +286,7 @@ func (h *TargetHandler) documentUpdated(ctxt context.Context) {
f.Nodes = make(map[cdp.NodeID]*cdp.Node) f.Nodes = make(map[cdp.NodeID]*cdp.Node)
f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, h) f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, h)
if err != nil { if err != nil {
log.Printf("error could not retrieve document root for %s, got: %v", f.ID, err) h.errorf("could not retrieve document root for %s, got: %v", f.ID, err)
return return
} }
f.Root.Invalidated = make(chan struct{}) f.Root.Invalidated = make(chan struct{})
@ -293,7 +300,9 @@ func (h *TargetHandler) processResult(msg *cdp.Message) error {
res, ok := h.res[msg.ID] res, ok := h.res[msg.ID]
if !ok { if !ok {
panic(fmt.Sprintf("expected result to be present for message id %d", msg.ID)) err := fmt.Errorf("expected result to be present for message id %d", msg.ID)
h.errorf(err.Error())
return err
} }
if msg.Error != nil { if msg.Error != nil {
@ -316,7 +325,7 @@ func (h *TargetHandler) processCommand(cmd *cdp.Message) error {
return err return err
} }
log.Printf("<- %s", string(buf)) h.debugf("<- %s", string(buf))
// write // write
return h.conn.Write(buf) return h.conn.Write(buf)
@ -539,12 +548,13 @@ func (h *TargetHandler) pageEvent(ctxt context.Context, ev interface{}) {
return return
default: default:
panic(fmt.Sprintf("unhandled page event %s", reflect.TypeOf(ev))) h.errorf("unhandled page event %s", reflect.TypeOf(ev))
return
} }
f, err := h.WaitFrame(ctxt, id) f, err := h.WaitFrame(ctxt, id)
if err != nil { if err != nil {
log.Printf("error could not get frame %s, got: %v", id, err) h.errorf("could not get frame %s, got: %v", id, err)
return return
} }
@ -564,7 +574,7 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
// wait current frame // wait current frame
f, err := h.WaitFrame(ctxt, EmptyFrameID) f, err := h.WaitFrame(ctxt, EmptyFrameID)
if err != nil { if err != nil {
log.Printf("error processing DOM event %s: error waiting for frame, got: %v", reflect.TypeOf(ev), err) h.errorf("error processing DOM event %s: error waiting for frame, got: %v", reflect.TypeOf(ev), err)
return return
} }
@ -624,7 +634,8 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
return return
default: default:
panic(fmt.Sprintf("unhandled node event %s", reflect.TypeOf(ev))) h.errorf("unhandled node event %s", reflect.TypeOf(ev))
return
} }
s := strings.TrimPrefix(strings.TrimSuffix(runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(), ".func1"), "github.com/knq/chromedp.") s := strings.TrimPrefix(strings.TrimSuffix(runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(), ".func1"), "github.com/knq/chromedp.")
@ -632,7 +643,7 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
// retrieve node // retrieve node
n, err := h.WaitNode(ctxt, f, id) n, err := h.WaitNode(ctxt, f, id)
if err != nil { if err != nil {
log.Printf("error could not perform (%s) operation on node %d (wait node error), got: %v", s, id, err) h.errorf("error could not perform (%s) operation on node %d (wait node error), got: %v", s, id, err)
return return
} }

22
pool.go
View File

@ -3,6 +3,7 @@ package chromedp
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"sync" "sync"
"github.com/knq/chromedp/runner" "github.com/knq/chromedp/runner"
@ -19,6 +20,9 @@ type Pool struct {
// res are the running chrome resources. // res are the running chrome resources.
res map[int]*Res res map[int]*Res
// logging funcs
logf, debugf, errorf LogFunc
rw sync.RWMutex rw sync.RWMutex
} }
@ -30,6 +34,9 @@ func NewPool(opts ...PoolOption) (*Pool, error) {
start: DefaultPoolStartPort, start: DefaultPoolStartPort,
end: DefaultPoolEndPort, end: DefaultPoolEndPort,
res: make(map[int]*Res), res: make(map[int]*Res),
logf: log.Printf,
debugf: func(string, ...interface{}) {},
errorf: func(s string, v ...interface{}) { log.Printf("error: "+s, v...) },
} }
// apply opts // apply opts
@ -85,7 +92,10 @@ func (p *Pool) Allocate(ctxt context.Context, opts ...runner.CommandLineOption)
} }
// setup cdp // setup cdp
r.c, err = New(ctxt, WithRunner(r.r)) r.c, err = New(
ctxt, WithRunner(r.r),
WithLogf(p.logf), WithDebugf(p.debugf), WithErrorf(p.errorf),
)
if err != nil { if err != nil {
cancel() cancel()
return nil, err return nil, err
@ -173,3 +183,13 @@ func PortRange(start, end int) PoolOption {
return nil return nil
} }
} }
// PoolLog is a pool option to set the logging to use for the pool.
func PoolLog(logf, debugf, errorf LogFunc) PoolOption {
return func(p *Pool) error {
p.logf = logf
p.debugf = debugf
p.errorf = errorf
return nil
}
}