Files
LazyPM/pkg/task/metrics_store.go
2026-03-18 15:20:16 +01:00

93 lines
2.1 KiB
Go

package task
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"os"
"path/filepath"
"time"
"github.com/LazyBachelor/LazyPM/internal/models"
"go.mongodb.org/mongo-driver/v2/bson"
)
type MetricsStore interface {
Append(ctx context.Context, taskName string, run models.TaskRunMetrics) error
}
type FileMetricsStore struct {
path string
participantID bson.ObjectID
logger *slog.Logger
}
func NewFileMetricsStore(path string, participantID bson.ObjectID, logger *slog.Logger) *FileMetricsStore {
return &FileMetricsStore{
path: path,
participantID: participantID,
logger: logger,
}
}
func (s *FileMetricsStore) Append(ctx context.Context, taskName string, run models.TaskRunMetrics) error {
if s.path == "" {
return nil
}
dir := filepath.Dir(s.path)
if dir != "." {
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("create metrics directory: %w", err)
}
}
metrics := models.TaskMetricsFile{
ID: bson.NewObjectID(),
ParticipantID: s.participantID,
TaskName: taskName,
Runs: []models.TaskRunMetrics{},
}
if err := readMetrics(&metrics, s.path); err != nil {
return err
}
if metrics.TaskName == "" {
metrics.TaskName = taskName
}
run.RunID = len(metrics.Runs) + 1
metrics.Runs = append(metrics.Runs, run)
metrics.Summary = buildTaskStatsSummary(metrics.Runs)
metrics.UpdatedAt = time.Now()
data, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
return fmt.Errorf("encode metrics: %w", err)
}
if err := os.WriteFile(s.path, data, 0o644); err != nil {
return fmt.Errorf("write metrics file: %w", err)
}
if s.logger != nil {
s.logger.Info("task metrics persisted", "path", s.path, "task", taskName, "run_id", run.RunID)
}
return nil
}
func readMetrics(metrics *models.TaskMetricsFile, path string) error {
if bytes, err := os.ReadFile(path); err == nil {
if len(bytes) > 0 {
if err := json.Unmarshal(bytes, metrics); err != nil {
return fmt.Errorf("failed to parse metrics file: %w", err)
}
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to read metrics file: %w", err)
}
return nil
}