network/pkg/serverless/registry/invocation_logger.go
2026-01-20 10:03:55 +02:00

105 lines
2.6 KiB
Go

package registry
import (
"context"
"fmt"
"time"
"github.com/DeBrosOfficial/network/pkg/rqlite"
"github.com/google/uuid"
"go.uber.org/zap"
)
// InvocationLogger handles logging of function invocations and their logs.
type InvocationLogger struct {
db rqlite.Client
logger *zap.Logger
}
// NewInvocationLogger creates a new invocation logger.
func NewInvocationLogger(db rqlite.Client, logger *zap.Logger) *InvocationLogger {
return &InvocationLogger{
db: db,
logger: logger,
}
}
// Log records a function invocation and its logs to the database.
func (l *InvocationLogger) Log(ctx context.Context, inv *InvocationRecordData) error {
if inv == nil {
return nil
}
invQuery := `
INSERT INTO function_invocations (
id, function_id, request_id, trigger_type, caller_wallet,
input_size, output_size, started_at, completed_at,
duration_ms, status, error_message, memory_used_mb
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`
_, err := l.db.Exec(ctx, invQuery,
inv.ID, inv.FunctionID, inv.RequestID, inv.TriggerType, inv.CallerWallet,
inv.InputSize, inv.OutputSize, inv.StartedAt, inv.CompletedAt,
inv.DurationMS, inv.Status, inv.ErrorMessage, inv.MemoryUsedMB,
)
if err != nil {
return fmt.Errorf("failed to insert invocation record: %w", err)
}
if len(inv.Logs) > 0 {
for _, entry := range inv.Logs {
logID := uuid.New().String()
logQuery := `
INSERT INTO function_logs (
id, function_id, invocation_id, level, message, timestamp
) VALUES (?, ?, ?, ?, ?, ?)
`
_, err := l.db.Exec(ctx, logQuery,
logID, inv.FunctionID, inv.ID, entry.Level, entry.Message, entry.Timestamp,
)
if err != nil {
l.logger.Warn("Failed to insert function log", zap.Error(err))
}
}
}
return nil
}
// GetLogs retrieves logs for a function.
func (l *InvocationLogger) GetLogs(ctx context.Context, namespace, name string, limit int) ([]LogEntry, error) {
if limit <= 0 {
limit = 100
}
query := `
SELECT l.level, l.message, l.timestamp
FROM function_logs l
JOIN functions f ON l.function_id = f.id
WHERE f.namespace = ? AND f.name = ?
ORDER BY l.timestamp DESC
LIMIT ?
`
var results []struct {
Level string `db:"level"`
Message string `db:"message"`
Timestamp time.Time `db:"timestamp"`
}
if err := l.db.Query(ctx, &results, query, namespace, name, limit); err != nil {
return nil, fmt.Errorf("failed to query logs: %w", err)
}
logs := make([]LogEntry, len(results))
for i, res := range results {
logs[i] = LogEntry{
Level: res.Level,
Message: res.Message,
Timestamp: res.Timestamp,
}
}
return logs, nil
}