[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: go\narch:\n  - AMD64\n  - ppc64le\ngo:\n  - 1.12\n  - 1.13\n  - 1.14\n  - 1.15\n\nscript:\n  - go test\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Yangliang Li\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "ginpprof\n========\n\n[![GoDoc](https://godoc.org/github.com/DeanThompson/ginpprof?status.svg)](https://godoc.org/github.com/DeanThompson/ginpprof)\n[![Build\nStatus](https://travis-ci.org/DeanThompson/ginpprof.svg?branch=master)](https://travis-ci.org/DeanThompson/ginpprof)\n\nA wrapper for [golang web framework gin](https://github.com/gin-gonic/gin) to use `net/http/pprof` easily.\n\n## Install\n\nFirst install ginpprof to your GOPATH using `go get`:\n\n```sh\ngo get github.com/DeanThompson/ginpprof\n```\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/DeanThompson/ginpprof\"\n)\n\nfunc main() {\n\trouter := gin.Default()\n\n\trouter.GET(\"/ping\", func(c *gin.Context) {\n\t\tc.String(200, \"pong\")\n\t})\n\n\t// automatically add routers for net/http/pprof\n\t// e.g. /debug/pprof, /debug/pprof/heap, etc.\n\tginpprof.Wrap(router)\n\n\t// ginpprof also plays well with *gin.RouterGroup\n\t// group := router.Group(\"/debug/pprof\")\n\t// ginpprof.WrapGroup(group)\n\n\trouter.Run(\":8080\")\n}\n```\n\nStart this server, and you will see such outputs:\n\n```text\n[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/             --> github.com/DeanThompson/ginpprof.IndexHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/heap         --> github.com/DeanThompson/ginpprof.HeapHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/goroutine    --> github.com/DeanThompson/ginpprof.GoroutineHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/block        --> github.com/DeanThompson/ginpprof.BlockHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/threadcreate --> github.com/DeanThompson/ginpprof.ThreadCreateHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/cmdline      --> github.com/DeanThompson/ginpprof.CmdlineHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/profile      --> github.com/DeanThompson/ginpprof.ProfileHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/symbol       --> github.com/DeanThompson/ginpprof.SymbolHandler.func1 (3 handlers)\n[GIN-debug] POST   /debug/pprof/symbol       --> github.com/DeanThompson/ginpprof.SymbolHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/trace        --> github.com/DeanThompson/ginpprof.TraceHandler.func1 (3 handlers)\n[GIN-debug] GET    /debug/pprof/mutex        --> github.com/DeanThompson/ginpprof.MutexHandler.func1 (3 handlers)\n[GIN-debug] Listening and serving HTTP on :8080\n```\n\nNow visit [http://127.0.0.1:8080/debug/pprof/](http://127.0.0.1:8080/debug/pprof/) and you'll see what you want.\n\nHave Fun.\n"
  },
  {
    "path": "example/example.go",
    "content": "package main\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/DeanThompson/ginpprof\"\n)\n\nfunc main() {\n\trouter := gin.Default()\n\n\trouter.GET(\"/ping\", func(c *gin.Context) {\n\t\tc.String(200, \"pong\")\n\t})\n\n\t// automatically add routers for net/http/pprof\n\t// e.g. /debug/pprof, /debug/pprof/heap, etc.\n\tginpprof.Wrap(router)\n\n\t// ginpprof also plays well with *gin.RouterGroup\n\t// group := router.Group(\"/debug/pprof\")\n\t// ginpprof.WrapGroup(group)\n\n\trouter.Run(\":8080\")\n}\n"
  },
  {
    "path": "pprof.go",
    "content": "package ginpprof\n\nimport (\n\t\"net/http/pprof\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\n// Wrap adds several routes from package `net/http/pprof` to *gin.Engine object\nfunc Wrap(router *gin.Engine) {\n\tWrapGroup(&router.RouterGroup)\n}\n\n// Wrapper make sure we are backward compatible\nvar Wrapper = Wrap\n\n// WrapGroup adds several routes from package `net/http/pprof` to *gin.RouterGroup object\nfunc WrapGroup(router *gin.RouterGroup) {\n\trouters := []struct {\n\t\tMethod  string\n\t\tPath    string\n\t\tHandler gin.HandlerFunc\n\t}{\n\t\t{\"GET\", \"/debug/pprof/\", IndexHandler()},\n\t\t{\"GET\", \"/debug/pprof/heap\", HeapHandler()},\n\t\t{\"GET\", \"/debug/pprof/goroutine\", GoroutineHandler()},\n\t\t{\"GET\", \"/debug/pprof/allocs\", AllocsHandler()},\n\t\t{\"GET\", \"/debug/pprof/block\", BlockHandler()},\n\t\t{\"GET\", \"/debug/pprof/threadcreate\", ThreadCreateHandler()},\n\t\t{\"GET\", \"/debug/pprof/cmdline\", CmdlineHandler()},\n\t\t{\"GET\", \"/debug/pprof/profile\", ProfileHandler()},\n\t\t{\"GET\", \"/debug/pprof/symbol\", SymbolHandler()},\n\t\t{\"POST\", \"/debug/pprof/symbol\", SymbolHandler()},\n\t\t{\"GET\", \"/debug/pprof/trace\", TraceHandler()},\n\t\t{\"GET\", \"/debug/pprof/mutex\", MutexHandler()},\n\t}\n\n\tbasePath := strings.TrimSuffix(router.BasePath(), \"/\")\n\tvar prefix string\n\n\tswitch {\n\tcase basePath == \"\":\n\t\tprefix = \"\"\n\tcase strings.HasSuffix(basePath, \"/debug\"):\n\t\tprefix = \"/debug\"\n\tcase strings.HasSuffix(basePath, \"/debug/pprof\"):\n\t\tprefix = \"/debug/pprof\"\n\t}\n\n\tfor _, r := range routers {\n\t\trouter.Handle(r.Method, strings.TrimPrefix(r.Path, prefix), r.Handler)\n\t}\n}\n\n// IndexHandler will pass the call from /debug/pprof to pprof\nfunc IndexHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Index(ctx.Writer, ctx.Request)\n\t}\n}\n\n// HeapHandler will pass the call from /debug/pprof/heap to pprof\nfunc HeapHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"heap\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n\n// GoroutineHandler will pass the call from /debug/pprof/goroutine to pprof\nfunc GoroutineHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"goroutine\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n\n// AllocsHandler will pass the call from /debug/pprof/allocs to pprof\nfunc AllocsHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"allocs\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n\n// BlockHandler will pass the call from /debug/pprof/block to pprof\nfunc BlockHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"block\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n\n// ThreadCreateHandler will pass the call from /debug/pprof/threadcreate to pprof\nfunc ThreadCreateHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"threadcreate\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n\n// CmdlineHandler will pass the call from /debug/pprof/cmdline to pprof\nfunc CmdlineHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Cmdline(ctx.Writer, ctx.Request)\n\t}\n}\n\n// ProfileHandler will pass the call from /debug/pprof/profile to pprof\nfunc ProfileHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Profile(ctx.Writer, ctx.Request)\n\t}\n}\n\n// SymbolHandler will pass the call from /debug/pprof/symbol to pprof\nfunc SymbolHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Symbol(ctx.Writer, ctx.Request)\n\t}\n}\n\n// TraceHandler will pass the call from /debug/pprof/trace to pprof\nfunc TraceHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Trace(ctx.Writer, ctx.Request)\n\t}\n}\n\n// MutexHandler will pass the call from /debug/pprof/mutex to pprof\nfunc MutexHandler() gin.HandlerFunc {\n\treturn func(ctx *gin.Context) {\n\t\tpprof.Handler(\"mutex\").ServeHTTP(ctx.Writer, ctx.Request)\n\t}\n}\n"
  },
  {
    "path": "pprof_test.go",
    "content": "package ginpprof\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc newServer() *gin.Engine {\n\tr := gin.Default()\n\treturn r\n}\n\nfunc checkRouters(routers gin.RoutesInfo, t *testing.T) {\n\texpectedRouters := map[string]string{\n\t\t\"/debug/pprof/\":             \"IndexHandler\",\n\t\t\"/debug/pprof/heap\":         \"HeapHandler\",\n\t\t\"/debug/pprof/goroutine\":    \"GoroutineHandler\",\n\t\t\"/debug/pprof/allocs\":       \"AllocsHandler\",\n\t\t\"/debug/pprof/block\":        \"BlockHandler\",\n\t\t\"/debug/pprof/threadcreate\": \"ThreadCreateHandler\",\n\t\t\"/debug/pprof/cmdline\":      \"CmdlineHandler\",\n\t\t\"/debug/pprof/profile\":      \"ProfileHandler\",\n\t\t\"/debug/pprof/symbol\":       \"SymbolHandler\",\n\t\t\"/debug/pprof/trace\":        \"TraceHandler\",\n\t\t\"/debug/pprof/mutex\":        \"MutexHandler\",\n\t}\n\n\tfor _, router := range routers {\n\t\t//fmt.Println(router.Path, router.Method, router.Handler)\n\t\tname, ok := expectedRouters[router.Path]\n\t\tif !ok {\n\t\t\tt.Errorf(\"missing router %s\", router.Path)\n\t\t}\n\t\tif !strings.Contains(router.Handler, name) {\n\t\t\tt.Errorf(\"handler for %s should contain %s, got %s\", router.Path, name, router.Handler)\n\t\t}\n\t}\n}\n\nfunc TestWrap(t *testing.T) {\n\tr := newServer()\n\tWrap(r)\n\tcheckRouters(r.Routes(), t)\n}\n\nfunc TestWrapGroup(t *testing.T) {\n\tfor _, prefix := range []string{\"/debug\", \"/debug/\", \"/debug/pprof\", \"/debug/pprof/\"} {\n\t\tr := newServer()\n\t\tg := r.Group(prefix)\n\t\tWrapGroup(g)\n\t\tcheckRouters(r.Routes(), t)\n\t}\n}\n"
  }
]