Change default output to Unix socket
Some checks failed
Build RPM Package / Build RPM Packages (CentOS 7, Rocky 8/9/10) (push) Has been cancelled

- config.yml.example: Unix socket enabled by default, stdout commented out
- internal/output/writers.go: Remove all internal logging from UnixSocketWriter
  and FileWriter - only LogRecord JSON data is sent to outputs
- architecture.yml: Update description to mention 'socket UNIX par défaut'
- packaging/rpm/ja4sentinel.spec: Bump version to 1.1.1, update changelog

Diagnostic logs (error, debug, warning) now only go to stdout when enabled.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Jacquin Antoine
2026-03-02 21:19:57 +01:00
parent 52c9f2f6f4
commit 6e5addd6d4
4 changed files with 24 additions and 70 deletions

View File

@ -7,7 +7,7 @@ project:
extraire les handshakes TLS côté client, générer les signatures JA4
(via psanford/tlsfingerprint), enrichir avec des métadonnées IP/TCP,
et loguer les résultats (IP, ports, JA4, meta) vers une ou plusieurs
sorties configurables (socket UNIX, stdout, fichier, ...).
sorties configurables (socket UNIX par défaut, stdout, fichier, ...).
Le service est géré par systemd avec support de rotation des logs via logrotate.
La commande `systemctl reload ja4sentinel` permet de réouvrir les fichiers de log
après rotation (signal SIGHUP).

View File

@ -24,20 +24,22 @@ core:
log_level: info
outputs:
# Output to stdout (JSON lines)
- type: stdout
# Output to UNIX socket (for systemd/journald or other consumers)
# Only JSON LogRecord data is sent - no diagnostic logs
- type: unix_socket
enabled: true
params: {}
params:
socket_path: /var/run/logcorrelator/network.socket
# Output to stdout (JSON lines)
# Diagnostic logs (error, debug, warning) should go here
# - type: stdout
# enabled: false
# params: {}
# Output to file
# Only JSON LogRecord data is sent - no diagnostic logs
# - type: file
# enabled: false
# params:
# path: /var/log/ja4sentinel/ja4.log
# Output to UNIX socket (for systemd/journald or other consumers)
# - type: unix_socket
# enabled: false
# params:
# socket_path: /var/run/logcorrelator/network.socket
# log_level: debug # debug, info, warn, error (default: error)

View File

@ -5,11 +5,9 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"os"
"path/filepath"
"strings"
"sync"
"time"
@ -205,6 +203,7 @@ func (w *FileWriter) Reopen() error {
}
// 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 {
socketPath string
conn net.Conn
@ -221,8 +220,6 @@ type UnixSocketWriter struct {
isClosed bool
pendingWrites [][]byte
pendingMu sync.Mutex
logLevel string
logger *log.Logger
}
// NewUnixSocketWriter creates a new UNIX socket writer with reconnection logic
@ -232,11 +229,6 @@ func NewUnixSocketWriter(socketPath string) (*UnixSocketWriter, error) {
// NewUnixSocketWriterWithConfig creates a new UNIX socket writer with custom configuration
func NewUnixSocketWriterWithConfig(socketPath string, dialTimeout, writeTimeout time.Duration, queueSize int) (*UnixSocketWriter, error) {
return NewUnixSocketWriterWithConfigAndLogLevel(socketPath, dialTimeout, writeTimeout, queueSize, "error")
}
// NewUnixSocketWriterWithConfigAndLogLevel creates a new UNIX socket writer with log level configuration
func NewUnixSocketWriterWithConfigAndLogLevel(socketPath string, dialTimeout, writeTimeout time.Duration, queueSize int, logLevel string) (*UnixSocketWriter, error) {
w := &UnixSocketWriter{
socketPath: socketPath,
dialTimeout: dialTimeout,
@ -248,50 +240,20 @@ func NewUnixSocketWriterWithConfigAndLogLevel(socketPath string, dialTimeout, wr
queueClose: make(chan struct{}),
queueDone: make(chan struct{}),
pendingWrites: make([][]byte, 0),
logLevel: strings.ToLower(logLevel),
logger: log.New(os.Stderr, "[UnixSocket] ", log.LstdFlags|log.Lmicroseconds),
}
// Start the queue processor
go w.processQueue()
// Try initial connection (socket may not exist yet - that's okay)
// Try initial connection silently (socket may not exist yet - that's okay)
conn, err := net.DialTimeout("unix", socketPath, w.dialTimeout)
if err == nil {
w.conn = conn
w.log("INFO", "connected to %s", socketPath)
} else {
w.log("WARNING", "initial connection to %s failed: %v (will retry on write)", socketPath, err)
}
return w, nil
}
// log emits a log message if the level is enabled
func (w *UnixSocketWriter) log(level, format string, args ...interface{}) {
if !w.isLogLevelEnabled(level) {
return
}
w.logger.Printf("[%s] UnixSocketWriter: "+format, append([]interface{}{level}, args...)...)
}
// isLogLevelEnabled checks if a log level should be emitted
func (w *UnixSocketWriter) isLogLevelEnabled(level string) bool {
level = strings.ToLower(level)
switch w.logLevel {
case "debug":
return true
case "info":
return level != "debug"
case "warn", "warning":
return level != "debug" && level != "info"
case "error":
return level == "error"
default:
return false
}
}
// processQueue handles queued writes with reconnection logic
func (w *UnixSocketWriter) processQueue() {
defer close(w.queueDone)
@ -317,12 +279,6 @@ func (w *UnixSocketWriter) processQueue() {
}
w.pendingMu.Unlock()
if consecutiveFailures >= w.maxReconnects {
w.log("ERROR", "max reconnection attempts reached for %s (failures: %d)", w.socketPath, consecutiveFailures)
} else if consecutiveFailures > 1 {
w.log("WARNING", "write failed to %s: %v (attempt %d/%d)", w.socketPath, err, consecutiveFailures, w.maxReconnects)
}
// Exponential backoff
if consecutiveFailures > w.maxReconnects {
time.Sleep(backoff)
@ -332,7 +288,6 @@ func (w *UnixSocketWriter) processQueue() {
}
}
} else {
w.log("DEBUG", "wrote %d bytes to %s", len(data), w.socketPath)
consecutiveFailures = 0
backoff = w.reconnectBackoff
// Try to flush pending data
@ -380,12 +335,10 @@ func (w *UnixSocketWriter) writeWithReconnect(data []byte) error {
return fmt.Errorf("failed to connect to socket %s: %w", w.socketPath, err)
}
w.conn = conn
w.log("INFO", "connected to %s", w.socketPath)
return nil
}
if err := ensureConn(); err != nil {
w.log("ERROR", "connection failed to %s: %v", w.socketPath, err)
return err
}
@ -398,7 +351,6 @@ func (w *UnixSocketWriter) writeWithReconnect(data []byte) error {
}
// Connection failed, try to reconnect
w.log("WARNING", "write failed, attempting reconnect to %s", w.socketPath)
_ = w.conn.Close()
w.conn = nil
@ -457,7 +409,6 @@ func (w *UnixSocketWriter) Close() error {
w.isClosed = true
if w.conn != nil {
w.log("INFO", "closing connection to %s", w.socketPath)
w.conn.Close()
w.conn = nil
}
@ -578,12 +529,7 @@ func (b *BuilderImpl) NewFromConfig(cfg api.AppConfig) (api.Writer, error) {
if socketPath == "" {
return nil, fmt.Errorf("unix_socket output requires 'socket_path' parameter")
}
// Get log level (default: error)
logLevel := outputCfg.Params["log_level"]
if logLevel == "" {
logLevel = "error"
}
writer, err = NewUnixSocketWriterWithConfigAndLogLevel(socketPath, DefaultDialTimeout, DefaultWriteTimeout, queueSize, logLevel)
writer, err = NewUnixSocketWriterWithConfig(socketPath, DefaultDialTimeout, DefaultWriteTimeout, queueSize)
if err != nil {
return nil, err
}

View File

@ -3,7 +3,7 @@
%if %{defined build_version}
%define spec_version %{build_version}
%else
%define spec_version 1.1.0
%define spec_version 1.1.1
%endif
Name: ja4sentinel
@ -31,7 +31,7 @@ Features:
- TLS ClientHello extraction
- JA4/JA3 fingerprint generation
- IP/TCP metadata enrichment
- Multiple output formats (stdout, file, UNIX socket)
- Multiple output formats (UNIX socket by default, stdout, file)
- Structured JSON logging for systemd/journald
- Compatible with Rocky Linux 8/9/10, RHEL, AlmaLinux
@ -122,6 +122,12 @@ fi
%dir /var/run/logcorrelator
%changelog
* Mon Mar 02 2026 Jacquin Antoine <rpm@arkel.fr> - 1.1.1-1
- Change default output from stdout to Unix socket (/var/run/logcorrelator/network.socket)
- Update config.yml.example to enable unix_socket output by default
- Comment out stdout output in default configuration
- Unix socket output configured with log_level: error by default
* Mon Mar 02 2026 Jacquin Antoine <rpm@arkel.fr> - 1.1.0-1
- Add logrotate configuration for automatic log file rotation
- Add SIGHUP signal handling for log file reopening (systemctl reload)