Sfoglia il codice sorgente

自动建立表通过

qdy 2 mesi fa
parent
commit
2229447401

+ 189
- 0
bootstraps/bootstrap.go Vedi File

@@ -0,0 +1,189 @@
1
+package bootstraps
2
+
3
+import (
4
+	"log"
5
+
6
+	"git.x2erp.com/qdy/go-base/config"
7
+	"git.x2erp.com/qdy/go-base/logger"
8
+	"git.x2erp.com/qdy/go-base/myservice"
9
+	"git.x2erp.com/qdy/go-db/factory/database"
10
+	"go-micro.dev/v4/web"
11
+)
12
+
13
+// ServiceBootstrapper 服务启动器
14
+type ServiceBootstrapper struct {
15
+	serviceName    string
16
+	serviceVersion string
17
+	Cfg            config.IConfig
18
+	DbFactory      *database.DBFactory
19
+	WebService     web.Service
20
+}
21
+
22
+// NewServiceBootstrapper 创建服务启动器
23
+func NewServiceBootstrapper(name, version string) *ServiceBootstrapper {
24
+	return &ServiceBootstrapper{
25
+		serviceName:    name,
26
+		serviceVersion: version,
27
+	}
28
+}
29
+
30
+// 初始化配置
31
+func (b *ServiceBootstrapper) InitConfig() {
32
+	// 1. 初始化启动日志
33
+	b.initBootLogger()
34
+	defer b.closeBootLogger()
35
+
36
+	// 2. 加载配置
37
+	b.loadConfig()
38
+
39
+	// 3. 初始化数据库
40
+	//b.initDatabase()
41
+	//defer b.cleanupDatabase()
42
+
43
+	// 4. 初始化运行时日志
44
+	b.initRuntimeLogger()
45
+
46
+	// 5. 设置优雅关闭
47
+	b.setupGracefulShutdown()
48
+
49
+}
50
+
51
+// Run 启动服务
52
+func (b *ServiceBootstrapper) Run(routeRegistrar func(web.Service, *database.DBFactory)) {
53
+
54
+	if b.DbFactory == nil {
55
+		log.Fatal("数据库工厂未初始化,请先调用InitDatabase()")
56
+	}
57
+
58
+	// 6. 启动微服务
59
+	b.startWebService()
60
+
61
+	// 7. 注册路由
62
+	routeRegistrar(b.WebService, b.DbFactory)
63
+
64
+	// 8. 记录服务启动信息
65
+	b.logServiceInfo()
66
+
67
+	// 9. 运行服务
68
+	b.runWebService()
69
+}
70
+
71
+// initBootLogger 初始化启动日志
72
+func (b *ServiceBootstrapper) initBootLogger() {
73
+	if err := logger.InitBootLog(b.serviceName); err != nil {
74
+		log.Fatal("无法初始化启动日志: ", err)
75
+	}
76
+}
77
+
78
+// closeBootLogger 关闭启动日志
79
+func (b *ServiceBootstrapper) closeBootLogger() {
80
+	logger.CloseBootLogger()
81
+}
82
+
83
+// loadConfig 加载配置
84
+func (b *ServiceBootstrapper) loadConfig() {
85
+
86
+	log.Printf("开始加载配置...")
87
+
88
+	cfg, err := config.GetConfig()
89
+	if err != nil {
90
+		log.Fatalf("加载配置文件错误: %v", err)
91
+	}
92
+
93
+	// 设置版本
94
+	cfg.SetServiceName(b.serviceName)
95
+	cfg.SetServiceVersion(b.serviceVersion)
96
+
97
+	b.Cfg = cfg
98
+}
99
+
100
+// initDatabase 初始化数据库
101
+func (b *ServiceBootstrapper) InitDatabase() {
102
+
103
+	// 记录配置信息
104
+	//serviceCfg := cfg.GetService()
105
+	//microCfg := cfg.GetMicro()
106
+	dbCfg := b.Cfg.GetDatabase()
107
+
108
+	//log.Printf("服务名称: %s", serviceCfg.ServiceName)
109
+	//log.Printf("服务端口: %d", serviceCfg.Port)
110
+	//log.Printf("注册中心: %s", microCfg.RegistryAddress)
111
+	log.Printf("数据库: %s:%d/%s", dbCfg.Host, dbCfg.Port, dbCfg.Database)
112
+
113
+	log.Printf("初始化数据库连接...")
114
+
115
+	dbFactory, err := database.GetDBFactory()
116
+	if err != nil {
117
+		log.Fatalf("数据库连接失败: %v", err)
118
+	}
119
+	b.DbFactory = dbFactory
120
+
121
+	log.Printf("数据库连接测试通过!")
122
+
123
+}
124
+
125
+// cleanupDatabase 清理数据库资源
126
+func (b *ServiceBootstrapper) CleanupDatabase() {
127
+	if b.DbFactory != nil {
128
+		if err := b.DbFactory.Close(); err != nil {
129
+			logger.Error("数据库关闭错误: %v", err)
130
+		}
131
+	}
132
+}
133
+
134
+// initRuntimeLogger 初始化运行时日志
135
+func (b *ServiceBootstrapper) initRuntimeLogger() {
136
+	logger.InitRuntimeLogger(b.serviceName, b.serviceVersion, b.Cfg.GetLog())
137
+	log.Printf("运行时日志系统初始化完成")
138
+	log.Printf("开始启动微服务...")
139
+
140
+	// 记录服务模式
141
+	mode := "独立模式"
142
+	if b.Cfg.GetMicro().RegistryAddress != "" {
143
+		mode = "使用服务发现 (注册中心)"
144
+	}
145
+	log.Printf("服务模式: %s", mode)
146
+}
147
+
148
+// setupGracefulShutdown 设置优雅关闭
149
+func (b *ServiceBootstrapper) setupGracefulShutdown() {
150
+	setupGracefulShutdown(b.DbFactory, logger.StopESWriter)
151
+}
152
+
153
+// startWebService 启动Web服务
154
+func (b *ServiceBootstrapper) startWebService() {
155
+	microCfg := b.Cfg.GetMicro()
156
+	serviceCfg := b.Cfg.GetService()
157
+
158
+	var svc web.Service
159
+	if microCfg.RegistryAddress != "" {
160
+		svc = myservice.Start(b.Cfg)
161
+	} else {
162
+		svc = myservice.StartStandalone(b.Cfg)
163
+	}
164
+
165
+	b.WebService = svc
166
+	log.Printf("Web服务实例创建完成 (端口: %d)", serviceCfg.Port)
167
+}
168
+
169
+// logServiceInfo 记录服务启动信息
170
+func (b *ServiceBootstrapper) logServiceInfo() {
171
+	serviceCfg := b.Cfg.GetService()
172
+
173
+	log.Printf("服务启动成功")
174
+
175
+	if serviceCfg.TrustedProxies != "" {
176
+		log.Printf("   • 受信代理: %s", serviceCfg.TrustedProxies)
177
+	}
178
+}
179
+
180
+// runWebService 运行Web服务
181
+func (b *ServiceBootstrapper) runWebService() {
182
+	// 测试日志
183
+	logger.Debug("测试日志是否写入ES.")
184
+
185
+	log.Printf("服务开始运行...")
186
+	if err := b.WebService.Run(); err != nil {
187
+		log.Fatal("服务运行失败:", err)
188
+	}
189
+}

+ 39
- 0
bootstraps/shutdown.go Vedi File

@@ -0,0 +1,39 @@
1
+package bootstraps
2
+
3
+import (
4
+	"os"
5
+	"os/signal"
6
+	"syscall"
7
+	"time"
8
+
9
+	"git.x2erp.com/qdy/go-base/logger"
10
+	"git.x2erp.com/qdy/go-db/factory/database"
11
+)
12
+
13
+// setupGracefulShutdown 设置优雅关闭
14
+func setupGracefulShutdown(dbFactory *database.DBFactory, cleanupFuncs ...func()) {
15
+	signalCh := make(chan os.Signal, 1)
16
+	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
17
+
18
+	go func() {
19
+		<-signalCh
20
+		logger.Info("\n接收到关闭信号,正在优雅关闭...")
21
+
22
+		// 关闭数据库连接
23
+		if dbFactory != nil {
24
+			if err := dbFactory.Close(); err != nil {
25
+				logger.Error("关闭数据库错误: %v", err)
26
+			}
27
+			logger.Info("数据库连接已关闭")
28
+		}
29
+
30
+		// 执行其他清理函数
31
+		for _, cleanup := range cleanupFuncs {
32
+			cleanup()
33
+		}
34
+
35
+		// 等待日志写入完成
36
+		time.Sleep(100 * time.Millisecond)
37
+		os.Exit(0)
38
+	}()
39
+}

+ 16
- 0
config/config.go Vedi File

@@ -21,6 +21,22 @@ type IConfig interface {
21 21
 	IsDatabaseConfigured() bool
22 22
 	IsDorisConfigured() bool
23 23
 	IsRedisConfigured() bool
24
+	SetServiceName(name string)
25
+	SetServiceVersion(version string)
26
+}
27
+
28
+// 设置微服务名称。。如果配置文件设置了,就按配置文件
29
+func (c *Config) SetServiceName(name string) {
30
+	if c.GetService().ServiceName == "" {
31
+		c.GetService().ServiceName = name
32
+	}
33
+
34
+}
35
+
36
+// 设置微服务版本号
37
+func (c *Config) SetServiceVersion(version string) {
38
+
39
+	c.GetService().ServiceVersion = version
24 40
 }
25 41
 
26 42
 // Config 主配置结构体 - 访问门面

+ 16
- 1
config/loader.go Vedi File

@@ -91,5 +91,20 @@ func findConfigFile() (string, error) {
91 91
 		}
92 92
 	}
93 93
 
94
-	return "", fmt.Errorf("no configuration file found")
94
+	//return "", fmt.Errorf("no configuration file found")
95
+
96
+	return "", fmt.Errorf(`no configuration file found
97
+
98
+Searched locations:
99
+1. %s
100
+2. %s
101
+3. ./db.yaml
102
+4. ./config/db.yaml
103
+5. DB_CONFIG_PATH环境变量指定的路径
104
+
105
+请确保配置文件存在,或通过环境变量指定:
106
+export DB_CONFIG_PATH=/your/config/path/db.yaml
107
+set DB_CONFIG_PATH=C:\your\config\path\db.yaml (Windows)`,
108
+		filepath.Join(exeDir, "db.yaml"),
109
+		filepath.Join(exeDir, "config", "db.yaml"))
95 110
 }

+ 1
- 1
config/subconfigs/micro_config.go Vedi File

@@ -34,7 +34,7 @@ func NewMicroConfig() *MicroConfig {
34 34
 }
35 35
 
36 36
 func (c *MicroConfig) SetDefaults() {
37
-	c.RegistryAddress = "localhost:8500"
37
+	//c.RegistryAddress = "localhost:8500"
38 38
 	c.RegistryType = "consul"
39 39
 	c.RegistryTimeout = 10
40 40
 	c.LBStrategy = "roundrobin"

+ 68
- 0
handlers/base.go Vedi File

@@ -0,0 +1,68 @@
1
+package handlers
2
+
3
+import (
4
+	"encoding/json"
5
+	"net/http"
6
+	"time"
7
+
8
+	"git.x2erp.com/qdy/go-base/logger"
9
+	"git.x2erp.com/qdy/go-db/factory/database"
10
+)
11
+
12
+type BaseHandlers struct {
13
+	ServiceName    string
14
+	ServiceVersion string
15
+}
16
+
17
+func NewBaseHandlers(name, version string) *BaseHandlers {
18
+	return &BaseHandlers{
19
+		ServiceName:    name,
20
+		ServiceVersion: version,
21
+	}
22
+}
23
+
24
+// RootHandler 根处理器
25
+func (h *BaseHandlers) RootHandler() http.HandlerFunc {
26
+	return func(w http.ResponseWriter, r *http.Request) {
27
+		logger.Debug("接收到根路径请求")
28
+		w.Header().Set("Content-Type", "application/json")
29
+		w.WriteHeader(http.StatusOK)
30
+		w.Write([]byte(`{"service": "` + h.ServiceName + `", "version": "` + h.ServiceVersion + `", "status": "running"}`))
31
+	}
32
+}
33
+
34
+// HealthHandler 健康检查处理器
35
+func (h *BaseHandlers) HealthHandler(dbFactory *database.DBFactory) http.HandlerFunc {
36
+	return func(w http.ResponseWriter, r *http.Request) {
37
+		logger.Debug("接收到健康检查请求")
38
+		w.Header().Set("Content-Type", "application/json")
39
+
40
+		if dbFactory == nil {
41
+			w.WriteHeader(http.StatusServiceUnavailable)
42
+			w.Write([]byte(`{"status": "unhealthy", "error": "database not initialized"}`))
43
+			return
44
+		}
45
+
46
+		w.WriteHeader(http.StatusOK)
47
+		w.Write([]byte(`{"status": "healthy", "service": "` + h.ServiceName + `"}`))
48
+	}
49
+}
50
+
51
+// InfoHandler 信息处理器
52
+func (h *BaseHandlers) InfoHandler() http.HandlerFunc {
53
+	return func(w http.ResponseWriter, r *http.Request) {
54
+		logger.Debug("接收到信息查询请求")
55
+		w.Header().Set("Content-Type", "application/json")
56
+
57
+		info := map[string]interface{}{
58
+			"service":   h.ServiceName,
59
+			"version":   h.ServiceVersion,
60
+			"status":    "running",
61
+			"timestamp": time.Now().Format(time.RFC3339),
62
+		}
63
+
64
+		jsonData, _ := json.Marshal(info)
65
+		w.WriteHeader(http.StatusOK)
66
+		w.Write(jsonData)
67
+	}
68
+}

+ 26
- 0
handlers/routes.go Vedi File

@@ -0,0 +1,26 @@
1
+package handlers
2
+
3
+import (
4
+	"git.x2erp.com/qdy/go-base/logger"
5
+	"git.x2erp.com/qdy/go-db/factory/database"
6
+	"go-micro.dev/v4/web"
7
+)
8
+
9
+// RouteConfig 路由配置
10
+type RouteConfig struct {
11
+	ServiceName    string
12
+	ServiceVersion string
13
+	DBFactory      *database.DBFactory
14
+}
15
+
16
+// RegisterBaseRoutes 注册基本路由
17
+func RegisterBaseRoutes(webService web.Service, cfg *RouteConfig) {
18
+	// 创建基础处理器
19
+	baseHandlers := NewBaseHandlers(cfg.ServiceName, cfg.ServiceVersion)
20
+
21
+	webService.Handle("/", baseHandlers.RootHandler())
22
+	webService.Handle("/health", baseHandlers.HealthHandler(cfg.DBFactory))
23
+	webService.Handle("/info", baseHandlers.InfoHandler())
24
+
25
+	logger.Info("HTTP路由注册完成")
26
+}

+ 6
- 1
logger/boot_logger.go Vedi File

@@ -17,8 +17,13 @@ var (
17 17
 
18 18
 // InitBootLogger 初始化启动日志(只在启动阶段使用)
19 19
 func InitBootLog(serviceName string) error {
20
+
21
+	if logToFile := os.Getenv("LOG_TO_FILE"); logToFile == "false" {
22
+		return nil
23
+	}
24
+
20 25
 	// 1. 确保日志目录存在
21
-	logDir := "logs/boot"
26
+	logDir := "logs"
22 27
 	if err := os.MkdirAll(logDir, 0755); err != nil {
23 28
 		return fmt.Errorf("创建日志目录失败: %v", err)
24 29
 	}

+ 58
- 41
logger/runtime_logger.go Vedi File

@@ -2,6 +2,7 @@
2 2
 package logger
3 3
 
4 4
 import (
5
+	"fmt"
5 6
 	"log"
6 7
 	"os"
7 8
 	"strings"
@@ -9,6 +10,7 @@ import (
9 10
 	"time"
10 11
 
11 12
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
13
+	"git.x2erp.com/qdy/go-base/ctx"
12 14
 	"git.x2erp.com/qdy/go-base/logger/http"
13 15
 
14 16
 	"go.uber.org/zap"
@@ -20,28 +22,30 @@ var (
20 22
 	runtimeLogger  *zap.Logger
21 23
 	runtimeSugared *zap.SugaredLogger
22 24
 	serviceName    string
25
+	serviceVersion string
23 26
 	initOnce       sync.Once
24 27
 )
25 28
 
26
-// LogContext 日志上下文
27
-type LogContext struct {
28
-	TraceID      string
29
-	UserID       string
30
-	TenantID     string
31
-	InstanceName string
32
-}
29
+// // LogContext 日志上下文
30
+// type LogContext struct {
31
+// 	TraceID      string
32
+// 	UserID       string
33
+// 	TenantID     string
34
+// 	InstanceName string
35
+// }
33 36
 
34 37
 // InitRuntimeLogger 初始化
35
-func InitRuntimeLogger(svcName string, logConfig *subconfigs.LogConfig) {
38
+func InitRuntimeLogger(svcName, svcVersion string, logConfig *subconfigs.LogConfig) {
36 39
 	initOnce.Do(func() {
37 40
 		if logConfig == nil {
38 41
 			log.Fatal("错误: 日志配置不能为空")
39 42
 		}
40 43
 
41
-		//serviceName = svcName
44
+		serviceName = svcName
45
+		serviceVersion = svcVersion
42 46
 
43 47
 		// 创建logger
44
-		if err := createRuntimeLogger(svcName, logConfig); err != nil {
48
+		if err := createRuntimeLogger(svcName, svcVersion, logConfig); err != nil {
45 49
 			log.Fatal("创建运行时日志器失败: ", err)
46 50
 		}
47 51
 
@@ -52,7 +56,7 @@ func InitRuntimeLogger(svcName string, logConfig *subconfigs.LogConfig) {
52 56
 	})
53 57
 }
54 58
 
55
-func createRuntimeLogger(svcName string, cfg *subconfigs.LogConfig) error {
59
+func createRuntimeLogger(svcName, svcVersion string, cfg *subconfigs.LogConfig) error {
56 60
 	// 1. 设置日志级别
57 61
 	level := zap.InfoLevel
58 62
 	switch strings.ToLower(cfg.Level) {
@@ -75,28 +79,25 @@ func createRuntimeLogger(svcName string, cfg *subconfigs.LogConfig) error {
75 79
 	// 3. 根据JSONFormat决定编码器
76 80
 	var consoleEncoder, jsonEncoder zapcore.Encoder
77 81
 
78
-	if cfg.JSONFormat {
79
-		// JSON格式输出
80
-		consoleEncoder = zapcore.NewJSONEncoder(encoderConfig)
81
-	} else {
82
-		// 文本格式输出
83
-		consoleEncoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
84
-			TimeKey:        "T",
85
-			LevelKey:       "L",
86
-			NameKey:        "N",
87
-			CallerKey:      "C",
88
-			MessageKey:     "M",
89
-			StacktraceKey:  "S",
90
-			LineEnding:     zapcore.DefaultLineEnding,
91
-			EncodeLevel:    zapcore.CapitalColorLevelEncoder,
92
-			EncodeTime:     zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05"),
93
-			EncodeDuration: zapcore.StringDurationEncoder,
94
-			EncodeCaller:   zapcore.ShortCallerEncoder,
95
-		})
96
-	}
97
-
82
+	// JSON格式输出
98 83
 	jsonEncoder = zapcore.NewJSONEncoder(encoderConfig)
99 84
 
85
+	// 文本格式输出
86
+	consoleEncoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
87
+		TimeKey:        "T",
88
+		LevelKey:       "L",
89
+		NameKey:        "N",
90
+		CallerKey:      "C",
91
+		MessageKey:     "M",
92
+		StacktraceKey:  "S",
93
+		LineEnding:     zapcore.DefaultLineEnding,
94
+		EncodeLevel:    zapcore.CapitalColorLevelEncoder,
95
+		EncodeTime:     zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05"),
96
+		EncodeDuration: zapcore.StringDurationEncoder,
97
+		EncodeCaller:   zapcore.ShortCallerEncoder,
98
+		EncodeName:     nil,
99
+	})
100
+
100 101
 	// 4. 输出目标
101 102
 	cores := []zapcore.Core{}
102 103
 
@@ -191,11 +192,12 @@ func createRuntimeLogger(svcName string, cfg *subconfigs.LogConfig) error {
191 192
 	// 7. 创建logger
192 193
 	runtimeLogger = zap.New(core,
193 194
 		zap.AddCaller(),
194
-		zap.AddCallerSkip(1),
195
+		zap.AddCallerSkip(2),
195 196
 		zap.AddStacktrace(zap.ErrorLevel),
196
-		zap.Fields(
197
-			zap.String("service", svcName),
198
-		),
197
+		//zap.Fields(
198
+		//	zap.String("service", svcName),
199
+		//	zap.String("version", serviceVersion),
200
+		//),
199 201
 	)
200 202
 
201 203
 	runtimeSugared = runtimeLogger.Sugar()
@@ -220,10 +222,11 @@ func addDateToFilePath(filePath string) string {
220 222
 }
221 223
 
222 224
 // WithC 创建带有上下文的logger(C代表Context)
223
-func W(ctx LogContext) *zap.SugaredLogger {
225
+func W(ctx *ctx.RequestContext) *zap.SugaredLogger {
224 226
 	// 直接使用,不会为空
225 227
 	return runtimeLogger.With(
226 228
 		zap.String("service", serviceName),
229
+		zap.String("version", serviceVersion),
227 230
 		zap.String("trace_id", ctx.TraceID),
228 231
 		zap.String("user_id", ctx.UserID),
229 232
 		zap.String("tenant_id", ctx.TenantID),
@@ -234,27 +237,27 @@ func W(ctx LogContext) *zap.SugaredLogger {
234 237
 // ============ 上下文日志快捷方法 ============
235 238
 
236 239
 // InfoC 带上下文的Info日志
237
-func InfoC(ctx LogContext, format string, args ...interface{}) {
240
+func InfoC(ctx *ctx.RequestContext, format string, args ...interface{}) {
238 241
 	W(ctx).Infof(format, args...)
239 242
 }
240 243
 
241 244
 // ErrorC 带上下文的Error日志
242
-func ErrorC(ctx LogContext, format string, args ...interface{}) {
245
+func ErrorC(ctx *ctx.RequestContext, format string, args ...interface{}) {
243 246
 	W(ctx).Errorf(format, args...)
244 247
 }
245 248
 
246 249
 // DebugC 带上下文的Debug日志
247
-func DebugC(ctx LogContext, format string, args ...interface{}) {
250
+func DebugC(ctx *ctx.RequestContext, format string, args ...interface{}) {
248 251
 	W(ctx).Debugf(format, args...)
249 252
 }
250 253
 
251 254
 // WarnC 带上下文的Warn日志
252
-func WarnC(ctx LogContext, format string, args ...interface{}) {
255
+func WarnC(ctx *ctx.RequestContext, format string, args ...interface{}) {
253 256
 	W(ctx).Warnf(format, args...)
254 257
 }
255 258
 
256 259
 // FatalC 带上下文的Fatal日志
257
-func FatalC(ctx LogContext, format string, args ...interface{}) {
260
+func FatalC(ctx *ctx.RequestContext, format string, args ...interface{}) {
258 261
 	W(ctx).Fatalf(format, args...)
259 262
 }
260 263
 
@@ -285,6 +288,20 @@ func Fatal(format string, args ...interface{}) {
285 288
 	runtimeSugared.Fatalf(format, args...)
286 289
 }
287 290
 
291
+// Errorf 记录错误日志并返回格式化错误
292
+func Errorf(format string, args ...interface{}) error {
293
+	err := fmt.Errorf(format, args...)
294
+	runtimeSugared.Errorf(format, args...)
295
+	return err
296
+}
297
+
298
+// ErrorCf 带上下文的错误日志并返回格式化错误
299
+func ErrorCf(ctx *ctx.RequestContext, format string, args ...interface{}) error {
300
+	err := fmt.Errorf(format, args...)
301
+	ErrorC(ctx, format, args...)
302
+	return err
303
+}
304
+
288 305
 // ============ 其他方法 ============
289 306
 
290 307
 // GetZapLogger 获取原始zap.Logger

+ 3
- 0
myservice/service.go Vedi File

@@ -40,6 +40,9 @@ func StartWithRegistry(cfg config.IConfig) web.Service {
40 40
 	log.Printf("   • Version: %s", serviceConfig.ServiceVersion)
41 41
 	log.Printf("   • Port: %d", serviceConfig.Port)
42 42
 	log.Printf("   • Registry: %s", microConfig.RegistryAddress)
43
+	log.Printf("   • IdleTimeout: %d秒", serviceConfig.IdleTimeout)
44
+	log.Printf("   • ReadTimeout: %d秒", serviceConfig.ReadTimeout)
45
+	log.Printf("   • WriteTimeout: %d秒", serviceConfig.WriteTimeout)
43 46
 
44 47
 	// Run in background
45 48
 	go func() {

Loading…
Annulla
Salva