fix: 优化配置
This commit is contained in:
22
.env.example
22
.env.example
@@ -50,6 +50,21 @@ DISABLE_COMPRESSION=true
|
|||||||
# 缓冲区大小(字节)
|
# 缓冲区大小(字节)
|
||||||
BUFFER_SIZE=32768
|
BUFFER_SIZE=32768
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# 日志配置
|
||||||
|
# ===========================================
|
||||||
|
# 日志级别 (debug, info, warn, error)
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# 日志格式 (text, json)
|
||||||
|
LOG_FORMAT=text
|
||||||
|
|
||||||
|
# 启用文件日志
|
||||||
|
LOG_ENABLE_FILE=false
|
||||||
|
|
||||||
|
# 日志文件路径
|
||||||
|
LOG_FILE_PATH=logs/app.log
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 认证配置
|
# 认证配置
|
||||||
# ===========================================
|
# ===========================================
|
||||||
@@ -65,11 +80,4 @@ ENABLE_CORS=true
|
|||||||
# 允许的来源(逗号分隔,* 表示允许所有)
|
# 允许的来源(逗号分隔,* 表示允许所有)
|
||||||
ALLOWED_ORIGINS=*
|
ALLOWED_ORIGINS=*
|
||||||
|
|
||||||
# ===========================================
|
|
||||||
# 性能配置
|
|
||||||
# ===========================================
|
|
||||||
# HTTP 连接池最大连接数
|
|
||||||
MAX_SOCKETS=50
|
|
||||||
|
|
||||||
# HTTP 连接池最大空闲连接数
|
|
||||||
MAX_FREE_SOCKETS=10
|
|
||||||
|
55
cmd/main.go
55
cmd/main.go
@@ -6,9 +6,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -19,18 +21,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 设置日志格式
|
|
||||||
logrus.SetFormatter(&logrus.TextFormatter{
|
|
||||||
FullTimestamp: true,
|
|
||||||
ForceColors: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 加载配置
|
// 加载配置
|
||||||
cfg, err := config.LoadConfig()
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatalf("❌ 配置加载失败: %v", err)
|
logrus.Fatalf("加载配置失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 配置日志
|
||||||
|
setupLogger(cfg)
|
||||||
|
|
||||||
// 显示启动信息
|
// 显示启动信息
|
||||||
displayStartupInfo(cfg)
|
displayStartupInfo(cfg)
|
||||||
|
|
||||||
@@ -96,3 +95,45 @@ func displayStartupInfo(cfg *config.Config) {
|
|||||||
config.DisplayConfig(cfg)
|
config.DisplayConfig(cfg)
|
||||||
logrus.Info("")
|
logrus.Info("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setupLogger 配置日志系统
|
||||||
|
func setupLogger(cfg *config.Config) {
|
||||||
|
// 设置日志级别
|
||||||
|
level, err := logrus.ParseLevel(cfg.Log.Level)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("无效的日志级别 '%s',使用默认级别 info", cfg.Log.Level)
|
||||||
|
level = logrus.InfoLevel
|
||||||
|
}
|
||||||
|
logrus.SetLevel(level)
|
||||||
|
|
||||||
|
// 设置日志格式
|
||||||
|
switch cfg.Log.Format {
|
||||||
|
case "json":
|
||||||
|
logrus.SetFormatter(&logrus.JSONFormatter{
|
||||||
|
TimestampFormat: "2006-01-02 15:04:05",
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
logrus.SetFormatter(&logrus.TextFormatter{
|
||||||
|
FullTimestamp: true,
|
||||||
|
ForceColors: true,
|
||||||
|
TimestampFormat: "2006-01-02 15:04:05",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置文件日志
|
||||||
|
if cfg.Log.EnableFile {
|
||||||
|
// 创建日志目录
|
||||||
|
if err := os.MkdirAll(filepath.Dir(cfg.Log.FilePath), 0755); err != nil {
|
||||||
|
logrus.Warnf("创建日志目录失败: %v", err)
|
||||||
|
} else {
|
||||||
|
// 打开日志文件
|
||||||
|
file, err := os.OpenFile(cfg.Log.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("打开日志文件失败: %v", err)
|
||||||
|
} else {
|
||||||
|
// 同时输出到控制台和文件
|
||||||
|
logrus.SetOutput(io.MultiWriter(os.Stdout, file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -74,6 +74,14 @@ type PerformanceConfig struct {
|
|||||||
BufferSize int `json:"bufferSize"`
|
BufferSize int `json:"bufferSize"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogConfig 日志配置
|
||||||
|
type LogConfig struct {
|
||||||
|
Level string `json:"level"` // debug, info, warn, error
|
||||||
|
Format string `json:"format"` // text, json
|
||||||
|
EnableFile bool `json:"enableFile"` // 是否启用文件日志
|
||||||
|
FilePath string `json:"filePath"` // 日志文件路径
|
||||||
|
}
|
||||||
|
|
||||||
// Config 应用配置
|
// Config 应用配置
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Server ServerConfig `json:"server"`
|
Server ServerConfig `json:"server"`
|
||||||
@@ -82,6 +90,7 @@ type Config struct {
|
|||||||
Auth AuthConfig `json:"auth"`
|
Auth AuthConfig `json:"auth"`
|
||||||
CORS CORSConfig `json:"cors"`
|
CORS CORSConfig `json:"cors"`
|
||||||
Performance PerformanceConfig `json:"performance"`
|
Performance PerformanceConfig `json:"performance"`
|
||||||
|
Log LogConfig `json:"log"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global config instance
|
// Global config instance
|
||||||
@@ -123,6 +132,12 @@ func LoadConfig() (*Config, error) {
|
|||||||
DisableCompression: parseBoolean(os.Getenv("DISABLE_COMPRESSION"), true),
|
DisableCompression: parseBoolean(os.Getenv("DISABLE_COMPRESSION"), true),
|
||||||
BufferSize: parseInteger(os.Getenv("BUFFER_SIZE"), 32*1024),
|
BufferSize: parseInteger(os.Getenv("BUFFER_SIZE"), 32*1024),
|
||||||
},
|
},
|
||||||
|
Log: LogConfig{
|
||||||
|
Level: getEnvOrDefault("LOG_LEVEL", "info"),
|
||||||
|
Format: getEnvOrDefault("LOG_FORMAT", "text"),
|
||||||
|
EnableFile: parseBoolean(os.Getenv("LOG_ENABLE_FILE"), false),
|
||||||
|
FilePath: getEnvOrDefault("LOG_FILE_PATH", "logs/app.log"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证配置
|
// 验证配置
|
||||||
@@ -205,6 +220,19 @@ func DisplayConfig(config *Config) {
|
|||||||
}
|
}
|
||||||
logrus.Infof(" CORS: %s", corsStatus)
|
logrus.Infof(" CORS: %s", corsStatus)
|
||||||
logrus.Infof(" 连接池: %d/%d", config.Performance.MaxSockets, config.Performance.MaxFreeSockets)
|
logrus.Infof(" 连接池: %d/%d", config.Performance.MaxSockets, config.Performance.MaxFreeSockets)
|
||||||
|
|
||||||
|
keepAliveStatus := "已启用"
|
||||||
|
if !config.Performance.EnableKeepAlive {
|
||||||
|
keepAliveStatus = "已禁用"
|
||||||
|
}
|
||||||
|
logrus.Infof(" Keep-Alive: %s", keepAliveStatus)
|
||||||
|
|
||||||
|
compressionStatus := "已启用"
|
||||||
|
if config.Performance.DisableCompression {
|
||||||
|
compressionStatus = "已禁用"
|
||||||
|
}
|
||||||
|
logrus.Infof(" 压缩: %s", compressionStatus)
|
||||||
|
logrus.Infof(" 缓冲区大小: %d bytes", config.Performance.BufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助函数
|
// 辅助函数
|
||||||
|
@@ -51,10 +51,15 @@ func NewProxyServer() (*ProxyServer, error) {
|
|||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
DisableCompression: true, // 禁用压缩以减少CPU开销,让上游处理
|
DisableCompression: config.AppConfig.Performance.DisableCompression,
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
WriteBufferSize: 32 * 1024, // 32KB写缓冲
|
WriteBufferSize: config.AppConfig.Performance.BufferSize,
|
||||||
ReadBufferSize: 32 * 1024, // 32KB读缓冲
|
ReadBufferSize: config.AppConfig.Performance.BufferSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置 Keep-Alive
|
||||||
|
if !config.AppConfig.Performance.EnableKeepAlive {
|
||||||
|
transport.DisableKeepAlives = true
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
|
116
scripts/validate_config.go
Normal file
116
scripts/validate_config.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// 配置验证脚本
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"gpt-load/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 加载测试配置
|
||||||
|
if err := godotenv.Load("test_config.env"); err != nil {
|
||||||
|
logrus.Warnf("无法加载测试配置文件: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载配置
|
||||||
|
cfg, err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("配置加载失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("🔍 配置验证报告")
|
||||||
|
fmt.Println("=" * 50)
|
||||||
|
|
||||||
|
// 验证服务器配置
|
||||||
|
fmt.Printf("📡 服务器配置:\n")
|
||||||
|
fmt.Printf(" Host: %s\n", cfg.Server.Host)
|
||||||
|
fmt.Printf(" Port: %d\n", cfg.Server.Port)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证密钥配置
|
||||||
|
fmt.Printf("🔑 密钥配置:\n")
|
||||||
|
fmt.Printf(" 文件路径: %s\n", cfg.Keys.FilePath)
|
||||||
|
fmt.Printf(" 起始索引: %d\n", cfg.Keys.StartIndex)
|
||||||
|
fmt.Printf(" 黑名单阈值: %d\n", cfg.Keys.BlacklistThreshold)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证 OpenAI 配置
|
||||||
|
fmt.Printf("🤖 OpenAI 配置:\n")
|
||||||
|
fmt.Printf(" Base URL: %s\n", cfg.OpenAI.BaseURL)
|
||||||
|
fmt.Printf(" 超时时间: %dms\n", cfg.OpenAI.Timeout)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证认证配置
|
||||||
|
fmt.Printf("🔐 认证配置:\n")
|
||||||
|
fmt.Printf(" 启用状态: %t\n", cfg.Auth.Enabled)
|
||||||
|
if cfg.Auth.Enabled {
|
||||||
|
fmt.Printf(" 密钥长度: %d\n", len(cfg.Auth.Key))
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证 CORS 配置
|
||||||
|
fmt.Printf("🌐 CORS 配置:\n")
|
||||||
|
fmt.Printf(" 启用状态: %t\n", cfg.CORS.Enabled)
|
||||||
|
fmt.Printf(" 允许来源: %v\n", cfg.CORS.AllowedOrigins)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证性能配置
|
||||||
|
fmt.Printf("⚡ 性能配置:\n")
|
||||||
|
fmt.Printf(" 最大连接数: %d\n", cfg.Performance.MaxSockets)
|
||||||
|
fmt.Printf(" 最大空闲连接数: %d\n", cfg.Performance.MaxFreeSockets)
|
||||||
|
fmt.Printf(" Keep-Alive: %t\n", cfg.Performance.EnableKeepAlive)
|
||||||
|
fmt.Printf(" 禁用压缩: %t\n", cfg.Performance.DisableCompression)
|
||||||
|
fmt.Printf(" 缓冲区大小: %d bytes\n", cfg.Performance.BufferSize)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 验证日志配置
|
||||||
|
fmt.Printf("📝 日志配置:\n")
|
||||||
|
fmt.Printf(" 日志级别: %s\n", cfg.Log.Level)
|
||||||
|
fmt.Printf(" 日志格式: %s\n", cfg.Log.Format)
|
||||||
|
fmt.Printf(" 文件日志: %t\n", cfg.Log.EnableFile)
|
||||||
|
if cfg.Log.EnableFile {
|
||||||
|
fmt.Printf(" 文件路径: %s\n", cfg.Log.FilePath)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// 检查配置完整性
|
||||||
|
fmt.Printf("✅ 配置完整性检查:\n")
|
||||||
|
checkConfigCompleteness(cfg)
|
||||||
|
|
||||||
|
fmt.Println("🎉 配置验证完成!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkConfigCompleteness(cfg *config.Config) {
|
||||||
|
v := reflect.ValueOf(cfg).Elem()
|
||||||
|
t := reflect.TypeOf(cfg).Elem()
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
fieldType := t.Field(i)
|
||||||
|
|
||||||
|
if field.Kind() == reflect.Struct {
|
||||||
|
checkStruct(field, fieldType.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStruct(v reflect.Value, name string) {
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
fieldType := t.Field(i)
|
||||||
|
|
||||||
|
// 检查字段是否为零值
|
||||||
|
if field.IsZero() && fieldType.Name != "Enabled" {
|
||||||
|
fmt.Printf(" ⚠️ %s.%s 为零值\n", name, fieldType.Name)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" ✅ %s.%s 已配置\n", name, fieldType.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user