A modern, layered Go framework for building Connect-RPC microservices with observability, configuration management, and clean architecture.
Egg is a comprehensive microservices framework designed for building production-grade Go services with minimal boilerplate. It provides:
- One-line service startup with integrated configuration, logging, database, and tracing
- Clean layered architecture with clear dependency boundaries
- Connect-RPC first with automatic interceptor stack
- Hot configuration reloading from Kubernetes ConfigMaps
- Production-ready observability with OpenTelemetry
- Type-safe dependency injection container
- Clarity over cleverness - Explicit, readable code
- Layered dependencies - No circular imports, clear dependency flow
- Interface-driven design - Public API separate from implementation
- Production-ready defaults - Sensible configuration out of the box
- CLI-driven development - Never manually edit
go.modorgo.work
go get go.eggybyte.com/egg/servicex@latestpackage main
import (
"context"
"log/slog"
"go.eggybyte.com/egg/configx"
"go.eggybyte.com/egg/logx"
"go.eggybyte.com/egg/servicex"
)
type AppConfig struct {
configx.BaseConfig
}
func register(app *servicex.App) error {
// Register your Connect handlers here
app.Mux().HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, Egg!"))
})
return nil
}
func main() {
ctx := context.Background()
// Create logger (optional - servicex creates one if not provided)
logger := logx.New(
logx.WithFormat(logx.FormatConsole),
logx.WithLevel(slog.LevelInfo),
logx.WithColor(true),
)
cfg := &AppConfig{}
err := servicex.Run(ctx,
servicex.WithService("my-service", "1.0.0"),
servicex.WithLogger(logger),
servicex.WithAppConfig(cfg), // Auto-detects database from BaseConfig
servicex.WithRegister(register),
)
if err != nil {
logger.Error(err, "service failed to start")
}
}Run with:
# Default log level (info)
go run main.go
# With debug logging
LOG_LEVEL=debug go run main.goEnvironment-Based Log Level Control
- Use
LOG_LEVELenvironment variable instead ofWithDebugLogs() - Supports:
debug,info,warn,error - Automatically applied when using
servicex
Simplified Database Configuration
WithAppConfig()now auto-detects database configuration fromconfigx.BaseConfig- No need for separate
WithDatabase()call - Database settings loaded from environment variables after config binding
Enhanced Logging Helpers
- Added
Int32(),Int64(),Float64(),String()tocore/log - More convenient structured logging
Example:
// Old pattern
servicex.WithConfig(cfg),
servicex.WithDatabase(servicex.FromBaseConfig(&cfg.Database)),
servicex.WithDebugLogs(true),
// New pattern (recommended)
servicex.WithAppConfig(cfg), // Auto-detects database
// Set LOG_LEVEL=debug via environment variableEgg follows a strict layered architecture to prevent circular dependencies and ensure maintainability:
┌─────────────────────────────────────────────────┐
│ L4: Integration Layer │
│ ┌─────────────────────────────────────────┐ │
│ │ servicex: One-line service startup │ │
│ └─────────────────────────────────────────┘ │
└────────────────┬────────────────────────────────┘
│
┌────────────────┴────────────────────────────────┐
│ L3: Runtime & Communication Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │runtimex │ │connectx │ │clientx │ │
│ │(lifecycle)│ │(RPC) │ │(client) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└────────────────┬────────────────────────────────┘
│
┌────────────────┴────────────────────────────────┐
│ L2: Capability Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │configx │ │obsx │ │httpx │ │
│ │(config) │ │(tracing) │ │(HTTP) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└────────────────┬────────────────────────────────┘
│
┌────────────────┴────────────────────────────────┐
│ L1: Foundation Layer │
│ ┌─────────────────────────────────────────┐ │
│ │ logx: Structured logging │ │
│ └─────────────────────────────────────────┘ │
└────────────────┬────────────────────────────────┘
│
┌────────────────┴────────────────────────────────┐
│ L0: Core Layer (Zero Dependencies) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │errors │ │identity │ │log │ │
│ │(types) │ │(context) │ │(interface)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────┘
Auxiliary Modules (can depend on any layer):
┌─────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │storex │ │k8sx │ │testingx │ │
│ │(storage) │ │(k8s) │ │(testing) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────┘
- Rule 1: A module can only depend on modules in the same or lower layers
- Rule 2: No circular dependencies between modules
- Rule 3: Core modules (L0) have zero external dependencies
- Rule 4: Public interface files are thin (~100-200 lines), complex logic in
internal/
servicex - One-Line Service Startup
The highest-level module that integrates all components for microservice initialization.
servicex.Run(ctx,
servicex.WithService("my-service", "1.0.0"),
servicex.WithLogger(logger),
servicex.WithAppConfig(cfg), // Auto-detects database from BaseConfig
servicex.WithAutoMigrate(&model.User{}),
servicex.WithRegister(register),
)Key Features:
- Integrated configuration, logging, database, tracing
- Automatic database configuration from
BaseConfig - Environment-based log level control (
LOG_LEVEL) - Connect RPC interceptor stack
- Graceful shutdown with hooks
- Dependency injection container
runtimex - Service Lifecycle Management
Manages service startup, shutdown, and health checks.
runtimex.Run(ctx, services, runtimex.Options{
Logger: logger,
HTTP: &runtimex.HTTPOptions{Addr: ":8080", Mux: mux},
Health: &runtimex.Endpoint{Addr: ":8081"},
})Key Features:
- Concurrent service startup/shutdown
- Health check aggregation
- Multiple server support (HTTP, RPC, Health, Metrics)
- Configurable shutdown timeout
connectx - Connect RPC Interceptors
Provides a unified interceptor stack for Connect-RPC services.
interceptors := connectx.DefaultInterceptors(connectx.Options{
Logger: logger,
Otel: provider,
SlowRequestMillis: 1000,
})Key Features:
- Timeout enforcement with header override
- Structured logging with correlation
- Error mapping to Connect codes
- OpenTelemetry tracing integration
clientx - Connect Client Factory
Creates Connect HTTP clients with retry, circuit breaker, and timeouts.
client := clientx.NewHTTPClient("https://api.example.com",
clientx.WithTimeout(5*time.Second),
clientx.WithRetry(3),
)configx - Configuration Management
Unified configuration with hot reloading from multiple sources.
manager, _ := configx.DefaultManager(ctx, logger)
var cfg AppConfig
manager.Bind(&cfg)Key Features:
- Multiple sources (Env, File, K8s ConfigMap)
- Hot reload with debouncing
- Struct binding with validation
- Change notifications
obsx - OpenTelemetry Provider
Simplified OpenTelemetry initialization for tracing and metrics.
provider, _ := obsx.NewProvider(ctx, obsx.Options{
ServiceName: "user-service",
ServiceVersion: "1.0.0",
OTLPEndpoint: "otel-collector:4317",
})Key Features:
- Trace and metric provider setup
- Configurable sampling
- Resource attributes
- Graceful shutdown
httpx - HTTP Utilities
HTTP helpers for binding, validation, and security.
var req UserRequest
httpx.BindAndValidate(r, &req)
handler := httpx.SecureMiddleware(httpx.DefaultSecurityHeaders())(next)logx - Structured Logging
Structured logging based on log/slog with logfmt/JSON output.
logger := logx.New(
logx.WithFormat(logx.FormatLogfmt),
logx.WithLevel(slog.LevelInfo),
)
logger.Info("user created", "user_id", "u-123")Key Features:
- Logfmt and JSON formats
- Field sorting and colorization
- Payload limits and sensitive field masking
- Context-aware logging
core/errors - Error Types
Structured error types with codes for API responses.
core/identity - Identity Context
Request metadata and user identity extraction.
core/log - Logger Interface
Zero-dependency logger interface.
storex - Storage Abstraction
GORM-based storage with health checks.
store, _ := storex.NewGORMStore(storex.GORMOptions{
DSN: "user:pass@tcp(localhost:3306)/mydb",
Driver: "mysql",
Logger: logger,
})k8sx - Kubernetes Integration
ConfigMap watching and service discovery.
testingx - Testing Utilities
Test helpers and utilities (planned).
All major modules follow a clean architecture pattern:
module/
├── module.go # Public API (~100-200 lines)
│ ├── Interface definitions
│ ├── Option functions
│ └── Constructor (delegates to internal)
└── internal/
├── implementation.go # Actual logic
├── helpers.go # Internal helpers
└── types.go # Internal types
Benefits:
- Public API surface is minimal and focused
- Implementation details hidden
- Easy to test and mock
- Clear separation of concerns
Complex initialization is split into logical stages (servicex example):
1. initializeLogger() → Setup logging
2. initializeConfig() → Load configuration
3. initializeDatabase() → Connect database
4. initializeObservability() → Setup tracing
5. buildApp() → Create app context
6. startServers() → Start HTTP servers
7. gracefulShutdown() → Cleanup resourcesAll modules use functional options for configuration:
servicex.Run(ctx,
servicex.WithService("my-service", "1.0.0"),
servicex.WithLogger(logger),
servicex.WithAppConfig(cfg), // Auto-detects database
servicex.WithAutoMigrate(&model.User{}),
servicex.WithRegister(register),
)Configuration via Environment:
# Service configuration
SERVICE_NAME=my-service
SERVICE_VERSION=1.0.0
ENV=production
# Log level control
LOG_LEVEL=info # debug, info, warn, error
# Database (auto-detected from BaseConfig)
DB_DRIVER=mysql
DB_DSN=user:pass@tcp(localhost:3306)/mydb
DB_MAX_IDLE=10
DB_MAX_OPEN=100
DB_MAX_LIFETIME=1h
# Ports
HTTP_PORT=8080
HEALTH_PORT=8081
METRICS_PORT=9091See examples/user-service for a complete Connect-RPC service with:
- Configuration management
- Database integration with migrations
- Connect RPC handlers
- Health checks
- OpenTelemetry tracing
cd examples/user-service
make run- Go 1.21+
- Docker and Docker Compose
- Make
make buildmake testmake lintmake docsegg/
├── core/ # L0: Core types and interfaces
│ ├── errors/
│ ├── identity/
│ └── log/
├── logx/ # L1: Structured logging
├── configx/ # L2: Configuration management
├── obsx/ # L2: OpenTelemetry provider
├── httpx/ # L2: HTTP utilities
├── runtimex/ # L3: Lifecycle management
├── connectx/ # L3: Connect interceptors
├── clientx/ # L3: Connect client
├── servicex/ # L4: Service integration
├── storex/ # Auxiliary: Storage
├── k8sx/ # Auxiliary: Kubernetes
├── examples/ # Example services
├── docs/ # Documentation
└── scripts/ # Build and deployment scripts
All modules follow strict quality standards:
- Documentation: All exported symbols have GoDoc comments in English
- Testing: Comprehensive test coverage with table-driven tests
- Linting: Clean
golangci-lintoutput - File Size: Public interface files < 300 lines, implementation < 500 lines
- Dependencies: Minimal external dependencies, managed via
go work
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Additional storage backends (Redis, MongoDB)
- More comprehensive testing utilities
- Performance benchmarks
- Additional examples
- Documentation improvements
- Core framework modules (L0-L4)
- Connect-RPC integration
- OpenTelemetry observability
- Configuration management with hot reload
- Database integration with GORM
- Redis cache integration
- Message queue integration (Kafka, RabbitMQ)
- Service mesh integration (Istio, Linkerd)
- CLI tool for project scaffolding
- GraphQL support
- Architecture Guide - Detailed architecture documentation
- Logging Standards - Logging format and practices
- Code Guidelines - Code quality standards
- Module Guide - Module-by-module guide
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ by the EggyByte team.
Special thanks to:
- Connect-RPC for the excellent RPC framework
- OpenTelemetry for observability standards
- The Go community for inspiration and best practices
Made with Go 🚀 | Built for Production 🏭 | Designed for Scale 📈