Ingen beskrivning

main.go 2.7KB

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