package auditing import ( "RenewCMS/internal/domain/audit" "context" "log" "time" ) type Recorder struct { repository audit.Repository now func() time.Time logger *log.Logger } var _ audit.Recorder = &Recorder{} func NewRecorder(repository audit.Repository, now func() time.Time, logger *log.Logger) *Recorder { return &Recorder{repository, now, logger} } func (r *Recorder) Record(ctx context.Context, event audit.Event) { defer func() { if recovered := recover(); recovered != nil { r.logger.Printf("audit: writing the %s event panicked: %v", event.Action, recovered) } }() event = r.complete(ctx, event).Truncated() if err := event.Validate(); err != nil { r.logger.Printf("audit: dropped the %s event: %v", event.Action, err) return } if _, err := r.repository.Append(event); err != nil { r.logger.Printf("audit: failed to write the %s event: %v", event.Action, err) } } func (r *Recorder) complete(ctx context.Context, event audit.Event) audit.Event { origin, _ := audit.OriginFrom(ctx) if event.Actor.Type == "" { event.Actor = origin.Actor } if event.Source == "" { event.Source = origin.Source } if event.IP == nil && origin.IP != "" { ip := origin.IP event.IP = &ip } if event.UserAgent == nil && origin.UserAgent != "" { userAgent := origin.UserAgent event.UserAgent = &userAgent } event.CreatedAt = r.now().UTC() return event }