Files
Charon/backend/internal/logger/logger.go
T
akanealw eec8c28fb3
Go Benchmark / Performance Regression Check (push) Has been cancelled
Cerberus Integration / Cerberus Security Stack Integration (push) Has been cancelled
Upload Coverage to Codecov / Backend Codecov Upload (push) Has been cancelled
Upload Coverage to Codecov / Frontend Codecov Upload (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (go) (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Has been cancelled
CrowdSec Integration / CrowdSec Bouncer Integration (push) Has been cancelled
Docker Build, Publish & Test / build-and-push (push) Has been cancelled
Quality Checks / Auth Route Protection Contract (push) Has been cancelled
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Has been cancelled
Quality Checks / Backend (Go) (push) Has been cancelled
Quality Checks / Frontend (React) (push) Has been cancelled
Rate Limit integration / Rate Limiting Integration (push) Has been cancelled
Security Scan (PR) / Trivy Binary Scan (push) Has been cancelled
Supply Chain Verification (PR) / Verify Supply Chain (push) Has been cancelled
WAF integration / Coraza WAF Integration (push) Has been cancelled
Docker Build, Publish & Test / Security Scan PR Image (push) Has been cancelled
Repo Health Check / Repo health (push) Has been cancelled
History Rewrite Dry-Run / Dry-run preview for history rewrite (push) Has been cancelled
Prune Renovate Branches / prune (push) Has been cancelled
Renovate / renovate (push) Has been cancelled
Nightly Build & Package / sync-development-to-nightly (push) Has been cancelled
Nightly Build & Package / Trigger Nightly Validation Workflows (push) Has been cancelled
Nightly Build & Package / build-and-push-nightly (push) Has been cancelled
Nightly Build & Package / test-nightly-image (push) Has been cancelled
Nightly Build & Package / verify-nightly-supply-chain (push) Has been cancelled
Update GeoLite2 Checksum / update-checksum (push) Has been cancelled
Container Registry Prune / prune-ghcr (push) Has been cancelled
Container Registry Prune / prune-dockerhub (push) Has been cancelled
Container Registry Prune / summarize (push) Has been cancelled
Supply Chain Verification / Verify SBOM (push) Has been cancelled
Supply Chain Verification / Verify Release Artifacts (push) Has been cancelled
Supply Chain Verification / Verify Docker Image Supply Chain (push) Has been cancelled
Monitor Caddy Major Release / check-caddy-major (push) Has been cancelled
Weekly Nightly to Main Promotion / Verify Nightly Branch Health (push) Has been cancelled
Weekly Nightly to Main Promotion / Create Promotion PR (push) Has been cancelled
Weekly Nightly to Main Promotion / Trigger Missing Required Checks (push) Has been cancelled
Weekly Nightly to Main Promotion / Notify on Failure (push) Has been cancelled
Weekly Nightly to Main Promotion / Workflow Summary (push) Has been cancelled
Weekly Security Rebuild / Security Rebuild & Scan (push) Has been cancelled
changed perms
2026-04-22 18:19:14 +00:00

128 lines
3.1 KiB
Go
Executable File

// Package logger provides logging functionality with broadcast capabilities for real-time log streaming.
package logger
import (
"io"
"os"
"sync"
"github.com/sirupsen/logrus"
)
var _log = logrus.New()
var _broadcastHook *BroadcastHook
// Init initializes the global logger with output writer and debug level.
func Init(debug bool, out io.Writer) {
if out == nil {
out = os.Stdout
}
_log.SetOutput(out)
if debug {
_log.SetLevel(logrus.DebugLevel)
_log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
} else {
_log.SetLevel(logrus.InfoLevel)
_log.SetFormatter(&logrus.JSONFormatter{})
}
// Initialize and add broadcast hook
_broadcastHook = NewBroadcastHook()
_log.AddHook(_broadcastHook)
}
// Log returns a standard logger entry to use across packages.
func Log() *logrus.Entry {
return logrus.NewEntry(_log)
}
// WithFields returns a logger entry with provided fields.
func WithFields(fields logrus.Fields) *logrus.Entry {
return Log().WithFields(fields)
}
// GetBroadcastHook returns the global broadcast hook instance.
func GetBroadcastHook() *BroadcastHook {
if _broadcastHook == nil {
_broadcastHook = NewBroadcastHook()
_log.AddHook(_broadcastHook)
}
return _broadcastHook
}
// BroadcastHook implements logrus.Hook to broadcast log entries to active listeners.
type BroadcastHook struct {
mu sync.RWMutex
listeners map[string]chan *logrus.Entry
}
// NewBroadcastHook creates a new BroadcastHook instance.
func NewBroadcastHook() *BroadcastHook {
return &BroadcastHook{
listeners: make(map[string]chan *logrus.Entry),
}
}
// Levels returns all log levels that this hook should fire for.
func (h *BroadcastHook) Levels() []logrus.Level {
return logrus.AllLevels
}
// Fire broadcasts the log entry to all active listeners.
func (h *BroadcastHook) Fire(entry *logrus.Entry) error {
h.mu.RLock()
defer h.mu.RUnlock()
// Broadcast to all listeners (non-blocking)
for _, ch := range h.listeners {
select {
case ch <- entry:
default:
// Skip if channel is full (prevents blocking)
}
}
return nil
}
// Subscribe adds a new listener and returns a channel for receiving log entries.
// The caller must call Unsubscribe when done to prevent resource leaks.
func (h *BroadcastHook) Subscribe(id string) <-chan *logrus.Entry {
h.mu.Lock()
defer h.mu.Unlock()
ch := make(chan *logrus.Entry, 100) // Buffer to prevent blocking
h.listeners[id] = ch
return ch
}
// Unsubscribe removes a listener and closes its channel.
func (h *BroadcastHook) Unsubscribe(id string) {
h.mu.Lock()
defer h.mu.Unlock()
if ch, ok := h.listeners[id]; ok {
close(ch)
delete(h.listeners, id)
}
}
// ActiveListeners returns the count of active listeners.
func (h *BroadcastHook) ActiveListeners() int {
h.mu.RLock()
defer h.mu.RUnlock()
return len(h.listeners)
}
// ListenerIDs returns the IDs of all active listeners. Intended for tests/observability only.
func (h *BroadcastHook) ListenerIDs() []string {
h.mu.RLock()
defer h.mu.RUnlock()
ids := make([]string, 0, len(h.listeners))
for id := range h.listeners {
ids = append(ids, id)
}
return ids
}