func Load() error {
	c := &AppConfig{AppConfigODS: *getDefaultConfig()}
	for _, l := range loaders {
		err := l.load(c)
		if err != nil {
			return err
		}
		if err = l.parseConfig(c); err != nil {
			return err
		}
	}
	if err := parseConfig(c); err != nil {
		return err
	}
	cfg.Store(c)
	return nil
}
Load creates the config
package config
import (
	"fmt"
	"os"
	"runtime"
	"sync/atomic"
	"text/template"
	"time"
	"github.com/uber/storagetapper/types"
)
type AppConfigODS struct {
	LogType  string `yaml:"log_type"`
	LogLevel string `yaml:"log_level"`
	ServiceName string `yaml:"serviceName"`
	Port        int    `yaml:"port"`
	MaxNumProcs int    `yaml:"max_num_procs"`
	StateUpdateInterval time.Duration `yaml:"state_update_interval"`
	WorkerIdleInterval  time.Duration `yaml:"worker_idle_interval"`
	LockExpireTimeout   time.Duration `yaml:"lock_expire_timeout"`
	StateConnectURL     string        `yaml:"state_connect_url"`
	StateDBName         string        `yaml:"state_db_name"`
	StateClusterName    string        `yaml:"state_cluster_name"`
	ChangelogPipeType                 string                       `yaml:"changelog_pipe_type"`
	ChangelogTopicNameTemplateDefault string                       `yaml:"changelog_topic_name_template_default"`
	ChangelogTopicNameTemplate        map[string]map[string]string `yaml:"changelog_topic_name_template"`
	ChangelogWatchdogInterval         time.Duration
	OutputTopicNameTemplateDefault string                       `yaml:"output_topic_name_template_default"`
	OutputTopicNameTemplate        map[string]map[string]string `yaml:"output_topic_name_template"`
	Verbose bool
	ChangelogBuffer       bool `yaml:"changelog_buffer"`
	ForceMasterConnection bool `yaml:"force_master_connection"`
	InternalEncoding string `yaml:"internal_encoding"`
	TableParams `yaml:",inline"`  
	Filters map[string]map[string]RowFilter `yaml:"filters"`
	ConfigRefreshInterval time.Duration `yaml:"config_refresh_interval"`
}
type EncryptionConfig struct {
	Enabled    bool
	PublicKey  string `yaml:"public_key"`   
	PrivateKey string `yaml:"private_key"`  
	SigningKey string `yaml:"signing_key"`  
}
type PipeConfig struct {
	MaxBatchSize      int `yaml:"max_batch_size"`
	MaxBatchSizeBytes int `yaml:"max_batch_size_bytes"`
	BaseDir string `yaml:"base_dir"`
	MaxFileSize     int64 `yaml:"max_file_size"`       
	MaxFileDataSize int64 `yaml:"max_file_data_size"`  
	Compression bool
	FileDelimited bool `yaml:"file_delimited"`
	NonBlocking bool `yaml:"non_blocking"`
	EndOfStreamMark bool
	Encryption EncryptionConfig
	S3     S3Config
	Hadoop HadoopConfig
	Kafka  KafkaConfig
	SQL SQLConfig `yaml:"sql"`
}
type KafkaConfig struct {
	Addresses       []string
	MaxMessageBytes int `yaml:"max_message_bytes"`
}
type S3Config struct {
	Region   string
	Endpoint string
	Bucket   string
	BaseDir  string `yaml:"base_dir"`
	AccessKeyID     string `yaml:"access_key_id"`
	SecretAccessKey string `yaml:"secret_access_key"`
	SessionToken    string `yaml:"session_token"`
	Timeout time.Duration
}
type HadoopConfig struct {
	User      string
	Addresses []string
	BaseDir   string `yaml:"base_dir"`
}
type SQLConfig struct {
	Type    string
	DSN     string `yaml:"dsn"`
	Service string
	Cluster string
	DB      string
}
type ScheduleConfig struct {
	Interval time.Duration  
}
type TableParams struct {
	ClusterConcurrency int   `yaml:"cluster_concurrency"`
	ThrottleTargetMB   int64 `yaml:"throttle_target_mb"`
	ThrottleTargetIOPS int64 `yaml:"throttle_target_iops"`
	Pipe     PipeConfig
	Schedule ScheduleConfig
	RowFilter  RowFilter   `yaml:"row_filter"`
	RowFilters []RowFilter `yaml:"row_filters"`  
	ForceIndex string `yaml:"force_index"`
	NoSnapshot bool `yaml:"no_snapshot"`
	NoDeleteOnUpdate bool `yaml:"no_delete_on_update"`
}
type RowFilter struct {
	Column    string   `yaml:"column"`
	Values    []string `yaml:"values"`
	Condition string   `yaml:"condition"`
	Operator  string   `yaml:"operator"`
}
type AppConfig struct {
	AppConfigODS
	PortDyn                                 int
	ChangelogTopicNameTemplateParsed        map[string]map[string]*template.Template
	OutputTopicNameTemplateParsed           map[string]map[string]*template.Template
	ChangelogTopicNameTemplateDefaultParsed *template.Template
	OutputTopicNameTemplateDefaultParsed    *template.Template
}
func log(format string, args ...interface{}) {
	_, _ = fmt.Fprintf(os.Stderr, format, args...)
}
func getDefaultConfig() *AppConfigODS {
	return &AppConfigODS{
		Port: 7836,
		MaxNumProcs:         runtime.NumCPU(),
		StateDBName:         types.MyDBName,
		StateClusterName:    types.MyClusterName,
		StateUpdateInterval: 300 * time.Second,
		WorkerIdleInterval:  30 * time.Second,
		ChangelogPipeType:                 "kafka",
		ChangelogTopicNameTemplateDefault: types.MySvcName + ".service.{{.Service}}.db.{{.DB}}.table.{{.Table}}{{if .Version}}.v{{.Version}}{{end}}",
		OutputTopicNameTemplateDefault: "hp-tap-{{.Service}}-{{.DB}}-{{.Table}}{{if .Version}}-v{{.Version}}{{end}}",
		ChangelogBuffer:                true,
		ChangelogWatchdogInterval:      300 * time.Second,
		LogType:  "std",
		LogLevel: "info",
		InternalEncoding: "json",
		TableParams: TableParams{
			Pipe: PipeConfig{
				BaseDir:           fmt.Sprintf("/var/lib/%s", types.MySvcName),
				MaxFileSize:       1024 * 1024 * 1024,
				MaxBatchSize:      4096,
				MaxBatchSizeBytes: 32 * 1024 * 1024,
				FileDelimited:     true,
				S3: S3Config{
					Timeout: 7 * 24 * time.Hour,
				},
				Kafka: KafkaConfig{
					MaxMessageBytes: 30 * 1024 * 1024,
				},
			},
		},
		ConfigRefreshInterval: 300 * time.Second,
	}
}
const (
	EnvProduction  = "production"
	EnvDevelopment = "development"
	EnvStaging     = "staging"
	EnvTest        = "test"
)
type configLoader interface {
	environment() string
	load(*AppConfig) error
	loadSection(interface{}) error
	zone() string
	save(*AppConfig) error
	parseConfig(cfg *AppConfig) error
}
var loaders = []configLoader{&std{loadFn: stdReadFile}, &std{loadFn: mysqlRead, saveFn: mysqlWrite}}
var cfg atomic.Value
var updatedAt atomic.Value
func Get() *AppConfig {
	c := cfg.Load()
	if c != nil {
		ac := c.(*AppConfig)
		updAt := updatedAt.Load()
		if updAt != nil && updAt.(time.Time).After(time.Now().Add(-ac.ConfigRefreshInterval)) {
			return ac
		}
	}
	err := Load()
	c = cfg.Load()
	if err != nil {
		log("error (re)loading config: %v\n", err.Error())
		if c == nil {
			exit(1)
			return nil  
		}
	} else {
		updatedAt.Store(time.Now())
	}
	return c.(*AppConfig)
}
func Set(a *AppConfigODS) error {
	c := &AppConfig{AppConfigODS: *a}
	for _, l := range loaders {
		err := l.parseConfig(c)
		if err != nil {
			return err
		}
	}
	err := parseConfig(c)
	if err != nil {
		return err
	}
	cfg.Store(c)
	return nil
}