config

package module
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2025 License: Apache-2.0 Imports: 11 Imported by: 1

README

Test

Config Module

A flexible configuration management module for Go applications with support for YAML/JSON files, environment variables, and type-safe access to configuration values.

Installation

go get github.com/inovacc/config

Features

  • Load configuration from YAML or JSON files
  • Type-safe access to service-specific configuration using generics
  • Support for environment variable overrides with custom prefixes
  • Secure handling of sensitive configuration values
  • Automatic generation of default configuration files with sensible defaults
  • Built-in validation for configuration values
  • Structured logging integration
  • Based on a customized version of Viper for configuration management

Quick Start

Loading and Using Configuration
package main

import (
	"fmt"
	"log"

	"github.com/inovacc/config"
)

type ServiceConfig struct {
	Port int    `yaml:"port"`
	Host string `yaml:"host"`
}

func main() {
	// Initialize with default values
	svc := &ServiceConfig{
		Port: 8080,
		Host: "localhost",
	}

	// Load configuration from a file, applying defaults if needed
	if err := config.InitServiceConfig(svc, "config.yaml"); err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}

	// Get the loaded configuration with type safety
	cfg, err := config.GetServiceConfig[*ServiceConfig]()
	if err != nil {
		log.Fatalf("Failed to get service config: %v", err)
	}

	fmt.Printf("Service running on %s:%d\n", cfg.Host, cfg.Port)

	// Access base configuration
	baseCfg := config.GetBaseConfig()
	fmt.Printf("Application ID: %s\n", baseCfg.AppID)
}

Advanced Features

Validation Rules and Default Values

The config module includes built-in validation for configuration values:

  • AppID: Must be at least 8 characters long. If not provided, a UUID is automatically generated.
  • AppSecret: Must be at least 12 characters long. If not provided, a UUID is automatically generated.
  • Logger.LogLevel: Must be one of "DEBUG", "INFO", "WARN", "WARNING", or "ERROR" (case-insensitive).
Creating Default Configuration

You can generate a default configuration file with random credentials using the DefaultConfig function:

// Generate a default config file with a zeroed MyServiceConfig
if err := config.DefaultConfig[*MyServiceConfig]("config.yaml"); err != nil {
    log.Fatal(err)
}
Environment Variable Overrides

You can override configuration values using environment variables:

// Set a prefix for environment variables
config.SetEnvPrefix("APP")

// Now environment variables like APP_PORT will override config values
// For example, setting APP_LOGGER_LOGLEVEL=INFO will override logger.logLevel
Secure Handling of Sensitive Values

The base configuration includes built-in masking for the AppSecret field. You can mark additional fields as sensitive with the sensitive:"true" tag (though note that currently only the base AppSecret field is automatically masked):

type MyConfig struct {
    Username string `yaml:"username"`
    Password string `yaml:"password" sensitive:"true"`
}

// Get a copy with sensitive values masked
secureCfg := config.GetSecureCopy()

// Log configuration safely
config.LogConfig()

Note: Currently, only the AppSecret field in the base configuration is automatically masked. Support for automatically masking custom fields marked with sensitive:"true" is planned for a future release. See IMPROVEMENTS.md for more details.

Project Structure

github.com/inovacc/config/
├── config.go         # Main implementation
├── config_test.go    # Tests
├── go.mod            # Module definition
├── go.sum            # Dependencies
├── internal/         # Internal packages
│   └── viper/        # Customized version of Viper
├── LICENSE           # License information
├── README.md         # Documentation
├── IMPROVEMENTS.md   # Improvement suggestions and future plans
├── Taskfile.yml      # Task runner configuration
└── testdata/         # Test data
    └── config.yaml   # Sample configuration

Configuration Example

Below is an example of a config.yml file based on the module's structure:

appversion: 0.0.0-development
environment: dev
appID: 3222706d-aa89-4737-a6e3-46d29a7b8b02
appSecret: a6e780be-8b0b-4f5d-b907-72ae0d651eb8
logger:
  logLevel: DEBUG
service:
  username: ""
  password: ""

Future Improvements

The module has several planned improvements documented in the IMPROVEMENTS.md file, including:

  • Configuration reloading: Support for watching configuration files for changes
  • Reflection-based sensitive value handling: Enhance GetSecureCopy to mask all fields with the sensitive:"true" tag
  • Custom validation rules: Support for custom validation of configuration values
  • Configuration versioning: Support for versioning and migration
  • Configuration encryption: Support for encrypting sensitive values
  • Configuration profiles: Support for different environments (dev, test, prod)
  • Comprehensive testing: More tests for edge cases

For more details, see the IMPROVEMENTS.md file.

Acknowledgments

This project is based on a customized version of Viper, originally created by Steve Francia (@spf13). We would like to express our gratitude to Steve and all the contributors to the Viper project for their excellent work.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultConfig

func DefaultConfig[T any](configPath string) error

DefaultConfig generates a base configuration file with random credentials and zeroed service configuration for a given type.

It should be used to bootstrap a config.yaml with sensible defaults.

Example:

err := config.DefaultConfig[*MyServiceConfig]("config.yaml")
if err != nil {
    log.Fatal(err)
}

func GetServiceConfig

func GetServiceConfig[T any]() (T, error)

GetServiceConfig returns the previously registered service-specific configuration with type safety using generics.

If the type does not match what was stored, an error is returned.

Example:

cfg, err := config.GetServiceConfig[*MyServiceConfig]()
if err != nil {
    log.Fatal(err)
}

func InitServiceConfig

func InitServiceConfig(v any, configPath string) error

InitServiceConfig loads a configuration file and binds a service-specific struct to the `Service` field in the global config.

It must be called before accessing the service configuration via GetServiceConfig.

If the configuration file does not exist, a default one will be created. Default values from the provided service config struct will be used if corresponding values are not found in the configuration file.

Example:

type MyServiceConfig struct {
    Port int
    Mode string
}

svc := &MyServiceConfig{
    Port: 8080,  // Default value
    Mode: "dev", // Default value
}

err := config.InitServiceConfig(svc, "config.yaml")
if err != nil {
    log.Fatal(err)
}

func LogConfig

func LogConfig()

LogConfig logs the configuration at debug level, masking sensitive values.

This is a convenience method for safely logging the configuration.

Example:

config.LogConfig()

func SetEnvPrefix

func SetEnvPrefix(prefix string)

SetEnvPrefix sets a prefix for environment variables.

Environment variables that match the pattern {prefix}_* will override the corresponding configuration values. The matching is case-insensitive.

For example, if the prefix is "APP", then the environment variable "APP_LOGGER_LOGLEVEL" will override the value of "logger.logLevel" in the configuration file.

Example:

config.SetEnvPrefix("APP")

Types

type Config

type Config struct {
	Environment string `yaml:"environment" mapstructure:"environment"`
	AppVersion  string `yaml:"-" mapstructure:"-"`
	ConfigFile  string `yaml:"-" mapstructure:"-"`
	AppID       string `yaml:"appID" mapstructure:"appID"`
	AppSecret   string `yaml:"appSecret" mapstructure:"appSecret" sensitive:"true"`
	Logger      Logger `yaml:"logger" mapstructure:"logger"`
	Service     any    `yaml:"service" mapstructure:"service"`
	// contains filtered or unexported fields
}

Config represents the global application configuration.

Fields:

  • Environment: The current environment (e.g., "dev", "prod").
  • AppVersion: The application version.
  • AppID: Unique application identifier.
  • AppSecret: Secret key for the application (sensitive).
  • Logger: Structured logging configuration.
  • Service: Service-specific configuration.

func GetBaseConfig

func GetBaseConfig() *Config

GetBaseConfig returns a pointer to the global configuration base object.

This allows access to common fields like AppID, Logger, and AppSecret.

Example:

cfg := config.GetBaseConfig()
fmt.Println("AppID:", cfg.AppID)

func GetSecureCopy

func GetSecureCopy() Config

GetSecureCopy returns a copy of the configuration with sensitive values masked.

This is useful for logging or displaying the configuration without exposing sensitive information like secrets or passwords.

Example:

secureCfg := config.GetSecureCopy()
fmt.Printf("%+v\n", secureCfg)

type Logger

type Logger struct {
	LogLevel string `yaml:"logLevel" mapstructure:"logLevel"`
}

Logger defines the configuration for structured logging.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL