feat: 重构日志处理和错误输出格式

refactor: 重构日志处理和错误输出格式
fix: 修正配置加载路径和温度参数类型
docs: 更新结构体字段注释格式
This commit is contained in:
cnphpbb
2025-09-11 10:34:04 +08:00
parent 4b81647da1
commit 51f4b3c8eb
4 changed files with 95 additions and 142 deletions

View File

@@ -11,12 +11,20 @@ import (
// MCPRequest 定义MCP请求结构
type MCPRequest struct {
Data interface{} `json:"data"` Type string `json:"type"` Metadata map[string]string `json:"metadata,omitempty"` Timestamp int64 `json:"timestamp"`
Data interface{} `json:"data"`
Type string `json:"type"`
Metadata map[string]string `json:"metadata,omitempty"`
Timestamp int64 `json:"timestamp"`
}
// MCPResponse 定义MCP响应结构
type MCPResponse struct {
Success bool `json:"success"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` AIResult interface{} `json:"ai_result,omitempty"` RequestID string `json:"request_id,omitempty"` Timestamp int64 `json:"timestamp"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
Data interface{} `json:"data,omitempty"`
AIResult interface{} `json:"ai_result,omitempty"`
RequestID string `json:"request_id,omitempty"`
Timestamp int64 `json:"timestamp"`
}
func main() {
@@ -24,10 +32,10 @@ func main() {
diskData := map[string]interface{}{
"disk_id": "sda",
"smart_data": map[string]interface{}{
"temperature": 38,
"power_on_hours": 12345,
"read_errors": 0,
"write_errors": 0,
"temperature": 38,
"power_on_hours": 12345,
"read_errors": 0,
"write_errors": 0,
"reallocated_sectors": 0,
},
"performance_data": map[string]interface{}{
@@ -85,8 +93,8 @@ func main() {
fmt.Printf(" 成功状态: %v\n", mcpResponse.Success)
fmt.Printf(" 消息: %s\n", mcpResponse.Message)
fmt.Printf(" 请求ID: %s\n", mcpResponse.RequestID)
fmt.Printf(" 时间戳: %d (%s)\n",
mcpResponse.Timestamp,
fmt.Printf(" 时间戳: %d (%s)\n",
mcpResponse.Timestamp,
time.Unix(mcpResponse.Timestamp, 0).Format("2006-01-02 15:04:05"))
// 输出AI分析结果如果有
@@ -122,4 +130,4 @@ func testHealthCheck() {
fmt.Printf("健康检查状态码: %d\n", resp.StatusCode)
fmt.Printf("健康检查响应: %s\n", string(body))
}
}

View File

@@ -1,107 +1,34 @@
module mcp_server_go
go 1.21
go 1.25.0
require (
github.com/fsnotify/fsnotify v1.7.0
github.com/fsnotify/fsnotify v1.9.0
github.com/google/uuid v1.6.0
github.com/prometheus/client_golang v1.18.0
github.com/sashabaranov/go-openai v1.17.4
github.com/spf13/viper v1.17.0
golang.org/x/time v0.5.0
github.com/prometheus/client_golang v1.23.2
github.com/sashabaranov/go-openai v1.41.1
github.com/spf13/viper v1.21.0
golang.org/x/time v0.13.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/OneOfOne/xxhash v1.2.2 // indirect
github.com/alecthomas/kingpin v1.3.1 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/gojq v0.12.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pierrec/lz4 v4.1.17+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sashabaranov/go-openai v1.17.4 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.17.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/toml-lang/toml v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/yosssi/gohtml v0.0.0-20230121090043-345651034a4d // indirect
github.com/yosssi/gi v0.0.0-20180507055002-ea47d430d263 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231019153415-0f05c00091f9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231019153415-0f05c00091f9 // indirect
google.golang.org/grpc v1.58.3 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)

View File

@@ -8,6 +8,7 @@ import (
"log/slog"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
@@ -25,42 +26,69 @@ import (
// Config 结构体用于存储配置
type Config struct {
Server ServerConfig `mapstructure:"server"` OpenAI OpenAIConfig `mapstructure:"openai"` Logging LoggingConfig `mapstructure:"logging"` Security SecurityConfig `mapstructure:"security"`
Server ServerConfig `mapstructure:"server"`
OpenAI OpenAIConfig `mapstructure:"openai"`
Logging LoggingConfig `mapstructure:"logging"`
Security SecurityConfig `mapstructure:"security"`
}
// ServerConfig 服务器配置
type ServerConfig struct {
ListenAddr string `mapstructure:"listen_addr"` ReadTimeout int `mapstructure:"read_timeout"` WriteTimeout int `mapstructure:"write_timeout"` MaxHeaderBytes int `mapstructure:"max_header_bytes"`
ListenAddr string `mapstructure:"listen_addr"`
ReadTimeout int `mapstructure:"read_timeout"`
WriteTimeout int `mapstructure:"write_timeout"`
MaxHeaderBytes int `mapstructure:"max_header_bytes"`
}
// OpenAIConfig OpenAI API配置
type OpenAIConfig struct {
APIKey string `mapstructure:"api_key"` BaseURL string `mapstructure:"base_url"` Model string `mapstructure:"model"` Temperature float64 `mapstructure:"temperature"` MaxTokens int `mapstructure:"max_tokens"` RequestTimeout int `mapstructure:"request_timeout"`
APIKey string `mapstructure:"api_key"`
BaseURL string `mapstructure:"base_url"`
Model string `mapstructure:"model"`
Temperature float64 `mapstructure:"temperature"`
MaxTokens int `mapstructure:"max_tokens"`
RequestTimeout int `mapstructure:"request_timeout"`
}
// LoggingConfig 日志配置
type LoggingConfig struct {
Level string `mapstructure:"level"` Format string `mapstructure:"format"` OutputPath string `mapstructure:"output_path"` MaxSize int `mapstructure:"max_size"` MaxAge int `mapstructure:"max_age"` MaxBackups int `mapstructure:"max_backups"` Compress bool `mapstructure:"compress"`
Level string `mapstructure:"level"`
Format string `mapstructure:"format"`
OutputPath string `mapstructure:"output_path"`
MaxSize int `mapstructure:"max_size"`
MaxAge int `mapstructure:"max_age"`
MaxBackups int `mapstructure:"max_backups"`
Compress bool `mapstructure:"compress"`
}
// SecurityConfig 安全配置
type SecurityConfig struct {
AllowedOrigins []string `mapstructure:"allowed_origins"` AllowedMethods []string `mapstructure:"allowed_methods"` AllowedHeaders []string `mapstructure:"allowed_headers"`
AllowedOrigins []string `mapstructure:"allowed_origins"`
AllowedMethods []string `mapstructure:"allowed_methods"`
AllowedHeaders []string `mapstructure:"allowed_headers"`
}
// MCPRequest MCP请求结构体
type MCPRequest struct {
Data interface{} `json:"data"` Type string `json:"type"` Metadata map[string]string `json:"metadata,omitempty"` Timestamp int64 `json:"timestamp"`
Data interface{} `json:"data"`
Type string `json:"type"`
Metadata map[string]string `json:"metadata,omitempty"`
Timestamp int64 `json:"timestamp"`
}
// MCPResponse MCP响应结构体
type MCPResponse struct {
Success bool `json:"success"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` AIResult interface{} `json:"ai_result,omitempty"` RequestID string `json:"request_id,omitempty"` Timestamp int64 `json:"timestamp"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
Data interface{} `json:"data,omitempty"`
AIResult interface{} `json:"ai_result,omitempty"`
RequestID string `json:"request_id,omitempty"`
Timestamp int64 `json:"timestamp"`
}
var (
config Config
logger *slog.Logger
config Config
logger *slog.Logger
openaiClient *openai.Client
// 速率限制器
limiter = rate.NewLimiter(rate.Limit(10), 20)
@@ -69,7 +97,7 @@ var (
prometheus.CounterOpts{
Name: "mcp_server_requests_total",
Help: "Total number of MCP server requests",
},
},
[]string{"endpoint", "status"},
)
requestDuration = prometheus.NewHistogramVec(
@@ -77,7 +105,7 @@ var (
Name: "mcp_server_request_duration_seconds",
Help: "Duration of MCP server requests in seconds",
Buckets: prometheus.DefBuckets,
},
},
[]string{"endpoint"},
)
)
@@ -95,6 +123,7 @@ func loadConfig() error {
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/mcp_server/")
viper.AddConfigPath("$HOME/.mcp_server/")
viper.AddConfigPath("$HOME/.config/mcp_server/")
if err := viper.ReadInConfig(); err != nil {
return fmt.Errorf("读取配置文件失败: %w", err)
@@ -149,20 +178,7 @@ func initLogger() error {
logLevel = slog.LevelInfo
}
// 创建日志处理
var handler slog.Handler
if config.Logging.Format == "json" {
handler = slog.NewJSONHandler(logFile, &slog.HandlerOptions{
Level: logLevel,
})
} else {
handler = slog.NewTextHandler(logFile, &slog.HandlerOptions{
Level: logLevel,
})
}
// 同时输出到控制台和文件
multiHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel})
// 创建日志器,同时输出到控制台和文件
logger = slog.New(slog.NewTextHandler(
io.MultiWriter(os.Stdout, logFile),
&slog.HandlerOptions{Level: logLevel},
@@ -225,7 +241,7 @@ func loggingMiddleware(next http.Handler) http.Handler {
wrappedWriter := &responseWriter{
ResponseWriter: w,
statusCode: http.StatusOK,
statusCode: http.StatusOK,
}
next.ServeHTTP(wrappedWriter, r)
@@ -272,9 +288,9 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
}
response := map[string]interface{}{
"status": "ok",
"version": "1.0.0",
"timestamp": time.Now().Unix(),
"status": "ok",
"version": "1.0.0",
"timestamp": time.Now().Unix(),
"openai_health": oaiHealthy,
}
@@ -296,7 +312,7 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
// 解析请求体
var mcpRequest MCPRequest
if err := json.NewDecoder(r.Body).Decode(&mcpRequest); err != nil {
logger.Error("解析请求体失败", slog.String("request_id", requestID), slog.Error(err))
logger.Error("解析请求体失败", slog.String("request_id", requestID), slog.Any("error", err))
http.Error(w, "无效的请求体", http.StatusBadRequest)
requestCounter.WithLabelValues("/mcp/v1/submit", "400").Inc()
return
@@ -310,7 +326,7 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
// 调用OpenAI API进行分析
aIResult, err := analyzeWithOpenAI(r.Context(), mcpRequest, requestID)
if err != nil {
logger.Error("OpenAI API调用失败", slog.String("request_id", requestID), slog.Error(err))
logger.Error("OpenAI API调用失败", slog.String("request_id", requestID), slog.Any("error", err))
http.Error(w, "AI分析失败", http.StatusInternalServerError)
requestCounter.WithLabelValues("/mcp/v1/submit", "500").Inc()
return
@@ -329,7 +345,7 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
// 发送响应
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
logger.Error("发送响应失败", slog.String("request_id", requestID), slog.Error(err))
logger.Error("发送响应失败", slog.String("request_id", requestID), slog.Any("error", err))
}
requestCounter.WithLabelValues("/mcp/v1/submit", "200").Inc()
@@ -371,7 +387,7 @@ func analyzeWithOpenAI(ctx context.Context, request MCPRequest, requestID string
Content: prompt,
},
},
Temperature: config.OpenAI.Temperature,
Temperature: float32(config.OpenAI.Temperature),
MaxTokens: config.OpenAI.MaxTokens,
}
@@ -445,7 +461,7 @@ func main() {
// 启动服务器
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Error("服务器启动失败", slog.Error(err))
logger.Error("服务器启动失败", slog.Any("error", err))
os.Exit(1)
}
}()
@@ -465,9 +481,9 @@ func main() {
// 优雅关闭服务器
if err := srv.Shutdown(ctx); err != nil {
logger.Error("服务器关闭失败", slog.Error(err))
logger.Error("服务器关闭失败", slog.Any("error", err))
os.Exit(1)
}
logger.Info("MCP服务器已安全关闭")
}
}