func reflectAttr()

in go/mqtt/internal/log_utils.go [50:113]


func reflectAttr(name string, val reflect.Value) []slog.Attr {
	// Ignore zero values to keep the log cleaner.
	if missingValue(val) {
		return nil
	}

	switch name {
	// Paho's struct nesting is not particularly useful to log.
	case "properties":
		return reflectAttrs(val)

	// Subscriptions are one-at-a-time for the session client.
	case "subscriptions":
		if subs, ok := val.Interface().([]paho.SubscribeOptions); ok {
			return reflectAttrs(reflect.ValueOf(subs[0]))
		}
	case "topics":
		if topics, ok := val.Interface().([]string); ok {
			return []slog.Attr{slog.String("topic", topics[0])}
		}
	case "reasons":
		if reasons, ok := val.Interface().([]byte); ok {
			return []slog.Attr{slog.Int("reason_code", int(reasons[0]))}
		}

	// Fix QoS not being actually PascalCased.
	case "qo_s":
		return []slog.Attr{slog.Any("qos", val.Interface())}

	// Do not log secrets.
	case "password", "auth_data":
		return nil
	}

	switch v := val.Interface().(type) {
	case []byte:
		return []slog.Attr{slog.String(name, string(v))}

	case paho.UserProperties:
		if len(v) == 0 {
			return nil
		}
		attrs := make([]any, len(v))
		for i, p := range v {
			attrs[i] = slog.String(p.Key, p.Value)
		}
		return []slog.Attr{slog.Group(name, attrs...)}
	}

	if val.Kind() == reflect.Struct {
		as := reflectAttrs(val)
		if len(as) == 0 {
			return nil
		}

		cpy := make([]any, len(as))
		for i, a := range as {
			cpy[i] = a
		}
		return []slog.Attr{slog.Group(name, cpy...)}
	}

	return []slog.Attr{slog.Any(name, val.Interface())}
}