feat: add log collection and viewing system
Log Collectors (backend/internal/collectors/logs/): - LogEntry model with level, source, message, fields - Manager for coordinating multiple collectors - JournalCollector: systemd journal via journalctl CLI - FileCollector: tail log files with format parsing (plain, json, nginx) - DockerCollector: docker container logs via docker CLI - All collectors are pure Go (no CGO dependencies) Database Storage: - Add logs table with indexes for efficient querying - StoreLogs: batch insert log entries - QueryLogs: filter by agent, source, level, time, full-text search - DeleteOldLogs: retention cleanup - Implementations for both SQLite and PostgreSQL Frontend Log Viewer: - Log types and level color definitions - Logs API client with streaming support - /logs route with search, level filters, source filters - Live streaming mode for real-time log tailing - Paginated loading with load more 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,11 @@ type Database interface {
|
||||
|
||||
// Retention
|
||||
RunRetention(ctx context.Context) error
|
||||
|
||||
// Logs
|
||||
StoreLogs(ctx context.Context, entries []LogEntry) error
|
||||
QueryLogs(ctx context.Context, filter LogFilter) ([]LogEntry, int, error)
|
||||
DeleteOldLogs(ctx context.Context, before time.Time) (int, error)
|
||||
}
|
||||
|
||||
// MetricPoint represents a single metric data point.
|
||||
@@ -182,6 +187,42 @@ type AlertFilter struct {
|
||||
Offset int
|
||||
}
|
||||
|
||||
// LogLevel represents log severity.
|
||||
type LogLevel string
|
||||
|
||||
const (
|
||||
LogLevelDebug LogLevel = "debug"
|
||||
LogLevelInfo LogLevel = "info"
|
||||
LogLevelWarning LogLevel = "warning"
|
||||
LogLevelError LogLevel = "error"
|
||||
LogLevelFatal LogLevel = "fatal"
|
||||
)
|
||||
|
||||
// LogEntry represents a stored log entry.
|
||||
type LogEntry struct {
|
||||
ID int64 `json:"id"`
|
||||
AgentID string `json:"agentId"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Source string `json:"source"` // "journal", "file", "docker"
|
||||
SourceName string `json:"sourceName"` // Unit name, filename, container
|
||||
Level LogLevel `json:"level"`
|
||||
Message string `json:"message"`
|
||||
Fields map[string]string `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// LogFilter specifies criteria for querying logs.
|
||||
type LogFilter struct {
|
||||
AgentID string // Filter by agent
|
||||
Source string // Filter by source type (journal, file, docker)
|
||||
SourceName string // Filter by source name
|
||||
Level []LogLevel // Filter by levels
|
||||
Query string // Full-text search query
|
||||
From time.Time
|
||||
To time.Time
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
// RetentionConfig defines data retention policies.
|
||||
type RetentionConfig struct {
|
||||
// Raw metrics retention (default: 24 hours)
|
||||
@@ -195,6 +236,9 @@ type RetentionConfig struct {
|
||||
|
||||
// Hourly aggregation retention (default: 1 year)
|
||||
HourlyRetention time.Duration
|
||||
|
||||
// Log retention (default: 7 days)
|
||||
LogRetention time.Duration
|
||||
}
|
||||
|
||||
// DefaultRetentionConfig returns default retention settings.
|
||||
@@ -204,5 +248,6 @@ func DefaultRetentionConfig() RetentionConfig {
|
||||
OneMinuteRetention: 7 * 24 * time.Hour,
|
||||
FiveMinuteRetention: 30 * 24 * time.Hour,
|
||||
HourlyRetention: 365 * 24 * time.Hour,
|
||||
LogRetention: 7 * 24 * time.Hour,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user