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, "/usr/bin/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") }