watchyourlan/backend/internal/clickhouse/clickhouse.go
2026-06-04 21:27:32 +02:00

73 lines
1.7 KiB
Go

package clickhouse
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"time"
"github.com/aceberg/WatchYourLAN/internal/models"
)
// Global HTTP Client to enable Keep-Alive Connection-Reuse
var httpClient = &http.Client{
Timeout: 10 * time.Second,
}
// Add - write data to ClickHouse
func Add(appConfig models.Conf, oneHist models.Host) {
if appConfig.ClickhouseAddr == "" {
return
}
db := appConfig.ClickhouseDB
if db == "" {
db = "default"
}
table := appConfig.ClickhouseTable
if table == "" {
table = "watch_your_lan"
}
insertSQL := fmt.Sprintf("INSERT INTO %s.%s (ts, known, mac, iface, ip, name) FORMAT JSONEachRow", db, table)
jsonRow := map[string]any{
"ts": time.Now().UTC().Format("2006-01-02 15:04:05"),
"known": oneHist.Known,
"mac": oneHist.Mac,
"iface": oneHist.Iface,
"ip": oneHist.IP,
"name": oneHist.Name,
}
jsonData, err := json.Marshal(jsonRow)
if err != nil {
slog.Error("ClickHouse JSON error", "err", err)
return
}
reqURL := fmt.Sprintf("%s/?query=%s", appConfig.ClickhouseAddr, url.QueryEscape(insertSQL))
req, err := http.NewRequest(http.MethodPost, reqURL, bytes.NewBuffer(jsonData))
if err != nil {
slog.Error("ClickHouse Request error", "err", err)
return
}
req.Header.Set("X-ClickHouse-User", appConfig.ClickhouseUser)
req.Header.Set("X-ClickHouse-Key", appConfig.ClickhousePassword)
res, err := httpClient.Do(req)
if err != nil {
slog.Error("ClickHouse network error", "err", err)
return
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if res.StatusCode != http.StatusOK {
slog.Error("ClickHouse HTTP error", "status", res.StatusCode, "body", string(body))
}
}