1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-06-18 22:17:44 +02:00

feat(logger): add logger option to all micro components (override DefaultLogger) closes #2556 (#2559)

* feat(logger): add logger option to all components

* fix: refactor api/rpc.go

* fix: refactor api/stream.go

* fix: api/options.go comment

* fix(logger): do not use logger.Helper internally

* fix(logger): fix comments

* fix(logger): use level.Enabled method

* fix: rename mlogger to log

* fix: run go fmt

* fix: log level

* fix: factories

Co-authored-by: Mohamed MHAMDI <mmhamdi@hubside.com>
Co-authored-by: Davincible <david.brouwer.99@gmail.com>
This commit is contained in:
Mohamed MHAMDI
2022-09-29 16:44:53 +02:00
committed by GitHub
parent 57a0ef5a0f
commit 1db36357d5
63 changed files with 818 additions and 673 deletions

View File

@ -162,7 +162,7 @@ func Validate(e *Endpoint) error {
// //
// Usage: // Usage:
// //
// proto.RegisterHandler(service.Server(), new(Handler), api.WithEndpoint( // proto.RegisterHandler(service.Server(), new(Handler), api.WithEndpoint(
// &api.Endpoint{ // &api.Endpoint{
// Name: "Greeter.Hello", // Name: "Greeter.Hello",
// Path: []string{"/greeter"}, // Path: []string{"/greeter"},

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"go-micro.dev/v4/api/router" "go-micro.dev/v4/api/router"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
"go-micro.dev/v4/logger"
) )
var ( var (
@ -14,13 +15,17 @@ type Options struct {
Namespace string Namespace string
Router router.Router Router router.Router
Client client.Client Client client.Client
Logger logger.Logger
} }
type Option func(o *Options) type Option func(o *Options)
// NewOptions fills in the blanks // NewOptions fills in the blanks
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
var options Options options := Options{
Logger: logger.DefaultLogger,
}
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
@ -33,6 +38,10 @@ func NewOptions(opts ...Option) Options {
options.MaxRecvSize = DefaultMaxRecvSize options.MaxRecvSize = DefaultMaxRecvSize
} }
if options.Logger == nil {
options.Logger = logger.LoggerOrDefault(options.Logger)
}
return options return options
} }
@ -56,9 +65,16 @@ func WithClient(c client.Client) Option {
} }
} }
// WithmaxRecvSize specifies max body size // WithMaxRecvSize specifies max body size
func WithMaxRecvSize(size int64) Option { func WithMaxRecvSize(size int64) Option {
return func(o *Options) { return func(o *Options) {
o.MaxRecvSize = size o.MaxRecvSize = size
} }
} }
// WithLogger specifies the logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -11,6 +11,7 @@ import (
jsonpatch "github.com/evanphx/json-patch/v5" jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/oxtoacart/bpool" "github.com/oxtoacart/bpool"
"go-micro.dev/v4/api/handler" "go-micro.dev/v4/api/handler"
"go-micro.dev/v4/api/internal/proto" "go-micro.dev/v4/api/internal/proto"
"go-micro.dev/v4/api/router" "go-micro.dev/v4/api/router"
@ -19,7 +20,7 @@ import (
"go-micro.dev/v4/codec/jsonrpc" "go-micro.dev/v4/codec/jsonrpc"
"go-micro.dev/v4/codec/protorpc" "go-micro.dev/v4/codec/protorpc"
"go-micro.dev/v4/errors" "go-micro.dev/v4/errors"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/selector" "go-micro.dev/v4/selector"
@ -28,7 +29,8 @@ import (
) )
const ( const (
Handler = "rpc" Handler = "rpc"
packageID = "go.micro.api"
) )
var ( var (
@ -73,6 +75,7 @@ func strategy(services []*registry.Service) selector.Strategy {
} }
func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := h.opts.Logger
bsize := handler.DefaultMaxRecvSize bsize := handler.DefaultMaxRecvSize
if h.opts.MaxRecvSize > 0 { if h.opts.MaxRecvSize > 0 {
bsize = h.opts.MaxRecvSize bsize = h.opts.MaxRecvSize
@ -87,13 +90,19 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// try get service from router // try get service from router
s, err := h.opts.Router.Route(r) s, err := h.opts.Router.Route(r)
if err != nil { if err != nil {
writeError(w, r, errors.InternalServerError("go.micro.api", err.Error())) werr := writeError(w, r, errors.InternalServerError(packageID, err.Error()))
if werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
service = s service = s
} else { } else {
// we have no way of routing the request // we have no way of routing the request
writeError(w, r, errors.InternalServerError("go.micro.api", "no route found")) werr := writeError(w, r, errors.InternalServerError(packageID, "no route found"))
if werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
@ -133,7 +142,9 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// drop older context as it can have timeouts and create new // drop older context as it can have timeouts and create new
// md, _ := metadata.FromContext(cx) // md, _ := metadata.FromContext(cx)
//serveWebsocket(context.TODO(), w, r, service, c) //serveWebsocket(context.TODO(), w, r, service, c)
serveWebsocket(cx, w, r, service, c) if err := serveWebsocket(cx, w, r, service, c); err != nil {
logger.Log(log.ErrorLevel, err)
}
return return
} }
@ -144,7 +155,9 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// get payload // get payload
br, err := requestPayload(r) br, err := requestPayload(r)
if err != nil { if err != nil {
writeError(w, r, err) if werr := writeError(w, r, err); werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
@ -171,14 +184,18 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// make the call // make the call
if err := c.Call(cx, req, response, client.WithSelectOption(so)); err != nil { if err := c.Call(cx, req, response, client.WithSelectOption(so)); err != nil {
writeError(w, r, err) if werr := writeError(w, r, err); werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
// marshall response // marshall response
rsp, err = response.Marshal() rsp, err = response.Marshal()
if err != nil { if err != nil {
writeError(w, r, err) if werr := writeError(w, r, err); werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
@ -206,20 +223,26 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
) )
// make the call // make the call
if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil { if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil {
writeError(w, r, err) if werr := writeError(w, r, err); werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
// marshall response // marshall response
rsp, err = response.MarshalJSON() rsp, err = response.MarshalJSON()
if err != nil { if err != nil {
writeError(w, r, err) if werr := writeError(w, r, err); werr != nil {
logger.Log(log.ErrorLevel, werr)
}
return return
} }
} }
// write the response // write the response
writeResponse(w, r, rsp) if err := writeResponse(w, r, rsp); err != nil {
logger.Log(log.ErrorLevel, err)
}
} }
func (rh *rpcHandler) String() string { func (rh *rpcHandler) String() string {
@ -275,7 +298,9 @@ func requestPayload(r *http.Request) ([]byte, error) {
} }
return raw.Marshal() return raw.Marshal()
case strings.Contains(ct, "application/www-x-form-urlencoded"): case strings.Contains(ct, "application/www-x-form-urlencoded"):
r.ParseForm() if err := r.ParseForm(); err != nil {
return nil, err
}
// generate a new set of values from the form // generate a new set of values from the form
vals := make(map[string]string) vals := make(map[string]string)
@ -441,14 +466,14 @@ func requestPayload(r *http.Request) ([]byte, error) {
return []byte{}, nil return []byte{}, nil
} }
func writeError(w http.ResponseWriter, r *http.Request, err error) { func writeError(w http.ResponseWriter, r *http.Request, err error) error {
ce := errors.Parse(err.Error()) ce := errors.Parse(err.Error())
switch ce.Code { switch ce.Code {
case 0: case 0:
// assuming it's totally screwed // assuming it's totally screwed
ce.Code = 500 ce.Code = 500
ce.Id = "go.micro.api" ce.Id = packageID
ce.Status = http.StatusText(500) ce.Status = http.StatusText(500)
ce.Detail = "error during request: " + ce.Detail ce.Detail = "error during request: " + ce.Detail
w.WriteHeader(500) w.WriteHeader(500)
@ -468,14 +493,10 @@ func writeError(w http.ResponseWriter, r *http.Request, err error) {
} }
_, werr := w.Write([]byte(ce.Error())) _, werr := w.Write([]byte(ce.Error()))
if werr != nil { return werr
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(werr)
}
}
} }
func writeResponse(w http.ResponseWriter, r *http.Request, rsp []byte) { func writeResponse(w http.ResponseWriter, r *http.Request, rsp []byte) error {
w.Header().Set("Content-Type", r.Header.Get("Content-Type")) w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
w.Header().Set("Content-Length", strconv.Itoa(len(rsp))) w.Header().Set("Content-Length", strconv.Itoa(len(rsp)))
@ -494,12 +515,7 @@ func writeResponse(w http.ResponseWriter, r *http.Request, rsp []byte) {
// write response // write response
_, err := w.Write(rsp) _, err := w.Write(rsp)
if err != nil { return err
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(err)
}
}
} }
func NewHandler(opts ...handler.Option) handler.Handler { func NewHandler(opts ...handler.Option) handler.Handler {

View File

@ -12,15 +12,15 @@ import (
"github.com/gobwas/httphead" "github.com/gobwas/httphead"
"github.com/gobwas/ws" "github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil" "github.com/gobwas/ws/wsutil"
"go-micro.dev/v4/api/router" "go-micro.dev/v4/api/router"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
raw "go-micro.dev/v4/codec/bytes" raw "go-micro.dev/v4/codec/bytes"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/selector" "go-micro.dev/v4/selector"
) )
// serveWebsocket will stream rpc back over websockets assuming json // serveWebsocket will stream rpc back over websockets assuming json
func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request, service *router.Route, c client.Client) { func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request, service *router.Route, c client.Client) (err error) {
var op ws.OpCode var op ws.OpCode
ct := r.Header.Get("Content-Type") ct := r.Header.Get("Content-Type")
@ -49,9 +49,6 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
} }
payload, err := requestPayload(r) payload, err := requestPayload(r)
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(err)
}
return return
} }
@ -72,18 +69,12 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
conn, rw, _, err := upgrader.Upgrade(r, w) conn, rw, _, err := upgrader.Upgrade(r, w)
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(err)
}
return return
} }
defer func() { defer func() {
if err := conn.Close(); err != nil { if cErr := conn.Close(); cErr != nil && err == nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { err = cErr
logger.Error(err)
}
return
} }
}() }()
@ -114,22 +105,20 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
// create a new stream // create a new stream
stream, err := c.Stream(ctx, req, client.WithSelectOption(so)) stream, err := c.Stream(ctx, req, client.WithSelectOption(so))
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(err)
}
return return
} }
if request != nil { if request != nil {
if err = stream.Send(request); err != nil { if err = stream.Send(request); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(err)
}
return return
} }
} }
go writeLoop(rw, stream) go func() {
if wErr := writeLoop(rw, stream); wErr != nil && err == nil {
err = wErr
}
}()
rsp := stream.Response() rsp := stream.Response()
@ -137,49 +126,40 @@ func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request,
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return nil
case <-stream.Context().Done(): case <-stream.Context().Done():
return return nil
default: default:
// read backend response body // read backend response body
buf, err := rsp.Read() buf, err := rsp.Read()
if err != nil { if err != nil {
// wants to avoid import grpc/status.Status // wants to avoid import grpc/status.Status
if strings.Contains(err.Error(), "context canceled") { if strings.Contains(err.Error(), "context canceled") {
return return nil
} }
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { return err
logger.Error(err)
}
return
} }
// write the response // write the response
if err := wsutil.WriteServerMessage(rw, op, buf); err != nil { if err = wsutil.WriteServerMessage(rw, op, buf); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { return err
logger.Error(err)
}
return
} }
if err = rw.Flush(); err != nil { if err = rw.Flush(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { return err
logger.Error(err)
}
return
} }
} }
} }
} }
// writeLoop // writeLoop
func writeLoop(rw io.ReadWriter, stream client.Stream) { func writeLoop(rw io.ReadWriter, stream client.Stream) error {
// close stream when done // close stream when done
defer stream.Close() defer stream.Close()
for { for {
select { select {
case <-stream.Context().Done(): case <-stream.Context().Done():
return return nil
default: default:
buf, op, err := wsutil.ReadClientData(rw) buf, op, err := wsutil.ReadClientData(rw)
if err != nil { if err != nil {
@ -187,16 +167,13 @@ func writeLoop(rw io.ReadWriter, stream client.Stream) {
switch wserr.Code { switch wserr.Code {
case ws.StatusGoingAway: case ws.StatusGoingAway:
// this happens when user leave the page // this happens when user leave the page
return return nil
case ws.StatusNormalClosure, ws.StatusNoStatusRcvd: case ws.StatusNormalClosure, ws.StatusNoStatusRcvd:
// this happens when user close ws connection, or we don't get any status // this happens when user close ws connection, or we don't get any status
return return nil
} }
} }
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { return err
logger.Error(err)
}
return
} }
switch op { switch op {
default: default:
@ -210,10 +187,7 @@ func writeLoop(rw io.ReadWriter, stream client.Stream) {
// if the extracted payload isn't empty lets use it // if the extracted payload isn't empty lets use it
request := &raw.Frame{Data: buf} request := &raw.Frame{Data: buf}
if err := stream.Send(request); err != nil { if err := stream.Send(request); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { return err
logger.Error(err)
}
return
} }
} }
} }

View File

@ -3,6 +3,7 @@ package router
import ( import (
"go-micro.dev/v4/api/resolver" "go-micro.dev/v4/api/resolver"
"go-micro.dev/v4/api/resolver/vpath" "go-micro.dev/v4/api/resolver/vpath"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
) )
@ -10,6 +11,7 @@ type Options struct {
Handler string Handler string
Registry registry.Registry Registry registry.Registry
Resolver resolver.Resolver Resolver resolver.Resolver
Logger logger.Logger
} }
type Option func(o *Options) type Option func(o *Options)
@ -18,6 +20,7 @@ func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Handler: "meta", Handler: "meta",
Registry: registry.DefaultRegistry, Registry: registry.DefaultRegistry,
Logger: logger.DefaultLogger,
} }
for _, o := range opts { for _, o := range opts {
@ -50,3 +53,10 @@ func WithResolver(r resolver.Resolver) Option {
o.Resolver = r o.Resolver = r
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -12,7 +12,7 @@ import (
"go-micro.dev/v4/api/router" "go-micro.dev/v4/api/router"
"go-micro.dev/v4/api/router/util" "go-micro.dev/v4/api/router/util"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/registry/cache" "go-micro.dev/v4/registry/cache"
@ -51,14 +51,13 @@ func (r *registryRouter) isStopped() bool {
// refresh list of api services // refresh list of api services
func (r *registryRouter) refresh() { func (r *registryRouter) refresh() {
var attempts int var attempts int
logger := r.Options().Logger
for { for {
services, err := r.opts.Registry.ListServices() services, err := r.opts.Registry.ListServices()
if err != nil { if err != nil {
attempts++ attempts++
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "unable to list services: %v", err)
logger.Errorf("unable to list services: %v", err)
}
time.Sleep(time.Duration(attempts) * time.Second) time.Sleep(time.Duration(attempts) * time.Second)
continue continue
} }
@ -69,9 +68,7 @@ func (r *registryRouter) refresh() {
for _, s := range services { for _, s := range services {
service, err := r.rc.GetService(s.Name) service, err := r.rc.GetService(s.Name)
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "unable to get service: %v", err)
logger.Errorf("unable to get service: %v", err)
}
continue continue
} }
r.store(service) r.store(service)
@ -89,6 +86,7 @@ func (r *registryRouter) refresh() {
// process watch event // process watch event
func (r *registryRouter) process(res *registry.Result) { func (r *registryRouter) process(res *registry.Result) {
logger := r.Options().Logger
// skip these things // skip these things
if res == nil || res.Service == nil { if res == nil || res.Service == nil {
return return
@ -97,9 +95,7 @@ func (r *registryRouter) process(res *registry.Result) {
// get entry from cache // get entry from cache
service, err := r.rc.GetService(res.Service.Name) service, err := r.rc.GetService(res.Service.Name)
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "unable to get service: %v", err)
logger.Errorf("unable to get service: %v", err)
}
return return
} }
@ -109,6 +105,7 @@ func (r *registryRouter) process(res *registry.Result) {
// store local endpoint cache // store local endpoint cache
func (r *registryRouter) store(services []*registry.Service) { func (r *registryRouter) store(services []*registry.Service) {
logger := r.Options().Logger
// endpoints // endpoints
eps := map[string]*router.Route{} eps := map[string]*router.Route{}
@ -129,9 +126,7 @@ func (r *registryRouter) store(services []*registry.Service) {
// if we got nothing skip // if we got nothing skip
if err := router.Validate(end); err != nil { if err := router.Validate(end); err != nil {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { logger.Logf(log.TraceLevel, "endpoint validation failed: %v", err)
logger.Tracef("endpoint validation failed: %v", err)
}
continue continue
} }
@ -176,9 +171,7 @@ func (r *registryRouter) store(services []*registry.Service) {
} }
hostreg, err := regexp.CompilePOSIX(h) hostreg, err := regexp.CompilePOSIX(h)
if err != nil { if err != nil {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { logger.Logf(log.TraceLevel, "endpoint have invalid host regexp: %v", err)
logger.Tracef("endpoint have invalid host regexp: %v", err)
}
continue continue
} }
cep.hostregs = append(cep.hostregs, hostreg) cep.hostregs = append(cep.hostregs, hostreg)
@ -197,20 +190,16 @@ func (r *registryRouter) store(services []*registry.Service) {
rule, err := util.Parse(p) rule, err := util.Parse(p)
if err != nil && !pcreok { if err != nil && !pcreok {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { logger.Logf(log.TraceLevel, "endpoint have invalid path pattern: %v", err)
logger.Tracef("endpoint have invalid path pattern: %v", err)
}
continue continue
} else if err != nil && pcreok { } else if err != nil && pcreok {
continue continue
} }
tpl := rule.Compile() tpl := rule.Compile()
pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "") pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "", util.PatternLogger(logger))
if err != nil { if err != nil {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { logger.Logf(log.TraceLevel, "endpoint have invalid path pattern: %v", err)
logger.Tracef("endpoint have invalid path pattern: %v", err)
}
continue continue
} }
cep.pathregs = append(cep.pathregs, pathreg) cep.pathregs = append(cep.pathregs, pathreg)
@ -223,6 +212,7 @@ func (r *registryRouter) store(services []*registry.Service) {
// watch for endpoint changes // watch for endpoint changes
func (r *registryRouter) watch() { func (r *registryRouter) watch() {
var attempts int var attempts int
logger := r.Options().Logger
for { for {
if r.isStopped() { if r.isStopped() {
@ -233,9 +223,7 @@ func (r *registryRouter) watch() {
w, err := r.opts.Registry.Watch() w, err := r.opts.Registry.Watch()
if err != nil { if err != nil {
attempts++ attempts++
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "error watching endpoints: %v", err)
logger.Errorf("error watching endpoints: %v", err)
}
time.Sleep(time.Duration(attempts) * time.Second) time.Sleep(time.Duration(attempts) * time.Second)
continue continue
} }
@ -258,9 +246,7 @@ func (r *registryRouter) watch() {
// process next event // process next event
res, err := w.Next() res, err := w.Next()
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "error getting next endoint: %v", err)
logger.Errorf("error getting next endoint: %v", err)
}
close(ch) close(ch)
break break
} }
@ -293,6 +279,7 @@ func (r *registryRouter) Deregister(ep *router.Route) error {
} }
func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) { func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
logger := r.Options().Logger
if r.isStopped() { if r.isStopped() {
return nil, errors.New("router closed") return nil, errors.New("router closed")
} }
@ -325,9 +312,8 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
if !mMatch { if !mMatch {
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("api method match %s", req.Method) logger.Logf(log.DebugLevel, "api method match %s", req.Method)
}
// 2. try host // 2. try host
if len(ep.Host) == 0 { if len(ep.Host) == 0 {
@ -348,22 +334,17 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
if !hMatch { if !hMatch {
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("api host match %s", req.URL.Host) logger.Logf(log.DebugLevel, "api host match %s", req.URL.Host)
}
// 3. try path via google.api path matching // 3. try path via google.api path matching
for _, pathreg := range cep.pathregs { for _, pathreg := range cep.pathregs {
matches, err := pathreg.Match(path, "") matches, err := pathreg.Match(path, "")
if err != nil { if err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api gpath not match %s != %v", path, pathreg)
logger.Debugf("api gpath not match %s != %v", path, pathreg)
}
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api gpath match %s = %v", path, pathreg)
logger.Debugf("api gpath match %s = %v", path, pathreg)
}
pMatch = true pMatch = true
ctx := req.Context() ctx := req.Context()
md, ok := metadata.FromContext(ctx) md, ok := metadata.FromContext(ctx)
@ -381,14 +362,10 @@ func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) {
// 4. try path via pcre path matching // 4. try path via pcre path matching
for _, pathreg := range cep.pcreregs { for _, pathreg := range cep.pcreregs {
if !pathreg.MatchString(req.URL.Path) { if !pathreg.MatchString(req.URL.Path) {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api pcre path not match %s != %v", path, pathreg)
logger.Debugf("api pcre path not match %s != %v", path, pathreg)
}
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api pcre path match %s != %v", path, pathreg)
logger.Debugf("api pcre path match %s != %v", path, pathreg)
}
pMatch = true pMatch = true
break break
} }

View File

@ -10,7 +10,7 @@ import (
"go-micro.dev/v4/api/router" "go-micro.dev/v4/api/router"
"go-micro.dev/v4/api/router/util" "go-micro.dev/v4/api/router/util"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
rutil "go-micro.dev/v4/util/registry" rutil "go-micro.dev/v4/util/registry"
@ -129,7 +129,7 @@ func (r *staticRouter) Register(route *router.Route) error {
} }
tpl := rule.Compile() tpl := rule.Compile()
pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "") pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "", util.PatternLogger(r.Options().Logger))
if err != nil { if err != nil {
return err return err
} }
@ -222,6 +222,7 @@ func (r *staticRouter) Endpoint(req *http.Request) (*router.Route, error) {
} }
func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) { func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
logger := r.Options().Logger
if r.isStopd() { if r.isStopd() {
return nil, errors.New("router closed") return nil, errors.New("router closed")
} }
@ -250,9 +251,7 @@ func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
if !mMatch { if !mMatch {
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api method match %s", req.Method)
logger.Debugf("api method match %s", req.Method)
}
// 2. try host // 2. try host
if len(ep.apiep.Host) == 0 { if len(ep.apiep.Host) == 0 {
@ -273,22 +272,16 @@ func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
if !hMatch { if !hMatch {
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api host match %s", req.URL.Host)
logger.Debugf("api host match %s", req.URL.Host)
}
// 3. try google.api path // 3. try google.api path
for _, pathreg := range ep.pathregs { for _, pathreg := range ep.pathregs {
matches, err := pathreg.Match(path, "") matches, err := pathreg.Match(path, "")
if err != nil { if err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api gpath not match %s != %v", path, pathreg)
logger.Debugf("api gpath not match %s != %v", path, pathreg)
}
continue continue
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api gpath match %s = %v", path, pathreg)
logger.Debugf("api gpath match %s = %v", path, pathreg)
}
pMatch = true pMatch = true
ctx := req.Context() ctx := req.Context()
md, ok := metadata.FromContext(ctx) md, ok := metadata.FromContext(ctx)
@ -306,9 +299,7 @@ func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) {
// 4. try path via pcre path matching // 4. try path via pcre path matching
for _, pathreg := range ep.pcreregs { for _, pathreg := range ep.pcreregs {
if !pathreg.MatchString(req.URL.Path) { if !pathreg.MatchString(req.URL.Path) {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "api pcre path not match %s != %v", req.URL.Path, pathreg)
logger.Debugf("api pcre path not match %s != %v", req.URL.Path, pathreg)
}
continue continue
} }
pMatch = true pMatch = true

View File

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
) )
// InvalidTemplateError indicates that the path template is not valid. // InvalidTemplateError indicates that the path template is not valid.
@ -98,38 +98,36 @@ func tokenize(path string) (tokens []string, verb string) {
type parser struct { type parser struct {
tokens []string tokens []string
accepted []string accepted []string
logger log.Logger
} }
// topLevelSegments is the target of this parser. // topLevelSegments is the target of this parser.
func (p *parser) topLevelSegments() ([]segment, error) { func (p *parser) topLevelSegments() ([]segment, error) {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger := log.LoggerOrDefault(p.logger)
logger.Debugf("Parsing %q", p.tokens)
} logger.Logf(log.DebugLevel, "Parsing %q", p.tokens)
segs, err := p.segments() segs, err := p.segments()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "accept segments: %q; %q", p.accepted, p.tokens)
logger.Debugf("accept segments: %q; %q", p.accepted, p.tokens)
}
if _, err := p.accept(typeEOF); err != nil { if _, err := p.accept(typeEOF); err != nil {
return nil, fmt.Errorf("unexpected token %q after segments %q", p.tokens[0], strings.Join(p.accepted, "")) return nil, fmt.Errorf("unexpected token %q after segments %q", p.tokens[0], strings.Join(p.accepted, ""))
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "accept eof: %q; %q", p.accepted, p.tokens)
logger.Debugf("accept eof: %q; %q", p.accepted, p.tokens)
}
return segs, nil return segs, nil
} }
func (p *parser) segments() ([]segment, error) { func (p *parser) segments() ([]segment, error) {
logger := log.LoggerOrDefault(p.logger)
s, err := p.segment() s, err := p.segment()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "accept segment: %q; %q", p.accepted, p.tokens)
logger.Debugf("accept segment: %q; %q", p.accepted, p.tokens)
}
segs := []segment{s} segs := []segment{s}
for { for {
if _, err := p.accept("/"); err != nil { if _, err := p.accept("/"); err != nil {
@ -140,9 +138,7 @@ func (p *parser) segments() ([]segment, error) {
return segs, err return segs, err
} }
segs = append(segs, s) segs = append(segs, s)
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "accept segment: %q; %q", p.accepted, p.tokens)
logger.Debugf("accept segment: %q; %q", p.accepted, p.tokens)
}
} }
} }
@ -270,11 +266,12 @@ func (p *parser) accept(term termType) (string, error) {
// expectPChars determines if "t" consists of only pchars defined in RFC3986. // expectPChars determines if "t" consists of only pchars defined in RFC3986.
// //
// https://www.ietf.org/rfc/rfc3986.txt, P.49 // https://www.ietf.org/rfc/rfc3986.txt, P.49
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" //
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
// / "*" / "+" / "," / ";" / "=" // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
// pct-encoded = "%" HEXDIG HEXDIG // / "*" / "+" / "," / ";" / "="
// pct-encoded = "%" HEXDIG HEXDIG
func expectPChars(t string) error { func expectPChars(t string) error {
const ( const (
init = iota init = iota

View File

@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
) )
var ( var (
@ -43,11 +43,19 @@ type Pattern struct {
type patternOptions struct { type patternOptions struct {
assumeColonVerb bool assumeColonVerb bool
logger log.Logger
} }
// PatternOpt is an option for creating Patterns. // PatternOpt is an option for creating Patterns.
type PatternOpt func(*patternOptions) type PatternOpt func(*patternOptions)
// Logger sets the logger
func PatternLogger(l log.Logger) PatternOpt {
return func(po *patternOptions) {
po.logger = l
}
}
// NewPattern returns a new Pattern from the given definition values. // NewPattern returns a new Pattern from the given definition values.
// "ops" is a sequence of op codes. "pool" is a constant pool. // "ops" is a sequence of op codes. "pool" is a constant pool.
// "verb" is the verb part of the pattern. It is empty if the pattern does not have the part. // "verb" is the verb part of the pattern. It is empty if the pattern does not have the part.
@ -61,18 +69,16 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
o(&options) o(&options)
} }
logger := log.LoggerOrDefault(options.logger)
if version != 1 { if version != 1 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "unsupported version: %d", version)
logger.Debugf("unsupported version: %d", version)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
l := len(ops) l := len(ops)
if l%2 != 0 { if l%2 != 0 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "odd number of ops codes: %d", l)
logger.Debugf("odd number of ops codes: %d", l)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
@ -95,18 +101,14 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
stack++ stack++
case OpPushM: case OpPushM:
if pushMSeen { if pushMSeen {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "pushM appears twice")
logger.Debug("pushM appears twice")
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
pushMSeen = true pushMSeen = true
stack++ stack++
case OpLitPush: case OpLitPush:
if op.operand < 0 || len(pool) <= op.operand { if op.operand < 0 || len(pool) <= op.operand {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "negative literal index: %d", op.operand)
logger.Debugf("negative literal index: %d", op.operand)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
if pushMSeen { if pushMSeen {
@ -115,24 +117,18 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
stack++ stack++
case OpConcatN: case OpConcatN:
if op.operand <= 0 { if op.operand <= 0 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "negative concat size: %d", op.operand)
logger.Debugf("negative concat size: %d", op.operand)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
stack -= op.operand stack -= op.operand
if stack < 0 { if stack < 0 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "stack underflow")
logger.Debug("stack underflow")
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
stack++ stack++
case OpCapture: case OpCapture:
if op.operand < 0 || len(pool) <= op.operand { if op.operand < 0 || len(pool) <= op.operand {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "variable name index out of bound: %d", op.operand)
logger.Debugf("variable name index out of bound: %d", op.operand)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
v := pool[op.operand] v := pool[op.operand]
@ -140,15 +136,11 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
vars = append(vars, v) vars = append(vars, v)
stack-- stack--
if stack < 0 { if stack < 0 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "stack underflow")
logger.Debug("stack underflow")
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
default: default:
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "invalid opcode: %d", op.code)
logger.Debugf("invalid opcode: %d", op.code)
}
return Pattern{}, ErrInvalidPattern return Pattern{}, ErrInvalidPattern
} }
@ -171,9 +163,7 @@ func NewPattern(version int, ops []int, pool []string, verb string, opts ...Patt
// MustPattern is a helper function which makes it easier to call NewPattern in variable initialization. // MustPattern is a helper function which makes it easier to call NewPattern in variable initialization.
func MustPattern(p Pattern, err error) Pattern { func MustPattern(p Pattern, err error) Pattern {
if err != nil { if err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { log.Logf(log.FatalLevel, "Pattern initialization failed: %v", err)
logger.Fatalf("Pattern initialization failed: %v", err)
}
} }
return p return p
} }

View File

@ -7,13 +7,16 @@ import (
"net" "net"
"os" "os"
"go-micro.dev/v4/api/server/acme"
"go-micro.dev/v4/logger"
"golang.org/x/crypto/acme/autocert" "golang.org/x/crypto/acme/autocert"
"go-micro.dev/v4/api/server/acme"
log "go-micro.dev/v4/logger"
) )
// autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert // autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert
type autocertProvider struct{} type autocertProvider struct {
logger log.Logger
}
// Listen implements acme.Provider // Listen implements acme.Provider
func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) { func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) {
@ -22,6 +25,7 @@ func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) {
// TLSConfig returns a new tls config // TLSConfig returns a new tls config
func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) { func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
logger := log.LoggerOrDefault(a.logger)
// create a new manager // create a new manager
m := &autocert.Manager{ m := &autocert.Manager{
Prompt: autocert.AcceptTOS, Prompt: autocert.AcceptTOS,
@ -31,9 +35,7 @@ func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
} }
dir := cacheDir() dir := cacheDir()
if err := os.MkdirAll(dir, 0700); err != nil { if err := os.MkdirAll(dir, 0700); err != nil {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "warning: autocert not using a cache: %v", err)
logger.Infof("warning: autocert not using a cache: %v", err)
}
} else { } else {
m.Cache = autocert.DirCache(dir) m.Cache = autocert.DirCache(dir)
} }

View File

@ -1,6 +1,10 @@
package acme package acme
import "github.com/go-acme/lego/v4/challenge" import (
"github.com/go-acme/lego/v4/challenge"
"go-micro.dev/v4/logger"
)
// Option (or Options) are passed to New() to configure providers // Option (or Options) are passed to New() to configure providers
type Option func(o *Options) type Option func(o *Options)
@ -22,6 +26,9 @@ type Options struct {
// there's no defined interface, so if you consume this option // there's no defined interface, so if you consume this option
// sanity check it before using. // sanity check it before using.
Cache interface{} Cache interface{}
// Logger is the underling logging framework
Logger logger.Logger
} }
// AcceptToS indicates whether you accept your CA's terms of service // AcceptToS indicates whether you accept your CA's terms of service
@ -63,6 +70,13 @@ func Cache(c interface{}) Option {
} }
} }
// Logger sets the underline logger
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// DefaultOptions uses the Let's Encrypt Production CA, with DNS Challenge disabled. // DefaultOptions uses the Let's Encrypt Production CA, with DNS Challenge disabled.
func DefaultOptions() Options { func DefaultOptions() Options {
return Options{ return Options{

View File

@ -9,9 +9,10 @@ import (
"sync" "sync"
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"go-micro.dev/v4/api/server" "go-micro.dev/v4/api/server"
"go-micro.dev/v4/api/server/cors" "go-micro.dev/v4/api/server/cors"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
) )
type httpServer struct { type httpServer struct {
@ -24,10 +25,7 @@ type httpServer struct {
} }
func NewServer(address string, opts ...server.Option) server.Server { func NewServer(address string, opts ...server.Option) server.Server {
var options server.Options options := server.NewOptions(opts...)
for _, o := range opts {
o(&options)
}
return &httpServer{ return &httpServer{
opts: options, opts: options,
@ -70,6 +68,7 @@ func (s *httpServer) Handle(path string, handler http.Handler) {
} }
func (s *httpServer) Start() error { func (s *httpServer) Start() error {
logger := s.opts.Logger
var l net.Listener var l net.Listener
var err error var err error
@ -86,9 +85,7 @@ func (s *httpServer) Start() error {
return err return err
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "HTTP API Listening on %s", l.Addr().String())
logger.Infof("HTTP API Listening on %s", l.Addr().String())
}
s.mtx.Lock() s.mtx.Lock()
s.address = l.Addr().String() s.address = l.Addr().String()
@ -97,7 +94,8 @@ func (s *httpServer) Start() error {
go func() { go func() {
if err := http.Serve(l, s.mux); err != nil { if err := http.Serve(l, s.mux); err != nil {
// temporary fix // temporary fix
//logger.Fatal(err) //logger.Log(log.FatalLevel, err)
logger.Log(log.ErrorLevel, err)
} }
}() }()

View File

@ -2,9 +2,11 @@ package server
import ( import (
"crypto/tls" "crypto/tls"
"go-micro.dev/v4/api/server/cors"
"net/http" "net/http"
"go-micro.dev/v4/api/server/cors"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/api/resolver" "go-micro.dev/v4/api/resolver"
"go-micro.dev/v4/api/server/acme" "go-micro.dev/v4/api/server/acme"
) )
@ -21,10 +23,23 @@ type Options struct {
TLSConfig *tls.Config TLSConfig *tls.Config
Resolver resolver.Resolver Resolver resolver.Resolver
Wrappers []Wrapper Wrappers []Wrapper
Logger logger.Logger
} }
type Wrapper func(h http.Handler) http.Handler type Wrapper func(h http.Handler) http.Handler
func NewOptions(opts ...Option) Options {
options := Options{
Logger: logger.DefaultLogger,
}
for _, o := range opts {
o(&options)
}
return options
}
func WrapHandler(w Wrapper) Option { func WrapHandler(w Wrapper) Option {
return func(o *Options) { return func(o *Options) {
o.Wrappers = append(o.Wrappers, w) o.Wrappers = append(o.Wrappers, w)
@ -78,3 +93,10 @@ func Resolver(r resolver.Resolver) Option {
o.Resolver = r o.Resolver = r
} }
} }
// Logger sets the underline logging framework
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -3,13 +3,19 @@ package auth
import ( import (
"context" "context"
"time" "time"
"go-micro.dev/v4/logger"
) )
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
var options Options options := Options{
Logger: logger.DefaultLogger,
}
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
return options return options
} }
@ -28,6 +34,8 @@ type Options struct {
PrivateKey string PrivateKey string
// Addrs sets the addresses of auth // Addrs sets the addresses of auth
Addrs []string Addrs []string
// Logger is the underline logger
Logger logger.Logger
} }
type Option func(o *Options) type Option func(o *Options)
@ -60,6 +68,13 @@ func PrivateKey(key string) Option {
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// Credentials sets the auth credentials // Credentials sets the auth credentials
func Credentials(id, secret string) Option { func Credentials(id, secret string) Option {
return func(o *Options) { return func(o *Options) {

View File

@ -3,7 +3,6 @@ package broker
import ( import (
"bytes" "bytes"
"context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
@ -17,6 +16,8 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"golang.org/x/net/http2"
"go-micro.dev/v4/codec/json" "go-micro.dev/v4/codec/json"
merr "go-micro.dev/v4/errors" merr "go-micro.dev/v4/errors"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
@ -24,7 +25,6 @@ import (
maddr "go-micro.dev/v4/util/addr" maddr "go-micro.dev/v4/util/addr"
mnet "go-micro.dev/v4/util/net" mnet "go-micro.dev/v4/util/net"
mls "go-micro.dev/v4/util/tls" mls "go-micro.dev/v4/util/tls"
"golang.org/x/net/http2"
) )
// HTTP Broker is a point to point async broker // HTTP Broker is a point to point async broker
@ -107,11 +107,10 @@ func newTransport(config *tls.Config) *http.Transport {
} }
func newHttpBroker(opts ...Option) Broker { func newHttpBroker(opts ...Option) Broker {
options := Options{ options := *NewOptions(opts...)
Codec: json.Marshaler{},
Context: context.TODO(), options.Registry = registry.DefaultRegistry
Registry: registry.DefaultRegistry, options.Codec = json.Marshaler{}
}
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)

View File

@ -2,20 +2,20 @@
package broker package broker
import ( import (
"context"
"errors" "errors"
"math/rand" "math/rand"
"sync" "sync"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
maddr "go-micro.dev/v4/util/addr" maddr "go-micro.dev/v4/util/addr"
mnet "go-micro.dev/v4/util/net" mnet "go-micro.dev/v4/util/net"
) )
type memoryBroker struct { type memoryBroker struct {
opts Options opts *Options
addr string addr string
sync.RWMutex sync.RWMutex
@ -24,7 +24,7 @@ type memoryBroker struct {
} }
type memoryEvent struct { type memoryEvent struct {
opts Options opts *Options
topic string topic string
err error err error
message interface{} message interface{}
@ -39,7 +39,7 @@ type memorySubscriber struct {
} }
func (m *memoryBroker) Options() Options { func (m *memoryBroker) Options() Options {
return m.opts return *m.opts
} }
func (m *memoryBroker) Address() string { func (m *memoryBroker) Address() string {
@ -84,7 +84,7 @@ func (m *memoryBroker) Disconnect() error {
func (m *memoryBroker) Init(opts ...Option) error { func (m *memoryBroker) Init(opts ...Option) error {
for _, o := range opts { for _, o := range opts {
o(&m.opts) o(m.opts)
} }
return nil return nil
} }
@ -190,9 +190,7 @@ func (m *memoryEvent) Message() *Message {
case []byte: case []byte:
msg := &Message{} msg := &Message{}
if err := m.opts.Codec.Unmarshal(v, msg); err != nil { if err := m.opts.Codec.Unmarshal(v, msg); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { m.opts.Logger.Logf(log.ErrorLevel, "[memory]: failed to unmarshal: %v\n", err)
logger.Errorf("[memory]: failed to unmarshal: %v\n", err)
}
return nil return nil
} }
return msg return msg
@ -223,14 +221,9 @@ func (m *memorySubscriber) Unsubscribe() error {
} }
func NewMemoryBroker(opts ...Option) Broker { func NewMemoryBroker(opts ...Option) Broker {
options := Options{ options := NewOptions(opts...)
Context: context.Background(),
}
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
for _, o := range opts {
o(&options)
}
return &memoryBroker{ return &memoryBroker{
opts: options, opts: options,

View File

@ -5,6 +5,7 @@ import (
"crypto/tls" "crypto/tls"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
) )
@ -13,6 +14,9 @@ type Options struct {
Secure bool Secure bool
Codec codec.Marshaler Codec codec.Marshaler
// Logger is the underlying logger
Logger logger.Logger
// Handler executed when error happens in broker mesage // Handler executed when error happens in broker mesage
// processing // processing
ErrorHandler Handler ErrorHandler Handler
@ -58,6 +62,19 @@ func PublishContext(ctx context.Context) PublishOption {
type SubscribeOption func(*SubscribeOptions) type SubscribeOption func(*SubscribeOptions)
func NewOptions(opts ...Option) *Options {
options := Options{
Context: context.Background(),
Logger: logger.DefaultLogger,
}
for _, o := range opts {
o(&options)
}
return &options
}
func NewSubscribeOptions(opts ...SubscribeOption) SubscribeOptions { func NewSubscribeOptions(opts ...SubscribeOption) SubscribeOptions {
opt := SubscribeOptions{ opt := SubscribeOptions{
AutoAck: true, AutoAck: true,
@ -128,6 +145,13 @@ func TLSConfig(t *tls.Config) Option {
} }
} }
// Logger sets the underline logger
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// SubscribeContext set context // SubscribeContext set context
func SubscribeContext(ctx context.Context) SubscribeOption { func SubscribeContext(ctx context.Context) SubscribeOption {
return func(o *SubscribeOptions) { return func(o *SubscribeOptions) {

1
cache/cache.go vendored
View File

@ -22,7 +22,6 @@ var (
) )
// Cache is the interface that wraps the cache. // Cache is the interface that wraps the cache.
//
type Cache interface { type Cache interface {
// Get gets a cached value by key. // Get gets a cached value by key.
Get(ctx context.Context, key string) (interface{}, time.Time, error) Get(ctx context.Context, key string) (interface{}, time.Time, error)

12
cache/options.go vendored
View File

@ -3,6 +3,8 @@ package cache
import ( import (
"context" "context"
"time" "time"
"go-micro.dev/v4/logger"
) )
// Options represents the options for the cache. // Options represents the options for the cache.
@ -13,6 +15,8 @@ type Options struct {
Address string Address string
// Context should contain all implementation specific options, using context.WithValue. // Context should contain all implementation specific options, using context.WithValue.
Context context.Context Context context.Context
// Logger is the be used logger
Logger logger.Logger
} }
// Option manipulates the Options passed. // Option manipulates the Options passed.
@ -46,11 +50,19 @@ func WithContext(c context.Context) Option {
} }
} }
// WithLogger sets underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// NewOptions returns a new options struct. // NewOptions returns a new options struct.
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Expiration: DefaultExpiration, Expiration: DefaultExpiration,
Items: make(map[string]Item), Items: make(map[string]Item),
Logger: logger.DefaultLogger,
} }
for _, o := range opts { for _, o := range opts {

View File

@ -6,6 +6,7 @@ import (
"go-micro.dev/v4/broker" "go-micro.dev/v4/broker"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/selector" "go-micro.dev/v4/selector"
"go-micro.dev/v4/transport" "go-micro.dev/v4/transport"
@ -38,6 +39,9 @@ type Options struct {
// Default Call Options // Default Call Options
CallOptions CallOptions CallOptions CallOptions
// Logger is the underline logger
Logger logger.Logger
// Other options for implementations of the interface // Other options for implementations of the interface
// can be stored in a context // can be stored in a context
Context context.Context Context context.Context
@ -113,6 +117,7 @@ func NewOptions(options ...Option) Options {
Selector: selector.DefaultSelector, Selector: selector.DefaultSelector,
Registry: registry.DefaultRegistry, Registry: registry.DefaultRegistry,
Transport: transport.DefaultTransport, Transport: transport.DefaultTransport,
Logger: logger.DefaultLogger,
} }
for _, o := range options { for _, o := range options {
@ -364,3 +369,10 @@ func WithRouter(r Router) Option {
o.Router = r o.Router = r
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -89,14 +89,15 @@ func (c *cliSource) String() string {
// command line flags have already been parsed. // command line flags have already been parsed.
// //
// Example: // Example:
// cli.StringFlag{Name: "db-host"}, //
// cli.StringFlag{Name: "db-host"},
// //
// //
// { // {
// "database": { // "database": {
// "host": "localhost" // "host": "localhost"
// } // }
// } // }
func NewSource(opts ...source.Option) source.Source { func NewSource(opts ...source.Option) source.Source {
options := source.NewOptions(opts...) options := source.NewOptions(opts...)

View File

@ -117,15 +117,16 @@ func (e *env) String() string {
// Underscores are delimiters for nesting, and all keys are lowercased. // Underscores are delimiters for nesting, and all keys are lowercased.
// //
// Example: // Example:
// "DATABASE_SERVER_HOST=localhost" will convert to
// //
// { // "DATABASE_SERVER_HOST=localhost" will convert to
// "database": { //
// "server": { // {
// "host": "localhost" // "database": {
// } // "server": {
// } // "host": "localhost"
// } // }
// }
// }
func NewSource(opts ...source.Option) source.Source { func NewSource(opts ...source.Option) source.Source {
options := source.NewOptions(opts...) options := source.NewOptions(opts...)

View File

@ -89,13 +89,14 @@ func (fs *flagsrc) String() string {
// Hyphens are delimiters for nesting, and all keys are lowercased. // Hyphens are delimiters for nesting, and all keys are lowercased.
// //
// Example: // Example:
// dbhost := flag.String("database-host", "localhost", "the db host name")
// //
// { // dbhost := flag.String("database-host", "localhost", "the db host name")
// "database": { //
// "host": "localhost" // {
// } // "database": {
// } // "host": "localhost"
// }
// }
func NewSource(opts ...source.Option) source.Source { func NewSource(opts ...source.Option) source.Source {
return &flagsrc{opts: source.NewOptions(opts...)} return &flagsrc{opts: source.NewOptions(opts...)}
} }

View File

@ -8,18 +8,17 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors" "github.com/pkg/errors"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/store" "go-micro.dev/v4/store"
) )
// NewStream returns an initialized memory stream // NewStream returns an initialized memory stream
func NewStream(opts ...Option) (Stream, error) { func NewStream(opts ...Option) (Stream, error) {
// parse the options // parse the options
var options Options options := NewOptions(opts...)
for _, o := range opts {
o(&options) return &mem{store: store.NewMemoryStore(), options: options}, nil
}
return &mem{store: store.NewMemoryStore()}, nil
} }
type subscriber struct { type subscriber struct {
@ -35,7 +34,8 @@ type subscriber struct {
} }
type mem struct { type mem struct {
store store.Store options *Options
store store.Store
subs []*subscriber subs []*subscriber
sync.RWMutex sync.RWMutex
@ -147,10 +147,8 @@ func (m *mem) Consume(topic string, opts ...ConsumeOption) (<-chan Event, error)
func (m *mem) lookupPreviousEvents(sub *subscriber, startTime time.Time) { func (m *mem) lookupPreviousEvents(sub *subscriber, startTime time.Time) {
// lookup all events which match the topic (a blank topic will return all results) // lookup all events which match the topic (a blank topic will return all results)
recs, err := m.store.Read(sub.Topic+"/", store.ReadPrefix()) recs, err := m.store.Read(sub.Topic+"/", store.ReadPrefix())
if err != nil && logger.V(logger.ErrorLevel, logger.DefaultLogger) { if err != nil {
logger.Errorf("Error looking up previous events: %v", err) m.options.Logger.Logf(log.ErrorLevel, "Error looking up previous events: %v", err)
return
} else if err != nil {
return return
} }
@ -172,7 +170,7 @@ func (m *mem) handleEvent(ev *Event) {
m.RLock() m.RLock()
subs := m.subs subs := m.subs
m.RUnlock() m.RUnlock()
logger := m.options.Logger
// filteredSubs is a KV map of the queue name and subscribers. This is used to prevent a message // filteredSubs is a KV map of the queue name and subscribers. This is used to prevent a message
// being sent to two subscribers with the same queue. // being sent to two subscribers with the same queue.
filteredSubs := map[string]*subscriber{} filteredSubs := map[string]*subscriber{}
@ -186,46 +184,46 @@ func (m *mem) handleEvent(ev *Event) {
// send the message to each channel async (since one channel might be blocked) // send the message to each channel async (since one channel might be blocked)
for _, sub := range filteredSubs { for _, sub := range filteredSubs {
sendEvent(ev, sub) go func(s *subscriber) {
if err := sendEvent(ev, s); err != nil {
logger.Log(log.ErrorLevel, err)
}
}(sub)
} }
} }
func sendEvent(ev *Event, sub *subscriber) { func sendEvent(ev *Event, s *subscriber) error {
go func(s *subscriber) { evCopy := *ev
evCopy := *ev if s.autoAck {
if s.autoAck { s.Channel <- evCopy
s.Channel <- evCopy return nil
return }
evCopy.SetAckFunc(ackFunc(s, evCopy))
evCopy.SetNackFunc(nackFunc(s, evCopy))
s.retryMap[evCopy.ID] = 0
tick := time.NewTicker(s.ackWait)
defer tick.Stop()
for range tick.C {
s.Lock()
count, ok := s.retryMap[evCopy.ID]
s.Unlock()
if !ok {
// success
break
} }
evCopy.SetAckFunc(ackFunc(s, evCopy))
evCopy.SetNackFunc(nackFunc(s, evCopy))
s.retryMap[evCopy.ID] = 0
tick := time.NewTicker(s.ackWait)
defer tick.Stop()
for range tick.C {
s.Lock()
count, ok := s.retryMap[evCopy.ID]
s.Unlock()
if !ok {
// success
break
}
if s.retryLimit > -1 && count > s.retryLimit { if s.retryLimit > -1 && count > s.retryLimit {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Errorf("Message retry limit reached, discarding: %v %d %d", evCopy.ID, count, s.retryLimit)
}
s.Lock()
delete(s.retryMap, evCopy.ID)
s.Unlock()
return
}
s.Channel <- evCopy
s.Lock() s.Lock()
s.retryMap[evCopy.ID] = count + 1 delete(s.retryMap, evCopy.ID)
s.Unlock() s.Unlock()
return fmt.Errorf("Message retry limit reached, discarding: %v %d %d", evCopy.ID, count, s.retryLimit)
} }
}(sub) s.Channel <- evCopy
s.Lock()
s.retryMap[evCopy.ID] = count + 1
s.Unlock()
}
return nil
} }
func ackFunc(s *subscriber, evCopy Event) func() error { func ackFunc(s *subscriber, evCopy Event) func() error {

View File

@ -1,18 +1,44 @@
package events package events
import "time" import (
"time"
type Options struct{} "go-micro.dev/v4/logger"
)
type Options struct {
Logger logger.Logger
}
type Option func(o *Options) type Option func(o *Options)
func NewOptions(opts ...Option) *Options {
options := Options{
Logger: logger.DefaultLogger,
}
for _, o := range opts {
o(&options)
}
return &options
}
type StoreOptions struct { type StoreOptions struct {
TTL time.Duration TTL time.Duration
Backup Backup Backup Backup
Logger logger.Logger
} }
type StoreOption func(o *StoreOptions) type StoreOption func(o *StoreOptions)
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) StoreOption {
return func(o *StoreOptions) {
o.Logger = l
}
}
// PublishOptions contains all the options which can be provided when publishing an event // PublishOptions contains all the options which can be provided when publishing an event
type PublishOptions struct { type PublishOptions struct {
// Metadata contains any keys which can be used to query the data, for example a customer id // Metadata contains any keys which can be used to query the data, for example a customer id

View File

@ -5,7 +5,8 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/store" "go-micro.dev/v4/store"
) )
@ -22,6 +23,8 @@ func NewStore(opts ...StoreOption) Store {
options.TTL = time.Hour * 24 options.TTL = time.Hour * 24
} }
options.Logger = log.LoggerOrDefault(options.Logger)
// return the store // return the store
evs := &evStore{ evs := &evStore{
opts: options, opts: options,
@ -114,7 +117,7 @@ func (s *evStore) backupLoop() {
for { for {
err := s.opts.Backup.Snapshot(s.store) err := s.opts.Backup.Snapshot(s.store)
if err != nil { if err != nil {
logger.Errorf("Error running backup %s", err) s.opts.Logger.Logf(log.ErrorLevel, "Error running backup %s", err)
} }
time.Sleep(1 * time.Hour) time.Sleep(1 * time.Hour)

View File

@ -135,7 +135,7 @@ func (l *defaultLogger) Log(level Level, v ...interface{}) {
func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) { func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
// TODO decide does we need to write message if log level not used? // TODO decide does we need to write message if log level not used?
if level < l.opts.Level { if !l.opts.Level.Enabled(level) {
return return
} }

View File

@ -129,3 +129,10 @@ func (h *Helper) WithError(err error) *Helper {
func (h *Helper) WithFields(fields map[string]interface{}) *Helper { func (h *Helper) WithFields(fields map[string]interface{}) *Helper {
return &Helper{logger: h.logger.Fields(fields)} return &Helper{logger: h.logger.Fields(fields)}
} }
func HelperOrDefault(h *Helper) *Helper {
if h == nil {
return DefaultHelper
}
return h
}

View File

@ -4,6 +4,9 @@ package logger
var ( var (
// Default logger // Default logger
DefaultLogger Logger = NewLogger() DefaultLogger Logger = NewLogger()
// Default logger helper
DefaultHelper *Helper = NewHelper(DefaultLogger)
) )
// Logger is a generic logging interface // Logger is a generic logging interface
@ -41,3 +44,10 @@ func Logf(level Level, format string, v ...interface{}) {
func String() string { func String() string {
return DefaultLogger.String() return DefaultLogger.String()
} }
func LoggerOrDefault(l Logger) Logger {
if l == nil {
return DefaultLogger
}
return l
}

View File

@ -12,6 +12,7 @@ import (
"go-micro.dev/v4/config" "go-micro.dev/v4/config"
"go-micro.dev/v4/debug/profile" "go-micro.dev/v4/debug/profile"
"go-micro.dev/v4/debug/trace" "go-micro.dev/v4/debug/trace"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/runtime" "go-micro.dev/v4/runtime"
"go-micro.dev/v4/selector" "go-micro.dev/v4/selector"
@ -35,7 +36,7 @@ type Options struct {
Runtime runtime.Runtime Runtime runtime.Runtime
Transport transport.Transport Transport transport.Transport
Profile profile.Profile Profile profile.Profile
Logger logger.Logger
// Before and After funcs // Before and After funcs
BeforeStart []func() error BeforeStart []func() error
BeforeStop []func() error BeforeStop []func() error
@ -64,6 +65,7 @@ func newOptions(opts ...Option) Options {
Transport: transport.DefaultTransport, Transport: transport.DefaultTransport,
Context: context.Background(), Context: context.Background(),
Signal: true, Signal: true,
Logger: logger.DefaultLogger,
} }
for _, o := range opts { for _, o := range opts {
@ -340,3 +342,10 @@ func AfterStop(fn func() error) Option {
o.AfterStop = append(o.AfterStop, fn) o.AfterStop = append(o.AfterStop, fn)
} }
} }
// Logger sets the logger for the service
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -7,10 +7,11 @@ import (
"sync" "sync"
"time" "time"
"go-micro.dev/v4/logger" "golang.org/x/sync/singleflight"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
util "go-micro.dev/v4/util/registry" util "go-micro.dev/v4/util/registry"
"golang.org/x/sync/singleflight"
) )
// Cache is the registry cache interface // Cache is the registry cache interface
@ -24,6 +25,8 @@ type Cache interface {
type Options struct { type Options struct {
// TTL is the cache TTL // TTL is the cache TTL
TTL time.Duration TTL time.Duration
Logger log.Logger
} }
type Option func(o *Options) type Option func(o *Options)
@ -320,7 +323,7 @@ func (c *cache) run(service string) {
c.Lock() c.Lock()
c.watchedRunning[service] = true c.watchedRunning[service] = true
c.Unlock() c.Unlock()
logger := c.opts.Logger
// reset watcher on exit // reset watcher on exit
defer func() { defer func() {
c.Lock() c.Lock()
@ -352,9 +355,7 @@ func (c *cache) run(service string) {
c.setStatus(err) c.setStatus(err)
if a > 3 { if a > 3 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "rcache: ", err, " backing off ", d)
logger.Debug("rcache: ", err, " backing off ", d)
}
a = 0 a = 0
} }
@ -377,9 +378,7 @@ func (c *cache) run(service string) {
c.setStatus(err) c.setStatus(err)
if b > 3 { if b > 3 {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "rcache: ", err, " backing off ", d)
logger.Debug("rcache: ", err, " backing off ", d)
}
b = 0 b = 0
} }
@ -467,7 +466,8 @@ func (c *cache) String() string {
func New(r registry.Registry, opts ...Option) Cache { func New(r registry.Registry, opts ...Option) Cache {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
options := Options{ options := Options{
TTL: DefaultTTL, TTL: DefaultTTL,
Logger: log.DefaultLogger,
} }
for _, o := range opts { for _, o := range opts {

View File

@ -2,6 +2,8 @@ package cache
import ( import (
"time" "time"
"go-micro.dev/v4/logger"
) )
// WithTTL sets the cache TTL // WithTTL sets the cache TTL
@ -10,3 +12,10 @@ func WithTTL(t time.Duration) Option {
o.TTL = t o.TTL = t
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -16,7 +16,8 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/util/mdns" "go-micro.dev/v4/util/mdns"
) )
@ -38,7 +39,7 @@ type mdnsEntry struct {
} }
type mdnsRegistry struct { type mdnsRegistry struct {
opts Options opts *Options
// the mdns domain // the mdns domain
domain string domain string
@ -128,14 +129,8 @@ func decode(record []string) (*mdnsTxt, error) {
return txt, nil return txt, nil
} }
func newRegistry(opts ...Option) Registry { func newRegistry(opts ...Option) Registry {
options := Options{ mergedOpts := append([]Option{Timeout(time.Millisecond * 100)}, opts...)
Context: context.Background(), options := NewOptions(mergedOpts...)
Timeout: time.Millisecond * 100,
}
for _, o := range opts {
o(&options)
}
// set the domain // set the domain
domain := mdnsDomain domain := mdnsDomain
@ -155,19 +150,20 @@ func newRegistry(opts ...Option) Registry {
func (m *mdnsRegistry) Init(opts ...Option) error { func (m *mdnsRegistry) Init(opts ...Option) error {
for _, o := range opts { for _, o := range opts {
o(&m.opts) o(m.opts)
} }
return nil return nil
} }
func (m *mdnsRegistry) Options() Options { func (m *mdnsRegistry) Options() Options {
return m.opts return *m.opts
} }
func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error { func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
logger := m.opts.Logger
entries, ok := m.services[service.Name] entries, ok := m.services[service.Name]
// first entry, create wildcard used for list queries // first entry, create wildcard used for list queries
if !ok { if !ok {
@ -234,9 +230,8 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
} }
port, _ := strconv.Atoi(pt) port, _ := strconv.Atoi(pt)
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "[mdns] registry create new service with ip: %s for: %s", net.ParseIP(host).String(), host)
logger.Debugf("[mdns] registry create new service with ip: %s for: %s", net.ParseIP(host).String(), host)
}
// we got here, new node // we got here, new node
s, err := mdns.NewMDNSService( s, err := mdns.NewMDNSService(
node.Id, node.Id,
@ -305,6 +300,7 @@ func (m *mdnsRegistry) Deregister(service *Service, opts ...DeregisterOption) er
} }
func (m *mdnsRegistry) GetService(service string, opts ...GetOption) ([]*Service, error) { func (m *mdnsRegistry) GetService(service string, opts ...GetOption) ([]*Service, error) {
logger := m.opts.Logger
serviceMap := make(map[string]*Service) serviceMap := make(map[string]*Service)
entries := make(chan *mdns.ServiceEntry, 10) entries := make(chan *mdns.ServiceEntry, 10)
done := make(chan bool) done := make(chan bool)
@ -359,9 +355,7 @@ func (m *mdnsRegistry) GetService(service string, opts ...GetOption) ([]*Service
} else if len(e.AddrV6) > 0 { } else if len(e.AddrV6) > 0 {
addr = net.JoinHostPort(e.AddrV6.String(), fmt.Sprint(e.Port)) addr = net.JoinHostPort(e.AddrV6.String(), fmt.Sprint(e.Port))
} else { } else {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "[mdns]: invalid endpoint received: %v", e)
logger.Infof("[mdns]: invalid endpoint received: %v", e)
}
continue continue
} }
s.Nodes = append(s.Nodes, &Node{ s.Nodes = append(s.Nodes, &Node{

View File

@ -1,12 +1,12 @@
package registry package registry
import ( import (
"context"
"sync" "sync"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
) )
var ( var (
@ -29,7 +29,7 @@ type record struct {
} }
type memRegistry struct { type memRegistry struct {
options Options options *Options
sync.RWMutex sync.RWMutex
records map[string]map[string]*record records map[string]map[string]*record
@ -37,13 +37,7 @@ type memRegistry struct {
} }
func NewMemoryRegistry(opts ...Option) Registry { func NewMemoryRegistry(opts ...Option) Registry {
options := Options{ options := NewOptions(opts...)
Context: context.Background(),
}
for _, o := range opts {
o(&options)
}
records := getServiceRecords(options.Context) records := getServiceRecords(options.Context)
if records == nil { if records == nil {
@ -62,6 +56,7 @@ func NewMemoryRegistry(opts ...Option) Registry {
} }
func (m *memRegistry) ttlPrune() { func (m *memRegistry) ttlPrune() {
logger := m.options.Logger
prune := time.NewTicker(ttlPruneTime) prune := time.NewTicker(ttlPruneTime)
defer prune.Stop() defer prune.Stop()
@ -73,9 +68,7 @@ func (m *memRegistry) ttlPrune() {
for version, record := range records { for version, record := range records {
for id, n := range record.Nodes { for id, n := range record.Nodes {
if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL { if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry TTL expired for node %s of service %s", n.Id, name)
logger.Debugf("Registry TTL expired for node %s of service %s", n.Id, name)
}
delete(m.records[name][version].Nodes, id) delete(m.records[name][version].Nodes, id)
} }
} }
@ -111,7 +104,7 @@ func (m *memRegistry) sendEvent(r *Result) {
func (m *memRegistry) Init(opts ...Option) error { func (m *memRegistry) Init(opts ...Option) error {
for _, o := range opts { for _, o := range opts {
o(&m.options) o(m.options)
} }
// add services // add services
@ -138,13 +131,13 @@ func (m *memRegistry) Init(opts ...Option) error {
} }
func (m *memRegistry) Options() Options { func (m *memRegistry) Options() Options {
return m.options return *m.options
} }
func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error { func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
logger := m.options.Logger
var options RegisterOptions var options RegisterOptions
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
@ -158,9 +151,7 @@ func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error {
if _, ok := m.records[s.Name][s.Version]; !ok { if _, ok := m.records[s.Name][s.Version]; !ok {
m.records[s.Name][s.Version] = r m.records[s.Name][s.Version] = r
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry added new service: %s, version: %s", s.Name, s.Version)
logger.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version)
}
go m.sendEvent(&Result{Action: "update", Service: s}) go m.sendEvent(&Result{Action: "update", Service: s})
return nil return nil
} }
@ -186,18 +177,14 @@ func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error {
} }
if addedNodes { if addedNodes {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry added new node to service: %s, version: %s", s.Name, s.Version)
logger.Debugf("Registry added new node to service: %s, version: %s", s.Name, s.Version)
}
go m.sendEvent(&Result{Action: "update", Service: s}) go m.sendEvent(&Result{Action: "update", Service: s})
return nil return nil
} }
// refresh TTL and timestamp // refresh TTL and timestamp
for _, n := range s.Nodes { for _, n := range s.Nodes {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Updated registration for service: %s, version: %s", s.Name, s.Version)
logger.Debugf("Updated registration for service: %s, version: %s", s.Name, s.Version)
}
m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL
m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now() m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now()
} }
@ -208,29 +195,23 @@ func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error {
func (m *memRegistry) Deregister(s *Service, opts ...DeregisterOption) error { func (m *memRegistry) Deregister(s *Service, opts ...DeregisterOption) error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
logger := m.options.Logger
if _, ok := m.records[s.Name]; ok { if _, ok := m.records[s.Name]; ok {
if _, ok := m.records[s.Name][s.Version]; ok { if _, ok := m.records[s.Name][s.Version]; ok {
for _, n := range s.Nodes { for _, n := range s.Nodes {
if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok { if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry removed node from service: %s, version: %s", s.Name, s.Version)
logger.Debugf("Registry removed node from service: %s, version: %s", s.Name, s.Version)
}
delete(m.records[s.Name][s.Version].Nodes, n.Id) delete(m.records[s.Name][s.Version].Nodes, n.Id)
} }
} }
if len(m.records[s.Name][s.Version].Nodes) == 0 { if len(m.records[s.Name][s.Version].Nodes) == 0 {
delete(m.records[s.Name], s.Version) delete(m.records[s.Name], s.Version)
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry removed service: %s, version: %s", s.Name, s.Version)
logger.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version)
}
} }
} }
if len(m.records[s.Name]) == 0 { if len(m.records[s.Name]) == 0 {
delete(m.records, s.Name) delete(m.records, s.Name)
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Registry removed service: %s", s.Name)
logger.Debugf("Registry removed service: %s", s.Name)
}
} }
go m.sendEvent(&Result{Action: "delete", Service: s}) go m.sendEvent(&Result{Action: "delete", Service: s})
} }

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"time" "time"
"go-micro.dev/v4/logger"
) )
type Options struct { type Options struct {
@ -11,6 +13,7 @@ type Options struct {
Timeout time.Duration Timeout time.Duration
Secure bool Secure bool
TLSConfig *tls.Config TLSConfig *tls.Config
Logger logger.Logger
// Other options for implementations of the interface // Other options for implementations of the interface
// can be stored in a context // can be stored in a context
Context context.Context Context context.Context
@ -44,6 +47,19 @@ type ListOptions struct {
Context context.Context Context context.Context
} }
func NewOptions(opts ...Option) *Options {
options := Options{
Context: context.Background(),
Logger: logger.DefaultLogger,
}
for _, o := range opts {
o(&options)
}
return &options
}
// Addrs is the registry addresses to use // Addrs is the registry addresses to use
func Addrs(addrs ...string) Option { func Addrs(addrs ...string) Option {
return func(o *Options) { return func(o *Options) {
@ -146,3 +162,10 @@ func Services(s map[string][]*Service) Option {
o.Context = context.WithValue(o.Context, servicesKey{}, s) o.Context = context.WithValue(o.Context, servicesKey{}, s)
} }
} }
// Logger sets the underline logger
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -6,7 +6,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -14,7 +13,8 @@ import (
"time" "time"
"github.com/nxadm/tail" "github.com/nxadm/tail"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/runtime/local/git" "go-micro.dev/v4/runtime/local/git"
) )
@ -24,7 +24,7 @@ const defaultNamespace = "default"
type runtime struct { type runtime struct {
sync.RWMutex sync.RWMutex
// options configure runtime // options configure runtime
options Options options *Options
// used to stop the runtime // used to stop the runtime
closed chan bool closed chan bool
// used to start new services // used to start new services
@ -39,12 +39,7 @@ type runtime struct {
// NewRuntime creates new local runtime and returns it // NewRuntime creates new local runtime and returns it
func NewRuntime(opts ...Option) Runtime { func NewRuntime(opts ...Option) Runtime {
// get default options // get default options
options := Options{} options := NewOptions(opts...)
// apply requested options
for _, o := range opts {
o(&options)
}
// make the logs directory // make the logs directory
path := filepath.Join(os.TempDir(), "micro", "logs") path := filepath.Join(os.TempDir(), "micro", "logs")
@ -181,7 +176,7 @@ func (r *runtime) Init(opts ...Option) error {
defer r.Unlock() defer r.Unlock()
for _, o := range opts { for _, o := range opts {
o(&r.options) o(r.options)
} }
return nil return nil
@ -192,6 +187,7 @@ func (r *runtime) run(events <-chan Event) {
t := time.NewTicker(time.Second * 5) t := time.NewTicker(time.Second * 5)
defer t.Stop() defer t.Stop()
logger := r.options.Logger
// process event processes an incoming event // process event processes an incoming event
processEvent := func(event Event, service *service, ns string) error { processEvent := func(event Event, service *service, ns string) error {
// get current vals // get current vals
@ -205,9 +201,7 @@ func (r *runtime) run(events <-chan Event) {
return nil return nil
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime updating service %s in %v namespace", name, ns)
logger.Debugf("Runtime updating service %s in %v namespace", name, ns)
}
// this will cause a delete followed by created // this will cause a delete followed by created
if err := r.Update(service.Service, UpdateNamespace(ns)); err != nil { if err := r.Update(service.Service, UpdateNamespace(ns)); err != nil {
@ -234,13 +228,10 @@ func (r *runtime) run(events <-chan Event) {
} }
// TODO: check service error // TODO: check service error
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime starting %s", service.Name)
logger.Debugf("Runtime starting %s", service.Name)
}
if err := service.Start(); err != nil { if err := service.Start(); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime error starting %s: %v", service.Name, err)
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
}
} }
} }
} }
@ -250,18 +241,13 @@ func (r *runtime) run(events <-chan Event) {
continue continue
} }
// TODO: check service error // TODO: check service error
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime starting service %s", service.Name)
logger.Debugf("Runtime starting service %s", service.Name)
}
if err := service.Start(); err != nil { if err := service.Start(); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime error starting service %s: %v", service.Name, err)
logger.Debugf("Runtime error starting service %s: %v", service.Name, err)
}
} }
case event := <-events: case event := <-events:
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime received notification event: %v", event)
logger.Debugf("Runtime received notification event: %v", event)
}
// NOTE: we only handle Update events for now // NOTE: we only handle Update events for now
switch event.Type { switch event.Type {
case Update: case Update:
@ -273,22 +259,18 @@ func (r *runtime) run(events <-chan Event) {
r.RLock() r.RLock()
if _, ok := r.namespaces[ns]; !ok { if _, ok := r.namespaces[ns]; !ok {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime unknown namespace: %s", ns)
logger.Debugf("Runtime unknown namespace: %s", ns)
}
r.RUnlock() r.RUnlock()
continue continue
} }
service, ok := r.namespaces[ns][fmt.Sprintf("%v:%v", event.Service.Name, event.Service.Version)] service, ok := r.namespaces[ns][fmt.Sprintf("%v:%v", event.Service.Name, event.Service.Version)]
r.RUnlock() r.RUnlock()
if !ok { if !ok {
logger.Debugf("Runtime unknown service: %s", event.Service) logger.Logf(log.DebugLevel, "Runtime unknown service: %s", event.Service)
} }
if err := processEvent(event, service, ns); err != nil { if err := processEvent(event, service, ns); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime error updating service %s: %v", event.Service, err)
logger.Debugf("Runtime error updating service %s: %v", event.Service, err)
}
} }
continue continue
} }
@ -301,17 +283,13 @@ func (r *runtime) run(events <-chan Event) {
for ns, services := range namespaces { for ns, services := range namespaces {
for _, service := range services { for _, service := range services {
if err := processEvent(event, service, ns); err != nil { if err := processEvent(event, service, ns); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime error updating service %s: %v", service.Name, err)
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
}
} }
} }
} }
} }
case <-r.closed: case <-r.closed:
if logger.V(logger.DebugLevel, logger.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime stopped")
logger.Debugf("Runtime stopped")
}
return return
} }
} }
@ -357,11 +335,11 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
} }
// create new service // create new service
service := newService(s, options) service := newService(s, options, r.options.Logger)
f, err := os.OpenFile(logFile(service.Name), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) f, err := os.OpenFile(logFile(service.Name), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
log.Fatal(err) r.options.Logger.Log(log.FatalLevel, err)
} }
if service.output != nil { if service.output != nil {
@ -400,10 +378,12 @@ func (r *runtime) Logs(s *Service, options ...LogsOption) (LogStream, error) {
for _, o := range options { for _, o := range options {
o(&lopts) o(&lopts)
} }
ret := &logStream{ ret := &logStream{
service: s.Name, service: s.Name,
stream: make(chan LogRecord), stream: make(chan LogRecord),
stop: make(chan bool), stop: make(chan bool),
logger: r.options.Logger,
} }
fpath := logFile(s.Name) fpath := logFile(s.Name)
@ -461,8 +441,9 @@ type logStream struct {
service string service string
stream chan LogRecord stream chan LogRecord
sync.Mutex sync.Mutex
stop chan bool stop chan bool
err error err error
logger log.Logger
} }
func (l *logStream) Chan() chan LogRecord { func (l *logStream) Chan() chan LogRecord {
@ -485,7 +466,7 @@ func (l *logStream) Stop() error {
close(l.stream) close(l.stream)
err := l.tail.Stop() err := l.tail.Stop()
if err != nil { if err != nil {
logger.Errorf("Error stopping tail: %v", err) l.logger.Logf(log.ErrorLevel, "Error stopping tail: %v", err)
return err return err
} }
} }
@ -565,7 +546,7 @@ func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
} }
if err := service.Stop(); err != nil && err.Error() != "no such process" { if err := service.Stop(); err != nil && err.Error() != "no such process" {
logger.Errorf("Error stopping service %s: %s", service.Name, err) r.options.Logger.Logf(log.ErrorLevel, "Error stopping service %s: %s", service.Name, err)
return err return err
} }
@ -590,9 +571,7 @@ func (r *runtime) Delete(s *Service, opts ...DeleteOption) error {
return nil return nil
} }
if logger.V(logger.DebugLevel, logger.DefaultLogger) { r.options.Logger.Logf(log.DebugLevel, "Runtime deleting service %s", s.Name)
logger.Debugf("Runtime deleting service %s", s.Name)
}
service, ok := srvs[serviceKey(s)] service, ok := srvs[serviceKey(s)]
if !ok { if !ok {
@ -635,9 +614,7 @@ func (r *runtime) Start() error {
events, err = r.options.Scheduler.Notify() events, err = r.options.Scheduler.Notify()
if err != nil { if err != nil {
// TODO: should we bail here? // TODO: should we bail here?
if logger.V(logger.DebugLevel, logger.DefaultLogger) { r.options.Logger.Logf(log.DebugLevel, "Runtime failed to start update notifier")
logger.Debugf("Runtime failed to start update notifier")
}
} }
} }
@ -667,9 +644,7 @@ func (r *runtime) Stop() error {
// stop all the services // stop all the services
for _, services := range r.namespaces { for _, services := range r.namespaces {
for _, service := range services { for _, service := range services {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { r.options.Logger.Logf(log.DebugLevel, "Runtime stopping %s", service.Name)
logger.Debugf("Runtime stopping %s", service.Name)
}
service.Stop() service.Stop()
} }
} }

View File

@ -17,7 +17,7 @@ type action int
type kubernetes struct { type kubernetes struct {
sync.RWMutex sync.RWMutex
// options configure runtime // options configure runtime
options runtime.Options options *runtime.Options
// indicates if we're running // indicates if we're running
running bool running bool
// used to stop the runtime // used to stop the runtime
@ -235,7 +235,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
func (k *kubernetes) run(events <-chan runtime.Event) { func (k *kubernetes) run(events <-chan runtime.Event) {
t := time.NewTicker(time.Second * 10) t := time.NewTicker(time.Second * 10)
defer t.Stop() defer t.Stop()
logger := k.options.Logger
for { for {
select { select {
case <-t.C: case <-t.C:
@ -243,9 +243,7 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
// - do we even need the ticker for k8s services? // - do we even need the ticker for k8s services?
case event := <-events: case event := <-events:
// NOTE: we only handle Update events for now // NOTE: we only handle Update events for now
if log.V(log.DebugLevel, log.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime received notification event: %v", event)
log.Debugf("Runtime received notification event: %v", event)
}
switch event.Type { switch event.Type {
case runtime.Update: case runtime.Update:
// only process if there's an actual service // only process if there's an actual service
@ -277,9 +275,7 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
}, client.GetLabels(labels)) }, client.GetLabels(labels))
if err != nil { if err != nil {
if log.V(log.DebugLevel, log.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime update failed to get service %s: %v", event.Service, err)
log.Debugf("Runtime update failed to get service %s: %v", event.Service, err)
}
continue continue
} }
@ -298,21 +294,15 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
// update the build time // update the build time
service.Spec.Template.Metadata.Annotations["updated"] = fmt.Sprintf("%d", event.Timestamp.Unix()) service.Spec.Template.Metadata.Annotations["updated"] = fmt.Sprintf("%d", event.Timestamp.Unix())
if log.V(log.DebugLevel, log.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime updating service: %s deployment: %s", event.Service, service.Metadata.Name)
log.Debugf("Runtime updating service: %s deployment: %s", event.Service, service.Metadata.Name)
}
if err := k.client.Update(deploymentResource(&service)); err != nil { if err := k.client.Update(deploymentResource(&service)); err != nil {
if log.V(log.DebugLevel, log.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime failed to update service %s: %v", event.Service, err)
log.Debugf("Runtime failed to update service %s: %v", event.Service, err)
}
continue continue
} }
} }
} }
case <-k.closed: case <-k.closed:
if log.V(log.DebugLevel, log.DefaultLogger) { logger.Logf(log.DebugLevel, "Runtime stopped")
log.Debugf("Runtime stopped")
}
return return
} }
} }
@ -324,7 +314,7 @@ func (k *kubernetes) Init(opts ...runtime.Option) error {
defer k.Unlock() defer k.Unlock()
for _, o := range opts { for _, o := range opts {
o(&k.options) o(k.options)
} }
return nil return nil
@ -341,7 +331,7 @@ func (k *kubernetes) Logs(s *runtime.Service, options ...runtime.LogsOption) (ru
go func() { go func() {
records, err := klo.Read() records, err := klo.Read()
if err != nil { if err != nil {
log.Errorf("Failed to get logs for service '%v' from k8s: %v", err) k.options.Logger.Logf(log.ErrorLevel, "Failed to get logs for service '%v' from k8s: %v", err)
return return
} }
// @todo: this might actually not run before podLogStream starts // @todo: this might actually not run before podLogStream starts
@ -425,7 +415,7 @@ func (k *kubernetes) Create(s *runtime.Service, opts ...runtime.CreateOption) er
options.Image = k.getImage(s, options) options.Image = k.getImage(s, options)
// create new service // create new service
service := newService(s, options) service := newService(s, options, k.options.Logger)
// start the service // start the service
return service.Start(k.client, client.CreateNamespace(options.Namespace)) return service.Start(k.client, client.CreateNamespace(options.Namespace))
@ -542,7 +532,7 @@ func (k *kubernetes) Delete(s *runtime.Service, opts ...runtime.DeleteOption) er
service := newService(s, runtime.CreateOptions{ service := newService(s, runtime.CreateOptions{
Type: k.options.Type, Type: k.options.Type,
Namespace: options.Namespace, Namespace: options.Namespace,
}) }, k.options.Logger)
return service.Stop(k.client, client.DeleteNamespace(options.Namespace)) return service.Stop(k.client, client.DeleteNamespace(options.Namespace))
} }
@ -567,9 +557,7 @@ func (k *kubernetes) Start() error {
events, err = k.options.Scheduler.Notify() events, err = k.options.Scheduler.Notify()
if err != nil { if err != nil {
// TODO: should we bail here? // TODO: should we bail here?
if log.V(log.DebugLevel, log.DefaultLogger) { k.options.Logger.Logf(log.DebugLevel, "Runtime failed to start update notifier")
log.Debugf("Runtime failed to start update notifier")
}
} }
} }
@ -611,15 +599,9 @@ func (k *kubernetes) String() string {
// NewRuntime creates new kubernetes runtime // NewRuntime creates new kubernetes runtime
func NewRuntime(opts ...runtime.Option) runtime.Runtime { func NewRuntime(opts ...runtime.Option) runtime.Runtime {
// get default options // get default options
options := runtime.Options{ // Create labels with type "micro": "service"
// Create labels with type "micro": "service" mtops := append([]runtime.Option{runtime.WithType("service")}, opts...)
Type: "service", options := runtime.NewOptions(mtops...)
}
// apply requested options
for _, o := range opts {
o(&options)
}
// kubernetes client // kubernetes client
client := client.NewClusterClient() client := client.NewClusterClient()

View File

@ -5,7 +5,7 @@ import (
"strings" "strings"
"time" "time"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/runtime" "go-micro.dev/v4/runtime"
"go-micro.dev/v4/util/kubernetes/api" "go-micro.dev/v4/util/kubernetes/api"
"go-micro.dev/v4/util/kubernetes/client" "go-micro.dev/v4/util/kubernetes/client"
@ -18,6 +18,8 @@ type service struct {
kservice *client.Service kservice *client.Service
// Kubernetes deployment // Kubernetes deployment
kdeploy *client.Deployment kdeploy *client.Deployment
// to be used logger
logger log.Logger
} }
func parseError(err error) *api.Status { func parseError(err error) *api.Status {
@ -26,7 +28,7 @@ func parseError(err error) *api.Status {
return status return status
} }
func newService(s *runtime.Service, c runtime.CreateOptions) *service { func newService(s *runtime.Service, c runtime.CreateOptions, l log.Logger) *service {
// use pre-formatted name/version // use pre-formatted name/version
name := client.Format(s.Name) name := client.Format(s.Name)
version := client.Format(s.Version) version := client.Format(s.Version)
@ -93,6 +95,7 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
Service: s, Service: s,
kservice: kservice, kservice: kservice,
kdeploy: kdeploy, kdeploy: kdeploy,
logger: log.LoggerOrDefault(l),
} }
} }
@ -116,9 +119,7 @@ func serviceResource(s *client.Service) *client.Resource {
func (s *service) Start(k client.Client, opts ...client.CreateOption) error { func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
// create deployment first; if we fail, we dont create service // create deployment first; if we fail, we dont create service
if err := k.Create(deploymentResource(s.kdeploy), opts...); err != nil { if err := k.Create(deploymentResource(s.kdeploy), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to create deployment: %v", err)
logger.Debugf("Runtime failed to create deployment: %v", err)
}
s.Status("error", err) s.Status("error", err)
v := parseError(err) v := parseError(err)
if v.Reason == "AlreadyExists" { if v.Reason == "AlreadyExists" {
@ -128,9 +129,7 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
} }
// create service now that the deployment has been created // create service now that the deployment has been created
if err := k.Create(serviceResource(s.kservice), opts...); err != nil { if err := k.Create(serviceResource(s.kservice), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to create service: %v", err)
logger.Debugf("Runtime failed to create service: %v", err)
}
s.Status("error", err) s.Status("error", err)
v := parseError(err) v := parseError(err)
if v.Reason == "AlreadyExists" { if v.Reason == "AlreadyExists" {
@ -147,17 +146,13 @@ func (s *service) Start(k client.Client, opts ...client.CreateOption) error {
func (s *service) Stop(k client.Client, opts ...client.DeleteOption) error { func (s *service) Stop(k client.Client, opts ...client.DeleteOption) error {
// first attempt to delete service // first attempt to delete service
if err := k.Delete(serviceResource(s.kservice), opts...); err != nil { if err := k.Delete(serviceResource(s.kservice), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to delete service: %v", err)
logger.Debugf("Runtime failed to delete service: %v", err)
}
s.Status("error", err) s.Status("error", err)
return err return err
} }
// delete deployment once the service has been deleted // delete deployment once the service has been deleted
if err := k.Delete(deploymentResource(s.kdeploy), opts...); err != nil { if err := k.Delete(deploymentResource(s.kdeploy), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to delete deployment: %v", err)
logger.Debugf("Runtime failed to delete deployment: %v", err)
}
s.Status("error", err) s.Status("error", err)
return err return err
} }
@ -169,16 +164,12 @@ func (s *service) Stop(k client.Client, opts ...client.DeleteOption) error {
func (s *service) Update(k client.Client, opts ...client.UpdateOption) error { func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
if err := k.Update(deploymentResource(s.kdeploy), opts...); err != nil { if err := k.Update(deploymentResource(s.kdeploy), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to update deployment: %v", err)
logger.Debugf("Runtime failed to update deployment: %v", err)
}
s.Status("error", err) s.Status("error", err)
return err return err
} }
if err := k.Update(serviceResource(s.kservice), opts...); err != nil { if err := k.Update(serviceResource(s.kservice), opts...); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.logger.Logf(log.DebugLevel, "Runtime failed to update service: %v", err)
logger.Debugf("Runtime failed to update service: %v", err)
}
return err return err
} }

View File

@ -84,7 +84,7 @@ func NewBuilder(opts ...build.Option) build.Builder {
endpoint := "unix:///var/run/docker.sock" endpoint := "unix:///var/run/docker.sock"
client, err := docker.NewClient(endpoint) client, err := docker.NewClient(endpoint)
if err != nil { if err != nil {
logger.Fatal(err) logger.Log(logger.FatalLevel, err)
} }
return &Builder{ return &Builder{
Options: options, Options: options,

View File

@ -5,6 +5,7 @@ import (
"io" "io"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
"go-micro.dev/v4/logger"
) )
type Option func(o *Options) type Option func(o *Options)
@ -21,6 +22,20 @@ type Options struct {
Image string Image string
// Client to use when making requests // Client to use when making requests
Client client.Client Client client.Client
// Logger underline logger
Logger logger.Logger
}
func NewOptions(opts ...Option) *Options {
options := &Options{
Logger: logger.DefaultLogger,
}
for _, o := range opts {
o(options)
}
return options
} }
// WithSource sets the base image / repository // WithSource sets the base image / repository
@ -58,6 +73,13 @@ func WithClient(c client.Client) Option {
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
type CreateOption func(o *CreateOptions) type CreateOption func(o *CreateOptions)
type ReadOption func(o *ReadOptions) type ReadOption func(o *ReadOptions)

View File

@ -8,7 +8,7 @@ import (
"sync" "sync"
"time" "time"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/runtime/local/build" "go-micro.dev/v4/runtime/local/build"
"go-micro.dev/v4/runtime/local/process" "go-micro.dev/v4/runtime/local/process"
proc "go-micro.dev/v4/runtime/local/process/os" proc "go-micro.dev/v4/runtime/local/process/os"
@ -36,9 +36,11 @@ type service struct {
Exec *process.Executable Exec *process.Executable
// process pid // process pid
PID *process.PID PID *process.PID
// to be used logger
Logger log.Logger
} }
func newService(s *Service, c CreateOptions) *service { func newService(s *Service, c CreateOptions, l log.Logger) *service {
var exec string var exec string
var args []string var args []string
@ -58,6 +60,7 @@ func newService(s *Service, c CreateOptions) *service {
Args: args, Args: args,
Dir: s.Source, Dir: s.Source,
}, },
Logger: log.LoggerOrDefault(l),
closed: make(chan bool), closed: make(chan bool),
output: c.Output, output: c.Output,
updated: time.Now(), updated: time.Now(),
@ -101,7 +104,6 @@ func (s *service) Start() error {
if !s.shouldStart() { if !s.shouldStart() {
return nil return nil
} }
// reset // reset
s.err = nil s.err = nil
s.closed = make(chan bool) s.closed = make(chan bool)
@ -113,9 +115,7 @@ func (s *service) Start() error {
s.Status("starting", nil) s.Status("starting", nil)
// TODO: pull source & build binary // TODO: pull source & build binary
if logger.V(logger.DebugLevel, logger.DefaultLogger) { s.Logger.Log(log.DebugLevel, "Runtime service %s forking new process", s.Service.Name)
logger.Debugf("Runtime service %s forking new process", s.Service.Name)
}
p, err := s.Process.Fork(s.Exec) p, err := s.Process.Fork(s.Exec)
if err != nil { if err != nil {
@ -207,15 +207,13 @@ func (s *service) Wait() {
if s.PID.ID != thisPID.ID { if s.PID.ID != thisPID.ID {
// trying to update when it's already been switched out, ignore // trying to update when it's already been switched out, ignore
logger.Warnf("Trying to update a process status but PID doesn't match. Old %s, New %s. Skipping update.", thisPID.ID, s.PID.ID) s.Logger.Logf(log.WarnLevel, "Trying to update a process status but PID doesn't match. Old %s, New %s. Skipping update.", thisPID.ID, s.PID.ID)
return return
} }
// save the error // save the error
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { s.Logger.Logf(log.ErrorLevel, "Service %s terminated with error %s", s.Name, err)
logger.Errorf("Service %s terminated with error %s", s.Name, err)
}
s.retries++ s.retries++
s.Status("error", err) s.Status("error", err)
s.Metadata["retries"] = strconv.Itoa(s.retries) s.Metadata["retries"] = strconv.Itoa(s.retries)

View File

@ -3,6 +3,7 @@ package selector
import ( import (
"context" "context"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
) )
@ -13,6 +14,8 @@ type Options struct {
// Other options for implementations of the interface // Other options for implementations of the interface
// can be stored in a context // can be stored in a context
Context context.Context Context context.Context
// Logger is the underline logger
Logger logger.Logger
} }
type SelectOptions struct { type SelectOptions struct {
@ -58,3 +61,10 @@ func WithStrategy(fn Strategy) SelectOption {
o.Strategy = fn o.Strategy = fn
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -9,10 +9,36 @@ import (
"go-micro.dev/v4/broker" "go-micro.dev/v4/broker"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
"go-micro.dev/v4/debug/trace" "go-micro.dev/v4/debug/trace"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/transport" "go-micro.dev/v4/transport"
) )
type RouterOptions struct {
Logger logger.Logger
}
type RouterOption func(o *RouterOptions)
func newRouterOptions(opt ...RouterOption) RouterOptions {
opts := RouterOptions{
Logger: logger.DefaultLogger,
}
for _, o := range opt {
o(&opts)
}
return opts
}
// WithRouterLogger sets the underline router logger
func WithRouterLogger(l logger.Logger) RouterOption {
return func(o *RouterOptions) {
o.Logger = l
}
}
type Options struct { type Options struct {
Codecs map[string]codec.NewCodec Codecs map[string]codec.NewCodec
Broker broker.Broker Broker broker.Broker
@ -28,6 +54,7 @@ type Options struct {
HdlrWrappers []HandlerWrapper HdlrWrappers []HandlerWrapper
SubWrappers []SubscriberWrapper SubWrappers []SubscriberWrapper
ListenOptions []transport.ListenOption ListenOptions []transport.ListenOption
Logger logger.Logger
// RegisterCheck runs a check function before registering the service // RegisterCheck runs a check function before registering the service
RegisterCheck func(context.Context) error RegisterCheck func(context.Context) error
@ -53,6 +80,7 @@ func newOptions(opt ...Option) Options {
Metadata: map[string]string{}, Metadata: map[string]string{},
RegisterInterval: DefaultRegisterInterval, RegisterInterval: DefaultRegisterInterval,
RegisterTTL: DefaultRegisterTTL, RegisterTTL: DefaultRegisterTTL,
Logger: logger.DefaultLogger,
} }
for _, o := range opt { for _, o := range opt {
@ -228,6 +256,13 @@ func WithRouter(r Router) Option {
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// Wait tells the server to wait for requests to finish before exiting // Wait tells the server to wait for requests to finish before exiting
// If `wg` is nil, server only wait for completion of rpc handler. // If `wg` is nil, server only wait for completion of rpc handler.
// For user need finer grained control, pass a concrete `wg` here, server will // For user need finer grained control, pass a concrete `wg` here, server will

View File

@ -20,11 +20,12 @@ import (
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
merrors "go-micro.dev/v4/errors" merrors "go-micro.dev/v4/errors"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
) )
var ( var (
lastStreamResponseError = errors.New("EOS") errLastStreamResponse = errors.New("EOS")
// Precompute the reflect type for error. Can't use error directly // Precompute the reflect type for error. Can't use error directly
// because Typeof takes an empty interface value. This is annoying. // because Typeof takes an empty interface value. This is annoying.
@ -60,6 +61,7 @@ type response struct {
// router represents an RPC router. // router represents an RPC router.
type router struct { type router struct {
name string name string
ops RouterOptions
mu sync.Mutex // protects the serviceMap mu sync.Mutex // protects the serviceMap
serviceMap map[string]*service serviceMap map[string]*service
@ -93,8 +95,9 @@ func (r rpcRouter) ServeRequest(ctx context.Context, req Request, rsp Response)
return r.h(ctx, req, rsp) return r.h(ctx, req, rsp)
} }
func newRpcRouter() *router { func newRpcRouter(opts ...RouterOption) *router {
return &router{ return &router{
ops: newRouterOptions(opts...),
serviceMap: make(map[string]*service), serviceMap: make(map[string]*service),
subscribers: make(map[string][]*subscriber), subscribers: make(map[string][]*subscriber),
} }
@ -118,7 +121,7 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// prepareMethod returns a methodType for the provided method or nil // prepareMethod returns a methodType for the provided method or nil
// in case if the method was unsuitable. // in case if the method was unsuitable.
func prepareMethod(method reflect.Method) *methodType { func prepareMethod(method reflect.Method, logger log.Logger) *methodType {
mtype := method.Type mtype := method.Type
mname := method.Name mname := method.Name
var replyType, argType, contextType reflect.Type var replyType, argType, contextType reflect.Type
@ -141,7 +144,7 @@ func prepareMethod(method reflect.Method) *methodType {
replyType = mtype.In(3) replyType = mtype.In(3)
contextType = mtype.In(1) contextType = mtype.In(1)
default: default:
logger.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn()) logger.Logf(log.ErrorLevel, "method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
return nil return nil
} }
@ -149,7 +152,7 @@ func prepareMethod(method reflect.Method) *methodType {
// check stream type // check stream type
streamType := reflect.TypeOf((*Stream)(nil)).Elem() streamType := reflect.TypeOf((*Stream)(nil)).Elem()
if !argType.Implements(streamType) { if !argType.Implements(streamType) {
logger.Errorf("%v argument does not implement Stream interface: %v", mname, argType) logger.Logf(log.ErrorLevel, "%v argument does not implement Stream interface: %v", mname, argType)
return nil return nil
} }
} else { } else {
@ -157,30 +160,30 @@ func prepareMethod(method reflect.Method) *methodType {
// First arg need not be a pointer. // First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) { if !isExportedOrBuiltinType(argType) {
logger.Errorf("%v argument type not exported: %v", mname, argType) logger.Logf(log.ErrorLevel, "%v argument type not exported: %v", mname, argType)
return nil return nil
} }
if replyType.Kind() != reflect.Ptr { if replyType.Kind() != reflect.Ptr {
logger.Errorf("method %v reply type not a pointer: %v", mname, replyType) logger.Logf(log.ErrorLevel, "method %v reply type not a pointer: %v", mname, replyType)
return nil return nil
} }
// Reply type must be exported. // Reply type must be exported.
if !isExportedOrBuiltinType(replyType) { if !isExportedOrBuiltinType(replyType) {
logger.Errorf("method %v reply type not exported: %v", mname, replyType) logger.Logf(log.ErrorLevel, "method %v reply type not exported: %v", mname, replyType)
return nil return nil
} }
} }
// Method needs one out. // Method needs one out.
if mtype.NumOut() != 1 { if mtype.NumOut() != 1 {
logger.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut()) logger.Logf(log.ErrorLevel, "method %v has wrong number of outs: %v", mname, mtype.NumOut())
return nil return nil
} }
// The return type of the method must be error. // The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError { if returnType := mtype.Out(0); returnType != typeOfError {
logger.Errorf("method %v returns %v not error", mname, returnType.String()) logger.Logf(log.ErrorLevel, "method %v returns %v not error", mname, returnType.String())
return nil return nil
} }
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream} return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
@ -266,7 +269,7 @@ func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex,
return nil return nil
} else { } else {
// no error, we send the special EOS error // no error, we send the special EOS error
return lastStreamResponseError return errLastStreamResponse
} }
} }
@ -446,7 +449,7 @@ func (router *router) Handle(h Handler) error {
// Install the methods // Install the methods
for m := 0; m < s.typ.NumMethod(); m++ { for m := 0; m < s.typ.NumMethod(); m++ {
method := s.typ.Method(m) method := s.typ.Method(m)
if mt := prepareMethod(method); mt != nil { if mt := prepareMethod(method, router.ops.Logger); mt != nil {
s.method[method.Name] = mt s.method[method.Name] = mt
} }
} }
@ -509,8 +512,8 @@ func (router *router) ProcessMessage(ctx context.Context, msg Message) (err erro
defer func() { defer func() {
// recover any panics // recover any panics
if r := recover(); r != nil { if r := recover(); r != nil {
logger.Errorf("panic recovered: %v", r) router.ops.Logger.Logf(log.ErrorLevel, "panic recovered: %v", r)
logger.Error(string(debug.Stack())) router.ops.Logger.Log(log.ErrorLevel, string(debug.Stack()))
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r) err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
} }
}() }()

View File

@ -15,7 +15,8 @@ import (
"go-micro.dev/v4/broker" "go-micro.dev/v4/broker"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
raw "go-micro.dev/v4/codec/bytes" raw "go-micro.dev/v4/codec/bytes"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/transport" "go-micro.dev/v4/transport"
@ -131,6 +132,7 @@ func (s *rpcServer) HandleEvent(e broker.Event) error {
// ServeConn serves a single connection // ServeConn serves a single connection
func (s *rpcServer) ServeConn(sock transport.Socket) { func (s *rpcServer) ServeConn(sock transport.Socket) {
logger := s.opts.Logger
// global error tracking // global error tracking
var gerr error var gerr error
// streams are multiplexed on Micro-Stream or Micro-Id header // streams are multiplexed on Micro-Stream or Micro-Id header
@ -161,10 +163,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics // recover any panics
if r := recover(); r != nil { if r := recover(); r != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Log(log.ErrorLevel, "panic recovered: ", r)
logger.Error("panic recovered: ", r) logger.Log(log.ErrorLevel, string(debug.Stack()))
logger.Error(string(debug.Stack()))
}
} }
}() }()
@ -227,7 +227,7 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
if !ok && stream { if !ok && stream {
// check if its a last stream EOS error // check if its a last stream EOS error
err := msg.Header["Micro-Error"] err := msg.Header["Micro-Error"]
if err == lastStreamResponseError.Error() { if err == errLastStreamResponse.Error() {
pool.Release(psock) pool.Release(psock)
continue continue
} }
@ -383,10 +383,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics for outbound process // recover any panics for outbound process
if r := recover(); r != nil { if r := recover(); r != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Log(log.ErrorLevel, "panic recovered: ", r)
logger.Error("panic recovered: ", r) logger.Log(log.ErrorLevel, string(debug.Stack()))
logger.Error(string(debug.Stack()))
}
} }
}() }()
@ -414,8 +412,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics for call handler // recover any panics for call handler
if r := recover(); r != nil { if r := recover(); r != nil {
logger.Error("panic recovered: ", r) logger.Log(log.ErrorLevel, "panic recovered: ", r)
logger.Error(string(debug.Stack())) logger.Log(log.ErrorLevel, string(debug.Stack()))
} }
}() }()
@ -430,11 +428,11 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// if the server request is an EOS error we let the socket know // if the server request is an EOS error we let the socket know
// sometimes the socket is already closed on the other side, so we can ignore that error // sometimes the socket is already closed on the other side, so we can ignore that error
alreadyClosed := serveRequestError == lastStreamResponseError && writeError == io.EOF alreadyClosed := serveRequestError == errLastStreamResponse && writeError == io.EOF
// could not write error response // could not write error response
if writeError != nil && !alreadyClosed { if writeError != nil && !alreadyClosed {
logger.Debugf("rpc: unable to write error response: %v", writeError) logger.Logf(log.DebugLevel, "rpc: unable to write error response: %v", writeError)
} }
} }
}(id, psock) }(id, psock)
@ -517,7 +515,7 @@ func (s *rpcServer) Register() error {
rsvc := s.rsvc rsvc := s.rsvc
config := s.Options() config := s.Options()
s.RUnlock() s.RUnlock()
logger := s.opts.Logger
regFunc := func(service *registry.Service) error { regFunc := func(service *registry.Service) error {
// create registry options // create registry options
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)} rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
@ -650,9 +648,7 @@ func (s *rpcServer) Register() error {
s.RUnlock() s.RUnlock()
if !registered { if !registered {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
logger.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
}
} }
// register the service // register the service
@ -702,9 +698,7 @@ func (s *rpcServer) Register() error {
if err != nil { if err != nil {
return err return err
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Subscribing to topic: %s", sub.Topic())
logger.Infof("Subscribing to topic: %s", sub.Topic())
}
s.subscribers[sb] = []broker.Subscriber{sub} s.subscribers[sb] = []broker.Subscriber{sub}
} }
if cacheService { if cacheService {
@ -718,7 +712,7 @@ func (s *rpcServer) Register() error {
func (s *rpcServer) Deregister() error { func (s *rpcServer) Deregister() error {
var err error var err error
var advt, host, port string var advt, host, port string
logger := s.opts.Logger
s.RLock() s.RLock()
config := s.Options() config := s.Options()
s.RUnlock() s.RUnlock()
@ -763,9 +757,7 @@ func (s *rpcServer) Deregister() error {
Nodes: []*registry.Node{node}, Nodes: []*registry.Node{node},
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
logger.Infof("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
}
if err := config.Registry.Deregister(service); err != nil { if err := config.Registry.Deregister(service); err != nil {
return err return err
} }
@ -788,9 +780,7 @@ func (s *rpcServer) Deregister() error {
for sb, subs := range s.subscribers { for sb, subs := range s.subscribers {
for _, sub := range subs { for _, sub := range subs {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Unsubscribing %s from topic: %s", node.Id, sub.Topic())
logger.Infof("Unsubscribing %s from topic: %s", node.Id, sub.Topic())
}
sub.Unsubscribe() sub.Unsubscribe()
} }
s.subscribers[sb] = nil s.subscribers[sb] = nil
@ -807,7 +797,7 @@ func (s *rpcServer) Start() error {
return nil return nil
} }
s.RUnlock() s.RUnlock()
logger := s.opts.Logger
config := s.Options() config := s.Options()
// start listening on the transport // start listening on the transport
@ -816,9 +806,7 @@ func (s *rpcServer) Start() error {
return err return err
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
logger.Infof("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
}
// swap address // swap address
s.Lock() s.Lock()
@ -830,27 +818,19 @@ func (s *rpcServer) Start() error {
// connect to the broker // connect to the broker
if err := config.Broker.Connect(); err != nil { if err := config.Broker.Connect(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Broker [%s] connect error: %v", bname, err)
logger.Errorf("Broker [%s] connect error: %v", bname, err)
}
return err return err
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Broker [%s] Connected to %s", bname, config.Broker.Address())
logger.Infof("Broker [%s] Connected to %s", bname, config.Broker.Address())
}
// use RegisterCheck func before register // use RegisterCheck func before register
if err = s.opts.RegisterCheck(s.opts.Context); err != nil { if err = s.opts.RegisterCheck(s.opts.Context); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register check error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
}
} else { } else {
// announce self to the world // announce self to the world
if err = s.Register(); err != nil { if err = s.Register(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
}
} }
} }
@ -871,9 +851,7 @@ func (s *rpcServer) Start() error {
// check the error and backoff // check the error and backoff
default: default:
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Accept error: %v", err)
logger.Errorf("Accept error: %v", err)
}
time.Sleep(time.Second) time.Sleep(time.Second)
continue continue
} }
@ -906,25 +884,17 @@ func (s *rpcServer) Start() error {
s.RUnlock() s.RUnlock()
rerr := s.opts.RegisterCheck(s.opts.Context) rerr := s.opts.RegisterCheck(s.opts.Context)
if rerr != nil && registered { if rerr != nil && registered {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
logger.Errorf("Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
}
// deregister self in case of error // deregister self in case of error
if err := s.Deregister(); err != nil { if err := s.Deregister(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s deregister error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
}
} }
} else if rerr != nil && !registered { } else if rerr != nil && !registered {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register check error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
}
continue continue
} }
if err := s.Register(); err != nil { if err := s.Register(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
}
} }
// wait for exit // wait for exit
case ch = <-s.exit: case ch = <-s.exit:
@ -940,9 +910,7 @@ func (s *rpcServer) Start() error {
if registered { if registered {
// deregister self // deregister self
if err := s.Deregister(); err != nil { if err := s.Deregister(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s deregister error: %s", config.Name, config.Id, err)
logger.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
}
} }
} }
@ -958,14 +926,10 @@ func (s *rpcServer) Start() error {
// close transport listener // close transport listener
ch <- ts.Close() ch <- ts.Close()
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Broker [%s] Disconnected from %s", bname, config.Broker.Address())
logger.Infof("Broker [%s] Disconnected from %s", bname, config.Broker.Address())
}
// disconnect the broker // disconnect the broker
if err := config.Broker.Disconnect(); err != nil { if err := config.Broker.Disconnect(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Broker [%s] Disconnect error: %v", bname, err)
logger.Errorf("Broker [%s] Disconnect error: %v", bname, err)
}
} }
// swap back address // swap back address

View File

@ -65,7 +65,7 @@ func (r *rpcStream) Recv(msg interface{}) error {
if len(req.Error) > 0 { if len(req.Error) > 0 {
// Check the client closed the stream // Check the client closed the stream
switch req.Error { switch req.Error {
case lastStreamResponseError.Error(): case errLastStreamResponse.Error():
// discard body // discard body
r.Unlock() r.Unlock()
r.codec.ReadBody(nil) r.codec.ReadBody(nil)

View File

@ -8,8 +8,9 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
signalutil "go-micro.dev/v4/util/signal" signalutil "go-micro.dev/v4/util/signal"
) )
@ -111,12 +112,11 @@ type Stream interface {
// //
// Example: // Example:
// //
// type Greeter struct {} // type Greeter struct {}
//
// func (g *Greeter) Hello(context, request, response) error {
// return nil
// }
// //
// func (g *Greeter) Hello(context, request, response) error {
// return nil
// }
type Handler interface { type Handler interface {
Name() string Name() string
Handler() interface{} Handler() interface{}
@ -184,7 +184,6 @@ func NewSubscriber(topic string, h interface{}, opts ...SubscriberOption) Subscr
// func (f *Foo) Bar(ctx, req, rsp) error { // func (f *Foo) Bar(ctx, req, rsp) error {
// return nil // return nil
// } // }
//
func NewHandler(h interface{}, opts ...HandlerOption) Handler { func NewHandler(h interface{}, opts ...HandlerOption) Handler {
return DefaultServer.NewHandler(h, opts...) return DefaultServer.NewHandler(h, opts...)
} }
@ -210,27 +209,21 @@ func Run() error {
ch := make(chan os.Signal, 1) ch := make(chan os.Signal, 1)
signal.Notify(ch, signalutil.Shutdown()...) signal.Notify(ch, signalutil.Shutdown()...)
DefaultServer.Options().Logger.Logf(log.InfoLevel, "Received signal %s", <-ch)
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
logger.Infof("Received signal %s", <-ch)
}
return Stop() return Stop()
} }
// Start starts the default server // Start starts the default server
func Start() error { func Start() error {
config := DefaultServer.Options() config := DefaultServer.Options()
if logger.V(logger.InfoLevel, logger.DefaultLogger) { config.Logger.Logf(log.InfoLevel, "Starting server %s id %s", config.Name, config.Id)
logger.Infof("Starting server %s id %s", config.Name, config.Id)
}
return DefaultServer.Start() return DefaultServer.Start()
} }
// Stop stops the default server // Stop stops the default server
func Stop() error { func Stop() error {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { DefaultServer.Options().Logger.Logf(log.InfoLevel, "Stopping server")
logger.Infof("Stopping server")
}
return DefaultServer.Stop() return DefaultServer.Stop()
} }

View File

@ -7,7 +7,7 @@ import (
"sync" "sync"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/server" "go-micro.dev/v4/server"
"go-micro.dev/v4/store" "go-micro.dev/v4/store"
"go-micro.dev/v4/util/cmd" "go-micro.dev/v4/util/cmd"
@ -58,14 +58,14 @@ func (s *service) Init(opts ...Option) {
cmd.Store(&s.opts.Store), cmd.Store(&s.opts.Store),
cmd.Profile(&s.opts.Profile), cmd.Profile(&s.opts.Profile),
); err != nil { ); err != nil {
logger.Fatal(err) s.opts.Logger.Log(log.FatalLevel, err)
} }
// Explicitly set the table name to the service name // Explicitly set the table name to the service name
name := s.opts.Cmd.App().Name name := s.opts.Cmd.App().Name
err := s.opts.Store.Init(store.Table(name)) err := s.opts.Store.Init(store.Table(name))
if err != nil { if err != nil {
logger.Fatal(err) s.opts.Logger.Log(log.FatalLevel, err)
} }
}) })
} }
@ -125,6 +125,8 @@ func (s *service) Stop() error {
} }
func (s *service) Run() (err error) { func (s *service) Run() (err error) {
logger := s.opts.Logger
// exit when help flag is provided // exit when help flag is provided
for _, v := range os.Args[1:] { for _, v := range os.Args[1:] {
if v == "-h" || v == "--help" { if v == "-h" || v == "--help" {
@ -145,14 +147,12 @@ func (s *service) Run() (err error) {
defer func() { defer func() {
err = s.opts.Profile.Stop() err = s.opts.Profile.Stop()
if err != nil { if err != nil {
logger.Error(err) logger.Log(log.ErrorLevel, err)
} }
}() }()
} }
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Starting [service] %s", s.Name())
logger.Infof("Starting [service] %s", s.Name())
}
if err = s.Start(); err != nil { if err = s.Start(); err != nil {
return err return err

View File

@ -5,6 +5,7 @@ import (
"time" "time"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
"go-micro.dev/v4/logger"
) )
// Options contains configuration for the Store // Options contains configuration for the Store
@ -21,6 +22,8 @@ type Options struct {
Context context.Context Context context.Context
// Client to use for RPC // Client to use for RPC
Client client.Client Client client.Client
// Logger is the underline logger
Logger logger.Logger
} }
// Option sets values in Options // Option sets values in Options
@ -63,6 +66,13 @@ func WithClient(c client.Client) Option {
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// ReadOptions configures an individual Read operation // ReadOptions configures an individual Read operation
type ReadOptions struct { type ReadOptions struct {
Database, Table string Database, Table string

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"time" "time"
"go-micro.dev/v4/logger"
) )
// Nodes sets the addresses to use // Nodes sets the addresses to use
@ -47,3 +49,10 @@ func WithContext(c context.Context) Option {
o.Context = c o.Context = c
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -6,6 +6,8 @@ import (
"crypto/tls" "crypto/tls"
"errors" "errors"
"time" "time"
"go-micro.dev/v4/logger"
) )
var ( var (
@ -41,6 +43,7 @@ type Options struct {
Prefix string Prefix string
TLSConfig *tls.Config TLSConfig *tls.Config
Context context.Context Context context.Context
Logger logger.Logger
} }
type Option func(o *Options) type Option func(o *Options)

View File

@ -7,6 +7,7 @@ import (
"time" "time"
"go-micro.dev/v4/codec" "go-micro.dev/v4/codec"
"go-micro.dev/v4/logger"
) )
type Options struct { type Options struct {
@ -27,6 +28,8 @@ type Options struct {
// Other options for implementations of the interface // Other options for implementations of the interface
// can be stored in a context // can be stored in a context
Context context.Context Context context.Context
// Logger is the underline logger
Logger logger.Logger
} }
type DialOptions struct { type DialOptions struct {
@ -104,6 +107,13 @@ func WithTimeout(d time.Duration) DialOption {
} }
} }
// WithLogger sets the underline logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// NetListener Set net.Listener for httpTransport // NetListener Set net.Listener for httpTransport
func NetListener(customListener net.Listener) ListenOption { func NetListener(customListener net.Listener) ListenOption {
return func(o *ListenOptions) { return func(o *ListenOptions) {

View File

@ -3,13 +3,12 @@ package file
import ( import (
"bufio" "bufio"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"go-micro.dev/v4/client" "go-micro.dev/v4/client"
"go-micro.dev/v4/logger"
proto "go-micro.dev/v4/util/file/proto" proto "go-micro.dev/v4/util/file/proto"
) )
@ -145,7 +144,7 @@ func (c *fc) DownloadAt(filename, saveFile string, blockId int) error {
return err return err
} }
if stat.Type == "Directory" { if stat.Type == "Directory" {
return errors.New(fmt.Sprintf("%s is directory.", filename)) return fmt.Errorf("%s is directory", filename)
} }
blocks := int(stat.Size / blockSize) blocks := int(stat.Size / blockSize)
@ -153,7 +152,7 @@ func (c *fc) DownloadAt(filename, saveFile string, blockId int) error {
blocks += 1 blocks += 1
} }
log.Printf("Download %s in %d blocks\n", filename, blocks-blockId) logger.Logf(logger.InfoLevel, "Download %s in %d blocks\n", filename, blocks-blockId)
file, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666) file, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil { if err != nil {
@ -176,14 +175,14 @@ func (c *fc) DownloadAt(filename, saveFile string, blockId int) error {
} }
if i%((blocks-blockId)/100+1) == 0 { if i%((blocks-blockId)/100+1) == 0 {
log.Printf("Downloading %s [%d/%d] blocks", filename, i-blockId+1, blocks-blockId) logger.Logf(logger.InfoLevel, "Downloading %s [%d/%d] blocks", filename, i-blockId+1, blocks-blockId)
} }
if rerr == io.EOF { if rerr == io.EOF {
break break
} }
} }
log.Printf("Download %s completed", filename) logger.Logf(logger.InfoLevel, "Download %s completed", filename)
c.Close(sessionId) c.Close(sessionId)

View File

@ -6,11 +6,12 @@ import (
"path/filepath" "path/filepath"
"sync" "sync"
"golang.org/x/net/context"
"go-micro.dev/v4/errors" "go-micro.dev/v4/errors"
"go-micro.dev/v4/logger" log "go-micro.dev/v4/logger"
"go-micro.dev/v4/server" "go-micro.dev/v4/server"
proto "go-micro.dev/v4/util/file/proto" proto "go-micro.dev/v4/util/file/proto"
"golang.org/x/net/context"
) )
// NewHandler is a handler that can be registered with a micro Server // NewHandler is a handler that can be registered with a micro Server
@ -20,6 +21,7 @@ func NewHandler(readDir string) proto.FileHandler {
session: &session{ session: &session{
files: make(map[int64]*os.File), files: make(map[int64]*os.File),
}, },
logger: log.DefaultLogger,
} }
} }
@ -31,6 +33,7 @@ func RegisterHandler(s server.Server, readDir string) {
type handler struct { type handler struct {
readDir string readDir string
session *session session *session
logger log.Logger
} }
func (h *handler) Open(ctx context.Context, req *proto.OpenRequest, rsp *proto.OpenResponse) error { func (h *handler) Open(ctx context.Context, req *proto.OpenRequest, rsp *proto.OpenResponse) error {
@ -47,14 +50,14 @@ func (h *handler) Open(ctx context.Context, req *proto.OpenRequest, rsp *proto.O
rsp.Id = h.session.Add(file) rsp.Id = h.session.Add(file)
rsp.Result = true rsp.Result = true
logger.Debugf("Open %s, sessionId=%d", req.Filename, rsp.Id) h.logger.Logf(log.DebugLevel, "Open %s, sessionId=%d", req.Filename, rsp.Id)
return nil return nil
} }
func (h *handler) Close(ctx context.Context, req *proto.CloseRequest, rsp *proto.CloseResponse) error { func (h *handler) Close(ctx context.Context, req *proto.CloseRequest, rsp *proto.CloseResponse) error {
h.session.Delete(req.Id) h.session.Delete(req.Id)
logger.Debugf("Close sessionId=%d", req.Id) h.logger.Logf(log.DebugLevel, "Close sessionId=%d", req.Id)
return nil return nil
} }
@ -73,7 +76,7 @@ func (h *handler) Stat(ctx context.Context, req *proto.StatRequest, rsp *proto.S
} }
rsp.LastModified = fi.ModTime().Unix() rsp.LastModified = fi.ModTime().Unix()
logger.Debugf("Stat %s, %#v", req.Filename, rsp) h.logger.Logf(log.DebugLevel, "Stat %s, %#v", req.Filename, rsp)
return nil return nil
} }
@ -97,7 +100,7 @@ func (h *handler) Read(ctx context.Context, req *proto.ReadRequest, rsp *proto.R
rsp.Size = int64(n) rsp.Size = int64(n)
rsp.Data = rsp.Data[:n] rsp.Data = rsp.Data[:n]
logger.Debugf("Read sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset, rsp.Size) h.logger.Logf(log.DebugLevel, "Read sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset, rsp.Size)
return nil return nil
} }
@ -112,7 +115,7 @@ func (h *handler) Write(ctx context.Context, req *proto.WriteRequest, rsp *proto
return err return err
} }
logger.Debugf("Write sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset) h.logger.Logf(log.DebugLevel, "Write sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset)
return nil return nil
} }

View File

@ -4,10 +4,10 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"strings" "strings"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
"go-micro.dev/v4/selector" "go-micro.dev/v4/selector"
@ -39,7 +39,7 @@ func WriteInternalServerError(w http.ResponseWriter, err error) {
"error": err.Error(), "error": err.Error(),
}) })
if err != nil { if err != nil {
log.Println(err) logger.Log(logger.ErrorLevel, err)
return return
} }
Write(w, "application/json", 500, string(rawBody)) Write(w, "application/json", 500, string(rawBody))

View File

@ -20,7 +20,7 @@ var (
// path to kubernetes service account token // path to kubernetes service account token
serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount" serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
// ErrReadNamespace is returned when the names could not be read from service account // ErrReadNamespace is returned when the names could not be read from service account
ErrReadNamespace = errors.New("Could not read namespace from service account secret") ErrReadNamespace = errors.New("could not read namespace from service account secret")
// DefaultImage is default micro image // DefaultImage is default micro image
DefaultImage = "micro/go-micro" DefaultImage = "micro/go-micro"
// DefaultNamespace is the default k8s namespace // DefaultNamespace is the default k8s namespace
@ -228,7 +228,7 @@ func (c *client) Watch(r *Resource, opts ...WatchOption) (Watcher, error) {
// NewService returns default micro kubernetes service definition // NewService returns default micro kubernetes service definition
func NewService(name, version, typ, namespace string) *Service { func NewService(name, version, typ, namespace string) *Service {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { if logger.V(logger.TraceLevel, logger.DefaultLogger) {
logger.Tracef("kubernetes default service: name: %s, version: %s", name, version) logger.Logf(logger.TraceLevel, "kubernetes default service: name: %s, version: %s", name, version)
} }
Labels := map[string]string{ Labels := map[string]string{
@ -271,7 +271,7 @@ func NewService(name, version, typ, namespace string) *Service {
// NewService returns default micro kubernetes deployment definition // NewService returns default micro kubernetes deployment definition
func NewDeployment(name, version, typ, namespace string) *Deployment { func NewDeployment(name, version, typ, namespace string) *Deployment {
if logger.V(logger.TraceLevel, logger.DefaultLogger) { if logger.V(logger.TraceLevel, logger.DefaultLogger) {
logger.Tracef("kubernetes default deployment: name: %s, version: %s", name, version) logger.Logf(logger.TraceLevel, "kubernetes default deployment: name: %s, version: %s", name, version)
} }
Labels := map[string]string{ Labels := map[string]string{

View File

@ -3,7 +3,6 @@ package mdns
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"net" "net"
"strings" "strings"
"sync" "sync"
@ -12,6 +11,8 @@ import (
"github.com/miekg/dns" "github.com/miekg/dns"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
"go-micro.dev/v4/logger"
) )
// ServiceEntry is returned after we query for a service // ServiceEntry is returned after we query for a service
@ -146,7 +147,7 @@ func Listen(entries chan<- *ServiceEntry, exit chan struct{}) error {
m.SetQuestion(e.Name, dns.TypePTR) m.SetQuestion(e.Name, dns.TypePTR)
m.RecursionDesired = false m.RecursionDesired = false
if err := client.sendQuery(m); err != nil { if err := client.sendQuery(m); err != nil {
log.Printf("[ERR] mdns: Failed to query instance %s: %v", e.Name, err) logger.Logf(logger.ErrorLevel, "[mdns] failed to query instance %s: %v", e.Name, err)
} }
} }
} }
@ -184,7 +185,7 @@ func newClient() (*client, error) {
uconn4, err4 := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) uconn4, err4 := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
uconn6, err6 := net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0}) uconn6, err6 := net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
if err4 != nil && err6 != nil { if err4 != nil && err6 != nil {
log.Printf("[ERR] mdns: Failed to bind to udp port: %v %v", err4, err6) logger.Logf(logger.ErrorLevel, "[mdns] failed to bind to udp port: %v %v", err4, err6)
} }
if uconn4 == nil && uconn6 == nil { if uconn4 == nil && uconn6 == nil {
@ -202,7 +203,7 @@ func newClient() (*client, error) {
mconn4, err4 := net.ListenUDP("udp4", mdnsWildcardAddrIPv4) mconn4, err4 := net.ListenUDP("udp4", mdnsWildcardAddrIPv4)
mconn6, err6 := net.ListenUDP("udp6", mdnsWildcardAddrIPv6) mconn6, err6 := net.ListenUDP("udp6", mdnsWildcardAddrIPv6)
if err4 != nil && err6 != nil { if err4 != nil && err6 != nil {
log.Printf("[ERR] mdns: Failed to bind to udp port: %v %v", err4, err6) logger.Logf(logger.ErrorLevel, "[mdns] failed to bind to udp port: %v %v", err4, err6)
} }
if mconn4 == nil && mconn6 == nil { if mconn4 == nil && mconn6 == nil {
@ -239,7 +240,7 @@ func newClient() (*client, error) {
} }
if len(ifaces) == errCount1 && len(ifaces) == errCount2 { if len(ifaces) == errCount1 && len(ifaces) == errCount2 {
return nil, fmt.Errorf("Failed to join multicast group on all interfaces!") return nil, fmt.Errorf("failed to join multicast group on all interfaces")
} }
c := &client{ c := &client{
@ -375,7 +376,7 @@ func (c *client) query(params *QueryParam) error {
m.SetQuestion(inp.Name, inp.Type) m.SetQuestion(inp.Name, inp.Type)
m.RecursionDesired = false m.RecursionDesired = false
if err := c.sendQuery(m); err != nil { if err := c.sendQuery(m); err != nil {
log.Printf("[ERR] mdns: Failed to query instance %s: %v", inp.Name, err) logger.Logf(logger.ErrorLevel, "[mdns] failed to query instance %s: %v", inp.Name, err)
} }
} }
case <-params.Context.Done(): case <-params.Context.Done():

View File

@ -10,18 +10,19 @@ import "github.com/miekg/dns"
// register only the wrapped instance with the server. // register only the wrapped instance with the server.
// //
// Example usage: // Example usage:
// service := &mdns.DNSSDService{ //
// MDNSService: &mdns.MDNSService{ // service := &mdns.DNSSDService{
// Instance: "My Foobar Service", // MDNSService: &mdns.MDNSService{
// Service: "_foobar._tcp", // Instance: "My Foobar Service",
// Port: 8000, // Service: "_foobar._tcp",
// } // Port: 8000,
// } // }
// server, err := mdns.NewServer(&mdns.Config{Zone: service}) // }
// if err != nil { // server, err := mdns.NewServer(&mdns.Config{Zone: service})
// log.Fatalf("Error creating server: %v", err) // if err != nil {
// } // log.Fatalf("Error creating server: %v", err)
// defer server.Shutdown() // }
// defer server.Shutdown()
type DNSSDService struct { type DNSSDService struct {
MDNSService *MDNSService MDNSService *MDNSService
} }

View File

@ -45,10 +45,13 @@ func Unmarshal(dst interface{}, query string) error {
} }
// ToJSON will turn a query string like: // ToJSON will turn a query string like:
// cat=1&bar%5Bone%5D%5Btwo%5D=2&bar[one][red]=112 //
// cat=1&bar%5Bone%5D%5Btwo%5D=2&bar[one][red]=112
//
// Into a JSON object with all the data merged as nicely as // Into a JSON object with all the data merged as nicely as
// possible. Eg the example above would output: // possible. Eg the example above would output:
// {"bar":{"one":{"two":2,"red":112}}} //
// {"bar":{"one":{"two":2,"red":112}}}
func ToJSON(query string) ([]byte, error) { func ToJSON(query string) ([]byte, error) {
var ( var (
builder interface{} = make(map[string]interface{}) builder interface{} = make(map[string]interface{})
@ -65,13 +68,14 @@ func ToJSON(query string) ([]byte, error) {
} }
// queryToMap turns something like a[b][c]=4 into // queryToMap turns something like a[b][c]=4 into
// map[string]interface{}{ //
// "a": map[string]interface{}{ // map[string]interface{}{
// "b": map[string]interface{}{ // "a": map[string]interface{}{
// "c": 4, // "b": map[string]interface{}{
// }, // "c": 4,
// }, // },
// } // },
// }
func queryToMap(param string) (map[string]interface{}, error) { func queryToMap(param string) (map[string]interface{}, error) {
rawKey, rawValue, err := splitKeyAndValue(param) rawKey, rawValue, err := splitKeyAndValue(param)
if err != nil { if err != nil {

View File

@ -8,10 +8,11 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go-micro.dev/v4" "go-micro.dev/v4"
"go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
) )
//Options for web // Options for web
type Options struct { type Options struct {
Name string Name string
Version string Version string
@ -37,6 +38,7 @@ type Options struct {
Registry registry.Registry Registry registry.Registry
Service micro.Service Service micro.Service
Logger logger.Logger
Secure bool Secure bool
TLSConfig *tls.Config TLSConfig *tls.Config
@ -63,6 +65,7 @@ func newOptions(opts ...Option) Options {
Service: micro.NewService(), Service: micro.NewService(),
Context: context.TODO(), Context: context.TODO(),
Signal: true, Signal: true,
Logger: logger.DefaultLogger,
} }
for _, o := range opts { for _, o := range opts {
@ -93,7 +96,7 @@ func Icon(ico string) Option {
} }
} }
//Id for Unique server id // Id for Unique server id
func Id(id string) Option { func Id(id string) Option {
return func(o *Options) { return func(o *Options) {
o.Id = id o.Id = id
@ -121,7 +124,7 @@ func Address(a string) Option {
} }
} }
//Advertise The address to advertise for discovery - host:port // Advertise The address to advertise for discovery - host:port
func Advertise(a string) Option { func Advertise(a string) Option {
return func(o *Options) { return func(o *Options) {
o.Advertise = a o.Advertise = a
@ -144,28 +147,28 @@ func Registry(r registry.Registry) Option {
} }
} }
//RegisterTTL Register the service with a TTL // RegisterTTL Register the service with a TTL
func RegisterTTL(t time.Duration) Option { func RegisterTTL(t time.Duration) Option {
return func(o *Options) { return func(o *Options) {
o.RegisterTTL = t o.RegisterTTL = t
} }
} }
//RegisterInterval Register the service with at interval // RegisterInterval Register the service with at interval
func RegisterInterval(t time.Duration) Option { func RegisterInterval(t time.Duration) Option {
return func(o *Options) { return func(o *Options) {
o.RegisterInterval = t o.RegisterInterval = t
} }
} }
//Handler for custom handler // Handler for custom handler
func Handler(h http.Handler) Option { func Handler(h http.Handler) Option {
return func(o *Options) { return func(o *Options) {
o.Handler = h o.Handler = h
} }
} }
//Server for custom Server // Server for custom Server
func Server(srv *http.Server) Option { func Server(srv *http.Server) Option {
return func(o *Options) { return func(o *Options) {
o.Server = srv o.Server = srv
@ -257,3 +260,10 @@ func HandleSignal(b bool) Option {
o.Signal = b o.Signal = b
} }
} }
// Logger sets the underline logger
func Logger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}

View File

@ -13,8 +13,10 @@ import (
"time" "time"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go-micro.dev/v4" "go-micro.dev/v4"
"go-micro.dev/v4/logger"
log "go-micro.dev/v4/logger"
"go-micro.dev/v4/registry" "go-micro.dev/v4/registry"
maddr "go-micro.dev/v4/util/addr" maddr "go-micro.dev/v4/util/addr"
"go-micro.dev/v4/util/backoff" "go-micro.dev/v4/util/backoff"
@ -54,11 +56,13 @@ func (s *service) genSrv() *registry.Service {
var port string var port string
var err error var err error
logger := s.opts.Logger
// default host:port // default host:port
if len(s.opts.Address) > 0 { if len(s.opts.Address) > 0 {
host, port, err = net.SplitHostPort(s.opts.Address) host, port, err = net.SplitHostPort(s.opts.Address)
if err != nil { if err != nil {
logger.Fatal(err) logger.Log(log.FatalLevel, err)
} }
} }
@ -68,13 +72,13 @@ func (s *service) genSrv() *registry.Service {
if len(s.opts.Advertise) > 0 { if len(s.opts.Advertise) > 0 {
host, port, err = net.SplitHostPort(s.opts.Advertise) host, port, err = net.SplitHostPort(s.opts.Advertise)
if err != nil { if err != nil {
logger.Fatal(err) logger.Log(log.FatalLevel, err)
} }
} }
addr, err := maddr.Extract(host) addr, err := maddr.Extract(host)
if err != nil { if err != nil {
logger.Fatal(err) logger.Log(log.FatalLevel, err)
} }
if strings.Count(addr, ":") > 0 { if strings.Count(addr, ":") > 0 {
@ -120,6 +124,9 @@ func (s *service) register() error {
if s.srv == nil { if s.srv == nil {
return nil return nil
} }
logger := s.opts.Logger
// default to service registry // default to service registry
r := s.opts.Service.Client().Options().Registry r := s.opts.Service.Client().Options().Registry
// switch to option if specified // switch to option if specified
@ -134,9 +141,7 @@ func (s *service) register() error {
// use RegisterCheck func before register // use RegisterCheck func before register
if err := s.opts.RegisterCheck(s.opts.Context); err != nil { if err := s.opts.RegisterCheck(s.opts.Context); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) { logger.Logf(log.ErrorLevel, "Server %s-%s register check error: %s", s.opts.Name, s.opts.Id, err)
logger.Errorf("Server %s-%s register check error: %s", s.opts.Name, s.opts.Id, err)
}
return err return err
} }
@ -195,6 +200,8 @@ func (s *service) start() error {
return err return err
} }
logger := s.opts.Logger
s.opts.Address = l.Addr().String() s.opts.Address = l.Addr().String()
srv := s.genSrv() srv := s.genSrv()
srv.Endpoints = s.srv.Endpoints srv.Endpoints = s.srv.Endpoints
@ -221,9 +228,7 @@ func (s *service) start() error {
if s.static { if s.static {
_, err := os.Stat(static) _, err := os.Stat(static)
if err == nil { if err == nil {
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Enabling static file serving from %s", static)
logger.Infof("Enabling static file serving from %s", static)
}
s.mux.Handle("/", http.FileServer(http.Dir(static))) s.mux.Handle("/", http.FileServer(http.Dir(static)))
} }
} }
@ -255,9 +260,7 @@ func (s *service) start() error {
ch <- l.Close() ch <- l.Close()
}() }()
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Listening on %v", l.Addr().String())
logger.Infof("Listening on %v", l.Addr().String())
}
return nil return nil
} }
@ -279,9 +282,7 @@ func (s *service) stop() error {
s.exit <- ch s.exit <- ch
s.running = false s.running = false
if logger.V(logger.InfoLevel, logger.DefaultLogger) { s.opts.Logger.Log(log.InfoLevel, "Stopping")
logger.Info("Stopping")
}
for _, fn := range s.opts.AfterStop { for _, fn := range s.opts.AfterStop {
if err := fn(); err != nil { if err := fn(); err != nil {
@ -473,6 +474,7 @@ func (s *service) Run() error {
return err return err
} }
logger := s.opts.Logger
// start the profiler // start the profiler
if s.opts.Service.Options().Profile != nil { if s.opts.Service.Options().Profile != nil {
// to view mutex contention // to view mutex contention
@ -485,7 +487,7 @@ func (s *service) Run() error {
} }
defer func() { defer func() {
if err := s.opts.Service.Options().Profile.Stop(); err != nil { if err := s.opts.Service.Options().Profile.Stop(); err != nil {
logger.Error(err) logger.Log(log.ErrorLevel, err)
} }
}() }()
} }
@ -505,14 +507,10 @@ func (s *service) Run() error {
select { select {
// wait on kill signal // wait on kill signal
case sig := <-ch: case sig := <-ch:
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Logf(log.InfoLevel, "Received signal %s", sig)
logger.Infof("Received signal %s", sig)
}
// wait on context cancel // wait on context cancel
case <-s.opts.Context.Done(): case <-s.opts.Context.Done():
if logger.V(logger.InfoLevel, logger.DefaultLogger) { logger.Log(log.InfoLevel, "Received context shutdown")
logger.Info("Received context shutdown")
}
} }
// exit reg loop // exit reg loop

View File

@ -21,10 +21,10 @@ type Service interface {
Run() error Run() error
} }
//Option for web // Option for web
type Option func(o *Options) type Option func(o *Options)
//Web basic Defaults // Web basic Defaults
var ( var (
// For serving // For serving
DefaultName = "go-web" DefaultName = "go-web"

View File

@ -57,14 +57,14 @@ func testFunc() {
defer wg.Done() defer wg.Done()
err := s.Run() err := s.Run()
if err != nil { if err != nil {
logger.Errorf("micro run error: %v", err) logger.Logf(logger.ErrorLevel, "micro run error: %v", err)
} }
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
err := w.Run() err := w.Run()
if err != nil { if err != nil {
logger.Errorf("web run error: %v", err) logger.Logf(logger.ErrorLevel, "web run error: %v", err)
} }
}() }()