vcfg

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Jun 6, 2025 License: MIT Imports: 14 Imported by: 1

README

VCFG - Versatile Configuration Manager for Go

Go Version License Go Report Card

VCFG is a powerful and flexible configuration management library for Go applications that supports multiple configuration sources, automatic type conversion, validation, and an extensible plugin system. It provides both simple and advanced configuration loading patterns to meet various application needs.

Features

Core Features
  • Multiple Configuration Sources: Support for JSON, YAML, TOML files, environment variables, CLI flags, and custom providers
  • Type-Safe Configuration: Generic-based type safety with automatic unmarshaling
  • Configuration Merging: Intelligent merging of multiple configuration sources with priority handling
  • Hot Reloading: Automatic configuration reloading when files change
  • Validation: Built-in validation using github.com/go-playground/validator/v10
  • Default Values: Automatic application of default values using struct tags
Plugin System
  • Extensible Architecture: Plugin-based architecture for extending functionality
  • Built-in Plugins: Logger plugin with advanced features (rotation, multiple outputs, structured logging)
  • Plugin Lifecycle Management: Automatic plugin discovery, initialization, and cleanup
  • Hot Reload Support: Automatic plugin reloading when configuration changes are detected
  • Custom Plugins: Easy creation of custom plugins with well-defined interfaces
Advanced Features
  • Thread-Safe Operations: Concurrent access protection with atomic operations
  • Builder Pattern: Fluent API for configuration setup
  • CLI Integration: Seamless integration with urfave/cli/v3
  • Environment Variable Support: Flexible environment variable mapping
  • File Watching: Automatic detection of configuration file changes

Installation

go get github.com/nextpkg/vcfg

Quick Start

Simple Usage
package main

import (
    "fmt"
    "github.com/nextpkg/vcfg"
)

type Config struct {
    Name    string `json:"name" default:"MyApp"`
    Port    int    `json:"port" default:"8080"`
    Debug   bool   `json:"debug" default:"false"`
}

func main() {
    // Load configuration from file
    cm := vcfg.MustLoad[Config]("config.json")
    defer cm.Close()
    
    config := cm.Get()
    fmt.Printf("App: %s, Port: %d, Debug: %t\n", config.Name, config.Port, config.Debug)
}
Advanced Usage with Builder
package main

import (
    "context"
    "log"
    "github.com/nextpkg/vcfg"
    "github.com/urfave/cli/v3"
)

type AppConfig struct {
    Server struct {
        Host string `json:"host" default:"localhost"`
        Port int    `json:"port" default:"8080"`
    } `json:"server"`
    Database struct {
        URL      string `json:"url" validate:"required"`
        MaxConns int    `json:"max_conns" default:"10"`
    } `json:"database"`
    // Plugin configurations are automatically discovered by the plugin system
    // based on struct fields that implement plugins.Config interface
    Logger *LoggerConfig `json:"logger,omitempty"`
}

func main() {
    app := &cli.Command{
        Name: "myapp",
        Flags: []cli.Flag{
            &cli.StringFlag{
                Name:  "config",
                Value: "config.yaml",
                Usage: "Configuration file path",
            },
            &cli.IntFlag{
                Name:  "server.port",
                Usage: "Server port",
            },
        },
        Action: func(ctx context.Context, cmd *cli.Command) error {
            // Build configuration manager with multiple sources
            cm, err := vcfg.NewBuilder[AppConfig]().
                AddFile(cmd.String("config")).        // Configuration file
                AddEnv("MYAPP_").                     // Environment variables
                AddCliFlags(cmd, ".").                // CLI flags
                WithWatch().                          // Enable file watching
                WithPlugin().                         // Enable plugins
                Build(context.Background())
            if err != nil {
                return err
            }
            defer cm.Close()
            
            config := cm.Get()
            log.Printf("Server starting on %s:%d", config.Server.Host, config.Server.Port)
            
            // Your application logic here
            return nil
        },
    }
    
    if err := app.Run(context.Background(), os.Args); err != nil {
        log.Fatal(err)
    }
}

Configuration Sources

File Sources

Supported formats: JSON, YAML, TOML

// Single file
cm := vcfg.MustLoad[Config]("config.yaml")

// Multiple files (merged in order)
cm := vcfg.MustLoad[Config]("base.yaml", "env.yaml", "local.yaml")
Environment Variables
builder := vcfg.NewBuilder[Config]()
builder.AddEnv("MYAPP_") // Maps MYAPP_SERVER_PORT to server.port
CLI Flags
builder.AddCliFlags(cmd, ".") // Uses dot notation for nested keys
Custom Providers
import "github.com/knadh/koanf/providers/rawbytes"

provider := rawbytes.Provider([]byte(`{"key": "value"}`))
builder.AddProvider(provider)

Plugin System

Built-in Logger Plugin
# config.yaml
plugins:
  logger:
    type: "logger"
    level: "info"
    format: "json"
    output: "both"  # stdout, stderr, file, both
    file_path: "./logs/app.log"
    add_source: true
    enable_rotation: true
    rotate_interval: "daily"
    max_file_size: 524288000  # 500MB
    max_age: 7
Creating Custom Plugins
package myplugin

import (
    "context"
    "github.com/nextpkg/vcfg/plugins"
)

// Plugin configuration
type MyPluginConfig struct {
    plugins.BaseConfig `koanf:",squash"`
    Setting1 string `koanf:"setting1" default:"default_value"`
    Setting2 int    `koanf:"setting2" default:"42"`
}

// Plugin implementation
type MyPlugin struct {
    config *MyPluginConfig
}

func (p *MyPlugin) Startup(ctx context.Context, config any) error {
    p.config = config.(*MyPluginConfig)
    // Initialize plugin
    return nil
}

func (p *MyPlugin) Reload(ctx context.Context, config any) error {
    p.config = config.(*MyPluginConfig)
    // Handle configuration reload
    return nil
}

func (p *MyPlugin) Shutdown(ctx context.Context) error {
    // Cleanup resources
    return nil
}

// Register plugin
func init() {
    plugins.RegisterPluginType("myplugin", &MyPlugin{}, &MyPluginConfig{})
}

Configuration Validation

VCFG uses github.com/go-playground/validator/v10 for validation:

type Config struct {
    Email    string `json:"email" validate:"required,email"`
    Port     int    `json:"port" validate:"min=1,max=65535"`
    URL      string `json:"url" validate:"required,url"`
    Password string `json:"password" validate:"min=8"`
}

Default Values

Set default values using struct tags:

type Config struct {
    Host     string `json:"host" default:"localhost"`
    Port     int    `json:"port" default:"8080"`
    Debug    bool   `json:"debug" default:"false"`
    Timeout  string `json:"timeout" default:"30s"`
}

File Watching

Enable automatic configuration reloading:

cm := vcfg.NewBuilder[Config]().
    AddFile("config.yaml").
    WithWatch().  // Enable file watching
    MustBuild()

Thread Safety

VCFG is designed to be thread-safe:

// Safe to call from multiple goroutines
config := cm.Get()

// Safe concurrent access
go func() {
    for {
        config := cm.Get()
        // Use config
        time.Sleep(time.Second)
    }
}()

Error Handling

// Using Builder for error handling
cm, err := vcfg.NewBuilder[Config]().
    AddFile("config.yaml").
    Build(context.Background())
if err != nil {
    log.Fatal("Failed to build config:", err)
}

// Using MustLoad for simple cases (panics on error)
cm := vcfg.MustLoad[Config]("config.yaml")

Plugin Hot Reload

VCFG supports automatic plugin reloading when configuration changes are detected:

type AppConfig struct {
    Database DatabaseConfig `json:"database"`
    Cache    CacheConfig   `json:"cache"`
    // Nested plugin configurations are also supported
    Services struct {
        Auth    AuthConfig    `json:"auth"`
        Payment PaymentConfig `json:"payment"`
    } `json:"services"`
}

// When any plugin configuration changes, the corresponding plugin
// will be automatically reloaded without affecting other plugins
cm, err := vcfg.NewBuilder[AppConfig]().
    AddFile("config.yaml").
    WithWatch(). // Enable file watching for hot reload
    Build(context.Background())

Key Features:

  • Recursive Detection: Automatically detects changes in nested plugin configurations
  • Selective Reload: Only reloads plugins whose configurations have actually changed
  • Error Handling: Continues processing other plugins even if one plugin reload fails
  • Thread-Safe: All reload operations are thread-safe and non-blocking

Best Practices

  1. Use struct tags: Always define json, yaml, default, and validate tags
  2. Handle errors: Use Builder pattern for production code with proper error handling
  3. Close resources: Always call cm.Close() to clean up resources
  4. Validate configuration: Use validation tags to ensure configuration integrity
  5. Use plugins wisely: Leverage the plugin system for cross-cutting concerns
  6. Environment-specific configs: Use multiple configuration files for different environments
  7. Plugin hot reload: Implement proper Reload methods in custom plugins to support hot reloading

Examples

Check the example/ directory for more comprehensive examples:

  • Basic configuration loading
  • Multi-source configuration
  • Plugin usage
  • CLI integration
  • Hot reloading

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup
# Clone the repository
git clone https://github.com/nextpkg/vcfg.git
cd vcfg

# Install dependencies
go mod download

# Run tests
go test ./...

# Run tests with coverage
go test -cover ./...

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Support

If you have any questions or need help, please:

  1. Check the documentation and examples
  2. Search existing issues
  3. Create a new issue with detailed information

VCFG - Making configuration management in Go simple, powerful, and extensible.

Documentation

Overview

Package vcfg provides a flexible configuration management system. This file implements the Builder pattern for constructing ConfigManager instances with various configuration sources and options.

Package vcfg provides configuration management with comprehensive error handling. This file defines error types and structures for detailed error reporting across different configuration operations.

Package vcfg provides configuration management capabilities. This file implements the core ConfigManager that handles configuration loading, validation, watching, and plugin management with thread-safe operations.

Package vcfg provides a comprehensive configuration management system with support for multiple configuration sources, automatic type conversion, validation, and plugins. It offers both simple and advanced configuration loading patterns for Go applications.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

type Builder[T any] struct {
	// contains filtered or unexported fields
}

Builder provides a fluent interface for constructing ConfigManager instances. It allows step-by-step configuration of various sources, plugins, and options before building the final ConfigManager.

func NewBuilder

func NewBuilder[T any]() *Builder[T]

NewBuilder creates a new Builder instance for configuration type T. The builder is initialized with empty sources and plugins, ready for configuration.

func (*Builder[T]) AddCliFlags

func (b *Builder[T]) AddCliFlags(cmd *cli.Command, delim string) *Builder[T]

AddCliFlags adds CLI flags as a configuration source using the urfave/cli library. CLI flags are typically added last to ensure they override other configuration sources. The flags are processed through a wrapper that handles key name mapping and flattening.

func (*Builder[T]) AddEnv

func (b *Builder[T]) AddEnv(prefix string) *Builder[T]

AddEnv adds environment variables as a configuration source. Environment variables with the specified prefix will be included, with the prefix stripped and keys converted using dot notation.

func (*Builder[T]) AddFile

func (b *Builder[T]) AddFile(path string) *Builder[T]

AddFile adds a file path as a configuration source. The file format will be automatically detected based on the file extension. Supported formats include JSON, YAML, TOML, and others supported by koanf.

func (*Builder[T]) AddProvider

func (b *Builder[T]) AddProvider(provider koanf.Provider) *Builder[T]

AddProvider adds a custom koanf.Provider as a configuration source. This allows integration with any provider that implements the koanf.Provider interface.

func (*Builder[T]) Build

func (b *Builder[T]) Build(ctx context.Context) (*ConfigManager[T], error)

Build constructs and returns a ConfigManager instance based on the builder's configuration. It loads the initial configuration, initializes plugins if enabled, and sets up file watching if enabled.

Parameters:

  • ctx: Context for plugin initialization and other operations

Returns a fully configured ConfigManager or an error if building fails.

func (*Builder[T]) MustBuild

func (b *Builder[T]) MustBuild() *ConfigManager[T]

MustBuild 构建配置管理器,失败时panic

func (*Builder[T]) WithPlugin

func (b *Builder[T]) WithPlugin() *Builder[T]

WithPlugin enables plugin discovery and initialization. When enabled, the ConfigManager will automatically discover plugin configurations in the loaded config and initialize the corresponding plugin instances.

func (*Builder[T]) WithWatch

func (b *Builder[T]) WithWatch() *Builder[T]

WithWatch enables configuration file watching for automatic reloading. When enabled, the ConfigManager will monitor configuration files for changes and automatically reload the configuration when modifications are detected.

type ConfigError

type ConfigError struct {
	// Type categorizes the kind of error that occurred
	Type ErrorType
	// Source identifies where the error originated (file path, provider name, etc.)
	Source string
	// Message provides a human-readable description of the error
	Message string
	// Cause holds the underlying error that triggered this configuration error
	Cause error
}

ConfigError represents a structured configuration error with detailed context. It provides information about the error type, source, descriptive message, and the underlying cause for comprehensive error reporting.

func NewConfigError

func NewConfigError(errType ErrorType, source, message string, cause error) *ConfigError

NewConfigError 创建新的配置错误

func NewParseError

func NewParseError(source, message string, cause error) *ConfigError

NewParseError 创建解析错误

func NewValidationError

func NewValidationError(source, message string, cause error) *ConfigError

NewValidationError 创建验证错误

func (*ConfigError) Error

func (e *ConfigError) Error() string

Error implements the error interface by returning a formatted error message. The message includes the error type, source, and descriptive text for comprehensive error reporting.

func (*ConfigError) Is

func (e *ConfigError) Is(target error) bool

Is 检查错误类型

func (*ConfigError) Unwrap

func (e *ConfigError) Unwrap() error

Unwrap 返回底层错误

type ConfigManager

type ConfigManager[T any] struct {
	// contains filtered or unexported fields
}

ConfigManager is the core configuration manager that handles loading, validation, watching, and plugin management. It supports generic configuration types through the type parameter T and provides thread-safe access to configuration values.

The manager coordinates multiple configuration sources, automatically detects file formats, validates configurations, and manages plugin lifecycles.

func MustBuild

func MustBuild[T any](filePaths ...string) *ConfigManager[T]

MustBuild is a convenience function that creates a simple configuration manager using only file sources. It's a shorthand for common use cases where only file-based configuration is needed.

Type parameter:

  • T: The configuration struct type to unmarshal into

Parameters:

  • filePaths: Variable number of file paths to load configuration from

Returns a ConfigManager configured with the specified files. Panics if building fails - use Builder for error handling.

func MustLoad

func MustLoad[T any](sources ...any) *ConfigManager[T]

MustLoad is a convenience function that initializes a new ConfigManager with the provided sources and loads the initial configuration. It accepts both file paths (strings) and koanf.Provider instances.

Type parameter:

  • T: The configuration struct type to unmarshal into

Parameters:

  • sources: Variable number of configuration sources (file paths or koanf.Provider instances)

Returns a fully initialized ConfigManager with the configuration loaded. Panics if initialization or loading fails - use Builder for error handling.

func (*ConfigManager[T]) Close

func (cm *ConfigManager[T]) Close() error

Close closes the configuration manager with default context, including all plugins and watchers

func (*ConfigManager[T]) CloseWithContext

func (cm *ConfigManager[T]) CloseWithContext(ctx context.Context) error

CloseWithContext closes the configuration manager with context, including all plugins and watchers

func (*ConfigManager[T]) DisableWatch

func (cm *ConfigManager[T]) DisableWatch()

DisableWatch stops monitoring changes of all configuration providers.

func (*ConfigManager[T]) EnablePlugins

func (cm *ConfigManager[T]) EnablePlugins() error

EnablePlugins automatically discovers and registers plugin instances based on current configuration This method uses the global plugin type registry to automatically instantiate and register plugins for any configuration field that matches a registered plugin type

func (*ConfigManager[T]) EnableWatch

func (cm *ConfigManager[T]) EnableWatch() *ConfigManager[T]

EnableWatch enables watching for configuration changes. It sets up file watchers for providers that implement the Watcher interface. When a configuration change is detected, it reloads the configuration and triggers plugin reloads for affected plugins. This method is thread-safe and can be called multiple times safely.

func (*ConfigManager[T]) Get

func (cm *ConfigManager[T]) Get() *T

Get returns the current configuration value. It retrieves the stored configuration from atomic.Value and returns it as type T. Returns nil if configuration is not initialized.

func (*ConfigManager[T]) MustEnableAndStartPlugins

func (cm *ConfigManager[T]) MustEnableAndStartPlugins()

MustEnableAndStartPlugins enables and starts all plugins, panics on error This is a convenience method that combines EnablePlugins and StartPlugins

func (*ConfigManager[T]) StartPlugins

func (cm *ConfigManager[T]) StartPlugins(ctx context.Context) error

StartPlugins starts all registered plugins This method should be called after EnablePlugins to start the plugin instances

func (*ConfigManager[T]) StopPlugins

func (cm *ConfigManager[T]) StopPlugins(ctx context.Context) error

StopPlugins stops all running plugins This method gracefully stops all plugin instances

type ErrorType

type ErrorType int

ErrorType represents the category of configuration errors. It provides a way to classify different types of failures that can occur during configuration loading, parsing, validation, and management.

const (
	// ErrorTypeUnknown represents an unclassified error
	ErrorTypeUnknown ErrorType = iota
	// ErrorTypeFileNotFound indicates a configuration file could not be found
	ErrorTypeFileNotFound
	// ErrorTypeParseFailure indicates failure to parse configuration data
	ErrorTypeParseFailure
	// ErrorTypeValidationFailure indicates configuration validation failed
	ErrorTypeValidationFailure
	// ErrorTypeWatchFailure indicates failure in file watching functionality
	ErrorTypeWatchFailure
	// ErrorTypePluginFailure indicates failure in plugin operations
	ErrorTypePluginFailure
	// ErrorTypeMergeFailure indicates failure to merge configuration sources
	ErrorTypeMergeFailure
)

func (ErrorType) String

func (et ErrorType) String() string

String returns the string representation of the error type. This method implements the Stringer interface for better error reporting and debugging purposes.

type Unwatcher

type Unwatcher interface {
	// Unwatch stops watching for configuration changes
	Unwatch()
}

Unwatcher interface defines the contract for providers that support stopping the watch operation and cleaning up resources.

type Watcher

type Watcher interface {
	// Watch starts watching for configuration changes and calls the callback
	// when changes occur or errors happen
	Watch(cb func(event any, err error)) error
}

Watcher interface defines the contract for providers that support watching configuration changes and notifying about updates.

Directories

Path Synopsis
Package defaults provides functionality for setting default values on struct fields using struct tags.
Package defaults provides functionality for setting default values on struct fields using struct tags.
Package plugins provides the core plugin system for vcfg configuration management.
Package plugins provides the core plugin system for vcfg configuration management.
builtins
Package builtins provides built-in plugin implementations for the vcfg configuration system.
Package builtins provides built-in plugin implementations for the vcfg configuration system.
Package providers contains custom provider implementations and wrappers for the koanf configuration library.
Package providers contains custom provider implementations and wrappers for the koanf configuration library.
Package validator provides configuration validation functionality using the go-playground/validator library.
Package validator provides configuration validation functionality using the go-playground/validator library.

Jump to

Keyboard shortcuts

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