package infra import ( "fmt" "reflect" ) const secretMask = "***" // ConfigDump converts a configuration struct to a map[string]string. // Exported fields are included. Fields tagged with secret:"true" have their // value replaced with "***". Nested structs are not traversed — only top-level // exported fields are included. // // The map key is the field name. Values are formatted with fmt.Sprintf("%v", ...). func ConfigDump(cfg any) map[string]string { result := make(map[string]string) v := reflect.ValueOf(cfg) if v.Kind() == reflect.Ptr { if v.IsNil() { return result } v = v.Elem() } if v.Kind() != reflect.Struct { return result } t := v.Type() for i := 0; i < t.NumField(); i++ { field := t.Field(i) if !field.IsExported() { continue } key := field.Name if field.Tag.Get("secret") == "true" { result[key] = secretMask continue } fv := v.Field(i) result[key] = fmt.Sprintf("%v", fv.Interface()) } return result }