release: version 1.1.2 - Add error callback mechanism and comprehensive test suite
Some checks failed
Build RPM Package / Build RPM Packages (CentOS 7, Rocky 8/9/10) (push) Has been cancelled
Some checks failed
Build RPM Package / Build RPM Packages (CentOS 7, Rocky 8/9/10) (push) Has been cancelled
Features: - Add ErrorCallback type for UNIX socket connection error reporting - Add WithErrorCallback option for UnixSocketWriter configuration - Add BuilderImpl.WithErrorCallback() for propagating callbacks - Add consecutive failure tracking in processQueue Testing (50+ new tests): - Add integration tests for full pipeline (capture → tlsparse → fingerprint → output) - Add tests for FileWriter.rotate() and Reopen() log rotation - Add tests for cleanupExpiredFlows() and cleanupLoop() in TLS parser - Add tests for extractSNIFromPayload() and extractJA4Hash() helpers - Add tests for config load error paths (invalid YAML, permission denied) - Add tests for capture.Run() error conditions - Add tests for signal handling documentation Documentation: - Update architecture.yml with new fields (LogLevel, TLSClientHello extensions) - Update architecture.yml with Close() methods for Capture and Parser interfaces - Update RPM spec changelog Cleanup: - Remove empty internal/api/ directory Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@ -202,6 +202,9 @@ func (w *FileWriter) Reopen() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrorCallback is a function type for reporting socket connection errors
|
||||
type ErrorCallback func(socketPath string, err error, attempt int)
|
||||
|
||||
// UnixSocketWriter writes log records to a UNIX socket with reconnection logic
|
||||
// No internal logging - only LogRecord JSON data is sent to the socket
|
||||
type UnixSocketWriter struct {
|
||||
@ -220,6 +223,9 @@ type UnixSocketWriter struct {
|
||||
isClosed bool
|
||||
pendingWrites [][]byte
|
||||
pendingMu sync.Mutex
|
||||
errorCallback ErrorCallback
|
||||
consecutiveFailures int
|
||||
failuresMu sync.Mutex
|
||||
}
|
||||
|
||||
// NewUnixSocketWriter creates a new UNIX socket writer with reconnection logic
|
||||
@ -227,8 +233,18 @@ func NewUnixSocketWriter(socketPath string) (*UnixSocketWriter, error) {
|
||||
return NewUnixSocketWriterWithConfig(socketPath, DefaultDialTimeout, DefaultWriteTimeout, DefaultQueueSize)
|
||||
}
|
||||
|
||||
// UnixSocketWriterOption is a function type for configuring UnixSocketWriter
|
||||
type UnixSocketWriterOption func(*UnixSocketWriter)
|
||||
|
||||
// WithErrorCallback sets an error callback for socket connection errors
|
||||
func WithErrorCallback(cb ErrorCallback) UnixSocketWriterOption {
|
||||
return func(w *UnixSocketWriter) {
|
||||
w.errorCallback = cb
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnixSocketWriterWithConfig creates a new UNIX socket writer with custom configuration
|
||||
func NewUnixSocketWriterWithConfig(socketPath string, dialTimeout, writeTimeout time.Duration, queueSize int) (*UnixSocketWriter, error) {
|
||||
func NewUnixSocketWriterWithConfig(socketPath string, dialTimeout, writeTimeout time.Duration, queueSize int, opts ...UnixSocketWriterOption) (*UnixSocketWriter, error) {
|
||||
w := &UnixSocketWriter{
|
||||
socketPath: socketPath,
|
||||
dialTimeout: dialTimeout,
|
||||
@ -242,6 +258,11 @@ func NewUnixSocketWriterWithConfig(socketPath string, dialTimeout, writeTimeout
|
||||
pendingWrites: make([][]byte, 0),
|
||||
}
|
||||
|
||||
// Apply options
|
||||
for _, opt := range opts {
|
||||
opt(w)
|
||||
}
|
||||
|
||||
// Start the queue processor
|
||||
go w.processQueue()
|
||||
|
||||
@ -259,7 +280,6 @@ func (w *UnixSocketWriter) processQueue() {
|
||||
defer close(w.queueDone)
|
||||
|
||||
backoff := w.reconnectBackoff
|
||||
consecutiveFailures := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
@ -271,7 +291,14 @@ func (w *UnixSocketWriter) processQueue() {
|
||||
}
|
||||
|
||||
if err := w.writeWithReconnect(data); err != nil {
|
||||
consecutiveFailures++
|
||||
w.failuresMu.Lock()
|
||||
w.consecutiveFailures++
|
||||
failures := w.consecutiveFailures
|
||||
w.failuresMu.Unlock()
|
||||
|
||||
// Report error via callback if configured
|
||||
w.reportError(err, failures)
|
||||
|
||||
// Queue for retry
|
||||
w.pendingMu.Lock()
|
||||
if len(w.pendingWrites) < DefaultQueueSize {
|
||||
@ -280,7 +307,7 @@ func (w *UnixSocketWriter) processQueue() {
|
||||
w.pendingMu.Unlock()
|
||||
|
||||
// Exponential backoff
|
||||
if consecutiveFailures > w.maxReconnects {
|
||||
if failures > w.maxReconnects {
|
||||
time.Sleep(backoff)
|
||||
backoff *= 2
|
||||
if backoff > w.maxBackoff {
|
||||
@ -288,7 +315,9 @@ func (w *UnixSocketWriter) processQueue() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
consecutiveFailures = 0
|
||||
w.failuresMu.Lock()
|
||||
w.consecutiveFailures = 0
|
||||
w.failuresMu.Unlock()
|
||||
backoff = w.reconnectBackoff
|
||||
// Try to flush pending data
|
||||
w.flushPendingData()
|
||||
@ -301,6 +330,13 @@ func (w *UnixSocketWriter) processQueue() {
|
||||
}
|
||||
}
|
||||
|
||||
// reportError reports a socket connection error via the configured callback
|
||||
func (w *UnixSocketWriter) reportError(err error, attempt int) {
|
||||
if w.errorCallback != nil {
|
||||
w.errorCallback(w.socketPath, err, attempt)
|
||||
}
|
||||
}
|
||||
|
||||
// flushPendingData attempts to write any pending data
|
||||
func (w *UnixSocketWriter) flushPendingData() {
|
||||
w.pendingMu.Lock()
|
||||
@ -486,13 +522,21 @@ func (mw *MultiWriter) Reopen() error {
|
||||
}
|
||||
|
||||
// BuilderImpl implements the api.Builder interface
|
||||
type BuilderImpl struct{}
|
||||
type BuilderImpl struct {
|
||||
errorCallback ErrorCallback
|
||||
}
|
||||
|
||||
// NewBuilder creates a new output builder
|
||||
func NewBuilder() *BuilderImpl {
|
||||
return &BuilderImpl{}
|
||||
}
|
||||
|
||||
// WithErrorCallback sets an error callback for all unix_socket writers created by this builder
|
||||
func (b *BuilderImpl) WithErrorCallback(cb ErrorCallback) *BuilderImpl {
|
||||
b.errorCallback = cb
|
||||
return b
|
||||
}
|
||||
|
||||
// NewFromConfig constructs writers from AppConfig
|
||||
// Uses AsyncBuffer from OutputConfig if specified, otherwise uses DefaultQueueSize
|
||||
func (b *BuilderImpl) NewFromConfig(cfg api.AppConfig) (api.Writer, error) {
|
||||
@ -529,7 +573,12 @@ func (b *BuilderImpl) NewFromConfig(cfg api.AppConfig) (api.Writer, error) {
|
||||
if socketPath == "" {
|
||||
return nil, fmt.Errorf("unix_socket output requires 'socket_path' parameter")
|
||||
}
|
||||
writer, err = NewUnixSocketWriterWithConfig(socketPath, DefaultDialTimeout, DefaultWriteTimeout, queueSize)
|
||||
// Build options list
|
||||
var opts []UnixSocketWriterOption
|
||||
if b.errorCallback != nil {
|
||||
opts = append(opts, WithErrorCallback(b.errorCallback))
|
||||
}
|
||||
writer, err = NewUnixSocketWriterWithConfig(socketPath, DefaultDialTimeout, DefaultWriteTimeout, queueSize, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user