internal/README.md
This directory contains the refactored internal architecture for eCapture, implementing clean architecture principles and design patterns for improved maintainability, testability, and extensibility.
internal/
├── domain/ # Core interfaces and contracts
├── errors/ # Unified error handling
├── logger/ # Logging abstraction
├── config/ # Configuration management
├── builder/ # Fluent configuration builders
├── events/ # Event dispatching (Observer pattern)
├── factory/ # Probe factory (Factory pattern)
└── probe/
├── base/ # Base probe implementation
└── [probes]/ # Specific probe implementations
All core concepts are defined as interfaces in the domain package:
Probe: Lifecycle management for eBPF probesEvent: Event structure and processingConfiguration: Probe configurationEventDispatcher: Event distributionbuilder/)Fluent API for configuration:
config := NewConfigBuilder().
WithPid(1234).
WithDebug(true).
Build()
events/)Event dispatching to multiple handlers:
dispatcher.Register(handler1)
dispatcher.Register(handler2)
dispatcher.Dispatch(event) // Notifies all handlers
factory/)Centralized probe creation:
probe := factory.CreateProbe(ProbeTypeBash)
probe/base/)BaseProbe provides common functionality, concrete probes override specifics:
type MyProbe struct {
*base.BaseProbe
}
func (p *MyProbe) Start(ctx context.Context) error {
// Call base implementation
if err := p.BaseProbe.Start(ctx); err != nil {
return err
}
// Add probe-specific logic
return nil
}
All errors use structured error types with error codes:
// Create an error
err := errors.NewProbeStartError("openssl", cause)
// Add context
err.WithContext("pid", 1234).WithContext("uid", 0)
// Error codes
ErrCodeConfiguration = 101
ErrCodeProbeInit = 201
ErrCodeProbeStart = 202
ErrCodeEventDecode = 301
All packages have comprehensive unit tests:
*_test.go files alongside implementationgo test ./internal/...go test -race ./internal/...go test -cover ./internal/...errors: 100% (all error types and wrapping)config: 100% (validation and setters/getters)builder: 100% (fluent API)events: 100% (dispatcher and handlers)factory: 100% (probe creation)probe/base: 100% (lifecycle and event loops)// internal/probe/myprobe/config.go
type MyProbeConfig struct {
*config.BaseConfig
SpecificField string
}
func (c *MyProbeConfig) Validate() error {
if err := c.BaseConfig.Validate(); err != nil {
return err
}
// Add specific validation
return nil
}
// internal/probe/myprobe/event.go
type MyEvent struct {
Pid uint32
Data []byte
}
func (e *MyEvent) DecodeFromBytes(data []byte) error {
// Implement decoding using binary.Read
return nil
}
func (e *MyEvent) Validate() error {
// Validate event data
return nil
}
// internal/probe/myprobe/myprobe.go
type MyProbe struct {
*base.BaseProbe
manager *manager.Manager
}
func NewMyProbe() (*MyProbe, error) {
return &MyProbe{
BaseProbe: base.NewBaseProbe("myprobe"),
}, nil
}
func (p *MyProbe) Start(ctx context.Context) error {
if err := p.BaseProbe.Start(ctx); err != nil {
return err
}
// Load eBPF program
// Attach probes
// Start event readers
return nil
}
// internal/probe/myprobe/register.go
func init() {
factory.RegisterProbe(factory.ProbeTypeMyProbe, func() (domain.Probe, error) {
return NewMyProbe()
})
}
// internal/probe/myprobe/myprobe_test.go
func TestMyProbe(t *testing.T) {
probe, err := NewMyProbe()
// Test initialization, lifecycle, etc.
}
internal/errorsWithContext()internal/loggerClose() for cleanupdefer for guaranteed cleanupuser/module/ remain functionalWhen adding new functionality: