perf: 配置文件加载优化

This commit is contained in:
TsMask
2025-01-07 11:19:14 +08:00
parent 33dc2fa599
commit be9b9b1fdf
9 changed files with 110 additions and 173 deletions

View File

@@ -1,7 +1,6 @@
package src package src
import ( import (
"embed"
"fmt" "fmt"
"be.ems/src/framework/config" "be.ems/src/framework/config"
@@ -20,34 +19,19 @@ import (
"be.ems/src/modules/trace" "be.ems/src/modules/trace"
"be.ems/src/modules/ws" "be.ems/src/modules/ws"
"github.com/chenjiandongx/ginprom"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"
) )
//go:embed assets/* // AppEngine 路由函数句柄,交给由 http.ListenAndServe(addr, router)
var assetsDir embed.FS
// 路由函数句柄,交给由 http.ListenAndServe(addr, router)
func AppEngine() *gin.Engine { func AppEngine() *gin.Engine {
app := initAppEngine() app := initAppEngine()
// TODO 不建议在主分支中加入
// 性能分析监控
if promEnabled := config.Get("pprof.enabled"); promEnabled != nil && promEnabled.(bool) {
app.Use(ginprom.PromMiddleware(nil))
app.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))
}
// 初始全局默认 // 初始全局默认
initDefeat(app) initDefeat(app)
// 初始模块路由 // 初始模块路由
initModulesRoute(app) initModulesRoute(app)
// 设置程序内全局资源访问
config.SetAssetsDirFS(assetsDir)
// 首次安装启动记录 // 首次安装启动记录
machine.Launch() machine.Launch()
@@ -56,26 +40,6 @@ func AppEngine() *gin.Engine {
return app return app
} }
// 运行服务程序 main.go
//
// func main() {
// src.ConfigurationInit()
// if err := src.RunServer(); err != nil {
// src.ConfigurationClose()
// }
// }
func RunServer() error {
app := AppEngine()
// 读取服务配置
app.ForwardedByClientIP = config.Get("server.proxy").(bool)
addr := fmt.Sprintf(":%d", config.Get("server.port").(int))
// 启动服务
fmt.Printf("\nopen http://localhost%s \n\n", addr)
return app.Run(addr)
}
// 初始应用引擎 // 初始应用引擎
func initAppEngine() *gin.Engine { func initAppEngine() *gin.Engine {
var app *gin.Engine var app *gin.Engine

View File

@@ -1,9 +1,11 @@
# 应用服务配置 # 应用服务配置
server: server:
# 服务端口
port: 33030
# 是否开启代理 # 是否开启代理
proxy: false proxy: false
# 运行版本 standards/lite/tenants
runVersion: "standards"
# 运行模式 system/docker
runMode: "system"
# 日志 # 日志
logger: logger:

View File

@@ -1,6 +1,5 @@
# 应用服务配置 # 应用服务配置
server: server:
port: 33040
proxy: true proxy: true
# 日志 # 日志
@@ -10,10 +9,13 @@ logger:
# 静态文件配置, 相对项目根路径或填绝对路径 # 静态文件配置, 相对项目根路径或填绝对路径
staticFile: staticFile:
# 默认资源dir目录需要预先创建
default: default:
prefix: "/static"
dir: "C:/usr/local/omc/static" dir: "C:/usr/local/omc/static"
# 文件上传资源目录映射,与项目目录同级 # 文件上传资源目录映射,与项目目录同级
upload: upload:
prefix: "/upload"
dir: "C:/usr/local/omc/upload" dir: "C:/usr/local/omc/upload"
# security 安全 # security 安全

View File

@@ -1,6 +1,5 @@
# 应用服务配置 # 应用服务配置
server: server:
port: 33030
proxy: true proxy: true
# security 安全 # security 安全

View File

@@ -1,6 +1,8 @@
package src package src
import ( import (
"embed"
"be.ems/src/framework/config" "be.ems/src/framework/config"
"be.ems/src/framework/cron" "be.ems/src/framework/cron"
"be.ems/src/framework/datasource" "be.ems/src/framework/datasource"
@@ -8,10 +10,16 @@ import (
"be.ems/src/framework/redis" "be.ems/src/framework/redis"
) )
//go:embed config/*.yaml
var configDir embed.FS
//go:embed assets/*
var assetsDir embed.FS
// 配置中心初始加载 // 配置中心初始加载
func ConfigurationInit() { func ConfigurationInit() {
// 初始配置参数 // 初始配置参数
config.InitConfig() config.InitConfig(configDir, assetsDir)
// 初始程序日志 // 初始程序日志
logger.InitLogger() logger.InitLogger()
// 连接数据库实例 // 连接数据库实例

View File

@@ -8,18 +8,20 @@ import (
"os" "os"
"time" "time"
libConfig "be.ems/src/lib_features/config"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
libConfig "be.ems/lib/config"
libGlobal "be.ems/lib/global"
) )
//go:embed config/*.yaml var cfg *viper.Viper
var configFiles embed.FS
// 初始化程序配置 // 初始化程序配置
func InitConfig() { func InitConfig(configDir, assetsDir embed.FS) {
cfg = viper.New()
initFlag() initFlag()
initViper() initViper(configDir, assetsDir)
} }
// 指定参数绑定 // 指定参数绑定
@@ -28,7 +30,7 @@ func initFlag() {
pflag.String("env", "prod", "Specify Run Environment Configuration local or prod") pflag.String("env", "prod", "Specify Run Environment Configuration local or prod")
// --c /etc/restconf.yaml // --c /etc/restconf.yaml
// -c /etc/restconf.yaml // -c /etc/restconf.yaml
pConfig := pflag.StringP("config", "c", "./etc/restconf.yaml", "Specify Configuration File") pflag.StringP("config", "c", "./etc/restconf.yaml", "Specify Configuration File")
// --version // --version
// -V // -V
pVersion := pflag.BoolP("version", "V", false, "Output program version") pVersion := pflag.BoolP("version", "V", false, "Output program version")
@@ -39,7 +41,7 @@ func initFlag() {
// 参数固定输出 // 参数固定输出
if *pVersion { if *pVersion {
buildInfo := libConfig.BuildInfo() buildInfo := fmt.Sprintf("OMC version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer)
fmt.Println(buildInfo) fmt.Println(buildInfo)
os.Exit(1) os.Exit(1)
} }
@@ -48,113 +50,130 @@ func initFlag() {
os.Exit(1) os.Exit(1)
} }
// 外层lib和features使用的配置 cfg.BindPFlags(pflag.CommandLine)
libConfig.ConfigRead(*pConfig)
viper.BindPFlags(pflag.CommandLine)
} }
// 配置文件读取 // 配置文件读取
func initViper() { func initViper(configDir, assetsDir embed.FS) {
// 在当前工作目录中寻找配置
// viper.AddConfigPath("config")
// viper.AddConfigPath("src/config")
// 如果配置文件名中没有扩展名则需要设置Type // 如果配置文件名中没有扩展名则需要设置Type
viper.SetConfigType("yaml") cfg.SetConfigType("yaml")
// 从 embed.FS 中读取默认配置文件内容 // 从 embed.FS 中读取默认配置文件内容
configDefault, err := configFiles.ReadFile("config/config.default.yaml") configDefault, err := configDir.ReadFile("config/config.default.yaml")
if err != nil { if err != nil {
log.Fatalf("ReadFile config default file: %s", err) log.Fatalf("ReadFile config default file: %s", err)
return return
} }
// 设置默认配置文件内容到 viper // 设置默认配置文件内容到 viper
err = viper.ReadConfig(bytes.NewReader(configDefault)) err = cfg.ReadConfig(bytes.NewReader(configDefault))
if err != nil { if err != nil {
log.Fatalf("NewReader config default file: %s", err) log.Fatalf("NewReader config default file: %s", err)
return return
} }
// // 配置文件的名称(无扩展名) // 加载运行环境配置
// viper.SetConfigName("config.default") env := cfg.GetString("env")
// // 读取默认配置文件
// if err := viper.ReadInConfig(); err != nil {
// log.Fatalf("fatal error config default file: %s", err)
// }
env := viper.GetString("env")
if env != "local" && env != "prod" { if env != "local" && env != "prod" {
log.Fatalf("fatal error config env for local or prod : %s", env) log.Fatalf("fatal error config env for local or prod : %s", env)
} }
log.Printf("Current service environment operation configuration => %s \n", env) log.Printf("Current service environment operation configuration => %s \n", env)
// 加载运行配置文件合并相同配置 // 加载运行配置文件合并相同配置
if env == "prod" { envPath := "config/config.prod.yaml"
// viper.SetConfigName("config.prod") if env == "local" {
// 从 embed.FS 中读取默认配置文件内容 envPath = "config/config.local.yaml"
configProd, err := configFiles.ReadFile("config/config.prod.yaml")
if err != nil {
log.Fatalf("ReadFile config prod file: %s", err)
return
} }
// 设置默认配置文件内容到 viper
err = viper.MergeConfig(bytes.NewReader(configProd))
if err != nil {
log.Fatalf("NewReader config prod file: %s", err)
return
}
} else {
// viper.SetConfigName("config.local")
// 从 embed.FS 中读取默认配置文件内容 // 从 embed.FS 中读取默认配置文件内容
configLocal, err := configFiles.ReadFile("config/config.local.yaml") configEnv, err := configDir.ReadFile(envPath)
if err != nil { if err != nil {
log.Fatalf("ReadFile config local file: %s", err) log.Fatalf("ReadFile config local file: %s", err)
return return
} }
// 设置默认配置文件内容到 viper // 设置默认配置文件内容到 viper
err = viper.MergeConfig(bytes.NewReader(configLocal)) err = cfg.MergeConfig(bytes.NewReader(configEnv))
if err != nil { if err != nil {
log.Fatalf("NewReader config local file: %s", err) log.Fatalf("NewReader config local file: %s", err)
return return
} }
}
// if err := viper.MergeInConfig(); err != nil {
// log.Fatalf("fatal error config MergeInConfig: %s", err)
// }
// 合并外层lib和features使用配置 // 合并外使用配置
libConfig.ConfigInMerge() configFile := cfg.GetString("config")
if configFile != "" {
configInMerge(configFile)
}
// 记录程序开始运行的时间点 // 记录程序开始运行的时间点
viper.Set("runTime", time.Now()) cfg.Set("runTime", time.Now())
// 设置程序内全局资源访问
cfg.Set("AssetsDir", assetsDir)
}
// 配置文件读取进行内部参数合并
func configInMerge(configFile string) {
// 指定配置文件读取序列化
libConfig.ReadConfig(configFile)
uriPrefix := libConfig.GetYamlConfig().OMC.UriPrefix
if uriPrefix != "" {
libConfig.UriPrefix = uriPrefix
}
if libConfig.GetYamlConfig().TestConfig.Enabled {
libConfig.ReadTestConfigYaml(libConfig.GetYamlConfig().TestConfig.File)
}
// 配置文件读取
var v = viper.New()
// 设置配置文件路径
v.SetConfigFile(configFile)
v.SetConfigType("yaml")
// 读取配置文件
if err := v.ReadInConfig(); err != nil {
fmt.Printf("failure to read configuration file: %v \n", err)
return
}
// 合并外层lib和features使用配置
for key, value := range v.AllSettings() {
// 跳过配置
if key == "testconfig" || key == "logger" {
continue
}
// 数据库配置
if key == "database" {
item := value.(map[string]any)
defaultItem := cfg.GetStringMap("gorm.datasource.default")
defaultItem["type"] = item["type"]
defaultItem["host"] = item["host"]
defaultItem["port"] = item["port"]
defaultItem["username"] = item["user"]
defaultItem["password"] = item["password"]
defaultItem["database"] = item["name"]
continue
}
cfg.Set(key, value)
}
} }
// Env 获取运行服务环境 // Env 获取运行服务环境
// local prod // local prod
func Env() string { func Env() string {
return viper.GetString("env") return cfg.GetString("env")
} }
// RunTime 程序开始运行的时间 // RunTime 程序开始运行的时间
func RunTime() time.Time { func RunTime() time.Time {
return viper.GetTime("runTime") return cfg.GetTime("runTime")
} }
// Get 获取配置信息 // Get 获取配置信息
// //
// Get("server.port") // Get("server.proxy")
func Get(key string) any { func Get(key string) any {
return viper.Get(key) return cfg.Get(key)
} }
// GetAssetsDirFS 访问程序内全局资源访问 // GetAssetsDirFS 访问程序内全局资源访问
func GetAssetsDirFS() embed.FS { func GetAssetsDirFS() embed.FS {
return viper.Get("AssetsDir").(embed.FS) return cfg.Get("AssetsDir").(embed.FS)
}
// SetAssetsDirFS 设置程序内全局资源访问
func SetAssetsDirFS(assetsDir embed.FS) {
viper.Set("AssetsDir", assetsDir)
} }
// IsAdmin 用户是否为管理员 // IsAdmin 用户是否为管理员
@@ -165,7 +184,7 @@ func IsAdmin(userID string) bool {
// 从本地配置获取user信息 // 从本地配置获取user信息
admins := Get("user.adminList").([]any) admins := Get("user.adminList").([]any)
for _, s := range admins { for _, s := range admins {
if s.(string) == userID { if fmt.Sprint(s) == userID {
return true return true
} }
} }

View File

@@ -3,15 +3,15 @@ package logger
import ( import (
"log" "log"
"github.com/spf13/viper" "be.ems/src/framework/config"
) )
var logWriter *Logger var logWriter *Logger
// 初始程序日志 // 初始程序日志
func InitLogger() { func InitLogger() {
env := viper.GetString("env") env := config.Get("env").(string)
conf := viper.GetStringMap("logger") conf := config.Get("logger").(map[string]any)
fileDir := conf["filedir"].(string) fileDir := conf["filedir"].(string)
fileName := conf["filename"].(string) fileName := conf["filename"].(string)
level := conf["level"].(int) level := conf["level"].(int)

View File

@@ -1,53 +0,0 @@
package libfeatures
import (
"fmt"
libConf "be.ems/lib/core/conf"
libGlobal "be.ems/lib/global"
libConfig "be.ems/restagent/config"
"github.com/spf13/viper"
)
// BuildInfo 程序-V查看编译版本号信息
func BuildInfo() string {
return fmt.Sprintf("OMC restagent version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer)
}
// ConfigRead 指定配置文件读取
func ConfigRead(configFile string) {
// 外层lib和features使用的配置
libConfig.ReadConfig(configFile)
uriPrefix := libConfig.GetYamlConfig().OMC.UriPrefix
if uriPrefix != "" {
libConfig.UriPrefix = uriPrefix
}
if libConfig.GetYamlConfig().TestConfig.Enabled {
libConfig.ReadTestConfigYaml(libConfig.GetYamlConfig().TestConfig.File)
}
// 外层lib和features使用配置
libConf.InitConfig(configFile)
}
// 配置文件读取进行内部参数合并
func ConfigInMerge() {
// 合并外层lib和features使用配置
for key, value := range libConf.AllSettings() {
// 跳过配置
if key == "testconfig" || key == "rest" || key == "logger" {
continue
}
// 数据库配置
if key == "database" {
item := value.(map[string]any)
defaultItem := viper.GetStringMap("gorm.datasource.default")
defaultItem["host"] = item["host"]
defaultItem["port"] = item["port"]
defaultItem["username"] = item["user"]
defaultItem["password"] = item["password"]
defaultItem["database"] = item["name"]
continue
}
viper.Set(key, value)
}
}

View File

@@ -1,4 +0,0 @@
# 外层 lib 和 features 粘合层
- config.go 配置合并: restagent.yaml 文件内容,主要是数据库配置