v1.9.0
Welcome to go-zero v1.9.0! This release brings powerful new features, important fixes, and performance improvements to enhance your microservices development experience.
🆕 New Features
Section titled “🆕 New Features”1. Data Masking in Logging (logx)
Section titled “1. Data Masking in Logging (logx)”Enhanced security for sensitive data logging
What’s New: Support for masking sensitive data in log output by implementing the MaskSensitive() any method on data types.
Quick Start:
package main
import "github.com/zeromicro/go-zero/core/logx"
// Define a struct with sensitive datatype UserInfo struct { Username string `json:"username"` Password string `json:"password"` Email string `json:"email"`}
// Implement MaskSensitive method to control what gets loggedfunc (u UserInfo) MaskSensitive() any { return UserInfo{ Username: u.Username, Password: "***", // Mask the password Email: maskEmail(u.Email), // Partially mask email }}
func maskEmail(email string) string { parts := strings.Split(email, "@") if len(parts) != 2 { return "***" } return parts[0][:1] + "***@" + parts[1]}
func main() { user := UserInfo{ Username: "john", Password: "secret123", Email: "john@example.com", }
// This will automatically use MaskSensitive() method logx.Infow("User login", logx.Field("user", user)) // Output: {"user":{"username":"john","password":"***","email":"j***@example.com"}}}2. Field Tag Skip Logic in sqlx
Section titled “2. Field Tag Skip Logic in sqlx”Improved database field handling with skip tags
What’s New: Support for - field tag to skip fields during database operations.
Quick Start:
type User struct { ID int64 `db:"id"` Name string `db:"name"` Password string `db:"-"` // This field will be skipped Internal string `db:"-"` // This field will be skipped Email string `db:"email"`}
// Usage in queries - skipped fields are automatically ignoredvar user Usererr := sqlx.QueryRow(&user, "SELECT id, name, email FROM users WHERE id = ?", 1)3. MongoDB Driver v2 Upgrade
Section titled “3. MongoDB Driver v2 Upgrade”Modern MongoDB integration with improved performance
What’s New: Upgraded to mongo-driver v2 with v1 moved to zero-contrib for backward compatibility.
Migration Guide:
// Old way (v1 - now in zero-contrib)import "github.com/zeromicro/zero-contrib/stores/mongo"
// New way (v2 - built-in)import "github.com/zeromicro/go-zero/core/stores/mongo"
func main() { // New v2 API with improved performance client := mongo.MustNewModel("mongodb://localhost:27017", "mydb", "users")
// Enhanced query capabilities var users []User err := client.Find(context.Background(), &users, bson.M{"status": "active"})}4. Generic TypedSet with 2x Performance
Section titled “4. Generic TypedSet with 2x Performance”High-performance generic set implementation
What’s New: Generic TypedSet with compile-time safety and 2x performance improvement.
Quick Start:
import "github.com/zeromicro/go-zero/core/collection"
func main() { // Create a typed set for strings stringSet := collection.NewTypedSet[string]()
// Add items stringSet.Add("user1", "user2", "user3")
// Check membership (2x faster than previous implementation) if stringSet.Contains("user1") { fmt.Println("User found!") }
// Work with integers intSet := collection.NewTypedSet[int]() intSet.Add(1, 2, 3)
// Set operations union := stringSet.Union(otherStringSet) intersection := stringSet.Intersect(otherStringSet)}5. Gateway Custom Middleware (Onion Model)
Section titled “5. Gateway Custom Middleware (Onion Model)”Flexible middleware architecture for API gateways
What’s New: Support for custom middleware with onion model architecture in API gateways.
Quick Start:
import "github.com/zeromicro/go-zero/gateway"
// Define custom middlewarefunc authMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Authentication logic token := r.Header.Get("Authorization") if !validateToken(token) { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } next(w, r) }}
func rateLimitMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Rate limiting logic if !checkRateLimit(r.RemoteAddr) { http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests) return } next(w, r) }}
// Configure gateway with middleware stackfunc main() { gw := gateway.MustNewServer(gateway.GatewayConf{ Name: "api-gateway", Port: 8080, Upstreams: []gateway.Upstream{ { Name: "user-service", Mapping: "/api/users", Target: "http://localhost:8081", }, }, // Middleware stack (onion model - outer to inner) Middlewares: []gateway.Middleware{ rateLimitMiddleware, // Outer layer authMiddleware, // Inner layer }, })
gw.Start()}6. Redis Consumer Groups
Section titled “6. Redis Consumer Groups”Advanced Redis stream processing with consumer groups
What’s New: Native support for Redis consumer groups for scalable stream processing.
Quick Start:
import "github.com/zeromicro/go-zero/core/stores/redis"
func main() { rds := redis.MustNewRedis(redis.RedisConf{ Host: "localhost:6379", })
// Create consumer group err := rds.XGroupCreate("events", "processors", "0", true) if err != nil { log.Fatal(err) }
// Consumer function go func() { for { // Read from consumer group streams, err := rds.XReadGroup(&redis.XReadGroupArgs{ Group: "processors", Consumer: "worker-1", Streams: []string{"events", ">"}, Count: 10, Block: time.Second * 5, })
if err != nil { log.Printf("Error reading: %v", err) continue }
// Process messages for _, stream := range streams { for _, message := range stream.Messages { processMessage(message) // Acknowledge message rds.XAck("events", "processors", message.ID) } } } }()}
func processMessage(msg redis.XMessage) { fmt.Printf("Processing message %s: %v\n", msg.ID, msg.Values)}7. Gateway Request Parsing Enhancement
Section titled “7. Gateway Request Parsing Enhancement”Improved flexibility with unknown field handling
What’s New: Gateway now ignores unknown fields in request parsing, improving API compatibility.
Benefits:
- Backward Compatibility: Older clients can send requests with deprecated fields
- Forward Compatibility: Newer clients can send additional fields safely
- Graceful Degradation: Services continue working despite schema mismatches
Example:
// Service expects this structuretype UserRequest struct { Name string `json:"name"` Email string `json:"email"`}
// Client sends this (extra fields are now ignored, not rejected){ "name": "John Doe", "email": "john@example.com", "deprecated_field": "old_value", // Ignored gracefully "future_field": "new_value" // Ignored gracefully}8. Gateway gRPC Metadata Forwarding
Section titled “8. Gateway gRPC Metadata Forwarding”Enhanced gRPC metadata forwarding to HTTP headers in gateway
What’s New: Gateway now automatically forwards gRPC metadata (headers and trailers) from backend services to HTTP response headers.
Benefits:
- Full Metadata Propagation: All gRPC headers and trailers are forwarded to HTTP clients
- Tracing Support: Trace IDs and debugging information flow through the gateway
- Custom Headers: Backend services can set custom headers that reach frontend clients
- Seamless Integration: Works with existing gateway configurations
Quick Start:
// Backend gRPC service setting metadatafunc (s *Service) SomeMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) { // Set headers that will be forwarded to HTTP response err := grpc.SendHeader(ctx, metadata.Pairs( "X-Custom-Header", "custom-value", "X-Trace-ID", "trace-12345", )) if err != nil { return nil, err }
// Set trailers that will also be forwarded grpc.SetTrailer(ctx, metadata.Pairs( "X-Server-Info", "grpc-backend-v1", "X-Processing-Time", "150ms", ))
return &pb.Response{}, nil}
// Frontend HTTP client will now receive these headers:// X-Custom-Header: custom-value// X-Trace-ID: trace-12345// X-Server-Info: grpc-backend-v1// X-Processing-Time: 150ms🐛 Bug Fixes
Section titled “🐛 Bug Fixes”1. ETCD Auto-Registration Fix
Section titled “1. ETCD Auto-Registration Fix”Resolved service discovery reliability issues
Problem Fixed: Services failing to auto-re-register when ETCD keys disappeared.
Impact: Improved service discovery reliability and automatic recovery.
Before vs After:
// Before: Manual re-registration required// After: Automatic recoveryconfig := etcd.EtcdConf{ Hosts: []string{"localhost:2379"}, Key: "user.rpc", // Auto-recovery now works reliably}2. SSE Timeout Configuration
Section titled “2. SSE Timeout Configuration”Fixed Server-Sent Events timeout handling
Problem Fixed: SSE connections affected by http.Server’s WriteTimeout causing premature disconnections.
Solution: SSE now properly handles timeouts independently of server write timeout.
// SSE now works correctly with server timeoutsserver := &http.Server{ WriteTimeout: 10 * time.Second, // Won't affect SSE}
// SSE connections maintain their own timeout handlinghttp.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) { // SSE stream works regardless of server WriteTimeout sse.StreamEvents(w, r, eventSource)})3. Environment Variable Unmarshaling
Section titled “3. Environment Variable Unmarshaling”Fixed configuration loading from environment variables
Problem Fixed: Issues with unmarshaling environment variables for type time.Duration.
Example Fix:
type Config struct { Timeout time.Duration `json:",env=TIMEOUT"` // Now works correctly}4. Memory Optimization for Large Requests
Section titled “4. Memory Optimization for Large Requests”Reduced memory usage in detailed request logging
Problem Fixed: Large memory consumption when logging POST request details.
Impact: Significantly reduced memory footprint for applications with large request bodies when setting log to verbose.
5. JSON Serialization HTML Escaping
Section titled “5. JSON Serialization HTML Escaping”Fixed HTML escaping issues in httpx responses
Problem Fixed: Unwanted HTML escaping during JSON serialization causing malformed responses.
Before:
{"message": "Hello \\u003cworld\\u003e"} // Incorrect escapingAfter:
{"message": "Hello <world>"} // Correct output6. Concurrent Resource Access Fix
Section titled “6. Concurrent Resource Access Fix”Fixed race conditions in ImmutableResource
Problem Fixed: Concurrent access to ImmutableResource could lead to empty results.
Impact: Improved thread safety and reliability in high-concurrency scenarios.
⚡ Performance Improvements
Section titled “⚡ Performance Improvements”Optimized Field Logging
Section titled “Optimized Field Logging”Enhanced logging performance with structured field handling.
Improvement: Faster log processing with reduced allocations.
Usage:
// Optimized field logginglogx.Infow("User action", logx.Field("user_id", userID), logx.Field("action", "login"), logx.Field("timestamp", time.Now()),)🎯 Migration Guide
Section titled “🎯 Migration Guide”From v1.8.5 to v1.9.0
Section titled “From v1.8.5 to v1.9.0”- Update Dependencies:
go get github.com/zeromicro/go-zero@v1.9.0-
MongoDB Driver:
- Update imports from zero-contrib if using MongoDB v1
- Consider migrating to v2 for better performance
-
Consumer Groups:
- Update Redis stream processing to use new consumer group APIs
🙏 New Contributors
Section titled “🙏 New Contributors”Welcome to our amazing new contributors who made their first contributions:
- @Twilikiss - Documentation improvements
- @charmfocus - sqlx field tagging enhancement
- @csbzy - SSE timeout fix
- @DengY11 - Gateway middleware architecture
- @queryfast - Performance optimizations
- @sunhao1296 - Concurrent resource fix
- @ipinak - Testing improvements
📚 Additional Resources
Section titled “📚 Additional Resources”- Complete Tutorial Collection
- Code Examples Repository
- Migration Guide
- Best Practices
🔗 Links
Section titled “🔗 Links”- Full Changelog: https://github.com/zeromicro/go-zero/compare/v1.8.5…v1.9.0
- Documentation: https://go-zero.dev/
- Community: https://github.com/zeromicro/go-zero/discussions
Happy coding with go-zero v1.9.0! 🎉