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  }