in x-pack/filebeat/input/internal/private/private.go [119:295]
func redact(v reflect.Value, reps replacers, tag string, global []string, depth int, seen map[any]int) reflect.Value {
switch v.Kind() {
case reflect.Pointer:
if v.IsNil() {
return v
}
if depth > tooDeep {
ident := v.Interface()
if last, ok := seen[ident]; ok && last < depth {
panic(cycle{v.Type()})
}
seen[ident] = depth
defer delete(seen, ident)
}
return redact(v.Elem(), reps, tag, global, depth+1, seen).Addr()
case reflect.Interface:
if v.IsNil() {
return v
}
return redact(v.Elem(), reps, tag, global, depth+1, seen)
case reflect.Array:
if v.Len() == 0 {
return v
}
r := reflect.New(v.Type()).Elem()
for i := 0; i < v.Len(); i++ {
r.Index(i).Set(redact(v.Index(i), reps, tag, global, depth+1, seen))
}
return r
case reflect.Slice:
if v.Len() == 0 {
return v
}
if depth > tooDeep {
ident := struct {
data unsafe.Pointer
len int
}{
v.UnsafePointer(),
v.Len(),
}
if last, ok := seen[ident]; ok && last < depth {
panic(cycle{v.Type()})
}
seen[ident] = depth
defer delete(seen, ident)
}
r := reflect.MakeSlice(v.Type(), v.Len(), v.Cap())
for i := 0; i < v.Len(); i++ {
r.Index(i).Set(redact(v.Index(i), reps, tag, global, depth+1, seen))
}
return r
case reflect.Map:
if v.IsNil() {
return v
}
if depth > tooDeep {
ident := v.UnsafePointer()
if last, ok := seen[ident]; ok && last < depth {
panic(cycle{v.Type()})
}
seen[ident] = depth
defer delete(seen, ident)
}
private := nextStep(global)
if privateKey.CanConvert(v.Type().Key()) {
p := v.MapIndex(privateKey.Convert(v.Type().Key()))
if p.IsValid() && p.CanInterface() {
switch p := p.Interface().(type) {
case string:
private = append(private, p)
case []string:
private = append(private, p...)
case []any:
for _, s := range p {
private = append(private, fmt.Sprint(s))
}
}
}
}
r := reflect.MakeMap(v.Type())
it := v.MapRange()
for it.Next() {
name := it.Key().String()
if slices.Contains(private, name) {
v := replaceNestedWithin(it.Value(), reps)
if v.IsValid() {
r.SetMapIndex(it.Key(), v)
}
continue
}
r.SetMapIndex(it.Key(), redact(it.Value(), reps, tag, nextPath(name, global), depth+1, seen))
}
return r
case reflect.Struct:
private := nextStep(global)
rt := v.Type()
names := make([]string, rt.NumField())
for i := range names {
f := rt.Field(i)
// Look for `private:` tags.
p, ok := f.Tag.Lookup("private")
if ok {
if p != "" {
private = append(private, strings.Split(p, ",")...)
} else {
if tag == "" {
names[i] = f.Name
private = append(private, f.Name)
} else {
p = f.Tag.Get(tag)
if p != "" {
name, _, _ := strings.Cut(p, ",")
names[i] = name
private = append(private, name)
}
}
}
}
// Look after Private fields if we are not using a tag.
if tag == "" {
names[i] = f.Name
if f.Name == "Private" {
switch p := v.Field(i).Interface().(type) {
case string:
private = append(private, p)
case []string:
private = append(private, p...)
}
}
continue
}
// If we are using a tag, look for `tag:"<private>"`
// falling back to fields named Private if no tag is
// present.
p = f.Tag.Get(tag)
var name string
if p == "" {
name = f.Name
} else {
name, _, _ = strings.Cut(p, ",")
}
names[i] = name
if name == "private" {
switch p := v.Field(i).Interface().(type) {
case string:
private = append(private, p)
case []string:
private = append(private, p...)
}
}
}
r := reflect.New(v.Type()).Elem()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if f.IsZero() || !rt.Field(i).IsExported() {
continue
}
if slices.Contains(private, names[i]) {
v := replaceNestedWithin(f, reps)
if v.IsValid() {
r.Field(i).Set(v)
}
continue
}
if r.Field(i).CanSet() {
r.Field(i).Set(redact(f, reps, tag, nextPath(names[i], global), depth+1, seen))
}
}
return r
}
return v
}