Files
BAMS/backend/internal/services/audit/audit.go

75 lines
1.6 KiB
Go

package audit
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
"github.com/bams/backend/internal/config"
"github.com/bams/backend/internal/logger"
)
type AuditEntry struct {
Timestamp time.Time `json:"timestamp"`
User string `json:"user"`
Action string `json:"action"`
Resource string `json:"resource"`
Result string `json:"result"` // "success" or "failure"
Details string `json:"details,omitempty"`
}
type Service struct {
config *config.Config
logger *logger.Logger
logFile *os.File
}
func NewService(cfg *config.Config, log *logger.Logger) *Service {
auditDir := filepath.Join(cfg.DataDir, "audit")
os.MkdirAll(auditDir, 0755)
logPath := filepath.Join(auditDir, fmt.Sprintf("audit-%s.log", time.Now().Format("2006-01-02")))
file, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0640)
if err != nil {
log.Error("Failed to open audit log", "error", err)
}
return &Service{
config: cfg,
logger: log,
logFile: file,
}
}
func (s *Service) Log(user, action, resource, result, details string) {
entry := AuditEntry{
Timestamp: time.Now(),
User: user,
Action: action,
Resource: resource,
Result: result,
Details: details,
}
data, err := json.Marshal(entry)
if err != nil {
s.logger.Error("Failed to marshal audit entry", "error", err)
return
}
if s.logFile != nil {
s.logFile.WriteString(string(data) + "\n")
s.logFile.Sync()
}
s.logger.Info("Audit log", "user", user, "action", action, "resource", resource, "result", result)
}
func (s *Service) Close() {
if s.logFile != nil {
s.logFile.Close()
}
}