add clickhouse
This commit is contained in:
parent
ca9f644bcc
commit
3bd38b6367
10 changed files with 188 additions and 0 deletions
|
|
@ -86,3 +86,19 @@ func savePrometheusHandler(c *gin.Context) {
|
|||
|
||||
c.Redirect(http.StatusFound, c.Request.Referer())
|
||||
}
|
||||
|
||||
func saveClickhouseHandler(c *gin.Context) {
|
||||
|
||||
conf.AppConfig.ClickhouseAddr = c.PostForm("addr")
|
||||
conf.AppConfig.ClickhouseUser = c.PostForm("user")
|
||||
conf.AppConfig.ClickhousePassword = c.PostForm("password")
|
||||
conf.AppConfig.ClickhouseDB = c.PostForm("db")
|
||||
conf.AppConfig.ClickhouseTable = c.PostForm("table")
|
||||
|
||||
enable := c.PostForm("enable")
|
||||
conf.AppConfig.ClickhouseEnable = enable == "on"
|
||||
|
||||
conf.Write(conf.AppConfig)
|
||||
|
||||
c.Redirect(http.StatusFound, c.Request.Referer())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ func Routes(router *gin.Engine) {
|
|||
r0.POST("/config_settings/", saveSettingsHandler) // config.go
|
||||
r0.POST("/config_influx/", saveInfluxHandler) // config.go
|
||||
r0.POST("/config_prometheus/", savePrometheusHandler) // config.go
|
||||
r0.POST("/config_clickhouse/", saveClickhouseHandler) // config.go
|
||||
}
|
||||
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
|
|
|||
73
backend/internal/clickhouse/clickhouse.go
Normal file
73
backend/internal/clickhouse/clickhouse.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
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))
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,8 @@ func read(path string) (config models.Conf) {
|
|||
|
||||
viper.SetDefault("PROMETHEUS_ENABLE", false)
|
||||
|
||||
viper.SetDefault("CLICKHOUSE_ENABLE", false)
|
||||
|
||||
viper.SetConfigFile(path)
|
||||
viper.SetConfigType("yaml")
|
||||
err := viper.ReadInConfig()
|
||||
|
|
@ -63,6 +65,13 @@ func read(path string) (config models.Conf) {
|
|||
|
||||
config.PrometheusEnable = viper.GetBool("PROMETHEUS_ENABLE")
|
||||
|
||||
config.ClickhouseEnable = viper.GetBool("CLICKHOUSE_ENABLE")
|
||||
config.ClickhouseAddr, _ = viper.Get("CLICKHOUSE_ADDR").(string)
|
||||
config.ClickhouseUser, _ = viper.Get("CLICKHOUSE_USER").(string)
|
||||
config.ClickhousePassword, _ = viper.Get("CLICKHOUSE_PASSWORD").(string)
|
||||
config.ClickhouseDB, _ = viper.Get("CLICKHOUSE_DB").(string)
|
||||
config.ClickhouseTable, _ = viper.Get("CLICKHOUSE_TABLE").(string)
|
||||
|
||||
joined := viper.Get("ARP_STRS_JOINED").(string)
|
||||
// slog.Info("ARP_STRS_JOINED: " + joined)
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,13 @@ func Write(config models.Conf) {
|
|||
|
||||
viper.Set("PROMETHEUS_ENABLE", config.PrometheusEnable)
|
||||
|
||||
viper.Set("clickhouse_enable", config.ClickhouseEnable)
|
||||
viper.Set("clickhouse_addr", config.ClickhouseAddr)
|
||||
viper.Set("clickhouse_user", config.ClickhouseUser)
|
||||
viper.Set("clickhouse_password", config.ClickhousePassword)
|
||||
viper.Set("clickhouse_db", config.ClickhouseDB)
|
||||
viper.Set("clickhouse_table", config.ClickhouseTable)
|
||||
|
||||
err := viper.WriteConfig()
|
||||
check.IfError(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ type Conf struct {
|
|||
InfluxSkipTLS bool
|
||||
// Prometheus
|
||||
PrometheusEnable bool
|
||||
// Clickhouse
|
||||
ClickhouseEnable bool
|
||||
ClickhouseAddr string
|
||||
ClickhouseUser string
|
||||
ClickhousePassword string
|
||||
ClickhouseDB string
|
||||
ClickhouseTable string
|
||||
}
|
||||
|
||||
// Host - one host
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/aceberg/WatchYourLAN/internal/arp"
|
||||
"github.com/aceberg/WatchYourLAN/internal/check"
|
||||
"github.com/aceberg/WatchYourLAN/internal/clickhouse"
|
||||
"github.com/aceberg/WatchYourLAN/internal/conf"
|
||||
"github.com/aceberg/WatchYourLAN/internal/gdb"
|
||||
"github.com/aceberg/WatchYourLAN/internal/influx"
|
||||
|
|
@ -79,6 +80,9 @@ func compareHosts(foundHostsMap map[string]models.Host) {
|
|||
if conf.AppConfig.PrometheusEnable {
|
||||
prometheus.Add(aHost)
|
||||
}
|
||||
if conf.AppConfig.ClickhouseEnable {
|
||||
clickhouse.Add(conf.AppConfig, aHost)
|
||||
}
|
||||
}
|
||||
|
||||
for _, fHost := range foundHostsMap {
|
||||
|
|
|
|||
54
frontend/src/components/Config/Clickhouse.tsx
Normal file
54
frontend/src/components/Config/Clickhouse.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { apiPath } from "../../functions/api"
|
||||
import { appConfig } from "../../functions/exports"
|
||||
|
||||
function Clickhouse() {
|
||||
|
||||
return (
|
||||
<div class="card border-primary">
|
||||
<div class="card-header">ClickHouse config</div>
|
||||
<div class="card-body table-responsive">
|
||||
<form action={apiPath + '/api/config_clickhouse/'} method="post">
|
||||
<table class="table table-borderless"><tbody>
|
||||
<tr>
|
||||
<td>Enable</td>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
{appConfig().ClickhouseEnable
|
||||
? <input class="form-check-input" type="checkbox" name="enable" checked></input>
|
||||
: <input class="form-check-input" type="checkbox" name="enable"></input>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Address</td>
|
||||
<td><input name="addr" type="text" class="form-control" value={appConfig().ClickhouseAddr}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>User</td>
|
||||
<td><input name="user" type="text" class="form-control" value={appConfig().ClickhouseUser}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password</td>
|
||||
<td><input name="password" type="password" class="form-control" value={appConfig().ClickhousePassword}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Database</td>
|
||||
<td><input name="db" type="text" class="form-control" value={appConfig().ClickhouseDB}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Table</td>
|
||||
<td><input name="table" type="text" class="form-control" value={appConfig().ClickhouseTable}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button type="submit" class="btn btn-primary">Save</button></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Clickhouse
|
||||
|
|
@ -39,6 +39,13 @@ export interface Conf {
|
|||
InfluxSkipTLS: boolean;
|
||||
// Prometheus
|
||||
PrometheusEnable: boolean;
|
||||
// Clickhouse
|
||||
ClickhouseEnable: boolean;
|
||||
ClickhouseAddr: string;
|
||||
ClickhouseUser: string;
|
||||
ClickhousePassword: string;
|
||||
ClickhouseDB: string;
|
||||
ClickhouseTable: string;
|
||||
};
|
||||
|
||||
export const emptyHost:Host = {
|
||||
|
|
@ -77,6 +84,12 @@ export const emptyConf:Conf = {
|
|||
InfluxBucket: "",
|
||||
InfluxSkipTLS: false,
|
||||
PrometheusEnable: false,
|
||||
ClickhouseEnable: false,
|
||||
ClickhouseAddr: "",
|
||||
ClickhouseUser: "",
|
||||
ClickhousePassword: "",
|
||||
ClickhouseDB: "",
|
||||
ClickhouseTable: "",
|
||||
};
|
||||
|
||||
export const [allHosts, setAllHosts] = createStore<Host[]>([]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import About from "../components/Config/About"
|
||||
import Basic from "../components/Config/Basic"
|
||||
import Clickhouse from "../components/Config/Clickhouse"
|
||||
import Donate from "../components/Config/Donate"
|
||||
import Influx from "../components/Config/Influx"
|
||||
import Prometheus from "../components/Config/Prometheus"
|
||||
|
|
@ -27,6 +28,9 @@ function Config() {
|
|||
<div class="mt-4">
|
||||
<Prometheus></Prometheus>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<Clickhouse></Clickhouse>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<About></About>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue