Repository: grpc-ecosystem/go-grpc-middleware
Pull request #694 (2024-02-01 13:39:47)

Fix logging Example : log only first field
<!--
    Keep PR title verbose enough.
-->

## Changes

This PR follows issue #691.
<!-- Enumerate changes you made -->

## Verification

<!-- How you tested it? How do you know it works? -->

```go
grpc_logging.UnaryServerInterceptor(InterceptorLogrus(logger),grpc_logging.WithLogOnEvents(grpc_logging.FinishCall)),
```

My logging interceptor function : 
```go
func InterceptorLogrus(l log.FieldLogger) grpc_logging.Logger {
	return grpc_logging.LoggerFunc(func(_ context.Context, lvl grpc_logging.Level, msg string, fields ...any) {
		f := make(map[string]any, len(fields)/2)

		logFields := grpc_logging.Fields(fields)

		i := logFields.Iterator()

		for i.Next() {
			k, v := i.At()
			f[k] = v
		}
		l := l.WithFields(f)

		if _, ok := f["protocol"]; ok {
			l = l.WithField("system", f["protocol"])
		}
		l = l.WithField("span.kind", "server")

		switch lvl {
		case grpc_logging.LevelDebug:
			l.Debug(msg)
		case grpc_logging.LevelInfo:
			l.Info(msg)
		case grpc_logging.LevelWarn:
			l.Warn(msg)
		case grpc_logging.LevelError:
			l.Error(msg)
		default:
			l.Error(fmt.Sprintf("InterceptorLogrus : unknown level %v", lvl), " - logging message : ", msg)
		}
	})
}

```



Patch:
diff --git a/interceptors/realip/realip.go b/interceptors/realip/realip.go
index 8d5a021..41b2cde 100644
--- a/interceptors/realip/realip.go
+++ b/interceptors/realip/realip.go
@@ -83,10 +83,12 @@ func getRemoteIP(ctx context.Context, trustedPeers []netip.Prefix, headers []str
 		return noIP
 	}
 
-	ip, err := netip.ParseAddr(strings.Split(pr.String(), ":")[0])
+	addrPort, err := netip.ParseAddrPort(pr.String())
 	if err != nil {
 		return noIP
 	}
+	ip := addrPort.Addr()
+
 	if len(trustedPeers) == 0 || !ipInNets(ip, trustedPeers) {
 		return ip
 	}


Test patch:
diff --git a/interceptors/logging/examples/logrus/example_test.go b/interceptors/logging/examples/logrus/example_test.go
index d0f232f..23e33a3 100644
--- a/interceptors/logging/examples/logrus/example_test.go
+++ b/interceptors/logging/examples/logrus/example_test.go
@@ -18,7 +18,7 @@ func InterceptorLogger(l logrus.FieldLogger) logging.Logger {
 	return logging.LoggerFunc(func(_ context.Context, lvl logging.Level, msg string, fields ...any) {
 		f := make(map[string]any, len(fields)/2)
 		i := logging.Fields(fields).Iterator()
-		if i.Next() {
+		for i.Next() {
 			k, v := i.At()
 			f[k] = v
 		}
diff --git a/interceptors/realip/realip_test.go b/interceptors/realip/realip_test.go
index 4eeac51..9666ed5 100644
--- a/interceptors/realip/realip_test.go
+++ b/interceptors/realip/realip_test.go
@@ -19,17 +19,22 @@ import (
 var (
 	localnet []netip.Prefix = []netip.Prefix{
 		netip.MustParsePrefix("127.0.0.1/8"),
+		netip.MustParsePrefix("::1/128"),
 	}
 
 	privatenet []netip.Prefix = []netip.Prefix{
 		netip.MustParsePrefix("10.0.0.0/8"),
 		netip.MustParsePrefix("172.16.0.0/12"),
 		netip.MustParsePrefix("192.168.0.0/16"),
+		netip.MustParsePrefix("2002:c0a8::/32"),
 	}
 
-	privateIP netip.Addr = netip.MustParseAddr("192.168.0.1")
-	publicIP  netip.Addr = netip.MustParseAddr("8.8.8.8")
-	localhost netip.Addr = netip.MustParseAddr("127.0.0.1")
+	privateIP  netip.Addr = netip.MustParseAddr("192.168.0.1")
+	privateIP6 netip.Addr = netip.MustParseAddr("::ffff:c0a8:1")
+	publicIP   netip.Addr = netip.MustParseAddr("8.8.8.8")
+	publicIP6  netip.Addr = netip.MustParseAddr("::ffff:808:808")
+	localhost  netip.Addr = netip.MustParseAddr("127.0.0.1")
+	localhost6 netip.Addr = netip.MustParseAddr("::1")
 )
 
 func localhostPeer() *peer.Peer {
@@ -40,6 +45,14 @@ func localhostPeer() *peer.Peer {
 	}
 }
 
+func localhost6Peer() *peer.Peer {
+	return &peer.Peer{
+		Addr: &net.TCPAddr{
+			IP: net.ParseIP(localhost6.String()),
+		},
+	}
+}
+
 func publicPeer() *peer.Peer {
 	return &peer.Peer{
 		Addr: &net.TCPAddr{
@@ -56,6 +69,14 @@ func privatePeer() *peer.Peer {
 	}
 }
 
+func private6Peer() *peer.Peer {
+	return &peer.Peer{
+		Addr: &net.TCPAddr{
+			IP: net.ParseIP(privateIP6.String()),
+		},
+	}
+}
+
 type testCase struct {
 	trustedPeers []netip.Prefix
 	headerKeys   []string
@@ -331,6 +352,37 @@ func TestInterceptor(t *testing.T) {
 			testStreamServerInterceptor(t, tc)
 		})
 	})
+	t.Run("ipv6 from grpc peer", func(t *testing.T) {
+		tc := testCase{
+			trustedPeers: localnet,
+			headerKeys:   []string{},
+			peer:         localhost6Peer(),
+			expectedIP:   localhost6,
+		}
+		t.Run("unary", func(t *testing.T) {
+			testUnaryServerInterceptor(t, tc)
+		})
+		t.Run("stream", func(t *testing.T) {
+			testStreamServerInterceptor(t, tc)
+		})
+	})
+	t.Run("ipv6 from header", func(t *testing.T) {
+		tc := testCase{
+			trustedPeers: privatenet,
+			headerKeys:   []string{XForwardedFor},
+			inputHeaders: map[string]string{
+				XForwardedFor: publicIP6.String(),
+			},
+			peer:       private6Peer(),
+			expectedIP: publicIP6,
+		}
+		t.Run("unary", func(t *testing.T) {
+			testUnaryServerInterceptor(t, tc)
+		})
+		t.Run("stream", func(t *testing.T) {
+			testStreamServerInterceptor(t, tc)
+		})
+	})
 	t.Run("unix", func(t *testing.T) {
 		tc := testCase{
 			trustedPeers: localnet,