CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 56s
CI / bird2 (push) Successful in 14s
CI / release (push) Successful in 20s
Added new endpoints for estimating and executing runtime log auto-cleanup based on tenant settings. Introduced configuration options for auto-cleanup policies, including scheduling and file size limits. Updated the API documentation and UI components to reflect these changes, improving user interaction with runtime log management. Enhanced error handling and added new UI elements for better visibility of audit logs and cleanup actions.
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package runtimelogs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"evobgp/internal/store"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
// SchedulerDeps configures the runtime log auto-cleanup background scheduler.
|
|
type SchedulerDeps struct {
|
|
Service *Service
|
|
Store store.Backend
|
|
PolicyTenant string
|
|
}
|
|
|
|
// ResolvePolicyTenant picks the tenant whose settings drive auto-cleanup.
|
|
func ResolvePolicyTenant(st store.Backend, explicit string) (string, error) {
|
|
explicit = strings.TrimSpace(explicit)
|
|
if explicit != "" {
|
|
return explicit, nil
|
|
}
|
|
if st == nil {
|
|
return "", fmt.Errorf("runtimelogs: store required")
|
|
}
|
|
ids, err := st.ListTenantIDs()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
for _, id := range ids {
|
|
settings, err := st.ListGlobalSettings(id)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if PolicyFromSettings(settings).Enabled {
|
|
return id, nil
|
|
}
|
|
}
|
|
if len(ids) > 0 {
|
|
return ids[0], nil
|
|
}
|
|
return "", fmt.Errorf("runtimelogs: no tenants configured")
|
|
}
|
|
|
|
// StartAutoCleanupScheduler runs periodic auto-cleanup on evobgp-all when FS is available.
|
|
func StartAutoCleanupScheduler(ctx context.Context, deps SchedulerDeps, tick time.Duration) {
|
|
if deps.Service == nil || !deps.Service.Available() {
|
|
log.Printf("runtimelogs: auto-cleanup scheduler disabled (FS unavailable)")
|
|
return
|
|
}
|
|
if deps.Store == nil {
|
|
log.Printf("runtimelogs: auto-cleanup scheduler disabled (no store)")
|
|
return
|
|
}
|
|
if tick <= 0 {
|
|
tick = 30 * time.Second
|
|
}
|
|
|
|
go func() {
|
|
parser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
|
|
var mu sync.Mutex
|
|
lastFired := map[string]time.Time{}
|
|
|
|
t := time.NewTicker(tick)
|
|
defer t.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-t.C:
|
|
tenantID, err := ResolvePolicyTenant(deps.Store, deps.PolicyTenant)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
settings, err := deps.Store.ListGlobalSettings(tenantID)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
policy := PolicyFromSettings(settings)
|
|
if !policy.Enabled {
|
|
continue
|
|
}
|
|
sched, err := parser.Parse(policy.Schedule)
|
|
if err != nil {
|
|
log.Printf("runtimelogs: invalid cron %q: %v", policy.Schedule, err)
|
|
continue
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
mu.Lock()
|
|
prev := lastFired[policy.Schedule]
|
|
if prev.IsZero() {
|
|
prev = now.Add(-time.Minute)
|
|
}
|
|
next := sched.Next(prev)
|
|
if next.After(now) {
|
|
mu.Unlock()
|
|
continue
|
|
}
|
|
slot := next.Unix() / 60
|
|
if lf, ok := lastFired[policy.Schedule]; ok && lf.Unix()/60 == slot {
|
|
mu.Unlock()
|
|
continue
|
|
}
|
|
lastFired[policy.Schedule] = next
|
|
mu.Unlock()
|
|
|
|
_, err = RunAutoCleanup(ctx, AutoCleanupDeps{
|
|
Service: deps.Service,
|
|
Store: deps.Store,
|
|
TenantID: tenantID,
|
|
}, policy, false, "scheduler")
|
|
if err != nil {
|
|
log.Printf("runtimelogs: auto-cleanup run failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
log.Printf("runtimelogs: auto-cleanup scheduler started (tick=%s)", tick)
|
|
}
|