一個功能齊全的微服務可能需要下面幾個功能:
-
讀取命令行參數
-
讀取配置文件
-
路由
-
優雅退出
-
操作數據庫
這里實現一個微服務的雛形,實現上面除了操作數據庫以外的四個功能,方便以后參考。
想要運行該源碼,只需要准備一個配置文件/tmp/config.yaml:
log_path: /tmp/logstash.log.%Y%m%d%H%M # 定義日志文件名稱格式
然后執行命令:
go run main.go --config=/tmp/config.yaml
其中使用到的工具庫包括:
"github.com/gin-gonic/gin" 路由功能
"github.com/fvbock/endless" 優雅退出
"github.com/spf13/viper" 讀取配置文件
rotatelogs "github.com/lestrrat-go/file-rotatelogs" 日志定時清除
"flag" 讀取命令行參數
源碼:
package main
import (
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/spf13/viper"
)
func main() {
StartServer()
}
func StartServer() {
// 程序啟動命令:go run main.go --config=/tmp/config.yaml (文件內容:log_path: /tmp/logstash.log.%Y%m%d%H%M)
// 從啟動命令讀取配置文件路徑:config(string類型)
var configFile = flag.String("config", "", "set config file path by: -config=/path/to/log_file")
flag.Parse()
if *configFile == "" {
panic("please set config file path by: -config=/path/to/log_file")
}
fmt.Printf("log file path: %s\n", *configFile)
// 使用viper讀取配置文件
config := viper.New()
config.SetConfigFile(*configFile)
err := config.ReadInConfig()
if err != nil {
panic(fmt.Sprintf("failed to read configuration file: %s", *configFile))
}
// 日志文件:logstash.log.202105251600;每1小時產生一個日志文件;日志文件24小時以后自動清理
log_path := config.GetString("log_path")
logFile, err := rotatelogs.New(log_path,
rotatelogs.WithRotationTime(time.Duration(1)*time.Hour),
rotatelogs.WithMaxAge(time.Duration(24)*time.Hour))
if err != nil {
log.Fatalln("fail to create log file!")
}
log := log.New(logFile, "", log.Ldate|log.Ltime|log.Lshortfile)
// gin.SetMode(gin.ReleaseMode)
// gin 的日志輸出到日志文件以及控制台
gin.DefaultWriter = io.MultiWriter(logFile, os.Stdout)
router := gin.Default()
v1 := router.Group("/api/v1", func(c *gin.Context) {
log.Println("group v1...")
})
{
v1.GET("/configs/list", func(c *gin.Context) {
log.Println("v1 configs/list, wait 10 seconds...")
time.Sleep(10 * time.Second)
c.JSON(http.StatusOK, "action: list")
log.Println("v1 configs/list finished")
})
v1.GET("/configs/add", func(c *gin.Context) {
log.Println("v1 configs/add wait 5 seconds")
time.Sleep(5 * time.Second)
c.JSON(http.StatusOK, "action: add")
log.Println("v1 configs/add finished")
})
}
// SIGHUP will trigger a fork/restart
// syscall.SIGINT and syscall.SIGTERM will trigger a shutdown of the server (it will finish running requests)
endless.ListenAndServe(":8080", router)
}
