package main import ( "bytes" "encoding/json" "fmt" "net/http" "time" ) type LokiLogger struct { url string client *http.Client } func NewLokiLogger(url string) *LokiLogger { return &LokiLogger{ url: url, client: &http.Client{Timeout: 10 * time.Second}, } } type logEntry struct { Timestamp int64 `json:"ts"` Line string `json:"line"` } type logStream struct { Labels string `json:"labels"` Entries []logEntry `json:"entries"` } type pushRequest struct { Streams []logStream `json:"streams"` } func (l *LokiLogger) Log(label string, message string) error { entry := logEntry{ Timestamp: time.Now().UnixNano(), Line: message, } stream := logStream{ Labels: label, Entries: []logEntry{entry}, } reqBody := pushRequest{ Streams: []logStream{stream}, } body, err := json.Marshal(reqBody) if err != nil { return err } req, err := http.NewRequest("POST", l.url, bytes.NewBuffer(body)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") resp, err := l.client.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusNoContent { return fmt.Errorf("unexpected status code: %d", resp.StatusCode) } return nil } func (l *LokiLogger) Close() { // No cleanup needed for pure HTTP client }