Files
HellreigN/backend/internal/repository/log_repository.go
T
d3m0k1d 0f8b148279
ci-agent / build (push) Failing after 2m50s
fix: linter and docs
2026-04-04 19:44:16 +03:00

243 lines
4.9 KiB
Go

package repository
import (
"context"
"database/sql"
"fmt"
"sync"
"time"
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/storage"
)
type LogRepository struct {
mu sync.RWMutex
DB *sql.DB
}
func NewLogRepository() *LogRepository {
return &LogRepository{}
}
func (r *LogRepository) SetDB(db *sql.DB) {
r.mu.Lock()
defer r.mu.Unlock()
r.DB = db
}
func (r *LogRepository) IsConnected() bool {
r.mu.RLock()
defer r.mu.RUnlock()
return r.DB != nil
}
func (r *LogRepository) getDB() *sql.DB {
r.mu.RLock()
defer r.mu.RUnlock()
return r.DB
}
func (r *LogRepository) Init(ctx context.Context) error {
db := r.getDB()
if db == nil {
return nil
}
_, err := db.ExecContext(ctx, storage.CreateLogsTable)
return err
}
func (r *LogRepository) Insert(ctx context.Context, log storage.LogEntry) error {
db := r.getDB()
if db == nil {
return nil
}
_, err := db.ExecContext(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)
return err
}
func (r *LogRepository) InsertBatch(ctx context.Context, logs []storage.LogEntry) error {
db := r.getDB()
if db == nil {
return nil
}
if len(logs) == 0 {
return nil
}
// Build multi-row INSERT statement
query := "INSERT INTO logs (timestamp, level, service, agent, message) VALUES "
args := make([]interface{}, 0, len(logs)*5)
for i, log := range logs {
if i > 0 {
query += ", "
}
query += fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)",
i*5+1, i*5+2, i*5+3, i*5+4, i*5+5)
args = append(args, log.Timestamp, log.Level, log.Service, log.Agent, log.Message)
}
_, err := db.ExecContext(ctx, query, args...)
return err
}
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) {
db := r.getDB()
if db == nil {
return []storage.LogEntry{}, nil
}
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 := db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
logs := make([]storage.LogEntry, 0)
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) {
db := r.getDB()
if db == nil {
return []string{}, nil
}
rows, err := db.QueryContext(ctx, "SELECT DISTINCT service FROM logs ORDER BY service")
if err != nil {
return nil, err
}
defer rows.Close()
services := make([]string, 0)
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) {
db := r.getDB()
if db == nil {
return []string{}, nil
}
rows, err := db.QueryContext(ctx, "SELECT DISTINCT agent FROM logs ORDER BY agent")
if err != nil {
return nil, err
}
defer rows.Close()
agents := make([]string, 0)
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) {
db := r.getDB()
if db == nil {
return []string{}, nil
}
rows, err := db.QueryContext(ctx, "SELECT DISTINCT level FROM logs ORDER BY level")
if err != nil {
return nil, err
}
defer rows.Close()
levels := make([]string, 0)
for rows.Next() {
var level string
if err := rows.Scan(&level); err != nil {
return nil, err
}
levels = append(levels, level)
}
return levels, rows.Err()
}