feat: add config and logging

This commit is contained in:
shenlan 2025-08-07 23:13:44 +08:00
parent 8d25d50376
commit 9f6da286ba
7 changed files with 124 additions and 13 deletions

View File

@ -3,32 +3,72 @@ package main
import (
"context"
"io/fs"
"log"
"log/slog"
"net/http"
"os"
"strings"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
"github.com/redis/go-redis/v9"
"xcontrol/server"
"xcontrol/server/api"
"xcontrol/server/config"
"xcontrol/ui"
)
func main() {
cfg, err := config.Load()
if err != nil {
slog.Warn("load config", "err", err)
cfg = &config.Server{}
}
level := slog.LevelInfo
switch strings.ToLower(cfg.Log.Level) {
case "debug":
level = slog.LevelDebug
case "warn", "warning":
level = slog.LevelWarn
case "error":
level = slog.LevelError
}
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
slog.SetDefault(logger)
var conn *pgx.Conn
if dsn := os.Getenv("KB_DSN"); dsn != "" {
var err error
if dsn := cfg.Postgres.DSN; dsn != "" {
logger.Debug("connecting to postgres", "dsn", dsn)
conn, err = pgx.Connect(context.Background(), dsn)
if err != nil {
log.Printf("kb db connect error: %v", err)
logger.Error("postgres connect error", "err", err)
} else {
logger.Info("postgres connected")
}
} else {
logger.Warn("postgres dsn not provided")
}
if addr := cfg.Redis.Addr; addr != "" {
logger.Debug("connecting to redis", "addr", addr)
rdb := redis.NewClient(&redis.Options{
Addr: addr,
Password: cfg.Redis.Password,
})
if err := rdb.Ping(context.Background()).Err(); err != nil {
logger.Error("redis connect error", "err", err)
} else {
logger.Info("redis connected")
}
} else {
logger.Warn("redis addr not provided")
}
uiFS, err := fs.Sub(ui.Assets, "dist")
if err != nil {
log.Fatalf("ui assets: %v", err)
logger.Error("ui assets", "err", err)
return
}
r := server.New(

3
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/gin-gonic/gin v1.9.1
github.com/go-git/go-git/v5 v5.16.2
github.com/jackc/pgx/v5 v5.7.5
github.com/redis/go-redis/v9 v9.12.0
github.com/yuin/goldmark v1.7.13
gopkg.in/yaml.v3 v3.0.1
gorm.io/gorm v1.25.2
@ -18,9 +19,11 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect

10
go.sum
View File

@ -9,9 +9,15 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
@ -22,6 +28,8 @@ github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@ -104,6 +112,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.12.0 h1:XlVPGlflh4nxfhsNXPA8Qp6EmEfTo0rp8oaBzPipXnU=
github.com/redis/go-redis/v9 v9.12.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=

View File

@ -4,7 +4,7 @@ MODULE := xcontrol
PORT := 3001
OS := $(shell uname -s)
.PHONY: all build run clean init help dev
.PHONY: all build run clean init help dev test
all: build
@ -37,8 +37,12 @@ build:
go build -o $(APP_NAME) $(MAIN_FILE)
run:
@echo ">>> 运行 $(APP_NAME) on port $(PORT)"
PORT=$(PORT) go run $(MAIN_FILE)
@echo ">>> 运行 $(APP_NAME) on port $(PORT) (后台运行)"
@nohup env PORT=$(PORT) go run $(MAIN_FILE) > $(APP_NAME).log 2>&1 &
test:
@echo ">>> 运行单元测试"
go test ./...
dev:
@echo ">>> 开发模式运行 $(APP_NAME) (热重载) on port $(PORT)"
@ -57,7 +61,8 @@ help:
@echo " XControl Server Makefile"
@echo ""
@echo "make build 编译 server 可执行文件"
@echo "make run 运行 server (默认端口: $(PORT))"
@echo "make run 后台运行 server (默认端口: $(PORT))"
@echo "make test 运行单元测试"
@echo "make dev 开发模式运行 (自动检测 air如无则用 go run)"
@echo "make init 初始化依赖(自动选择国内/默认 Go 模块代理air 可选)"
@echo "make clean 清理构建产物"

41
server/config/config.go Normal file
View File

@ -0,0 +1,41 @@
package config
import (
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
type Log struct {
Level string `yaml:"level"`
}
type Redis struct {
Addr string `yaml:"addr"`
Password string `yaml:"password"`
}
type Postgres struct {
DSN string `yaml:"dsn"`
}
type Server struct {
Log Log `yaml:"log"`
Redis Redis `yaml:"redis"`
Postgres Postgres `yaml:"postgres"`
}
// Load reads server/config/server.yaml and unmarshals into Server struct.
func Load() (*Server, error) {
path := filepath.Join("server", "config", "server.yaml")
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var cfg Server
if err := yaml.Unmarshal(b, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}

View File

@ -4,7 +4,7 @@ YARN := $(shell command -v yarn 2>/dev/null)
MAGICK := $(shell command -v magick 2>/dev/null || command -v convert 2>/dev/null)
OS := $(shell uname -s)
.PHONY: init dev build export clean info icon
.PHONY: init dev build export clean info icon run test
icon:
@echo "🎨 Generating favicon and icon images..."
@ -51,6 +51,14 @@ dev:
@echo "🚀 Starting Next.js dev server (homepage)..."
yarn next dev -p 3001
run:
@echo "🚀 Starting Next.js dev server (homepage) in background..."
@nohup yarn next dev -p 3001 >/tmp/homepage.log 2>&1 &
test:
@echo "🔍 Running tests..."
@yarn test || echo "No tests configured"
build:
@echo "🔨 Building homepage..."
yarn next build

View File

@ -5,7 +5,7 @@ NODE_VERSION := $(shell node -v 2>/dev/null || echo "Not Found")
YARN := $(shell command -v yarn 2>/dev/null)
OS := $(shell uname -s)
.PHONY: init build run export clean info
.PHONY: init build run export clean info test
init:
@echo "🔧 Installing dependencies..."
@ -35,8 +35,12 @@ build:
yarn build
run:
@echo "🚀 Starting local dev server..."
yarn dev
@echo "🚀 Starting local dev server in background..."
@nohup yarn dev >/tmp/panel.log 2>&1 &
test:
@echo "🔍 Running tests..."
@yarn test || echo "No tests configured"
export:
@echo "📦 Exporting static site to ./out ..."