package logs import ( "fmt" "os" "path/filepath" "strings" "time" "github.com/bams/backend/internal/config" "github.com/bams/backend/internal/logger" ) type LogEntry struct { Timestamp time.Time `json:"timestamp"` Level string `json:"level"` Message string `json:"message"` } type Service struct { config *config.Config logger *logger.Logger } func NewService(cfg *config.Config, log *logger.Logger) *Service { return &Service{ config: cfg, logger: log, } } func (s *Service) GetLogs(service string, lines int) ([]*LogEntry, error) { var logPath string switch service { case "scst": logPath = "/var/log/scst.log" case "iscsi": logPath = "/var/log/kern.log" // iSCSI logs often in kernel log case "bacula": logPath = "/var/log/bacula/bacula.log" case "bams": logPath = "/var/log/bams/bams.log" default: return nil, fmt.Errorf("unknown service: %s", service) } if _, err := os.Stat(logPath); err != nil { return []*LogEntry{}, nil } data, err := os.ReadFile(logPath) if err != nil { return nil, fmt.Errorf("failed to read log file: %w", err) } entries := []*LogEntry{} logLines := strings.Split(string(data), "\n") // Get last N lines start := 0 if len(logLines) > lines { start = len(logLines) - lines } for i := start; i < len(logLines); i++ { if logLines[i] == "" { continue } entry := &LogEntry{ Timestamp: time.Now(), // Simplified - would parse from log line Level: "info", Message: logLines[i], } entries = append(entries, entry) } return entries, nil } func (s *Service) GenerateSupportBundle() ([]byte, error) { s.logger.Info("Generating support bundle") // Create temporary directory tmpDir := "/tmp/bams-bundle" os.MkdirAll(tmpDir, 0755) // Collect logs logs := []string{"scst", "iscsi", "bacula", "bams"} for _, service := range logs { logPath := s.getLogPath(service) if _, err := os.Stat(logPath); err == nil { data, _ := os.ReadFile(logPath) os.WriteFile(filepath.Join(tmpDir, fmt.Sprintf("%s.log", service)), data, 0644) } } // Collect configs configs := map[string]string{ "scst.conf": s.config.SCSTConfig, "bacula-sd.conf": s.config.BaculaConfig, } for name, path := range configs { if _, err := os.Stat(path); err == nil { data, _ := os.ReadFile(path) os.WriteFile(filepath.Join(tmpDir, name), data, 0644) } } // Collect system info systemInfo := fmt.Sprintf("OS: %s\n", "Linux") os.WriteFile(filepath.Join(tmpDir, "system-info.txt"), []byte(systemInfo), 0644) // Create zip (simplified - would use archive/zip) bundleData := []byte("Support bundle placeholder") // Cleanup os.RemoveAll(tmpDir) return bundleData, nil } func (s *Service) getLogPath(service string) string { switch service { case "scst": return "/var/log/scst.log" case "iscsi": return "/var/log/kern.log" case "bacula": return "/var/log/bacula/bacula.log" case "bams": return "/var/log/bams/bams.log" default: return "" } }