github.com/aavshr/aws-sdk-go@v1.41.3/aws/awsutil/prettify.go (about)

     1  package awsutil
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"reflect"
     8  	"strings"
     9  )
    10  
    11  // Prettify returns the string representation of a value.
    12  func Prettify(i interface{}) string {
    13  	var buf bytes.Buffer
    14  	prettify(reflect.ValueOf(i), 0, &buf)
    15  	return buf.String()
    16  }
    17  
    18  // prettify will recursively walk value v to build a textual
    19  // representation of the value.
    20  func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
    21  	for v.Kind() == reflect.Ptr {
    22  		v = v.Elem()
    23  	}
    24  
    25  	switch v.Kind() {
    26  	case reflect.Struct:
    27  		strtype := v.Type().String()
    28  		if strtype == "time.Time" {
    29  			fmt.Fprintf(buf, "%s", v.Interface())
    30  			break
    31  		} else if strings.HasPrefix(strtype, "io.") {
    32  			buf.WriteString("<buffer>")
    33  			break
    34  		}
    35  
    36  		buf.WriteString("{\n")
    37  
    38  		names := []string{}
    39  		for i := 0; i < v.Type().NumField(); i++ {
    40  			name := v.Type().Field(i).Name
    41  			f := v.Field(i)
    42  			if name[0:1] == strings.ToLower(name[0:1]) {
    43  				continue // ignore unexported fields
    44  			}
    45  			if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
    46  				continue // ignore unset fields
    47  			}
    48  			names = append(names, name)
    49  		}
    50  
    51  		for i, n := range names {
    52  			val := v.FieldByName(n)
    53  			ft, ok := v.Type().FieldByName(n)
    54  			if !ok {
    55  				panic(fmt.Sprintf("expected to find field %v on type %v, but was not found", n, v.Type()))
    56  			}
    57  
    58  			buf.WriteString(strings.Repeat(" ", indent+2))
    59  			buf.WriteString(n + ": ")
    60  
    61  			if tag := ft.Tag.Get("sensitive"); tag == "true" {
    62  				buf.WriteString("<sensitive>")
    63  			} else {
    64  				prettify(val, indent+2, buf)
    65  			}
    66  
    67  			if i < len(names)-1 {
    68  				buf.WriteString(",\n")
    69  			}
    70  		}
    71  
    72  		buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
    73  	case reflect.Slice:
    74  		strtype := v.Type().String()
    75  		if strtype == "[]uint8" {
    76  			fmt.Fprintf(buf, "<binary> len %d", v.Len())
    77  			break
    78  		}
    79  
    80  		nl, id, id2 := "", "", ""
    81  		if v.Len() > 3 {
    82  			nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
    83  		}
    84  		buf.WriteString("[" + nl)
    85  		for i := 0; i < v.Len(); i++ {
    86  			buf.WriteString(id2)
    87  			prettify(v.Index(i), indent+2, buf)
    88  
    89  			if i < v.Len()-1 {
    90  				buf.WriteString("," + nl)
    91  			}
    92  		}
    93  
    94  		buf.WriteString(nl + id + "]")
    95  	case reflect.Map:
    96  		buf.WriteString("{\n")
    97  
    98  		for i, k := range v.MapKeys() {
    99  			buf.WriteString(strings.Repeat(" ", indent+2))
   100  			buf.WriteString(k.String() + ": ")
   101  			prettify(v.MapIndex(k), indent+2, buf)
   102  
   103  			if i < v.Len()-1 {
   104  				buf.WriteString(",\n")
   105  			}
   106  		}
   107  
   108  		buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
   109  	default:
   110  		if !v.IsValid() {
   111  			fmt.Fprint(buf, "<invalid value>")
   112  			return
   113  		}
   114  		format := "%v"
   115  		switch v.Interface().(type) {
   116  		case string:
   117  			format = "%q"
   118  		case io.ReadSeeker, io.Reader:
   119  			format = "buffer(%p)"
   120  		}
   121  		fmt.Fprintf(buf, format, v.Interface())
   122  	}
   123  }