github.com/astaxie/beego@v1.12.3/utils/debug.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package utils 16 17 import ( 18 "bytes" 19 "fmt" 20 "log" 21 "reflect" 22 "runtime" 23 ) 24 25 var ( 26 dunno = []byte("???") 27 centerDot = []byte("·") 28 dot = []byte(".") 29 ) 30 31 type pointerInfo struct { 32 prev *pointerInfo 33 n int 34 addr uintptr 35 pos int 36 used []int 37 } 38 39 // Display print the data in console 40 func Display(data ...interface{}) { 41 display(true, data...) 42 } 43 44 // GetDisplayString return data print string 45 func GetDisplayString(data ...interface{}) string { 46 return display(false, data...) 47 } 48 49 func display(displayed bool, data ...interface{}) string { 50 var pc, file, line, ok = runtime.Caller(2) 51 52 if !ok { 53 return "" 54 } 55 56 var buf = new(bytes.Buffer) 57 58 fmt.Fprintf(buf, "[Debug] at %s() [%s:%d]\n", function(pc), file, line) 59 60 fmt.Fprintf(buf, "\n[Variables]\n") 61 62 for i := 0; i < len(data); i += 2 { 63 var output = fomateinfo(len(data[i].(string))+3, data[i+1]) 64 fmt.Fprintf(buf, "%s = %s", data[i], output) 65 } 66 67 if displayed { 68 log.Print(buf) 69 } 70 return buf.String() 71 } 72 73 // return data dump and format bytes 74 func fomateinfo(headlen int, data ...interface{}) []byte { 75 var buf = new(bytes.Buffer) 76 77 if len(data) > 1 { 78 fmt.Fprint(buf, " ") 79 80 fmt.Fprint(buf, "[") 81 82 fmt.Fprintln(buf) 83 } 84 85 for k, v := range data { 86 var buf2 = new(bytes.Buffer) 87 var pointers *pointerInfo 88 var interfaces = make([]reflect.Value, 0, 10) 89 90 printKeyValue(buf2, reflect.ValueOf(v), &pointers, &interfaces, nil, true, " ", 1) 91 92 if k < len(data)-1 { 93 fmt.Fprint(buf2, ", ") 94 } 95 96 fmt.Fprintln(buf2) 97 98 buf.Write(buf2.Bytes()) 99 } 100 101 if len(data) > 1 { 102 fmt.Fprintln(buf) 103 104 fmt.Fprint(buf, " ") 105 106 fmt.Fprint(buf, "]") 107 } 108 109 return buf.Bytes() 110 } 111 112 // check data is golang basic type 113 func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool { 114 switch kind { 115 case reflect.Bool: 116 return true 117 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 118 return true 119 case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: 120 return true 121 case reflect.Float32, reflect.Float64: 122 return true 123 case reflect.Complex64, reflect.Complex128: 124 return true 125 case reflect.String: 126 return true 127 case reflect.Chan: 128 return true 129 case reflect.Invalid: 130 return true 131 case reflect.Interface: 132 for _, in := range *interfaces { 133 if reflect.DeepEqual(in, val) { 134 return true 135 } 136 } 137 return false 138 case reflect.UnsafePointer: 139 if val.IsNil() { 140 return true 141 } 142 143 var elem = val.Elem() 144 145 if isSimpleType(elem, elem.Kind(), pointers, interfaces) { 146 return true 147 } 148 149 var addr = val.Elem().UnsafeAddr() 150 151 for p := *pointers; p != nil; p = p.prev { 152 if addr == p.addr { 153 return true 154 } 155 } 156 157 return false 158 } 159 160 return false 161 } 162 163 // dump value 164 func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) { 165 var t = val.Kind() 166 167 switch t { 168 case reflect.Bool: 169 fmt.Fprint(buf, val.Bool()) 170 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 171 fmt.Fprint(buf, val.Int()) 172 case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: 173 fmt.Fprint(buf, val.Uint()) 174 case reflect.Float32, reflect.Float64: 175 fmt.Fprint(buf, val.Float()) 176 case reflect.Complex64, reflect.Complex128: 177 fmt.Fprint(buf, val.Complex()) 178 case reflect.UnsafePointer: 179 fmt.Fprintf(buf, "unsafe.Pointer(0x%X)", val.Pointer()) 180 case reflect.Ptr: 181 if val.IsNil() { 182 fmt.Fprint(buf, "nil") 183 return 184 } 185 186 var addr = val.Elem().UnsafeAddr() 187 188 for p := *pointers; p != nil; p = p.prev { 189 if addr == p.addr { 190 p.used = append(p.used, buf.Len()) 191 fmt.Fprintf(buf, "0x%X", addr) 192 return 193 } 194 } 195 196 *pointers = &pointerInfo{ 197 prev: *pointers, 198 addr: addr, 199 pos: buf.Len(), 200 used: make([]int, 0), 201 } 202 203 fmt.Fprint(buf, "&") 204 205 printKeyValue(buf, val.Elem(), pointers, interfaces, structFilter, formatOutput, indent, level) 206 case reflect.String: 207 fmt.Fprint(buf, "\"", val.String(), "\"") 208 case reflect.Interface: 209 var value = val.Elem() 210 211 if !value.IsValid() { 212 fmt.Fprint(buf, "nil") 213 } else { 214 for _, in := range *interfaces { 215 if reflect.DeepEqual(in, val) { 216 fmt.Fprint(buf, "repeat") 217 return 218 } 219 } 220 221 *interfaces = append(*interfaces, val) 222 223 printKeyValue(buf, value, pointers, interfaces, structFilter, formatOutput, indent, level+1) 224 } 225 case reflect.Struct: 226 var t = val.Type() 227 228 fmt.Fprint(buf, t) 229 fmt.Fprint(buf, "{") 230 231 for i := 0; i < val.NumField(); i++ { 232 if formatOutput { 233 fmt.Fprintln(buf) 234 } else { 235 fmt.Fprint(buf, " ") 236 } 237 238 var name = t.Field(i).Name 239 240 if formatOutput { 241 for ind := 0; ind < level; ind++ { 242 fmt.Fprint(buf, indent) 243 } 244 } 245 246 fmt.Fprint(buf, name) 247 fmt.Fprint(buf, ": ") 248 249 if structFilter != nil && structFilter(t.String(), name) { 250 fmt.Fprint(buf, "ignore") 251 } else { 252 printKeyValue(buf, val.Field(i), pointers, interfaces, structFilter, formatOutput, indent, level+1) 253 } 254 255 fmt.Fprint(buf, ",") 256 } 257 258 if formatOutput { 259 fmt.Fprintln(buf) 260 261 for ind := 0; ind < level-1; ind++ { 262 fmt.Fprint(buf, indent) 263 } 264 } else { 265 fmt.Fprint(buf, " ") 266 } 267 268 fmt.Fprint(buf, "}") 269 case reflect.Array, reflect.Slice: 270 fmt.Fprint(buf, val.Type()) 271 fmt.Fprint(buf, "{") 272 273 var allSimple = true 274 275 for i := 0; i < val.Len(); i++ { 276 var elem = val.Index(i) 277 278 var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces) 279 280 if !isSimple { 281 allSimple = false 282 } 283 284 if formatOutput && !isSimple { 285 fmt.Fprintln(buf) 286 } else { 287 fmt.Fprint(buf, " ") 288 } 289 290 if formatOutput && !isSimple { 291 for ind := 0; ind < level; ind++ { 292 fmt.Fprint(buf, indent) 293 } 294 } 295 296 printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1) 297 298 if i != val.Len()-1 || !allSimple { 299 fmt.Fprint(buf, ",") 300 } 301 } 302 303 if formatOutput && !allSimple { 304 fmt.Fprintln(buf) 305 306 for ind := 0; ind < level-1; ind++ { 307 fmt.Fprint(buf, indent) 308 } 309 } else { 310 fmt.Fprint(buf, " ") 311 } 312 313 fmt.Fprint(buf, "}") 314 case reflect.Map: 315 var t = val.Type() 316 var keys = val.MapKeys() 317 318 fmt.Fprint(buf, t) 319 fmt.Fprint(buf, "{") 320 321 var allSimple = true 322 323 for i := 0; i < len(keys); i++ { 324 var elem = val.MapIndex(keys[i]) 325 326 var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces) 327 328 if !isSimple { 329 allSimple = false 330 } 331 332 if formatOutput && !isSimple { 333 fmt.Fprintln(buf) 334 } else { 335 fmt.Fprint(buf, " ") 336 } 337 338 if formatOutput && !isSimple { 339 for ind := 0; ind <= level; ind++ { 340 fmt.Fprint(buf, indent) 341 } 342 } 343 344 printKeyValue(buf, keys[i], pointers, interfaces, structFilter, formatOutput, indent, level+1) 345 fmt.Fprint(buf, ": ") 346 printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1) 347 348 if i != val.Len()-1 || !allSimple { 349 fmt.Fprint(buf, ",") 350 } 351 } 352 353 if formatOutput && !allSimple { 354 fmt.Fprintln(buf) 355 356 for ind := 0; ind < level-1; ind++ { 357 fmt.Fprint(buf, indent) 358 } 359 } else { 360 fmt.Fprint(buf, " ") 361 } 362 363 fmt.Fprint(buf, "}") 364 case reflect.Chan: 365 fmt.Fprint(buf, val.Type()) 366 case reflect.Invalid: 367 fmt.Fprint(buf, "invalid") 368 default: 369 fmt.Fprint(buf, "unknow") 370 } 371 } 372 373 // PrintPointerInfo dump pointer value 374 func PrintPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { 375 var anyused = false 376 var pointerNum = 0 377 378 for p := pointers; p != nil; p = p.prev { 379 if len(p.used) > 0 { 380 anyused = true 381 } 382 pointerNum++ 383 p.n = pointerNum 384 } 385 386 if anyused { 387 var pointerBufs = make([][]rune, pointerNum+1) 388 389 for i := 0; i < len(pointerBufs); i++ { 390 var pointerBuf = make([]rune, buf.Len()+headlen) 391 392 for j := 0; j < len(pointerBuf); j++ { 393 pointerBuf[j] = ' ' 394 } 395 396 pointerBufs[i] = pointerBuf 397 } 398 399 for pn := 0; pn <= pointerNum; pn++ { 400 for p := pointers; p != nil; p = p.prev { 401 if len(p.used) > 0 && p.n >= pn { 402 if pn == p.n { 403 pointerBufs[pn][p.pos+headlen] = '└' 404 405 var maxpos = 0 406 407 for i, pos := range p.used { 408 if i < len(p.used)-1 { 409 pointerBufs[pn][pos+headlen] = '┴' 410 } else { 411 pointerBufs[pn][pos+headlen] = '┘' 412 } 413 414 maxpos = pos 415 } 416 417 for i := 0; i < maxpos-p.pos-1; i++ { 418 if pointerBufs[pn][i+p.pos+headlen+1] == ' ' { 419 pointerBufs[pn][i+p.pos+headlen+1] = '─' 420 } 421 } 422 } else { 423 pointerBufs[pn][p.pos+headlen] = '│' 424 425 for _, pos := range p.used { 426 if pointerBufs[pn][pos+headlen] == ' ' { 427 pointerBufs[pn][pos+headlen] = '│' 428 } else { 429 pointerBufs[pn][pos+headlen] = '┼' 430 } 431 } 432 } 433 } 434 } 435 436 buf.WriteString(string(pointerBufs[pn]) + "\n") 437 } 438 } 439 } 440 441 // Stack get stack bytes 442 func Stack(skip int, indent string) []byte { 443 var buf = new(bytes.Buffer) 444 445 for i := skip; ; i++ { 446 var pc, file, line, ok = runtime.Caller(i) 447 448 if !ok { 449 break 450 } 451 452 buf.WriteString(indent) 453 454 fmt.Fprintf(buf, "at %s() [%s:%d]\n", function(pc), file, line) 455 } 456 457 return buf.Bytes() 458 } 459 460 // return the name of the function containing the PC if possible, 461 func function(pc uintptr) []byte { 462 fn := runtime.FuncForPC(pc) 463 if fn == nil { 464 return dunno 465 } 466 name := []byte(fn.Name()) 467 // The name includes the path name to the package, which is unnecessary 468 // since the file name is already included. Plus, it has center dots. 469 // That is, we see 470 // runtime/debug.*T·ptrmethod 471 // and want 472 // *T.ptrmethod 473 if period := bytes.Index(name, dot); period >= 0 { 474 name = name[period+1:] 475 } 476 name = bytes.Replace(name, centerDot, dot, -1) 477 return name 478 }