init project
This commit is contained in:
119
internal/initialize/loadconfig.go
Normal file
119
internal/initialize/loadconfig.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/dungnt11/senflow_app/global"
|
||||
"github.com/fatih/color"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func LoadConfig() error {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Cấu hình server
|
||||
global.Config.Server.Port = os.Getenv("PORT")
|
||||
global.Config.Server.AppEnv = os.Getenv("APP_ENV")
|
||||
|
||||
// Cấu hình database
|
||||
global.Config.Database.Host = os.Getenv("BLUEPRINT_DB_HOST")
|
||||
global.Config.Database.Port = os.Getenv("BLUEPRINT_DB_PORT")
|
||||
global.Config.Database.Database = os.Getenv("BLUEPRINT_DB_DATABASE")
|
||||
global.Config.Database.Username = os.Getenv("BLUEPRINT_DB_USERNAME")
|
||||
global.Config.Database.Password = os.Getenv("BLUEPRINT_DB_PASSWORD")
|
||||
global.Config.Database.RootPassword = os.Getenv("BLUEPRINT_DB_ROOT_PASSWORD")
|
||||
|
||||
// Chuyển đổi các giá trị cấu hình database từ string sang int
|
||||
if maxIdleConns := os.Getenv("BLUEPRINT_DB_MAX_IDLE_CONNS"); maxIdleConns != "" {
|
||||
fmt.Sscanf(maxIdleConns, "%d", &global.Config.Database.MaxIdleConns)
|
||||
}
|
||||
|
||||
if maxOpenConns := os.Getenv("BLUEPRINT_DB_MAX_OPEN_CONNS"); maxOpenConns != "" {
|
||||
fmt.Sscanf(maxOpenConns, "%d", &global.Config.Database.MaxOpenConns)
|
||||
}
|
||||
|
||||
if connMaxLifetime := os.Getenv("BLUEPRINT_DB_CONN_MAX_LIFETIME"); connMaxLifetime != "" {
|
||||
fmt.Sscanf(connMaxLifetime, "%d", &global.Config.Database.ConnMaxLifetime)
|
||||
}
|
||||
|
||||
// Cấu hình logger
|
||||
global.Config.Logger.LogLevel = os.Getenv("LOGGER_LOG_LEVEL")
|
||||
global.Config.Logger.FileLogName = os.Getenv("LOGGER_FILE_LOG_NAME")
|
||||
|
||||
// Chuyển đổi từ string sang int và bool
|
||||
if maxSize := os.Getenv("LOGGER_MAX_SIZE"); maxSize != "" {
|
||||
fmt.Sscanf(maxSize, "%d", &global.Config.Logger.MaxSize)
|
||||
}
|
||||
|
||||
if maxBackups := os.Getenv("LOGGER_MAX_BACKUPS"); maxBackups != "" {
|
||||
fmt.Sscanf(maxBackups, "%d", &global.Config.Logger.MaxBackups)
|
||||
}
|
||||
|
||||
if maxAge := os.Getenv("LOGGER_MAX_AGE"); maxAge != "" {
|
||||
fmt.Sscanf(maxAge, "%d", &global.Config.Logger.MaxAge)
|
||||
}
|
||||
|
||||
if compress := os.Getenv("LOGGER_COMPRESS"); compress != "" {
|
||||
global.Config.Logger.Compress = strings.ToLower(compress) == "true"
|
||||
}
|
||||
|
||||
printConfig()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printConfig() {
|
||||
// Tạo các đối tượng màu sắc
|
||||
titleColor := color.New(color.FgHiCyan, color.Bold)
|
||||
sectionColor := color.New(color.FgHiYellow, color.Bold)
|
||||
keyColor := color.New(color.FgHiGreen)
|
||||
valueColor := color.New(color.FgHiWhite)
|
||||
|
||||
fmt.Println() // Thêm dòng trống ở đầu
|
||||
|
||||
// In tiêu đề
|
||||
titleColor.Println("✨✨✨ CẤU HÌNH ỨNG DỤNG ✨✨✨")
|
||||
fmt.Println()
|
||||
|
||||
// Sử dụng reflection để tự động in tất cả các cấu hình
|
||||
configValue := reflect.ValueOf(global.Config)
|
||||
configType := configValue.Type()
|
||||
|
||||
// Duyệt qua tất cả các trường của cấu hình
|
||||
for i := 0; i < configValue.NumField(); i++ {
|
||||
sectionName := configType.Field(i).Name
|
||||
sectionValue := configValue.Field(i)
|
||||
sectionType := sectionValue.Type()
|
||||
|
||||
// In tên section
|
||||
sectionColor.Printf("[%s]\n", strings.ToUpper(sectionName))
|
||||
|
||||
// Duyệt qua tất cả các trường của section
|
||||
for j := 0; j < sectionValue.NumField(); j++ {
|
||||
fieldName := sectionType.Field(j).Name
|
||||
fieldValue := sectionValue.Field(j).Interface()
|
||||
|
||||
// Ẩn mật khẩu
|
||||
displayValue := fmt.Sprintf("%v", fieldValue)
|
||||
if strings.Contains(strings.ToLower(fieldName), "password") {
|
||||
displayValue = "******** (ẩn)"
|
||||
}
|
||||
|
||||
// In tên trường và giá trị
|
||||
keyColor.Printf(" %-15s: ", fieldName)
|
||||
valueColor.Printf("%s\n", displayValue)
|
||||
}
|
||||
|
||||
fmt.Println() // Thêm dòng trống giữa các section
|
||||
}
|
||||
|
||||
// In thông báo thành công
|
||||
titleColor.Println("✅ Cấu hình đã được tải thành công!")
|
||||
fmt.Println() // Thêm dòng trống ở cuối
|
||||
}
|
103
internal/initialize/logger.go
Normal file
103
internal/initialize/logger.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/dungnt11/senflow_app/global"
|
||||
"github.com/natefinch/lumberjack"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// InitLogger khởi tạo logger
|
||||
func InitLogger() *zap.Logger {
|
||||
// Đảm bảo thư mục logs tồn tại
|
||||
ensureLogDir(global.Config.Logger.FileLogName)
|
||||
|
||||
// Khởi tạo logger
|
||||
return newLogger(global.Config.Logger)
|
||||
}
|
||||
|
||||
// ensureLogDir đảm bảo thư mục logs tồn tại
|
||||
func ensureLogDir(logPath string) {
|
||||
// Tìm vị trí thư mục cuối cùng trong đường dẫn
|
||||
lastSlash := 0
|
||||
for i := len(logPath) - 1; i >= 0; i-- {
|
||||
if logPath[i] == '/' {
|
||||
lastSlash = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Nếu không có thư mục, không cần tạo
|
||||
if lastSlash == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Tạo thư mục nếu chưa tồn tại
|
||||
dirPath := logPath[:lastSlash]
|
||||
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||
os.MkdirAll(dirPath, 0755)
|
||||
}
|
||||
}
|
||||
|
||||
// newLogger tạo một logger mới
|
||||
func newLogger(config global.LoggerConfig) *zap.Logger {
|
||||
// Xác định level log
|
||||
var level zapcore.Level
|
||||
switch config.LogLevel {
|
||||
case "debug":
|
||||
level = zapcore.DebugLevel
|
||||
case "info":
|
||||
level = zapcore.InfoLevel
|
||||
case "warn":
|
||||
level = zapcore.WarnLevel
|
||||
case "error":
|
||||
level = zapcore.ErrorLevel
|
||||
default:
|
||||
level = zapcore.InfoLevel
|
||||
}
|
||||
|
||||
// Cấu hình encoder
|
||||
encoder := getEncoder()
|
||||
|
||||
// Cấu hình lumberjack để xoay vòng file log
|
||||
hook := lumberjack.Logger{
|
||||
Filename: config.FileLogName,
|
||||
MaxSize: config.MaxSize, // megabytes
|
||||
MaxBackups: config.MaxBackups,
|
||||
MaxAge: config.MaxAge, // days
|
||||
Compress: config.Compress,
|
||||
}
|
||||
|
||||
// Tạo core cho zap
|
||||
core := zapcore.NewCore(
|
||||
encoder,
|
||||
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)),
|
||||
level,
|
||||
)
|
||||
|
||||
// Tạo logger với các tùy chọn
|
||||
return zap.New(core,
|
||||
zap.AddCaller(),
|
||||
zap.AddStacktrace(zapcore.ErrorLevel),
|
||||
)
|
||||
}
|
||||
|
||||
// getEncoder trả về encoder cho zap
|
||||
func getEncoder() zapcore.Encoder {
|
||||
encoderConfig := zap.NewProductionEncoderConfig()
|
||||
|
||||
// Cấu hình thời gian
|
||||
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
encoderConfig.TimeKey = "time"
|
||||
|
||||
// Cấu hình level
|
||||
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||
|
||||
// Cấu hình caller
|
||||
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
|
||||
|
||||
// Trả về encoder JSON
|
||||
return zapcore.NewJSONEncoder(encoderConfig)
|
||||
}
|
46
internal/initialize/mysql.go
Normal file
46
internal/initialize/mysql.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/dungnt11/senflow_app/global"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// checkErrorPanic kiểm tra lỗi và gọi panic nếu có lỗi, đồng thời ghi log chi tiết.
|
||||
func checkErrorPanic(err error, errString string) {
|
||||
if err != nil {
|
||||
global.Logger.Error(errString, zap.Error(err))
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// InitMysql khởi tạo kết nối đến cơ sở dữ liệu MySQL và trả về đối tượng *gorm.DB.
|
||||
func InitMysql() *gorm.DB {
|
||||
m := global.Config.Database
|
||||
dsn := "%s:%s@tcp(%s:%v)/%s?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
s := fmt.Sprintf(dsn, m.Username, m.Password, m.Host, m.Port, m.Database)
|
||||
db, err := gorm.Open(mysql.Open(s), &gorm.Config{
|
||||
SkipDefaultTransaction: false,
|
||||
})
|
||||
checkErrorPanic(err, "InitMysql initialization error")
|
||||
global.Logger.Info("Initializing MySQL Successfully")
|
||||
setPool(db)
|
||||
return db
|
||||
}
|
||||
|
||||
// setPool thiết lập các thông số cho connection pool của cơ sở dữ liệu.
|
||||
func setPool(db *gorm.DB) {
|
||||
m := global.Config.Database
|
||||
sqlDb, err := db.DB()
|
||||
if err != nil {
|
||||
global.Logger.Error("Failed to get sql.DB from gorm.DB", zap.Error(err))
|
||||
return
|
||||
}
|
||||
sqlDb.SetMaxIdleConns(m.MaxIdleConns)
|
||||
sqlDb.SetMaxOpenConns(m.MaxOpenConns)
|
||||
sqlDb.SetConnMaxLifetime(time.Duration(m.ConnMaxLifetime) * time.Second)
|
||||
}
|
82
internal/initialize/run.go
Executable file
82
internal/initialize/run.go
Executable file
@@ -0,0 +1,82 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/dungnt11/senflow_app/global"
|
||||
"github.com/dungnt11/senflow_app/internal/routers"
|
||||
"github.com/dungnt11/senflow_app/internal/wire"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Run khởi động ứng dụng
|
||||
func Run() {
|
||||
// Tải cấu hình từ file .env
|
||||
if err := LoadConfig(); err != nil {
|
||||
fmt.Printf("Không thể tải cấu hình: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Khởi tạo logger
|
||||
global.Logger = InitLogger()
|
||||
if global.Logger == nil {
|
||||
fmt.Println("Khởi tạo logger thất bại")
|
||||
return
|
||||
}
|
||||
|
||||
// Khởi tạo database
|
||||
global.Mdb = InitMysql()
|
||||
if global.Mdb == nil {
|
||||
global.Logger.Error("Khởi tạo MySQL thất bại")
|
||||
return
|
||||
}
|
||||
|
||||
// Khởi tạo router
|
||||
r := gin.Default()
|
||||
|
||||
// Khởi tạo controllers thông qua wire
|
||||
controllers, err := wire.InitializeControllers()
|
||||
if err != nil {
|
||||
global.Logger.Error("Khởi tạo controllers thất bại", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Khởi tạo routers
|
||||
routers.InitRouters(r, controllers)
|
||||
|
||||
// Khởi động server
|
||||
port := global.Config.Server.Port
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%s", port),
|
||||
Handler: r,
|
||||
}
|
||||
|
||||
// Khởi động server trong goroutine riêng
|
||||
go func() {
|
||||
global.Logger.Info(fmt.Sprintf("Server đang chạy trên cổng %s", port))
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
global.Logger.Error("Server gặp lỗi", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
// Graceful shutdown
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
global.Logger.Info("Đang tắt server...")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
global.Logger.Error("Server shutdown gặp lỗi", zap.Error(err))
|
||||
}
|
||||
|
||||
global.Logger.Info("Server đã tắt thành công.")
|
||||
}
|
Reference in New Issue
Block a user