Ei kuvausta

main.go 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package main
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. _ "net/http/pprof"
  9. "os"
  10. "github.com/gin-gonic/gin"
  11. "github.com/google/pprof/pkg/driver"
  12. "github.com/google/pprof/profile"
  13. "github.com/sirupsen/logrus"
  14. )
  15. func main() {
  16. r := gin.Default()
  17. r.Static("/html", "html")
  18. r.GET("/", func(c *gin.Context) { c.Redirect(http.StatusFound, "/html/") })
  19. r.POST("/upload", upload)
  20. r.GET("/pprof/:hash/:method", mapping)
  21. r.Run(":8090")
  22. }
  23. func mapping(c *gin.Context) {
  24. hash := c.Param("hash")
  25. if hash == "" {
  26. c.AbortWithStatus(http.StatusNotFound)
  27. return
  28. }
  29. filename := fmt.Sprintf("%s.pprof", hash)
  30. f, err := os.OpenFile(filename, os.O_RDONLY, os.ModePerm)
  31. if err != nil {
  32. c.AbortWithError(http.StatusInternalServerError, err)
  33. return
  34. }
  35. defer f.Close()
  36. prof, err := profile.Parse(f)
  37. if err != nil {
  38. c.AbortWithError(http.StatusInternalServerError, err)
  39. return
  40. }
  41. ui, err := driver.MakeWebInterface(prof, nil)
  42. if err != nil {
  43. c.AbortWithError(http.StatusInternalServerError, err)
  44. return
  45. }
  46. method := c.Param("method")
  47. switch method {
  48. case "", "dot":
  49. ui.Dot(c.Writer, c.Request)
  50. case "top":
  51. ui.Top(c.Writer, c.Request)
  52. case "disasm":
  53. ui.Disasm(c.Writer, c.Request)
  54. case "source":
  55. ui.Source(c.Writer, c.Request)
  56. case "peek":
  57. ui.Peek(c.Writer, c.Request)
  58. case "flamegraph":
  59. ui.Flamegraph(c.Writer, c.Request)
  60. case "saveconfig":
  61. ui.SaveConfig(c.Writer, c.Request)
  62. case "deleteconfig":
  63. ui.DeleteConfig(c.Writer, c.Request)
  64. default:
  65. c.AbortWithStatus(http.StatusNotFound)
  66. }
  67. }
  68. func upload(c *gin.Context) {
  69. f, _, err := c.Request.FormFile("file")
  70. if err != nil {
  71. logrus.Errorln("upload file error:", err)
  72. c.AbortWithError(http.StatusInternalServerError, err)
  73. return
  74. }
  75. fdata, _ := ioutil.ReadAll(f)
  76. f.Close()
  77. rhash := hash(fdata)
  78. if fileExist(rhash) { // 文件已存在
  79. c.Redirect(http.StatusFound, fmt.Sprintf("/pprof/%s/flamegraph", rhash))
  80. return
  81. }
  82. fileDst := fmt.Sprintf("%s.pprof", rhash)
  83. file, err := os.Create(fileDst)
  84. if err != nil {
  85. c.AbortWithError(http.StatusInternalServerError, err)
  86. return
  87. }
  88. defer file.Close()
  89. if _, err := file.Write(fdata); err != nil {
  90. c.AbortWithError(http.StatusInternalServerError, err)
  91. return
  92. }
  93. c.JSONP(http.StatusOK, map[string]interface{}{
  94. "code": 0,
  95. "msg": "ok",
  96. "data": rhash,
  97. })
  98. }
  99. func hash(data []byte) string {
  100. h := md5.New()
  101. h.Write(data)
  102. return hex.EncodeToString(h.Sum(nil))
  103. }
  104. func fileExist(file string) bool {
  105. return false
  106. }