package repository import ( "context" "time" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage" "github.com/ClickHouse/clickhouse-go/v2/lib/driver" ) type LogRepository struct { Conn driver.Conn } func NewLogRepository(conn driver.Conn) *LogRepository { return &LogRepository{Conn: conn} } func (r *LogRepository) Init(ctx context.Context) error { return r.Conn.Exec(ctx, storage.CreateLogsTable) } func (r *LogRepository) Insert(ctx context.Context, log storage.LogEntry) error { return r.Conn.Exec(ctx, ` INSERT INTO logs (timestamp, level, service, agent, message) VALUES ($1, $2, $3, $4, $5) `, log.Timestamp, log.Level, log.Service, log.Agent, log.Message) } func (r *LogRepository) InsertBatch(ctx context.Context, logs []storage.LogEntry) error { batch, err := r.Conn.PrepareBatch(ctx, "INSERT INTO logs (timestamp, level, service, agent, message)") if err != nil { return err } for _, log := range logs { if err := batch.Append(log.Timestamp, log.Level, log.Service, log.Agent, log.Message); err != nil { return err } } return batch.Send() } type LogFilter struct { Level string Service string Agent string DateFrom time.Time DateTo time.Time Limit int Offset int } func (r *LogRepository) Search(ctx context.Context, filter LogFilter) ([]storage.LogEntry, error) { query := "SELECT timestamp, level, service, agent, message FROM logs WHERE 1=1" args := make([]interface{}, 0) argIdx := 1 if filter.Level != "" { query += " AND level = $" + string(rune('0'+argIdx)) args = append(args, filter.Level) argIdx++ } if filter.Service != "" { query += " AND service = $" + string(rune('0'+argIdx)) args = append(args, filter.Service) argIdx++ } if filter.Agent != "" { query += " AND agent = $" + string(rune('0'+argIdx)) args = append(args, filter.Agent) argIdx++ } if !filter.DateFrom.IsZero() { query += " AND timestamp >= $" + string(rune('0'+argIdx)) args = append(args, filter.DateFrom) argIdx++ } if !filter.DateTo.IsZero() { query += " AND timestamp <= $" + string(rune('0'+argIdx)) args = append(args, filter.DateTo) argIdx++ } query += " ORDER BY timestamp DESC" if filter.Limit > 0 { query += " LIMIT $" + string(rune('0'+argIdx)) args = append(args, filter.Limit) argIdx++ } else { query += " LIMIT 100" } if filter.Offset > 0 { query += " OFFSET $" + string(rune('0'+argIdx)) args = append(args, filter.Offset) } rows, err := r.Conn.Query(ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var logs []storage.LogEntry for rows.Next() { var log storage.LogEntry if err := rows.Scan(&log.Timestamp, &log.Level, &log.Service, &log.Agent, &log.Message); err != nil { return nil, err } logs = append(logs, log) } return logs, rows.Err() } func (r *LogRepository) GetDistinctServices(ctx context.Context) ([]string, error) { rows, err := r.Conn.Query(ctx, "SELECT DISTINCT service FROM logs ORDER BY service") if err != nil { return nil, err } defer rows.Close() var services []string for rows.Next() { var service string if err := rows.Scan(&service); err != nil { return nil, err } services = append(services, service) } return services, rows.Err() } func (r *LogRepository) GetDistinctAgents(ctx context.Context) ([]string, error) { rows, err := r.Conn.Query(ctx, "SELECT DISTINCT agent FROM logs ORDER BY agent") if err != nil { return nil, err } defer rows.Close() var agents []string for rows.Next() { var agent string if err := rows.Scan(&agent); err != nil { return nil, err } agents = append(agents, agent) } return agents, rows.Err() } func (r *LogRepository) GetDistinctLevels(ctx context.Context) ([]string, error) { rows, err := r.Conn.Query(ctx, "SELECT DISTINCT level FROM logs ORDER BY level") if err != nil { return nil, err } defer rows.Close() var levels []string for rows.Next() { var level string if err := rows.Scan(&level); err != nil { return nil, err } levels = append(levels, level) } return levels, rows.Err() }