Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement this repository #23

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .coverage/.keep
Empty file.
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
config/config-local.yaml
vendor/

vendor/
# we want to ignore files under this directory (ends with /*)
.coverage/*

# we want to keep track of this .keep files (starts with !)
!.keep
44 changes: 38 additions & 6 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,53 @@ package main

import (
"context"
"os"
"time"

"github.com/DoWithLogic/golang-clean-architecture/config"
"github.com/DoWithLogic/golang-clean-architecture/internal/app"
"github.com/DoWithLogic/golang-clean-architecture/pkg/observability"
"github.com/labstack/gommon/log"
)

func main() {
env := os.Getenv("env")
if env == "" {
env = "local"
// Load the application configuration from the specified directory.
cfg, err := config.LoadConfig("config")
if err != nil {
// If an error occurs while loading the configuration, panic with the error.
panic(err)
}

cfg, err := config.LoadConfig(env)
// Set the time zone to the specified value from the configuration.
_, err = time.LoadLocation(cfg.Server.TimeZone)
if err != nil {
panic(err)
// If an error occurs while setting the time zone, log the error and exit the function.
log.Error("Error on setting the time zone: ", err)
return
}

// Initialize observability components if observability is enabled in the configuration.
if cfg.Observability.Enable {
// Initialize the tracer provider for distributed tracing.
tracer, err := observability.InitTracerProvider(cfg)
if err != nil {
log.Warn("Failed to initialize tracer: ", err)
}

// Initialize the meter provider for metrics collection.
meter, err := observability.InitMeterProvider(cfg)
if err != nil {
log.Warn("Failed to initialize meter: ", err)
}

// Ensure that the tracer and meter are shut down when the main function exits.
defer func() {
if tracer != nil {
tracer.Shutdown(context.Background())
}
if meter != nil {
meter.Shutdown(context.Background())
}
}()
}

app.NewApp(context.Background(), cfg).Run()
Expand Down
26 changes: 26 additions & 0 deletions config/config-local.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
App:
Name: "golang-clean-architecture"
Version: "v0.0.1"
Scheme: "http"
Host: "localhost:3002"
Environment: local #local,development,staging,production

Server:
Port: "9090"
Debug: true
TimeZone: "Asia/Jakarta"


Database:
Host: 127.0.0.1
Port: 3306
Name: users
User: root
Password: pwd

Authentication:
Key: DoWithLogic!@#

Observability:
Enable: false
Mode: "otlp/http"
21 changes: 0 additions & 21 deletions config/config-local.yaml.example

This file was deleted.

99 changes: 80 additions & 19 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,41 @@
package config

import (
"errors"
"fmt"
"time"
"log"
"strings"

"github.com/spf13/viper"
)

type (
Config struct {
Database DatabaseConfig
App AppConfig
Server ServerConfig
Database DatabaseConfig
Authentication AuthenticationConfig
Observability ObservabilityConfig
JWT JWTConfig
}

// AppConfig holds the configuration related to the application settings.
AppConfig struct {
Name string
Version string
Schema string
Host string
Environment string
}

// ServerConfig holds the configuration for the server settings.
ServerConfig struct {
Port string // The port on which the server will listen.
Debug bool // Indicates if debug mode is enabled.
TimeZone string // The time zone setting for the server.
}

// DatabaseConfig holds the configuration for the database connection.
DatabaseConfig struct {
Host string
Port int
Expand All @@ -22,37 +44,76 @@ type (
Password string
}

ServerConfig struct {
Name string
Version string
RPCPort string
RESTPort string
Debug bool
Environment string
ReadTimeout time.Duration
WriteTimeout time.Duration
AuthenticationConfig struct {
Key string
}

AuthenticationConfig struct {
Key string
SecretKey string
SaltKey string
// ObservabilityConfig holds the configuration for observability settings.
ObservabilityConfig struct {
Enable bool // Indicates if observability is enabled.
Mode string // Specifies the observability mode.
}

JWTConfig struct {
Key string
Expired int
Label string
}
)

func LoadConfig(env string) (Config, error) {
viper.SetConfigFile(fmt.Sprintf("config/config-%s.yaml", env))
// LoadConfig loads the configuration from the specified filename.
func LoadConfig(filename string) (Config, error) {
// Create a new Viper instance.
v := viper.New()

if err := viper.ReadInConfig(); err != nil {
// Set the configuration file name, path, and environment variable settings.
v.SetConfigName(fmt.Sprintf("config/%s", filename))
v.AddConfigPath(".")
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// Read the configuration file.
if err := v.ReadInConfig(); err != nil {
fmt.Printf("Error reading config file: %v\n", err)
return Config{}, err
}

// Unmarshal the configuration into the Config struct.
var config Config
if err := viper.Unmarshal(&config); err != nil {
if err := v.Unmarshal(&config); err != nil {
fmt.Printf("Error unmarshaling config: %v\n", err)
return Config{}, err
}

return config, nil
}

// LoadConfigPath loads the configuration from the specified path.
func LoadConfigPath(path string) (Config, error) {
// Create a new Viper instance.
v := viper.New()

// Set the configuration file name, path, and environment variable settings.
v.SetConfigName(path)
v.AddConfigPath(".")
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// Read the configuration file.
if err := v.ReadInConfig(); err != nil {
// Handle the case where the configuration file is not found.
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
return Config{}, errors.New("config file not found")
}
return Config{}, err
}

// Parse the configuration into the Config struct.
var c Config
if err := v.Unmarshal(&c); err != nil {
log.Printf("unable to decode into struct, %v", err)
return Config{}, err
}

return c, nil
}
26 changes: 26 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
App:
Name: "golang-clean-architecture"
Version: "v0.0.1"
Scheme: "http"
Host: "localhost:3002"
Environment: local #local,development,staging,production

Server:
Port: "9090"
Debug: true
TimeZone: "Asia/Jakarta"


Database:
Host: 127.0.0.1
Port: 3306
Name: users
User: root
Password: pwd

Authentication:
Key: DoWithLogic!@#

Observability:
Enable: false
Mode: "otlp/http"
2 changes: 0 additions & 2 deletions database/mysql/migration/20230924142159_add_user_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ CREATE TABLE `users` (
`user_type` varchar(50) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`created_at` timestamp NOT NULL,
`created_by` varchar(255) NOT NULL,
`updated_at` timestamp DEFAULT NULL,
`updated_by` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Expand Down
15 changes: 4 additions & 11 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@ services:
interval: 0.5s
timeout: 10s
retries: 10
golang-clean-architecture:
build:
context: .
dockerfile: Dockerfile # Specify the path to your Dockerfile
ports:
- 8080:8080
- 9090:9090
volumes:
- ./config/config-local.yaml:/app/config/config-local.yaml
depends_on:
- mysql-db
entrypoint:
sh -c "
echo 'CREATE DATABASE IF NOT EXISTS users;' > /docker-entrypoint-initdb.d/init.sql;
/usr/local/bin/docker-entrypoint.sh --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci"
Loading