github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zlog/debug.go (about) 1 package zlog 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/parser" 7 "go/printer" 8 "go/token" 9 "io" 10 "reflect" 11 "strconv" 12 "strings" 13 "text/tabwriter" 14 15 "github.com/sohaha/zlsgo/zreflect" 16 ) 17 18 type indentWriter struct { 19 w io.Writer 20 pre [][]byte 21 sel int 22 off int 23 bol bool 24 } 25 26 func newIndentWriter(w io.Writer, pre ...[]byte) io.Writer { 27 return &indentWriter{ 28 w: w, 29 pre: pre, 30 bol: true, 31 } 32 } 33 34 func (w *indentWriter) Write(p []byte) (n int, err error) { 35 for _, c := range p { 36 if w.bol { 37 var i int 38 i, err = w.w.Write(w.pre[w.sel][w.off:]) 39 w.off += i 40 if err != nil { 41 return n, err 42 } 43 } 44 _, err = w.w.Write([]byte{c}) 45 if err != nil { 46 return n, err 47 } 48 n++ 49 w.bol = c == '\n' 50 if w.bol { 51 w.off = 0 52 if w.sel < len(w.pre)-1 { 53 w.sel++ 54 } 55 } 56 } 57 return n, nil 58 } 59 60 func argName(arg ast.Expr) string { 61 name := "" 62 63 switch a := arg.(type) { 64 case *ast.Ident: 65 switch { 66 case a.Obj == nil: 67 name = a.Name 68 case a.Obj.Kind == ast.Var, a.Obj.Kind == ast.Con: 69 name = a.Obj.Name 70 } 71 case *ast.BinaryExpr, 72 *ast.CallExpr, 73 *ast.IndexExpr, 74 *ast.KeyValueExpr, 75 *ast.ParenExpr, 76 *ast.SelectorExpr, 77 *ast.SliceExpr, 78 *ast.TypeAssertExpr, 79 *ast.UnaryExpr: 80 name = exprToString(arg) 81 } 82 83 return name 84 } 85 86 func argNames(filename string, line int) ([]string, error) { 87 fset := token.NewFileSet() 88 f, err := parser.ParseFile(fset, filename, nil, 0) 89 if err != nil { 90 return nil, fmt.Errorf("failed to parse %q: %v", filename, err) 91 } 92 93 var names []string 94 ast.Inspect(f, func(n ast.Node) bool { 95 call, is := n.(*ast.CallExpr) 96 if !is { 97 return true 98 } 99 if fset.Position(call.End()).Line != line { 100 return true 101 } 102 for _, arg := range call.Args { 103 names = append(names, argName(arg)) 104 } 105 return true 106 }) 107 108 return names, nil 109 } 110 111 func exprToString(arg ast.Expr) string { 112 var buf strings.Builder 113 fset := token.NewFileSet() 114 if err := printer.Fprint(&buf, fset, arg); err != nil { 115 return "" 116 } 117 return strings.Replace(buf.String(), "\t", " ", -1) 118 } 119 120 func (fo formatter) String() string { 121 return fmt.Sprint(fo.v.Interface()) 122 } 123 124 func (fo formatter) Format(f fmt.State, c rune) { 125 if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') { 126 w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0) 127 p := &zprinter{tw: w, Writer: w, visited: make(map[visit]int)} 128 p.printValue(fo.v, true, fo.quote) 129 _ = w.Flush() 130 return 131 } 132 fo.passThrough(f, c) 133 } 134 135 func (fo formatter) passThrough(f fmt.State, c rune) { 136 s := "%" 137 for i := 0; i < 128; i++ { 138 if f.Flag(i) { 139 s += strconv.FormatInt(int64(i), 10) 140 } 141 } 142 if w, ok := f.Width(); ok { 143 s += fmt.Sprintf("%d", w) 144 } 145 if p, ok := f.Precision(); ok { 146 s += fmt.Sprintf(".%d", p) 147 } 148 s += string(c) 149 _, _ = fmt.Fprintf(f, s, fo.v.Interface()) 150 } 151 152 func (p *zprinter) indent() *zprinter { 153 q := *p 154 q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0) 155 q.Writer = newIndentWriter(q.tw, []byte{'\t'}) 156 return &q 157 } 158 159 func (p *zprinter) printInline(v reflect.Value, x interface{}, showType bool) { 160 if showType { 161 _, _ = io.WriteString(p, v.Type().String()) 162 _, _ = fmt.Fprintf(p, "(%+v)", x) 163 } else { 164 _, _ = fmt.Fprintf(p, "%+v", x) 165 } 166 } 167 168 func (p *zprinter) printStruct(v reflect.Value, showType bool) (stop bool) { 169 t := v.Type() 170 if v.CanAddr() { 171 addr := v.UnsafeAddr() 172 vis := visit{v: addr, typ: t} 173 if vd, ok := p.visited[vis]; ok && vd < p.depth { 174 p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false) 175 return true 176 } 177 p.visited[vis] = p.depth 178 } 179 180 if showType { 181 _, _ = io.WriteString(p, t.String()) 182 } 183 184 writeByte(p, '{') 185 if zreflect.Nonzero(v) { 186 expand := !zreflect.CanInline(v.Type()) 187 pp := p 188 if expand { 189 writeByte(p, '\n') 190 pp = p.indent() 191 } 192 for i := 0; i < v.NumField(); i++ { 193 showTypeInStruct := true 194 if f := t.Field(i); f.Name != "" { 195 _, _ = io.WriteString(pp, f.Name) 196 writeByte(pp, ':') 197 if expand { 198 writeByte(pp, '\t') 199 } 200 showTypeInStruct = zreflect.IsLabel(f.Type) 201 } 202 val := v.Field(i) 203 if val.Kind() == reflect.Interface && !val.IsNil() { 204 val = val.Elem() 205 } 206 pp.printValue(val, showTypeInStruct, true) 207 if expand { 208 _, _ = io.WriteString(pp, ",\n") 209 } else if i < v.NumField()-1 { 210 _, _ = io.WriteString(pp, ", ") 211 } 212 } 213 if expand { 214 _ = pp.tw.Flush() 215 } 216 } 217 writeByte(p, '}') 218 return false 219 } 220 221 func (p *zprinter) printValue(v reflect.Value, showType, quote bool) { 222 if p.depth > 10 { 223 _, _ = io.WriteString(p, "!%v(DEPTH EXCEEDED)") 224 return 225 } 226 switch v.Kind() { 227 case reflect.Bool: 228 p.printInline(v, v.Bool(), showType) 229 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 230 p.printInline(v, v.Int(), showType) 231 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 232 p.printInline(v, v.Uint(), showType) 233 case reflect.Float32, reflect.Float64: 234 p.printInline(v, v.Float(), showType) 235 case reflect.Complex64, reflect.Complex128: 236 _, _ = fmt.Fprintf(p, "%#v", v.Complex()) 237 case reflect.String: 238 p.fmtString(v.String(), quote) 239 case reflect.Map: 240 t := v.Type() 241 if showType { 242 _, _ = io.WriteString(p, t.String()) 243 } 244 writeByte(p, '{') 245 if zreflect.Nonzero(v) { 246 expand := !zreflect.CanInline(v.Type()) 247 pp := p 248 if expand { 249 writeByte(p, '\n') 250 pp = p.indent() 251 } 252 keys := v.MapKeys() 253 for i := 0; i < v.Len(); i++ { 254 k := keys[i] 255 mv := v.MapIndex(k) 256 pp.printValue(k, false, true) 257 writeByte(pp, ':') 258 if expand { 259 writeByte(pp, '\t') 260 } 261 showTypeInStruct := t.Elem().Kind() == reflect.Interface 262 pp.printValue(mv, showTypeInStruct, true) 263 if expand { 264 _, _ = io.WriteString(pp, ",\n") 265 } else if i < v.Len()-1 { 266 _, _ = io.WriteString(pp, ", ") 267 } 268 } 269 if expand { 270 _ = pp.tw.Flush() 271 } 272 } 273 writeByte(p, '}') 274 case reflect.Struct: 275 if p.printStruct(v, showType) { 276 break 277 } 278 case reflect.Interface: 279 switch e := v.Elem(); { 280 case e.Kind() == reflect.Invalid: 281 _, _ = io.WriteString(p, "nil") 282 case e.IsValid(): 283 pp := *p 284 pp.depth++ 285 pp.printValue(e, showType, true) 286 default: 287 _, _ = io.WriteString(p, v.Type().String()) 288 _, _ = io.WriteString(p, "(nil)") 289 } 290 case reflect.Array, reflect.Slice: 291 t := v.Type() 292 if showType { 293 _, _ = io.WriteString(p, t.String()) 294 } 295 if v.Kind() == reflect.Slice && v.IsNil() && showType { 296 _, _ = io.WriteString(p, "(nil)") 297 break 298 } 299 if v.Kind() == reflect.Slice && v.IsNil() { 300 _, _ = io.WriteString(p, "nil") 301 break 302 } 303 writeByte(p, '{') 304 expand := !zreflect.CanInline(v.Type()) 305 pp := p 306 if expand { 307 writeByte(p, '\n') 308 pp = p.indent() 309 } 310 for i := 0; i < v.Len(); i++ { 311 showTypeInSlice := t.Elem().Kind() == reflect.Interface 312 pp.printValue(v.Index(i), showTypeInSlice, true) 313 if expand { 314 _, _ = io.WriteString(pp, ",\n") 315 } else if i < v.Len()-1 { 316 _, _ = io.WriteString(pp, ", ") 317 } 318 } 319 if expand { 320 _ = pp.tw.Flush() 321 } 322 writeByte(p, '}') 323 case reflect.Ptr: 324 e := v.Elem() 325 if !e.IsValid() { 326 writeByte(p, '(') 327 _, _ = io.WriteString(p, v.Type().String()) 328 _, _ = io.WriteString(p, ")(nil)") 329 } else { 330 pp := *p 331 pp.depth++ 332 writeByte(pp, '&') 333 pp.printValue(e, true, true) 334 } 335 case reflect.Chan: 336 x := v.Pointer() 337 if showType { 338 writeByte(p, '(') 339 _, _ = io.WriteString(p, v.Type().String()) 340 _, _ = fmt.Fprintf(p, ")(%#v)", x) 341 } else { 342 _, _ = fmt.Fprintf(p, "%#v", x) 343 } 344 case reflect.Func: 345 _, _ = io.WriteString(p, v.Type().String()) 346 _, _ = io.WriteString(p, " {...}") 347 case reflect.UnsafePointer: 348 p.printInline(v, v.Pointer(), showType) 349 case reflect.Invalid: 350 _, _ = io.WriteString(p, "nil") 351 } 352 } 353 354 func (p *zprinter) fmtString(s string, quote bool) { 355 if quote { 356 s = strconv.Quote(s) 357 } 358 _, _ = io.WriteString(p, s) 359 }