Search documentation of snmpkit

# SnmpKit.SnmpLib.Config (snmpkit v1.2.0)

Configuration management system for production SNMP deployments.

This module provides a flexible, environment-aware configuration system designed for real-world SNMP management applications. Based on patterns proven in large-scale deployments like the DDumb project managing 1000+ devices.

## Features

- Environment-Aware: Automatic detection of dev/test/prod environments
- Layered Configuration: Application, environment, and runtime overrides
- Dynamic Updates: Hot-reload configuration without service restart
- Validation: Schema validation for all configuration values
- Secrets Management: Secure handling of sensitive configuration data
- Multi-Tenant Support: Per-deployment configuration isolation

## Configuration Sources (in order of precedence)

1. Runtime environment variables
2. Configuration files (config/*.exs)
3. Application defaults
4. Module defaults

## Usage Patterns

    # Get configuration for a specific component
    pool_config = SnmpKit.SnmpLib.Config.get(:pool, :default_settings)

    # Get configuration with fallback
    timeout = SnmpKit.SnmpLib.Config.get(:snmp, :timeout, 5000)

    # Update configuration at runtime
    SnmpKit.SnmpLib.Config.put(:pool, :max_size, 50)

    # Load configuration from file
    SnmpKit.SnmpLib.Config.load_from_file("/etc/snmp_lib/production.exs")

    # Validate current configuration
    {:ok, _} = SnmpKit.SnmpLib.Config.validate()

## Environment Detection

The configuration system automatically detects the current environment:

- `:dev` - Development with verbose logging and relaxed timeouts
- `:test` - Testing with simulated backends and fast timeouts
- `:prod` - Production with optimized settings and monitoring
- `:staging` - Pre-production environment for integration testing

## Configuration Schema

All configuration follows a validated schema to prevent runtime errors:

    %{
      snmp: %{
        default_version: :v2c,
        default_timeout: 5_000,
        default_retries: 3,
        default_community: "public"
      },
      pool: %{
        default_size: 10,
        max_overflow: 5,
        strategy: :fifo,
        health_check_interval: 30_000
      },
      monitoring: %{
        metrics_enabled: true,
        prometheus_port: 9090,
        dashboard_enabled: true,
        alert_thresholds: %{...}
      }
    }

# Summary

## Types

config_key()
config_section()
config_value()
environment()

## Functions

all()

Gets all configuration as a nested map.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

environment()

Gets the current environment.

get(section, key, default \\ nil)

Gets a configuration value by key path with optional default.

load_from_file(file_path)

Loads configuration from a file and merges with current config.

merge_opts(opts)

Merges user-provided options with default SNMP configuration values.

put(section, key, value)

Sets a configuration value at runtime.

reload()

Reloads configuration from environment and files.

start_link(opts \\ [])

Starts the configuration manager with initial configuration.

validate()

Validates the current configuration against the schema.

watch(section, callback)

Registers a callback function to be called when configuration changes.

# Types

# config_key()

    @type config_key() :: atom() | [atom()]

# config_section()

    @type config_section() :: atom()

# config_value()

    @type config_value() :: any()

# environment()

    @type environment() :: :dev | :test | :prod | :staging

# Functions

# all()

    @spec all() :: map()

Gets all configuration as a nested map.

## Examples

    config = SnmpKit.SnmpLib.Config.all()
    IO.inspect(config.snmp.default_timeout)

# child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# environment()

    @spec environment() :: environment()

Gets the current environment.

## Examples

    env = SnmpKit.SnmpLib.Config.environment()  # :prod

# get(section, key, default \\ nil)

    @spec get(config_section(), config_key(), config_value()) :: config_value()

Gets a configuration value by key path with optional default.

## Parameters

- `section`: Configuration section (:snmp, :pool, :monitoring, etc.)
- `key`: Specific configuration key or nested key path
- `default`: Value to return if key is not found

## Examples

    # Get a simple value
    timeout = SnmpKit.SnmpLib.Config.get(:snmp, :default_timeout)

    # Get nested value
    threshold = SnmpKit.SnmpLib.Config.get(:monitoring, [:alert_thresholds, :error_rate])

    # Get with default
    community = SnmpKit.SnmpLib.Config.get(:snmp, :community, "public")

# load_from_file(file_path)

    @spec load_from_file(binary()) :: :ok | {:error, any()}

Loads configuration from a file and merges with current config.

## Examples

    :ok = SnmpKit.SnmpLib.Config.load_from_file("/etc/snmp_lib/production.exs")

# merge_opts(opts)

    @spec merge_opts(keyword()) :: keyword()

Merges user-provided options with default SNMP configuration values.

This function provides the default SNMP configuration options that are commonly used across SNMP operations, then merges them with user-provided options. User options take precedence over defaults.

## Default Values

- `community`: "public"
- `timeout`: 5000 (milliseconds)
- `retries`: 3
- `port`: 161
- `version`: :v2c
- `mib_paths`: []

## Parameters

- `opts`: Keyword list of user-provided options that override defaults

## Returns

Keyword list with defaults merged with user options, where user options take precedence.

## Examples

    iex> SnmpKit.SnmpLib.Config.merge_opts([])
    [community: "public", timeout: 5000, retries: 3, port: 161, version: :v2c, mib_paths: []]

    iex> result = SnmpKit.SnmpLib.Config.merge_opts([timeout: 10000])
    iex> result[:community]
    "public"
    iex> result[:timeout]
    10000
    iex> result[:retries]
    3

    iex> result = SnmpKit.SnmpLib.Config.merge_opts([community: "private", port: 162])
    iex> result[:community]
    "private"
    iex> result[:port]
    162
    iex> result[:timeout]
    5000

# put(section, key, value)

    @spec put(config_section(), config_key(), config_value()) :: :ok | {:error, any()}

Sets a configuration value at runtime.

Changes are applied immediately and optionally persisted.

## Examples

    :ok = SnmpKit.SnmpLib.Config.put(:pool, :default_size, 20)
    :ok = SnmpKit.SnmpLib.Config.put(:monitoring, [:alert_thresholds, :error_rate], 0.10)

# reload()

    @spec reload() :: :ok | {:error, any()}

Reloads configuration from environment and files.

## Examples

    :ok = SnmpKit.SnmpLib.Config.reload()

# start_link(opts \\ [])

    @spec start_link(keyword()) :: {:ok, pid()} | {:error, any()}

Starts the configuration manager with initial configuration.

## Options

- `config_file`: Path to configuration file to load on startup
- `environment`: Override automatic environment detection
- `validate_on_start`: Validate configuration on startup (default: true)

## Examples

    {:ok, _pid} = SnmpKit.SnmpLib.Config.start_link()
    {:ok, _pid} = SnmpKit.SnmpLib.Config.start_link(config_file: "/etc/snmp_lib/prod.exs")

# validate()

    @spec validate() :: {:ok, map()} | {:error, [any()]}

Validates the current configuration against the schema.

## Returns

- `{:ok, config}`: Configuration is valid
- `{:error, errors}`: List of validation errors

## Examples

    case SnmpKit.SnmpLib.Config.validate() do
      {:ok, _config} -> Logger.info("Configuration is valid")
      {:error, validation_errors} -> Logger.error("Configuration errors: " <> inspect(validation_errors))
    end

# watch(section, callback)

    @spec watch(config_section(), function()) :: :ok

Registers a callback function to be called when configuration changes.

## Examples

    SnmpKit.SnmpLib.Config.watch(:pool, fn old_config, new_config ->
      Logger.info("Pool configuration changed")
      SnmpKit.SnmpLib.Pool.reload_config(new_config)
    end)