feat: setup logs retention by max file size
This commit is contained in:
1 parent
70c8492f4f
commit
f914eae3c5
44 files changed
+2316
-161
No files matched your search
@@ -8,11 +8,12 @@ import (
|
||||
|
||||
type GetActivityRetentionUseCase struct {
|
||||
settings audit.SettingsRepository
|
||||
events audit.Repository
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewGetActivityRetentionUseCase(settings audit.SettingsRepository, now func() time.Time) *GetActivityRetentionUseCase {
|
||||
return &GetActivityRetentionUseCase{settings, now}
|
||||
func NewGetActivityRetentionUseCase(settings audit.SettingsRepository, events audit.Repository, now func() time.Time) *GetActivityRetentionUseCase {
|
||||
return &GetActivityRetentionUseCase{settings, events, now}
|
||||
}
|
||||
|
||||
func (g *GetActivityRetentionUseCase) GetActivityRetention() (audit.Settings, error) {
|
||||
@@ -20,38 +21,80 @@ func (g *GetActivityRetentionUseCase) GetActivityRetention() (audit.Settings, er
|
||||
if err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
current.LogSizeBytes, err = g.events.SizeBytes()
|
||||
if err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
return current.WithNextCleanup(g.now()), nil
|
||||
}
|
||||
|
||||
type UpdateActivityRetentionCommand struct {
|
||||
Days *int
|
||||
MaxGB *int
|
||||
}
|
||||
|
||||
type UpdateActivityRetentionUseCase struct {
|
||||
settings audit.SettingsRepository
|
||||
events audit.Repository
|
||||
recorder audit.Recorder
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewUpdateActivityRetentionUseCase(settings audit.SettingsRepository, recorder audit.Recorder, now func() time.Time) *UpdateActivityRetentionUseCase {
|
||||
return &UpdateActivityRetentionUseCase{settings, recorder, now}
|
||||
func NewUpdateActivityRetentionUseCase(settings audit.SettingsRepository, events audit.Repository, recorder audit.Recorder, now func() time.Time) *UpdateActivityRetentionUseCase {
|
||||
return &UpdateActivityRetentionUseCase{settings, events, recorder, now}
|
||||
}
|
||||
|
||||
func (u *UpdateActivityRetentionUseCase) UpdateActivityRetention(ctx context.Context, days int) (audit.Settings, error) {
|
||||
if err := audit.ValidateRetentionDays(days); err != nil {
|
||||
return audit.Settings{}, err
|
||||
func (u *UpdateActivityRetentionUseCase) UpdateActivityRetention(ctx context.Context, command UpdateActivityRetentionCommand) (audit.Settings, error) {
|
||||
if command.Days == nil && command.MaxGB == nil {
|
||||
return audit.Settings{}, audit.ErrInvalidRetention
|
||||
}
|
||||
if command.Days != nil {
|
||||
if err := audit.ValidateRetentionDays(*command.Days); err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
}
|
||||
if command.MaxGB != nil {
|
||||
if err := audit.ValidateRetentionMaxGB(*command.MaxGB); err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
}
|
||||
current, err := u.settings.Get()
|
||||
if err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
if current.RetentionDays == days {
|
||||
size, err := u.events.SizeBytes()
|
||||
if err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
current.LogSizeBytes = size
|
||||
|
||||
updated := current
|
||||
if command.Days != nil {
|
||||
updated.RetentionDays = *command.Days
|
||||
}
|
||||
if command.MaxGB != nil {
|
||||
updated.RetentionMaxGB = *command.MaxGB
|
||||
}
|
||||
daysChanged := updated.RetentionDays != current.RetentionDays
|
||||
sizeChanged := updated.RetentionMaxGB != current.RetentionMaxGB
|
||||
if !daysChanged && !sizeChanged {
|
||||
return current.WithNextCleanup(u.now()), nil
|
||||
}
|
||||
if err := u.settings.SaveRetention(days); err != nil {
|
||||
if err := u.settings.SaveRetention(updated.RetentionDays, updated.RetentionMaxGB); err != nil {
|
||||
return audit.Settings{}, err
|
||||
}
|
||||
|
||||
event := audit.NewEvent(audit.ActionRetentionChanged, audit.CategorySystem)
|
||||
event.Params = map[string]any{audit.ParamFrom: current.RetentionDays, audit.ParamTo: days}
|
||||
event.Params = map[string]any{}
|
||||
if daysChanged {
|
||||
event.Params[audit.ParamFrom] = current.RetentionDays
|
||||
event.Params[audit.ParamTo] = updated.RetentionDays
|
||||
}
|
||||
if sizeChanged {
|
||||
event.Params[audit.ParamMaxGBFrom] = current.RetentionMaxGB
|
||||
event.Params[audit.ParamMaxGBTo] = updated.RetentionMaxGB
|
||||
}
|
||||
u.recorder.Record(ctx, event)
|
||||
|
||||
current.RetentionDays = days
|
||||
return current.WithNextCleanup(u.now()), nil
|
||||
return updated.WithNextCleanup(u.now()), nil
|
||||
}
|
||||
@@ -6,14 +6,22 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultCleanupBatchSize = 1000
|
||||
|
||||
type CleanupActivityUseCase struct {
|
||||
events audit.Repository
|
||||
settings audit.SettingsRepository
|
||||
recorder audit.Recorder
|
||||
events audit.Repository
|
||||
settings audit.SettingsRepository
|
||||
recorder audit.Recorder
|
||||
batchSize int
|
||||
}
|
||||
|
||||
func NewCleanupActivityUseCase(events audit.Repository, settings audit.SettingsRepository, recorder audit.Recorder) *CleanupActivityUseCase {
|
||||
return &CleanupActivityUseCase{events, settings, recorder}
|
||||
return &CleanupActivityUseCase{events, settings, recorder, defaultCleanupBatchSize}
|
||||
}
|
||||
|
||||
func (c *CleanupActivityUseCase) WithBatchSize(batchSize int) *CleanupActivityUseCase {
|
||||
c.batchSize = batchSize
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *CleanupActivityUseCase) Tick(now time.Time) (audit.CleanupResult, bool, error) {
|
||||
@@ -21,13 +29,23 @@ func (c *CleanupActivityUseCase) Tick(now time.Time) (audit.CleanupResult, bool,
|
||||
if err != nil {
|
||||
return audit.CleanupResult{}, false, err
|
||||
}
|
||||
if settings.RetentionDays == audit.ForeverRetentionDays || !settings.CleanupDue(now) {
|
||||
if !settings.HasRetentionLimit() || !settings.CleanupDue(now) {
|
||||
return audit.CleanupResult{}, false, nil
|
||||
}
|
||||
|
||||
removed, err := c.events.DeleteOlderThan(audit.RetentionCutoff(now, settings.RetentionDays))
|
||||
if err != nil {
|
||||
return audit.CleanupResult{}, false, err
|
||||
removed := 0
|
||||
if settings.RetentionDays != audit.ForeverRetentionDays {
|
||||
removed, err = c.events.DeleteOlderThan(audit.RetentionCutoff(now, settings.RetentionDays))
|
||||
if err != nil {
|
||||
return audit.CleanupResult{}, false, err
|
||||
}
|
||||
}
|
||||
if settings.RetentionMaxGB != audit.NoSizeLimitGB {
|
||||
trimmed, err := c.trimToSize(now, settings.MaxLogSizeBytes())
|
||||
if err != nil {
|
||||
return audit.CleanupResult{}, false, err
|
||||
}
|
||||
removed += trimmed
|
||||
}
|
||||
if err := c.settings.SaveLastCleanup(now, removed); err != nil {
|
||||
return audit.CleanupResult{}, false, err
|
||||
@@ -38,6 +56,28 @@ func (c *CleanupActivityUseCase) Tick(now time.Time) (audit.CleanupResult, bool,
|
||||
return audit.CleanupResult{Removed: removed}, true, nil
|
||||
}
|
||||
|
||||
func (c *CleanupActivityUseCase) trimToSize(now time.Time, limitBytes int64) (int, error) {
|
||||
guard := audit.GuardCutoff(now)
|
||||
removed := 0
|
||||
for {
|
||||
size, err := c.events.SizeBytes()
|
||||
if err != nil {
|
||||
return removed, err
|
||||
}
|
||||
if size <= limitBytes {
|
||||
return removed, nil
|
||||
}
|
||||
batch, err := c.events.DeleteOldest(c.batchSize, guard)
|
||||
if err != nil {
|
||||
return removed, err
|
||||
}
|
||||
if batch == 0 {
|
||||
return removed, nil
|
||||
}
|
||||
removed += batch
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CleanupActivityUseCase) recordCleanup(removed int) {
|
||||
event := audit.NewEvent(audit.ActionCleanup, audit.CategorySystem)
|
||||
event.Actor = audit.SystemActor()
|
||||
|
||||
Reference in new issue
Block a user