imc-vibe/backend/internal/mail/logs.go
Christoph Haas 53ce3b06ae Add CLI flags for setup and server configuration
- Add --setup flag to create admin user
- Add --admin-user and --admin-password for setup
- Generate cryptographically random passwords for --setup
- Add --bind and --port flags for server binding
- Add BIND env var support
- Add SMTP email service for password reset
- Add password reset token storage
- Add auth header to queue/logs frontend pages
- Fix journalctl timestamp format
- Fix logs to return empty array instead of error when no entries
- Fix queue handler to return proper error message
- Hide Users/Aliases nav links when no domain selected
2026-03-22 01:17:43 +01:00

91 lines
1.8 KiB
Go

package mail
import (
"bufio"
"bytes"
"context"
"os/exec"
"regexp"
"strings"
"time"
)
type LogEntry struct {
Timestamp string `json:"timestamp"`
Priority string `json:"priority"`
Message string `json:"message"`
}
func GetLogs(hours int, filter string) ([]LogEntry, error) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
args := []string{
"-u", "postfix",
"--since", formatDuration(hours),
"--no-pager",
}
cmd := exec.CommandContext(ctx, "journalctl", args...)
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return nil, err
}
var entries []LogEntry
scanner := bufio.NewScanner(&out)
priorityRegex := regexp.MustCompile(`\[([^\]]+)\]`)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.Contains(line, "-- No entries") || line == "" {
continue
}
if filter != "" && !strings.Contains(strings.ToLower(line), strings.ToLower(filter)) {
continue
}
parts := strings.SplitN(line, " ", 4)
if len(parts) < 4 {
continue
}
timestamp := parts[0] + " " + parts[1]
matches := priorityRegex.FindStringSubmatch(parts[2])
priority := "info"
if len(matches) > 1 {
priority = matches[1]
} else if strings.Contains(parts[2], "err") {
priority = "err"
} else if strings.Contains(parts[2], "warning") || strings.Contains(parts[2], "warn") {
priority = "warning"
}
message := parts[3]
if filter != "" && !strings.Contains(strings.ToLower(message), strings.ToLower(filter)) {
continue
}
entries = append(entries, LogEntry{
Timestamp: timestamp,
Priority: priority,
Message: message,
})
}
if entries == nil {
entries = []LogEntry{}
}
return entries, nil
}
func formatDuration(hours int) string {
return time.Now().Add(-time.Duration(hours) * time.Hour).Format("2006-01-02 15:04:05")
}