Files
MyClub/internal/services/error_reporter.go
T
Tomas Dvorak 8762bde4bf dev day #89
2025-11-11 10:29:30 +01:00

105 lines
3.0 KiB
Go

package services
import (
"bytes"
"context"
"encoding/json"
"net/http"
"os"
"time"
"strings"
"fotbal-club/internal/config"
"fotbal-club/pkg/httpclient"
)
type ErrorEvent struct {
Origin string `json:"origin"`
Language string `json:"language"`
Severity string `json:"severity,omitempty"`
Message string `json:"message"`
Stack string `json:"stack,omitempty"`
Component string `json:"component,omitempty"`
File string `json:"file,omitempty"`
Line int `json:"line,omitempty"`
Column int `json:"column,omitempty"`
URL string `json:"url,omitempty"`
Method string `json:"method,omitempty"`
Status int `json:"status,omitempty"`
RequestID string `json:"request_id,omitempty"`
UserID *uint `json:"user_id,omitempty"`
Session string `json:"session_token,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Context map[string]interface{} `json:"context,omitempty"`
Env string `json:"env,omitempty"`
Version string `json:"version,omitempty"`
Hostname string `json:"hostname,omitempty"`
OccurredAt time.Time `json:"occurred_at"`
}
type ErrorReporter struct {
client *http.Client
endpoint string
token string
hostname string
appEnv string
}
func NewErrorReporter(cfg *config.Config) *ErrorReporter {
if cfg == nil {
return nil
}
endpoint := cfg.ErrorIngestURL
if strings.TrimSpace(endpoint) == "" {
if cfg.AppEnv == "production" {
endpoint = "https://errors.tdvorak.dev/api/v1/errors"
} else {
base := strings.TrimRight(cfg.PublicAPIBaseURL, "/")
if base != "" {
endpoint = base + "/errors"
}
}
}
if strings.TrimSpace(endpoint) == "" {
return nil
}
host, _ := os.Hostname()
return &ErrorReporter{
client: httpclient.FastClient(),
endpoint: endpoint,
token: cfg.ErrorIngestToken,
hostname: host,
appEnv: cfg.AppEnv,
}
}
func (r *ErrorReporter) Report(ctx context.Context, ev *ErrorEvent) {
if r == nil || ev == nil || r.endpoint == "" {
return
}
if ev.Env == "" {
ev.Env = r.appEnv
}
if ev.Hostname == "" {
ev.Hostname = r.hostname
}
if ev.OccurredAt.IsZero() {
ev.OccurredAt = time.Now()
}
b, err := json.Marshal(ev)
if err != nil {
return
}
ctx2, cancel := context.WithTimeout(ctx, 4*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx2, http.MethodPost, r.endpoint, bytes.NewReader(b))
if err != nil {
return
}
req.Header.Set("Content-Type", "application/json")
if r.token != "" {
req.Header.Set("Authorization", "Bearer "+r.token)
}
_, _ = r.client.Do(req)
}