diff --git a/client/cmd/root.go b/client/cmd/root.go index baf444b99..2cdf5a77a 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -21,6 +21,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + grpcLogger "github.com/netbirdio/netbird/client/grpc/logger" + "github.com/netbirdio/netbird/client/internal" ) @@ -241,6 +243,7 @@ func DialClientGRPCServer(ctx context.Context, addr string) (*grpc.ClientConn, e strings.TrimPrefix(addr, "tcp://"), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock(), + grpc.WithUnaryInterceptor(grpcLogger.UnaryClientInterceptor()), ) } diff --git a/client/grpc/logger/logger.go b/client/grpc/logger/logger.go new file mode 100644 index 000000000..6420c0290 --- /dev/null +++ b/client/grpc/logger/logger.go @@ -0,0 +1,57 @@ +package logger + +import ( + "context" + "time" + + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +// UnaryClientInterceptor logs gRPC requests using the global logrus logger +func UnaryClientInterceptor() grpc.UnaryClientInterceptor { + return func( + ctx context.Context, + method string, + req, reply interface{}, + cc *grpc.ClientConn, + invoker grpc.UnaryInvoker, + opts ...grpc.CallOption, + ) error { + start := time.Now() + + // og the request + if msg, ok := req.(proto.Message); ok { + if jsonReq, err := protojson.Marshal(msg); err == nil { + logrus.Debugf("gRPC request initiated: method=%s, request=%s", method, jsonReq) + } else { + logrus.Warnf("Could not marshal gRPC request: method=%s, error=%v", method, err) + } + } else { + logrus.Debugf("gRPC request initiated: method=%s, requestType=%T", method, req) + } + + err := invoker(ctx, method, req, reply, cc, opts...) + + duration := time.Since(start) + + // log the response + if err != nil { + logrus.Errorf("gRPC request failed: method=%s, duration=%v, error=%v", method, duration, err) + } else { + if msg, ok := reply.(proto.Message); ok { + if jsonReply, err := protojson.Marshal(msg); err == nil { + logrus.Debugf("gRPC request succeeded: method=%s, duration=%v, response=%s", method, duration, jsonReply) + } else { + logrus.Warnf("Could not marshal gRPC response: method=%s, error=%v", method, err) + } + } else { + logrus.Debugf("gRPC request succeeded: method=%s, duration=%v, responseType=%T", method, duration, reply) + } + } + + return err + } +} diff --git a/client/iface/bind/udp_mux.go b/client/iface/bind/udp_mux.go index 4c827de95..c48a64c86 100644 --- a/client/iface/bind/udp_mux.go +++ b/client/iface/bind/udp_mux.go @@ -9,7 +9,6 @@ import ( "sync" "github.com/pion/ice/v3" - "github.com/pion/logging" "github.com/pion/stun/v2" "github.com/pion/transport/v3" "github.com/pion/transport/v3/stdnet" @@ -48,7 +47,6 @@ const maxAddrSize = 512 // UDPMuxParams are parameters for UDPMux. type UDPMuxParams struct { - Logger logging.LeveledLogger UDPConn net.PacketConn // Required for gathering local addresses @@ -149,9 +147,6 @@ func isZeros(ip net.IP) bool { // NewUDPMuxDefault creates an implementation of UDPMux func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault { - if params.Logger == nil { - params.Logger = logging.NewDefaultLoggerFactory().NewLogger("ice") - } mux := &UDPMuxDefault{ addressMap: map[string][]*udpMuxedConn{}, @@ -174,12 +169,12 @@ func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault { func (m *UDPMuxDefault) updateLocalAddresses() { var localAddrsForUnspecified []net.Addr if addr, ok := m.params.UDPConn.LocalAddr().(*net.UDPAddr); !ok { - m.params.Logger.Errorf("LocalAddr is not a net.UDPAddr, got %T", m.params.UDPConn.LocalAddr()) + log.Errorf("LocalAddr is not a net.UDPAddr, got %T", m.params.UDPConn.LocalAddr()) } else if ok && addr.IP.IsUnspecified() { // For unspecified addresses, the correct behavior is to return errListenUnspecified, but // it will break the applications that are already using unspecified UDP connection // with UDPMuxDefault, so print a warn log and create a local address list for mux. - m.params.Logger.Warn("UDPMuxDefault should not listening on unspecified address, use NewMultiUDPMuxFromPort instead") + log.Warn("UDPMuxDefault should not listening on unspecified address, use NewMultiUDPMuxFromPort instead") var networks []ice.NetworkType switch { @@ -190,13 +185,13 @@ func (m *UDPMuxDefault) updateLocalAddresses() { networks = []ice.NetworkType{ice.NetworkTypeUDP4} default: - m.params.Logger.Errorf("LocalAddr expected IPV4 or IPV6, got %T", m.params.UDPConn.LocalAddr()) + log.Errorf("LocalAddr expected IPV4 or IPV6, got %T", m.params.UDPConn.LocalAddr()) } if len(networks) > 0 { if m.params.Net == nil { var err error if m.params.Net, err = stdnet.NewNet(); err != nil { - m.params.Logger.Errorf("failed to get create network: %v", err) + log.Errorf("failed to get create network: %v", err) } } @@ -206,7 +201,7 @@ func (m *UDPMuxDefault) updateLocalAddresses() { localAddrsForUnspecified = append(localAddrsForUnspecified, &net.UDPAddr{IP: ip, Port: addr.Port}) } } else { - m.params.Logger.Errorf("failed to get local interfaces for unspecified addr: %v", err) + log.Errorf("failed to get local interfaces for unspecified addr: %v", err) } } } @@ -369,7 +364,6 @@ func (m *UDPMuxDefault) createMuxedConn(key string) *udpMuxedConn { Key: key, AddrPool: m.pool, LocalAddr: m.LocalAddr(), - Logger: m.params.Logger, }) return c } diff --git a/client/iface/bind/udp_mux_universal.go b/client/iface/bind/udp_mux_universal.go index 6f851393e..b7091d436 100644 --- a/client/iface/bind/udp_mux_universal.go +++ b/client/iface/bind/udp_mux_universal.go @@ -14,7 +14,6 @@ import ( log "github.com/sirupsen/logrus" - "github.com/pion/logging" "github.com/pion/stun/v2" "github.com/pion/transport/v3" @@ -38,7 +37,6 @@ type UniversalUDPMuxDefault struct { // UniversalUDPMuxParams are parameters for UniversalUDPMux server reflexive. type UniversalUDPMuxParams struct { - Logger logging.LeveledLogger UDPConn net.PacketConn XORMappedAddrCacheTTL time.Duration Net transport.Net @@ -48,9 +46,6 @@ type UniversalUDPMuxParams struct { // NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux func NewUniversalUDPMuxDefault(params UniversalUDPMuxParams) *UniversalUDPMuxDefault { - if params.Logger == nil { - params.Logger = logging.NewDefaultLoggerFactory().NewLogger("ice") - } if params.XORMappedAddrCacheTTL == 0 { params.XORMappedAddrCacheTTL = time.Second * 25 } @@ -65,14 +60,12 @@ func NewUniversalUDPMuxDefault(params UniversalUDPMuxParams) *UniversalUDPMuxDef m.params.UDPConn = &udpConn{ PacketConn: params.UDPConn, mux: m, - logger: params.Logger, filterFn: params.FilterFn, address: params.WGAddress, } // embed UDPMux udpMuxParams := UDPMuxParams{ - Logger: params.Logger, UDPConn: m.params.UDPConn, Net: m.params.Net, } @@ -118,7 +111,6 @@ func (m *UniversalUDPMuxDefault) ReadFromConn(ctx context.Context) { type udpConn struct { net.PacketConn mux *UniversalUDPMuxDefault - logger logging.LeveledLogger filterFn FilterFn // TODO: reset cache on route changes addrCache sync.Map diff --git a/client/iface/bind/udp_muxed_conn.go b/client/iface/bind/udp_muxed_conn.go index 7cacf1c31..2ce508b41 100644 --- a/client/iface/bind/udp_muxed_conn.go +++ b/client/iface/bind/udp_muxed_conn.go @@ -11,7 +11,6 @@ import ( "sync" "time" - "github.com/pion/logging" "github.com/pion/transport/v3/packetio" ) @@ -20,7 +19,6 @@ type udpMuxedConnParams struct { AddrPool *sync.Pool Key string LocalAddr net.Addr - Logger logging.LeveledLogger } // udpMuxedConn represents a logical packet conn for a single remote as identified by ufrag diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index b2a6404bb..57aa85d02 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -38,6 +38,8 @@ import ( "github.com/netbirdio/netbird/client/ui/process" "github.com/netbirdio/netbird/util" + grpcLogger "github.com/netbirdio/netbird/client/grpc/logger" + "github.com/netbirdio/netbird/version" ) @@ -822,6 +824,7 @@ func (s *serviceClient) getSrvClient(timeout time.Duration) (proto.DaemonService strings.TrimPrefix(s.addr, "tcp://"), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock(), + grpc.WithUnaryInterceptor(grpcLogger.UnaryClientInterceptor()), grpc.WithUserAgent(desktop.GetUIUserAgent()), ) if err != nil { diff --git a/util/grpc/dialer.go b/util/grpc/dialer.go index f6d6d2f04..dbc642ebf 100644 --- a/util/grpc/dialer.go +++ b/util/grpc/dialer.go @@ -20,6 +20,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" + grpcLogger "github.com/netbirdio/netbird/client/grpc/logger" "github.com/netbirdio/netbird/util/embeddedroots" nbnet "github.com/netbirdio/netbird/util/net" ) @@ -84,6 +85,7 @@ func CreateConnection(addr string, tlsEnabled bool) (*grpc.ClientConn, error) { Time: 30 * time.Second, Timeout: 10 * time.Second, }), + grpc.WithUnaryInterceptor(grpcLogger.UnaryClientInterceptor()), ) if err != nil { log.Printf("DialContext error: %v", err)