Added the UI for Admin monitor page
Showing
3 changed files
with
587 additions
and
118 deletions
| 1 | // Beego (http://beego.me/) | 1 | // Beego (http://beego.me/) |
| 2 | // | ||
| 3 | // @description beego is an open-source, high-performance web framework for the Go programming language. | 2 | // @description beego is an open-source, high-performance web framework for the Go programming language. |
| 4 | // | ||
| 5 | // @link http://github.com/astaxie/beego for the canonical source repository | 3 | // @link http://github.com/astaxie/beego for the canonical source repository |
| 6 | // | ||
| 7 | // @license http://github.com/astaxie/beego/blob/master/LICENSE | 4 | // @license http://github.com/astaxie/beego/blob/master/LICENSE |
| 8 | // | ||
| 9 | // @authors astaxie | 5 | // @authors astaxie |
| 10 | package beego | 6 | package beego |
| 11 | 7 | ||
| 12 | import ( | 8 | import ( |
| 9 | "bytes" | ||
| 13 | "fmt" | 10 | "fmt" |
| 14 | "net/http" | 11 | "net/http" |
| 15 | "strconv" | 12 | "text/template" |
| 16 | "time" | 13 | "time" |
| 17 | 14 | ||
| 18 | "github.com/astaxie/beego/toolbox" | 15 | "github.com/astaxie/beego/toolbox" |
| ... | @@ -49,7 +46,6 @@ func init() { | ... | @@ -49,7 +46,6 @@ func init() { |
| 49 | beeAdminApp.Route("/prof", profIndex) | 46 | beeAdminApp.Route("/prof", profIndex) |
| 50 | beeAdminApp.Route("/healthcheck", healthcheck) | 47 | beeAdminApp.Route("/healthcheck", healthcheck) |
| 51 | beeAdminApp.Route("/task", taskStatus) | 48 | beeAdminApp.Route("/task", taskStatus) |
| 52 | beeAdminApp.Route("/runtask", runTask) | ||
| 53 | beeAdminApp.Route("/listconf", listConf) | 49 | beeAdminApp.Route("/listconf", listConf) |
| 54 | FilterMonitorFunc = func(string, string, time.Duration) bool { return true } | 50 | FilterMonitorFunc = func(string, string, time.Duration) bool { return true } |
| 55 | } | 51 | } |
| ... | @@ -57,22 +53,22 @@ func init() { | ... | @@ -57,22 +53,22 @@ func init() { |
| 57 | // AdminIndex is the default http.Handler for admin module. | 53 | // AdminIndex is the default http.Handler for admin module. |
| 58 | // it matches url pattern "/". | 54 | // it matches url pattern "/". |
| 59 | func adminIndex(rw http.ResponseWriter, r *http.Request) { | 55 | func adminIndex(rw http.ResponseWriter, r *http.Request) { |
| 60 | rw.Write([]byte("<html><head><title>beego admin dashboard</title></head><body>")) | 56 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) |
| 61 | rw.Write([]byte("Welcome to Admin Dashboard<br>\n")) | 57 | tmpl = template.Must(tmpl.Parse(indexTpl)) |
| 62 | rw.Write([]byte("There are servral functions:<br>\n")) | 58 | data := make(map[interface{}]interface{}) |
| 63 | rw.Write([]byte("1. Record all request and request time, <a href='/qps'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/qps</a><br>\n")) | 59 | tmpl.Execute(rw, data) |
| 64 | rw.Write([]byte("2. Get runtime profiling data by the pprof, <a href='/prof'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/prof</a><br>\n")) | ||
| 65 | rw.Write([]byte("3. Get healthcheck result from <a href='/healthcheck'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/healthcheck</a><br>\n")) | ||
| 66 | rw.Write([]byte("4. Get current task infomation from task <a href='/task'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/task</a><br> \n")) | ||
| 67 | rw.Write([]byte("5. To run a task passed a param <a href='/runtask'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/runtask</a><br>\n")) | ||
| 68 | rw.Write([]byte("6. Get all confige & router infomation <a href='/listconf'>http://localhost:" + strconv.Itoa(AdminHttpPort) + "/listconf</a><br>\n")) | ||
| 69 | rw.Write([]byte("</body></html>")) | ||
| 70 | } | 60 | } |
| 71 | 61 | ||
| 72 | // QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter. | 62 | // QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter. |
| 73 | // it's registered with url pattern "/qbs" in admin module. | 63 | // it's registered with url pattern "/qbs" in admin module. |
| 74 | func qpsIndex(rw http.ResponseWriter, r *http.Request) { | 64 | func qpsIndex(rw http.ResponseWriter, r *http.Request) { |
| 75 | toolbox.StatisticsMap.GetMap(rw) | 65 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) |
| 66 | tmpl = template.Must(tmpl.Parse(qpsTpl)) | ||
| 67 | data := make(map[interface{}]interface{}) | ||
| 68 | data["Content"] = toolbox.StatisticsMap.GetMap() | ||
| 69 | |||
| 70 | tmpl.Execute(rw, data) | ||
| 71 | |||
| 76 | } | 72 | } |
| 77 | 73 | ||
| 78 | // ListConf is the http.Handler of displaying all beego configuration values as key/value pair. | 74 | // ListConf is the http.Handler of displaying all beego configuration values as key/value pair. |
| ... | @@ -81,112 +77,217 @@ func listConf(rw http.ResponseWriter, r *http.Request) { | ... | @@ -81,112 +77,217 @@ func listConf(rw http.ResponseWriter, r *http.Request) { |
| 81 | r.ParseForm() | 77 | r.ParseForm() |
| 82 | command := r.Form.Get("command") | 78 | command := r.Form.Get("command") |
| 83 | if command != "" { | 79 | if command != "" { |
| 80 | data := make(map[interface{}]interface{}) | ||
| 84 | switch command { | 81 | switch command { |
| 85 | case "conf": | 82 | case "conf": |
| 86 | fmt.Fprintln(rw, "list all beego's conf:") | 83 | m := make(map[string]interface{}) |
| 87 | fmt.Fprintln(rw, "AppName:", AppName) | 84 | |
| 88 | fmt.Fprintln(rw, "AppPath:", AppPath) | 85 | m["AppName"] = AppName |
| 89 | fmt.Fprintln(rw, "AppConfigPath:", AppConfigPath) | 86 | m["AppPath"] = AppPath |
| 90 | fmt.Fprintln(rw, "StaticDir:", StaticDir) | 87 | m["AppConfigPath"] = AppConfigPath |
| 91 | fmt.Fprintln(rw, "StaticExtensionsToGzip:", StaticExtensionsToGzip) | 88 | m["StaticDir"] = StaticDir |
| 92 | fmt.Fprintln(rw, "HttpAddr:", HttpAddr) | 89 | m["StaticExtensionsToGzip"] = StaticExtensionsToGzip |
| 93 | fmt.Fprintln(rw, "HttpPort:", HttpPort) | 90 | m["HttpAddr"] = HttpAddr |
| 94 | fmt.Fprintln(rw, "HttpTLS:", EnableHttpTLS) | 91 | m["HttpPort"] = HttpPort |
| 95 | fmt.Fprintln(rw, "HttpCertFile:", HttpCertFile) | 92 | m["HttpTLS"] = EnableHttpTLS |
| 96 | fmt.Fprintln(rw, "HttpKeyFile:", HttpKeyFile) | 93 | m["HttpCertFile"] = HttpCertFile |
| 97 | fmt.Fprintln(rw, "RecoverPanic:", RecoverPanic) | 94 | m["HttpKeyFile"] = HttpKeyFile |
| 98 | fmt.Fprintln(rw, "AutoRender:", AutoRender) | 95 | m["RecoverPanic"] = RecoverPanic |
| 99 | fmt.Fprintln(rw, "ViewsPath:", ViewsPath) | 96 | m["AutoRender"] = AutoRender |
| 100 | fmt.Fprintln(rw, "RunMode:", RunMode) | 97 | m["ViewsPath"] = ViewsPath |
| 101 | fmt.Fprintln(rw, "SessionOn:", SessionOn) | 98 | m["RunMode"] = RunMode |
| 102 | fmt.Fprintln(rw, "SessionProvider:", SessionProvider) | 99 | m["SessionOn"] = SessionOn |
| 103 | fmt.Fprintln(rw, "SessionName:", SessionName) | 100 | m["SessionProvider"] = SessionProvider |
| 104 | fmt.Fprintln(rw, "SessionGCMaxLifetime:", SessionGCMaxLifetime) | 101 | m["SessionName"] = SessionName |
| 105 | fmt.Fprintln(rw, "SessionSavePath:", SessionSavePath) | 102 | m["SessionGCMaxLifetime"] = SessionGCMaxLifetime |
| 106 | fmt.Fprintln(rw, "SessionHashFunc:", SessionHashFunc) | 103 | m["SessionSavePath"] = SessionSavePath |
| 107 | fmt.Fprintln(rw, "SessionHashKey:", SessionHashKey) | 104 | m["SessionHashFunc"] = SessionHashFunc |
| 108 | fmt.Fprintln(rw, "SessionCookieLifeTime:", SessionCookieLifeTime) | 105 | m["SessionHashKey"] = SessionHashKey |
| 109 | fmt.Fprintln(rw, "UseFcgi:", UseFcgi) | 106 | m["SessionCookieLifeTime"] = SessionCookieLifeTime |
| 110 | fmt.Fprintln(rw, "MaxMemory:", MaxMemory) | 107 | m["UseFcgi"] = UseFcgi |
| 111 | fmt.Fprintln(rw, "EnableGzip:", EnableGzip) | 108 | m["MaxMemory"] = MaxMemory |
| 112 | fmt.Fprintln(rw, "DirectoryIndex:", DirectoryIndex) | 109 | m["EnableGzip"] = EnableGzip |
| 113 | fmt.Fprintln(rw, "HttpServerTimeOut:", HttpServerTimeOut) | 110 | m["DirectoryIndex"] = DirectoryIndex |
| 114 | fmt.Fprintln(rw, "ErrorsShow:", ErrorsShow) | 111 | m["HttpServerTimeOut"] = HttpServerTimeOut |
| 115 | fmt.Fprintln(rw, "XSRFKEY:", XSRFKEY) | 112 | m["ErrorsShow"] = ErrorsShow |
| 116 | fmt.Fprintln(rw, "EnableXSRF:", EnableXSRF) | 113 | m["XSRFKEY"] = XSRFKEY |
| 117 | fmt.Fprintln(rw, "XSRFExpire:", XSRFExpire) | 114 | m["EnableXSRF"] = EnableXSRF |
| 118 | fmt.Fprintln(rw, "CopyRequestBody:", CopyRequestBody) | 115 | m["XSRFExpire"] = XSRFExpire |
| 119 | fmt.Fprintln(rw, "TemplateLeft:", TemplateLeft) | 116 | m["CopyRequestBody"] = CopyRequestBody |
| 120 | fmt.Fprintln(rw, "TemplateRight:", TemplateRight) | 117 | m["TemplateLeft"] = TemplateLeft |
| 121 | fmt.Fprintln(rw, "BeegoServerName:", BeegoServerName) | 118 | m["TemplateRight"] = TemplateRight |
| 122 | fmt.Fprintln(rw, "EnableAdmin:", EnableAdmin) | 119 | m["BeegoServerName"] = BeegoServerName |
| 123 | fmt.Fprintln(rw, "AdminHttpAddr:", AdminHttpAddr) | 120 | m["EnableAdmin"] = EnableAdmin |
| 124 | fmt.Fprintln(rw, "AdminHttpPort:", AdminHttpPort) | 121 | m["AdminHttpAddr"] = AdminHttpAddr |
| 122 | m["AdminHttpPort"] = AdminHttpPort | ||
| 123 | |||
| 124 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 125 | tmpl = template.Must(tmpl.Parse(configTpl)) | ||
| 126 | |||
| 127 | data["Content"] = m | ||
| 128 | |||
| 129 | tmpl.Execute(rw, data) | ||
| 130 | |||
| 125 | case "router": | 131 | case "router": |
| 126 | fmt.Fprintln(rw, "Print all router infomation:") | 132 | resultList := new([][]string) |
| 133 | |||
| 134 | var result = []string{ | ||
| 135 | fmt.Sprintf("header"), | ||
| 136 | fmt.Sprintf("Router Pattern"), | ||
| 137 | fmt.Sprintf("Methods"), | ||
| 138 | fmt.Sprintf("Controller"), | ||
| 139 | } | ||
| 140 | *resultList = append(*resultList, result) | ||
| 141 | |||
| 127 | for method, t := range BeeApp.Handlers.routers { | 142 | for method, t := range BeeApp.Handlers.routers { |
| 128 | fmt.Fprintln(rw) | 143 | var result = []string{ |
| 129 | fmt.Fprintln(rw) | 144 | fmt.Sprintf("success"), |
| 130 | fmt.Fprintln(rw, " Method:", method) | 145 | fmt.Sprintf("Method: %s", method), |
| 131 | printTree(rw, t) | 146 | fmt.Sprintf(""), |
| 147 | fmt.Sprintf(""), | ||
| 148 | } | ||
| 149 | *resultList = append(*resultList, result) | ||
| 150 | |||
| 151 | printTree(resultList, t) | ||
| 132 | } | 152 | } |
| 133 | // @todo print routers | 153 | data["Content"] = resultList |
| 154 | data["Title"] = "Routers" | ||
| 155 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 156 | tmpl = template.Must(tmpl.Parse(routerAndFilterTpl)) | ||
| 157 | tmpl.Execute(rw, data) | ||
| 134 | case "filter": | 158 | case "filter": |
| 135 | fmt.Fprintln(rw, "Print all filter infomation:") | 159 | resultList := new([][]string) |
| 160 | |||
| 161 | var result = []string{ | ||
| 162 | fmt.Sprintf("header"), | ||
| 163 | fmt.Sprintf("Router Pattern"), | ||
| 164 | fmt.Sprintf("Filter Function"), | ||
| 165 | } | ||
| 166 | *resultList = append(*resultList, result) | ||
| 167 | |||
| 136 | if BeeApp.Handlers.enableFilter { | 168 | if BeeApp.Handlers.enableFilter { |
| 137 | fmt.Fprintln(rw, "BeforeRouter:") | 169 | var result = []string{ |
| 170 | fmt.Sprintf("success"), | ||
| 171 | fmt.Sprintf("Before Router"), | ||
| 172 | fmt.Sprintf(""), | ||
| 173 | } | ||
| 174 | *resultList = append(*resultList, result) | ||
| 175 | |||
| 138 | if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok { | 176 | if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok { |
| 139 | for _, f := range bf { | 177 | for _, f := range bf { |
| 140 | fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) | 178 | |
| 179 | var result = []string{ | ||
| 180 | fmt.Sprintf(""), | ||
| 181 | fmt.Sprintf("%s", f.pattern), | ||
| 182 | fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), | ||
| 183 | } | ||
| 184 | *resultList = append(*resultList, result) | ||
| 185 | |||
| 186 | } | ||
| 141 | } | 187 | } |
| 188 | result = []string{ | ||
| 189 | fmt.Sprintf("success"), | ||
| 190 | fmt.Sprintf("Before Exec"), | ||
| 191 | fmt.Sprintf(""), | ||
| 142 | } | 192 | } |
| 143 | fmt.Fprintln(rw, "BeforeExec:") | 193 | *resultList = append(*resultList, result) |
| 144 | if bf, ok := BeeApp.Handlers.filters[BeforeExec]; ok { | 194 | if bf, ok := BeeApp.Handlers.filters[BeforeExec]; ok { |
| 145 | for _, f := range bf { | 195 | for _, f := range bf { |
| 146 | fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) | 196 | |
| 197 | var result = []string{ | ||
| 198 | fmt.Sprintf(""), | ||
| 199 | fmt.Sprintf("%s", f.pattern), | ||
| 200 | fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), | ||
| 147 | } | 201 | } |
| 202 | *resultList = append(*resultList, result) | ||
| 203 | |||
| 148 | } | 204 | } |
| 149 | fmt.Fprintln(rw, "AfterExec:") | 205 | } |
| 206 | result = []string{ | ||
| 207 | fmt.Sprintf("success"), | ||
| 208 | fmt.Sprintf("AfterExec Exec"), | ||
| 209 | fmt.Sprintf(""), | ||
| 210 | } | ||
| 211 | *resultList = append(*resultList, result) | ||
| 212 | |||
| 150 | if bf, ok := BeeApp.Handlers.filters[AfterExec]; ok { | 213 | if bf, ok := BeeApp.Handlers.filters[AfterExec]; ok { |
| 151 | for _, f := range bf { | 214 | for _, f := range bf { |
| 152 | fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) | 215 | |
| 216 | var result = []string{ | ||
| 217 | fmt.Sprintf(""), | ||
| 218 | fmt.Sprintf("%s", f.pattern), | ||
| 219 | fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), | ||
| 220 | } | ||
| 221 | *resultList = append(*resultList, result) | ||
| 222 | |||
| 223 | } | ||
| 153 | } | 224 | } |
| 225 | result = []string{ | ||
| 226 | fmt.Sprintf("success"), | ||
| 227 | fmt.Sprintf("Finish Router"), | ||
| 228 | fmt.Sprintf(""), | ||
| 154 | } | 229 | } |
| 155 | fmt.Fprintln(rw, "FinishRouter:") | 230 | *resultList = append(*resultList, result) |
| 231 | |||
| 156 | if bf, ok := BeeApp.Handlers.filters[FinishRouter]; ok { | 232 | if bf, ok := BeeApp.Handlers.filters[FinishRouter]; ok { |
| 157 | for _, f := range bf { | 233 | for _, f := range bf { |
| 158 | fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) | 234 | |
| 235 | var result = []string{ | ||
| 236 | fmt.Sprintf(""), | ||
| 237 | fmt.Sprintf("%s", f.pattern), | ||
| 238 | fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), | ||
| 239 | } | ||
| 240 | *resultList = append(*resultList, result) | ||
| 241 | |||
| 159 | } | 242 | } |
| 160 | } | 243 | } |
| 161 | } | 244 | } |
| 245 | data["Content"] = resultList | ||
| 246 | data["Title"] = "Filters" | ||
| 247 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 248 | tmpl = template.Must(tmpl.Parse(routerAndFilterTpl)) | ||
| 249 | tmpl.Execute(rw, data) | ||
| 250 | |||
| 162 | default: | 251 | default: |
| 163 | rw.Write([]byte("command not support")) | 252 | rw.Write([]byte("command not support")) |
| 164 | } | 253 | } |
| 165 | } else { | 254 | } else { |
| 166 | rw.Write([]byte("<html><head><title>beego admin dashboard</title></head><body>")) | ||
| 167 | rw.Write([]byte("ListConf support this command:<br>\n")) | ||
| 168 | rw.Write([]byte("1. <a href='?command=conf'>command=conf</a><br>\n")) | ||
| 169 | rw.Write([]byte("2. <a href='?command=router'>command=router</a><br>\n")) | ||
| 170 | rw.Write([]byte("3. <a href='?command=filter'>command=filter</a><br>\n")) | ||
| 171 | rw.Write([]byte("</body></html>")) | ||
| 172 | } | 255 | } |
| 173 | } | 256 | } |
| 174 | 257 | ||
| 175 | func printTree(rw http.ResponseWriter, t *Tree) { | 258 | func printTree(resultList *[][]string, t *Tree) { |
| 176 | for _, tr := range t.fixrouters { | 259 | for _, tr := range t.fixrouters { |
| 177 | printTree(rw, tr) | 260 | printTree(resultList, tr) |
| 178 | } | 261 | } |
| 179 | if t.wildcard != nil { | 262 | if t.wildcard != nil { |
| 180 | printTree(rw, t.wildcard) | 263 | printTree(resultList, t.wildcard) |
| 181 | } | 264 | } |
| 182 | for _, l := range t.leaves { | 265 | for _, l := range t.leaves { |
| 183 | if v, ok := l.runObject.(*controllerInfo); ok { | 266 | if v, ok := l.runObject.(*controllerInfo); ok { |
| 184 | if v.routerType == routerTypeBeego { | 267 | if v.routerType == routerTypeBeego { |
| 185 | fmt.Fprintln(rw, v.pattern, v.methods, v.controllerType.Name()) | 268 | var result = []string{ |
| 269 | fmt.Sprintf(""), | ||
| 270 | fmt.Sprintf("%s", v.pattern), | ||
| 271 | fmt.Sprintf("%s", v.methods), | ||
| 272 | fmt.Sprintf("%s", v.controllerType), | ||
| 273 | } | ||
| 274 | *resultList = append(*resultList, result) | ||
| 186 | } else if v.routerType == routerTypeRESTFul { | 275 | } else if v.routerType == routerTypeRESTFul { |
| 187 | fmt.Fprintln(rw, v.pattern, v.methods) | 276 | var result = []string{ |
| 277 | fmt.Sprintf(""), | ||
| 278 | fmt.Sprintf("%s", v.pattern), | ||
| 279 | fmt.Sprintf("%s", v.methods), | ||
| 280 | fmt.Sprintf(""), | ||
| 281 | } | ||
| 282 | *resultList = append(*resultList, result) | ||
| 188 | } else if v.routerType == routerTypeHandler { | 283 | } else if v.routerType == routerTypeHandler { |
| 189 | fmt.Fprintln(rw, v.pattern, "handler") | 284 | var result = []string{ |
| 285 | fmt.Sprintf(""), | ||
| 286 | fmt.Sprintf("%s", v.pattern), | ||
| 287 | fmt.Sprintf(""), | ||
| 288 | fmt.Sprintf(""), | ||
| 289 | } | ||
| 290 | *resultList = append(*resultList, result) | ||
| 190 | } | 291 | } |
| 191 | } | 292 | } |
| 192 | } | 293 | } |
| ... | @@ -197,58 +298,106 @@ func printTree(rw http.ResponseWriter, t *Tree) { | ... | @@ -197,58 +298,106 @@ func printTree(rw http.ResponseWriter, t *Tree) { |
| 197 | func profIndex(rw http.ResponseWriter, r *http.Request) { | 298 | func profIndex(rw http.ResponseWriter, r *http.Request) { |
| 198 | r.ParseForm() | 299 | r.ParseForm() |
| 199 | command := r.Form.Get("command") | 300 | command := r.Form.Get("command") |
| 301 | data := make(map[interface{}]interface{}) | ||
| 302 | |||
| 303 | var result bytes.Buffer | ||
| 200 | if command != "" { | 304 | if command != "" { |
| 201 | toolbox.ProcessInput(command, rw) | 305 | toolbox.ProcessInput(command, &result) |
| 306 | data["Content"] = result.String() | ||
| 307 | data["Title"] = command | ||
| 308 | |||
| 309 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 310 | tmpl = template.Must(tmpl.Parse(profillingTpl)) | ||
| 311 | tmpl.Execute(rw, data) | ||
| 202 | } else { | 312 | } else { |
| 203 | rw.Write([]byte("<html><head><title>beego admin dashboard</title></head><body>")) | ||
| 204 | rw.Write([]byte("request url like '/prof?command=lookup goroutine'<br>\n")) | ||
| 205 | rw.Write([]byte("the command have below types:<br>\n")) | ||
| 206 | rw.Write([]byte("1. <a href='?command=lookup goroutine'>lookup goroutine</a><br>\n")) | ||
| 207 | rw.Write([]byte("2. <a href='?command=lookup heap'>lookup heap</a><br>\n")) | ||
| 208 | rw.Write([]byte("3. <a href='?command=lookup threadcreate'>lookup threadcreate</a><br>\n")) | ||
| 209 | rw.Write([]byte("4. <a href='?command=lookup block'>lookup block</a><br>\n")) | ||
| 210 | rw.Write([]byte("5. <a href='?command=start cpuprof'>start cpuprof</a><br>\n")) | ||
| 211 | rw.Write([]byte("6. <a href='?command=stop cpuprof'>stop cpuprof</a><br>\n")) | ||
| 212 | rw.Write([]byte("7. <a href='?command=get memprof'>get memprof</a><br>\n")) | ||
| 213 | rw.Write([]byte("8. <a href='?command=gc summary'>gc summary</a><br>\n")) | ||
| 214 | rw.Write([]byte("</body></html>")) | ||
| 215 | } | 313 | } |
| 216 | } | 314 | } |
| 217 | 315 | ||
| 218 | // Healthcheck is a http.Handler calling health checking and showing the result. | 316 | // Healthcheck is a http.Handler calling health checking and showing the result. |
| 219 | // it's in "/healthcheck" pattern in admin module. | 317 | // it's in "/healthcheck" pattern in admin module. |
| 220 | func healthcheck(rw http.ResponseWriter, req *http.Request) { | 318 | func healthcheck(rw http.ResponseWriter, req *http.Request) { |
| 319 | data := make(map[interface{}]interface{}) | ||
| 320 | |||
| 321 | resultList := new([][]string) | ||
| 322 | var result = []string{ | ||
| 323 | fmt.Sprintf("header"), | ||
| 324 | fmt.Sprintf("Name"), | ||
| 325 | fmt.Sprintf("Status"), | ||
| 326 | } | ||
| 327 | *resultList = append(*resultList, result) | ||
| 328 | |||
| 221 | for name, h := range toolbox.AdminCheckList { | 329 | for name, h := range toolbox.AdminCheckList { |
| 222 | if err := h.Check(); err != nil { | 330 | if err := h.Check(); err != nil { |
| 223 | fmt.Fprintf(rw, "%s : %s\n", name, err.Error()) | 331 | result = []string{ |
| 332 | fmt.Sprintf("error"), | ||
| 333 | fmt.Sprintf("%s", name), | ||
| 334 | fmt.Sprintf("%s", err.Error()), | ||
| 335 | } | ||
| 336 | |||
| 224 | } else { | 337 | } else { |
| 225 | fmt.Fprintf(rw, "%s : ok\n", name) | 338 | result = []string{ |
| 339 | fmt.Sprintf("success"), | ||
| 340 | fmt.Sprintf("%s", name), | ||
| 341 | fmt.Sprintf("OK"), | ||
| 226 | } | 342 | } |
| 343 | |||
| 344 | } | ||
| 345 | *resultList = append(*resultList, result) | ||
| 227 | } | 346 | } |
| 347 | |||
| 348 | data["Content"] = resultList | ||
| 349 | data["Title"] = "Health Check" | ||
| 350 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 351 | tmpl = template.Must(tmpl.Parse(healthCheckTpl)) | ||
| 352 | tmpl.Execute(rw, data) | ||
| 353 | |||
| 228 | } | 354 | } |
| 229 | 355 | ||
| 230 | // TaskStatus is a http.Handler with running task status (task name, status and the last execution). | 356 | // TaskStatus is a http.Handler with running task status (task name, status and the last execution). |
| 231 | // it's in "/task" pattern in admin module. | 357 | // it's in "/task" pattern in admin module. |
| 232 | func taskStatus(rw http.ResponseWriter, req *http.Request) { | 358 | func taskStatus(rw http.ResponseWriter, req *http.Request) { |
| 233 | for tname, tk := range toolbox.AdminTaskList { | 359 | data := make(map[interface{}]interface{}) |
| 234 | fmt.Fprintf(rw, "%s:%s:%s", tname, tk.GetStatus(), tk.GetPrev().String()) | ||
| 235 | } | ||
| 236 | } | ||
| 237 | 360 | ||
| 238 | // RunTask is a http.Handler to run a Task from the "query string. | 361 | // Run Task |
| 239 | // the request url likes /runtask?taskname=sendmail. | ||
| 240 | func runTask(rw http.ResponseWriter, req *http.Request) { | ||
| 241 | req.ParseForm() | 362 | req.ParseForm() |
| 242 | taskname := req.Form.Get("taskname") | 363 | taskname := req.Form.Get("taskname") |
| 364 | if taskname != "" { | ||
| 365 | |||
| 243 | if t, ok := toolbox.AdminTaskList[taskname]; ok { | 366 | if t, ok := toolbox.AdminTaskList[taskname]; ok { |
| 244 | err := t.Run() | 367 | err := t.Run() |
| 245 | if err != nil { | 368 | if err != nil { |
| 246 | fmt.Fprintf(rw, "%v", err) | 369 | data["Message"] = []string{"error", fmt.Sprintf("%s", err)} |
| 247 | } | 370 | } |
| 248 | fmt.Fprintf(rw, "%s run success,Now the Status is %s", taskname, t.GetStatus()) | 371 | data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is %s", taskname, t.GetStatus())} |
| 249 | } else { | 372 | } else { |
| 250 | fmt.Fprintf(rw, "there's no task which named:%s", taskname) | 373 | data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} |
| 251 | } | 374 | } |
| 375 | } | ||
| 376 | |||
| 377 | // List Tasks | ||
| 378 | resultList := new([][]string) | ||
| 379 | var result = []string{ | ||
| 380 | fmt.Sprintf("header"), | ||
| 381 | fmt.Sprintf("Task Name"), | ||
| 382 | fmt.Sprintf("Task Spec"), | ||
| 383 | fmt.Sprintf("Task Function"), | ||
| 384 | } | ||
| 385 | *resultList = append(*resultList, result) | ||
| 386 | for tname, tk := range toolbox.AdminTaskList { | ||
| 387 | result = []string{ | ||
| 388 | fmt.Sprintf(""), | ||
| 389 | fmt.Sprintf("%s", tname), | ||
| 390 | fmt.Sprintf("%s", tk.GetStatus()), | ||
| 391 | fmt.Sprintf("%s", tk.GetPrev().String()), | ||
| 392 | } | ||
| 393 | *resultList = append(*resultList, result) | ||
| 394 | } | ||
| 395 | |||
| 396 | data["Content"] = resultList | ||
| 397 | data["Title"] = "Tasks" | ||
| 398 | tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
| 399 | tmpl = template.Must(tmpl.Parse(tasksTpl)) | ||
| 400 | tmpl.Execute(rw, data) | ||
| 252 | } | 401 | } |
| 253 | 402 | ||
| 254 | // adminApp is an http.HandlerFunc map used as beeAdminApp. | 403 | // adminApp is an http.HandlerFunc map used as beeAdminApp. | ... | ... |
adminui.go
0 → 100644
| 1 | // Beego (http://beego.me/) | ||
| 2 | // @description beego is an open-source, high-performance web framework for the Go programming language. | ||
| 3 | // @link http://github.com/astaxie/beego for the canonical source repository | ||
| 4 | // @license http://github.com/astaxie/beego/blob/master/LICENSE | ||
| 5 | // @authors astaxie | ||
| 6 | |||
| 7 | package beego | ||
| 8 | |||
| 9 | var indexTpl = ` | ||
| 10 | {{define "content"}} | ||
| 11 | <h1>Beego Admin Dashboard</h1> | ||
| 12 | <p> | ||
| 13 | For detail usage please check our document: | ||
| 14 | </p> | ||
| 15 | <p> | ||
| 16 | <a target="_blank" href="http://beego.me/docs/module/toolbox.md">Toolbox</a> | ||
| 17 | </p> | ||
| 18 | <p> | ||
| 19 | <a target="_blank" href="http://beego.me/docs/advantage/monitor.md">Live Monitor</a> | ||
| 20 | </p> | ||
| 21 | {{.Content}} | ||
| 22 | {{end}}` | ||
| 23 | |||
| 24 | var profillingTpl = ` | ||
| 25 | {{define "content"}} | ||
| 26 | <h1>{{.Title}}</h1> | ||
| 27 | <pre> | ||
| 28 | {{.Content}} | ||
| 29 | </pre> | ||
| 30 | {{end}}` | ||
| 31 | |||
| 32 | var qpsTpl = ` | ||
| 33 | {{define "content"}} | ||
| 34 | <h1>Requests statistics</h1> | ||
| 35 | <table class="table table-striped table-hover "> | ||
| 36 | {{range $i, $slice := .Content}} | ||
| 37 | <tr> | ||
| 38 | {{range $j, $elem := $slice}} | ||
| 39 | {{if eq $i 0}} | ||
| 40 | <th> | ||
| 41 | {{else}} | ||
| 42 | <td> | ||
| 43 | {{end}} | ||
| 44 | {{$elem}} | ||
| 45 | {{if eq $i 0}} | ||
| 46 | </th> | ||
| 47 | {{else}} | ||
| 48 | </td> | ||
| 49 | {{end}} | ||
| 50 | {{end}} | ||
| 51 | |||
| 52 | </tr> | ||
| 53 | {{end}} | ||
| 54 | </table> | ||
| 55 | {{end}} | ||
| 56 | ` | ||
| 57 | |||
| 58 | var configTpl = ` | ||
| 59 | {{define "content"}} | ||
| 60 | <h1>Configurations</h1> | ||
| 61 | <pre> | ||
| 62 | {{range $index, $elem := .Content}} | ||
| 63 | {{$index}}={{$elem}} | ||
| 64 | {{end}} | ||
| 65 | </pre> | ||
| 66 | {{end}} | ||
| 67 | ` | ||
| 68 | |||
| 69 | var routerAndFilterTpl = ` | ||
| 70 | {{define "content"}} | ||
| 71 | |||
| 72 | <h1>{{.Title}}</h1> | ||
| 73 | <table class="table table-striped table-hover "> | ||
| 74 | {{range $i, $slice := .Content}} | ||
| 75 | <tr> | ||
| 76 | |||
| 77 | {{ $header := index $slice 0}} | ||
| 78 | {{if eq "header" $header }} | ||
| 79 | {{range $j, $elem := $slice}} | ||
| 80 | {{if ne $j 0}} | ||
| 81 | <th> | ||
| 82 | {{$elem}} | ||
| 83 | </th> | ||
| 84 | {{end}} | ||
| 85 | {{end}} | ||
| 86 | {{else if eq "success" $header}} | ||
| 87 | {{range $j, $elem := $slice}} | ||
| 88 | {{if ne $j 0}} | ||
| 89 | <th class="success"> | ||
| 90 | {{$elem}} | ||
| 91 | </th> | ||
| 92 | {{end}} | ||
| 93 | {{end}} | ||
| 94 | {{else}} | ||
| 95 | {{range $j, $elem := $slice}} | ||
| 96 | {{if ne $j 0}} | ||
| 97 | <td> | ||
| 98 | {{$elem}} | ||
| 99 | </td> | ||
| 100 | {{end}} | ||
| 101 | {{end}} | ||
| 102 | {{end}} | ||
| 103 | |||
| 104 | </tr> | ||
| 105 | {{end}} | ||
| 106 | </table> | ||
| 107 | {{end}} | ||
| 108 | ` | ||
| 109 | |||
| 110 | var tasksTpl = ` | ||
| 111 | {{define "content"}} | ||
| 112 | |||
| 113 | <h1>{{.Title}}</h1> | ||
| 114 | |||
| 115 | {{if .Message }} | ||
| 116 | {{ $messageType := index .Message 0}} | ||
| 117 | <p class="message | ||
| 118 | {{if eq "error" $messageType}} | ||
| 119 | bg-danger | ||
| 120 | {{else if eq "success" $messageType}} | ||
| 121 | bg-success | ||
| 122 | {{else}} | ||
| 123 | bg-warning | ||
| 124 | {{end}} | ||
| 125 | "> | ||
| 126 | {{index .Message 1}} | ||
| 127 | </p> | ||
| 128 | {{end}} | ||
| 129 | |||
| 130 | |||
| 131 | <table class="table table-striped table-hover "> | ||
| 132 | {{range $i, $slice := .Content}} | ||
| 133 | <tr> | ||
| 134 | |||
| 135 | {{ $header := index $slice 0}} | ||
| 136 | {{if eq "header" $header }} | ||
| 137 | {{range $j, $elem := $slice}} | ||
| 138 | {{if ne $j 0}} | ||
| 139 | <th> | ||
| 140 | {{$elem}} | ||
| 141 | </th> | ||
| 142 | {{end}} | ||
| 143 | {{end}} | ||
| 144 | <th> | ||
| 145 | Run Task | ||
| 146 | </th> | ||
| 147 | {{else}} | ||
| 148 | {{range $j, $elem := $slice}} | ||
| 149 | {{if ne $j 0}} | ||
| 150 | <td> | ||
| 151 | {{$elem}} | ||
| 152 | </td> | ||
| 153 | {{end}} | ||
| 154 | {{end}} | ||
| 155 | <td> | ||
| 156 | <a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 1}}">Run</a> | ||
| 157 | </td> | ||
| 158 | {{end}} | ||
| 159 | |||
| 160 | </tr> | ||
| 161 | {{end}} | ||
| 162 | </table> | ||
| 163 | {{end}} | ||
| 164 | ` | ||
| 165 | |||
| 166 | var healthCheckTpl = ` | ||
| 167 | {{define "content"}} | ||
| 168 | |||
| 169 | <h1>{{.Title}}</h1> | ||
| 170 | <table class="table table-striped table-hover "> | ||
| 171 | {{range $i, $slice := .Content}} | ||
| 172 | |||
| 173 | {{ $header := index $slice 0}} | ||
| 174 | {{if eq "header" $header }} | ||
| 175 | <tr> | ||
| 176 | {{range $j, $elem := $slice}} | ||
| 177 | {{if ne $j 0}} | ||
| 178 | <th> | ||
| 179 | {{$elem}} | ||
| 180 | </th> | ||
| 181 | {{end}} | ||
| 182 | {{end}} | ||
| 183 | </tr> | ||
| 184 | {{else}} | ||
| 185 | {{ if eq "success" $header}} | ||
| 186 | <tr class="success"> | ||
| 187 | {{else if eq "error" $header}} | ||
| 188 | <tr class="danger"> | ||
| 189 | {{else}} | ||
| 190 | <tr> | ||
| 191 | {{end}} | ||
| 192 | {{range $j, $elem := $slice}} | ||
| 193 | {{if ne $j 0}} | ||
| 194 | <td> | ||
| 195 | {{$elem}} | ||
| 196 | </td> | ||
| 197 | {{end}} | ||
| 198 | {{end}} | ||
| 199 | </tr> | ||
| 200 | {{end}} | ||
| 201 | |||
| 202 | {{end}} | ||
| 203 | </table> | ||
| 204 | {{end}}` | ||
| 205 | |||
| 206 | // The base dashboardTpl | ||
| 207 | var dashboardTpl = ` | ||
| 208 | <!DOCTYPE html> | ||
| 209 | <html lang="en"> | ||
| 210 | <head> | ||
| 211 | <!-- Meta, title, CSS, favicons, etc. --> | ||
| 212 | <meta charset="utf-8"> | ||
| 213 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
| 214 | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| 215 | |||
| 216 | <title> | ||
| 217 | |||
| 218 | Welcome to Beego Admin Dashboard | ||
| 219 | |||
| 220 | </title> | ||
| 221 | |||
| 222 | <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> | ||
| 223 | |||
| 224 | <style type="text/css"> | ||
| 225 | ul.nav li.dropdown:hover > ul.dropdown-menu { | ||
| 226 | display: block; | ||
| 227 | } | ||
| 228 | #logo { | ||
| 229 | width: 102px; | ||
| 230 | height: 32px; | ||
| 231 | margin-top: 5px; | ||
| 232 | } | ||
| 233 | .message { | ||
| 234 | padding: 15px; | ||
| 235 | } | ||
| 236 | </style> | ||
| 237 | |||
| 238 | </head> | ||
| 239 | <body> | ||
| 240 | |||
| 241 | <header class="navbar navbar-default navbar-static-top bs-docs-nav" id="top" role="banner"> | ||
| 242 | <div class="container"> | ||
| 243 | <div class="navbar-header"> | ||
| 244 | <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse"> | ||
| 245 | <span class="sr-only">Toggle navigation</span> | ||
| 246 | <span class="icon-bar"></span> | ||
| 247 | <span class="icon-bar"></span> | ||
| 248 | <span class="icon-bar"></span> | ||
| 249 | </button> | ||
| 250 | |||
| 251 | <a href="/"> | ||
| 252 | <img id="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAABNCAYAAACVH5l+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAV/QAAFf0BzXBRYQAAABZ0RVh0Q3JlYXRpb24gVGltZQAxMi8xMy8xM+ovEHIAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAQAklEQVR4nO2de7RcVXnAfzM3MckmhLdKtZYqoimtERVtXSjFNvYE6rsnFMFKy2MJC4tGdNECalFsKxRQ5GGDClUjzS6lltcuUmiryxRqFaEaCkgVqAkSakKSneTm3rn949uHOTNzzp1zZs5j7mT/1pqVmzMze39z73xnf/vb36OBx+OZFRuEvwusBp4fu7wROE0ZfUs9UiUzMzMDQLNmOTyeucB1dCo17v/XVS5JRrxiezz9OSDn9drxiu3xjCFesT2eMcQrtsczhnjF9njGEK/YHs8Y4hXb4xlDvGJ7PGOIV2yPZwzxiu3x9OfpnNdrxyu2x9Ofk5HY8Dgb3fWRpFG3AB6Ppzh8EojHM8Z4xfZ4xhCv2B7PGOIV2+MZQ+bVLYDHUzU2CE8AXg+8GHguMAW0gOmEn6PH7q6fdwOTsceurp+fca+1wJPAz4GfKaM3V/EZvVfcs0dhg/AC4D3AgcAixGrNqgczOZ9ruOuTiGLfBVygjH4is8A5ibziXrE9eww2CI8C1gL7INZq9P2PFLBIorGjcacRBf82sFIZvbXg+WQyp9jzbBBuRj7osDwFPALcA9wC3K2MbhUw7rMUKGsWHgMuUUZfMcib55Ksg2CDcCnwR8CbgJcCe2d5G3AzcJYyelOJ4vVOHISLgEuB/YAJqlvUonkmgAXAa4HfR4ojDo0NwiXAIcAPldFT0fUinWcHAb8BfAC4E3jQBuHxBY5fNS8CPmuD8Ji6BclAZbLaIFxgg/AzwH8B5wCvIptSAyjgeOCvShIvkW1vflcDkfXltL/zMxU/QJR8EXCWDcIDh/lMNgjn2SD8MLAB+D6w3gbhC6Lny/SKvxS4wQbhGhuEqsR5yua36xYgB6XK6v6OtwN/zHDfnaOLkSgbzWbz5cDpwHySla5VwCNpzDTlPgSxdgbCBuGrgXuBTyM3S4BDgS/tWLGyAdV4xU8AltggfJsyerqC+YrG1i1ADkqT1QbhBLI/LcIq2FnAGJlwJviFwL7uUlzJQH5n6921pntM9Pk3crg1ux646w3apvd8es3++cApNgi/pox+PMdnUcAngLPd+N0sB04FVld13HUc8FHgYxXNVxSTwI11C5GRsmW9APk7FsHagsbJwnGIhRApQuQom0FuMOcpo68pY2IbhPsD/wwcRvtmECn5wcCHEesny1i/A1yDrPazcfGOFSu/1khx8rSABzJJL+znBJ0/y2t2A0uV0T/KMW4HBcmahUngIeAKZfQ9gwwwl2Tthw3Co5GjmjTz+xngx/T3LD8J/CNwTRXWm9vH3gr8Cr2KPQ3co4wue/tyKvAXtE3m+I1lM3CsMvr7s7z/AOBy4KQc0y5LW7G3KqNfmWOgyExYDnwcSHrvfMSBcUaecTOQW9YamUuyAs8qxxrSlXo14uWerE6qzKyivVpGRHvfzYhJWzZrgROB19DpuANYDPypDcL3KqN7tic2COcDdwO/lmO+B4D1hTnPlNFWGf115AOkmVrvtkG4oKg5PeWydfk7G8D1wC+kvOTfgDNGUaltEL4GCUSZR69DaxdwgzL6B2XLoYx+BnFybaftaIP2nv4NwG+lvH0p+ZR6DXDMotvX7i7cK+5MrFPoTUwHWAIcVfScnnKYmJhYBRyb8vTTwAmj6BC1QbgYcZhFx3BxpZ4GfgJcVqFIdyJe7Gl6veQK+IA7j+7mUcSy6MdPgBXK6BMX3b72aSjpuEsZvY30hmWvL2NOT7HYIDwS+PNZXnKyMvqnVcmTk5XAEXRGlEXKZBF/RGWyK6N3A+cjvojuVbuBrMpvSXjfNuCDswzdQm5QhyujTfyJMs+x70i5fniJc3oKwAbhPsANpDtDLx+19rERLkjjTGAhvWGdU8B/Al+tWi5l9P3A3zsZIpkiL/lC4P1Jq7Yy+jrgtoQh7wNep4xepYze3v1kmYqdtn/5pRLn9BTD55HMpyS+B5xboSx5ORuJxGvSuVq3ELN2VY0+gUuRLWp38EoDCTA5JeV9pyHh2iAWx7nAkcro76RNVJpiK6N/hhxxdXNQWXN6hscG4WlI2GcS24HjldG7KhQpMzYIXwmEtCPMoK08u4AvKKMfqkk8lNGPIdbCLto3G2g70k63Qdiz8Lltw1JgGXCwMvov43HhSZRdaCEpEsrngI8oNggPBT4zy0vOUEY/XJU8ebBBuBA5L47HrUf72WngYQpKvBiSaxFnV7cjrYGkkp7lovw6UEZPKaPvd172vtRRQeU5Nczp6YNLlPhrJEkhia8oo79coUh5eTfwCnq/05HD7GpnRdaKk+FqJLAortQgQTTvQFbnoShNsW0QNklOW6wsTtiTnWazeRLpceCPUHxgUWHYIDwYOIvORSPax04B6xDH1aiwBniQ3r02yJHwh1xwysCUuWKneb+fKnFOzwC41fqClKcnkX31tgpFysu5SEhzPFwzOrP+OXCRMnpHfeJ14nwUH0csiUi5ob3XPgZJhx2YMhU7LWHgkZTrnppoNptvQNJsk/gzZfR3q5QnDy7C7DjEjI0UJFKW3cAXZ4vFrgtl9L8C36RdYy1elGQRcN4w45ei2DYI9yU9a+XeMub0DEWQcv1x4JIqBcmDDcJ5wEVIzHX8zDoywR8ErqpHukx8EthCr0neBF5tgzDt79KXwhXbBTesRUyjJG4tek7P0CxLuX79KMaBxzgZ2fLFTfBo9dsGXFpWbbEiUEavR8qITdF7/DUBfMLlk+emMMW2QXiYDcKzkeyS5Skvu0sZ7U3x0eOQlOv/VKUQebBB+DzEKoyKEsbDR6eRNNNv1CNdLi5D4u67U16byOL4vkEGTTtT3sflE2dlr1nGivMnOcbMShZZp5B84S8ro2c7py2bUZV1r5TrP6xo/kE4Ddif5Hjwp4BPj2ogTRxl9BM2CK9DYsKjwJroM80D3mOD8AZl9IY8486mjEVX2LxIGV3W/jqLrAcg+5bNyujrS5IjC6Moa1Ixwkll9P9VMPegHE1bAeLKPQWsbrVaAxf0qIGrkGi/F9Kbs30gUl7s0jwDVhWgsobRKYv0jroFyEFVsibVzxqZ46EUor1nd8HA7a1W68rFd9zYr5rLyOCO4i6kvdeOWyAN4DfzjlmVYttWq1VojXHPHk8UudXNvGaz+dqqhSmAbyA30+7Chw3St0qpVKXYpzabzTL214NwU90C5GAuyVo162gfE8X/XQCc547C5hLLkfTNpPLIuX0Fs334LTnG2Zv+N4kLbRDeWlKwQD9Z4w6pOvfXMLdk7YsNwrcAHwFeRvY8gC3K6GHTd/8GeBtSVrg773op8FZGK4w0FZeHfS6iQy16Pfyp6ZlppCn2FmX0vinPpQl3CFKw/iMkRzFNAJ+iuBK2EbllrZG5JGtfbBC+CvgH6kkmegT4OlK9M4o6ixR8AZICeWfWbKiaORN4Acke/i0MUBiiyGKGP1ZGXwv8KtKfKYkVNgh/sag5PbVzLDX1WHe11r6InAEnpUC+GHhXHbLlweVfn0D75hTfWuxGbpy5Yz/KKGY4iTQdS+pw0KD4Fduzh9JqtR4F/o7OPTbu5wXAScP2yKqA85GMLuhcracRHbpskIKRZRUztEhCeRKvK2NOTy3cRmfyQqW4I60vAP9Lsof8RUhFlZHEtfU9is72QHGH2SeV0XkCxZ6lTDPq9pTrh5Y4p6dCXNbX24FvIdFeWxIeZcvwJLIHjRcuiJR8HnD8KK7arsHGxxBPeES8RPK/K6MHDokt80jgwZTrI/dL9gyOMvpm0n0qVfUJ10gwz6H0Nsd7IfCHwMUly5AZV4Tk/UiMfpLDbCuzl37uS5nFDLcixe+6GShbxeNJQxm9CVm1d9J7BtxEVu1Rqo77y8DvkZxDPgXcpIxOWxgzUbZHM6mSom/x4ymDmxDvcdyBBrIi7guckVQksGpc4MwHkUaW3VFmLeCnwGeHnadsxV6YcG3kM248cw93Xr0aWbW7yw01gDcDL6lHug7e6B5xEzzKIZ8Eriwi+abMYoYHkbw6D+Tl83gyYJAm9klFAhcjgSC1YYNwb2S1jm9H42fX31NGF9I7vMwV+00p1x8tcU7PYFRtRZWSeeV6ZH0KSaboPtduAEfbIDysjLkzciLi4Euq+LIFKZVUCKUotmu/mtZM7D/KmNMzFElOziU2CIuoAZ9URre0YzB3BPct0jtbripr7tlwIdd/QHrRxduU0YUVtihcsbcuf2djYmLiYtIDUUaymdseTtKeroEUMxgYG4TLEGXq5slhxs3A5ciRUbQaxpX7FTYIjyh5/g5cjfDIYQadN5xppJ/XlUXOWWTNs4U2CIOJiYm7gA+lvOxeZfQDRc3pKYy0aiNXOOXMjQ3Cw5EMrCTuG2TMrLj+XN+k1+RvIOGbv17m/Am8keQIMxCH2bUu0KYw0gJU9rZBmOeXvxjpotkv4KWMKip5Zc3CJPAQ0kf5ngLHHVVZ70B6SnfzMuA+G4QbgKztcZpIEFJalVqYJaClQK5CCu93x01MIJ+rElzV3vfRtlzi3voW0lPsxqLnTVPEJuklaQfl+u7m3AVRhqwARwKhDcJlwwYLxBhVWf8WcTo9N+X5g5ldUfPwMMn9novmUeAJekOYZyjus2Th7Ugac7w+W7Q92IbUAizceVlVyt3d1HzUMCDPYQ6k/jkGltW176ni7zMDnKmMLj1xxGVEbSL56CspvqJwXE+x99LZ1jceYWbK6rJSRfmYrwCnj1LvpJwkOX9GlYFlVUbfaIPwTMrrnNFClPrOksZPIjr26o7w6vneu7iLw5Fwz+cjyr8L6a+13Y21M/bvM4iDbguy8u6I96x2EWbnIFZQd+XRGUpwmMUpU7HvB853SQJzmSq/iMMylKzK6KttED6OpEKmmeWD8CPk5n5XgWNmIR47HhHV6wbABuEBiH/hWOB5iEJHCSTx9yTRMa4NwvhcDcSK6h5nBvGLfFUZvTHn58lMkYq9EcnoWgfcrIxeV+DYdfAYcIky+u66BclAYbIqo2+xQfgSxIRcARyBKHme78pOYAPwbaSlk46vZhUSrdjdit10ZvJKZA+8P+JU617ZI9KuZ6F77hYS0164wyzOMAJ7PCONDcKPIllUcV/SDHLjsUhySJNOPYgfRQ1L92rdcvOeX9aWZGZGRJ9rJVo9njx0r9iRib0QyWOIVzft7tZZBN2r9W7gX6rwM3jF9owzu+hVLkhW3CRPfZqC57V0W4hS/w9QST82r9ieccaSrIRpjrG4uRx15ZhAzPXoEa360f+hM6Ksm0kko3E98Lm8zfUGxSu2Z5x5Glkp59OrdElm8n8jOd3fUUYnJcYk4o62FrrHXu6hEP2yyNHYJhcvUAlesT3jzEbkDHoJnUdYcZN8J3IcN3BIrvP4b3OPTcMIXBResT3jzONIqaGFtE3qiB3AD5AAqnUul3ts8IrtGWc2IDHw5yAtdOYjoZzfRRoN3FdGnPYo4M+xPWONK2C4H+1FbArYXFPATOlE59j/D6WId7YitGZUAAAAAElFTkSuQmCC"/> | ||
| 253 | </a> | ||
| 254 | |||
| 255 | </div> | ||
| 256 | <nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation"> | ||
| 257 | <ul class="nav navbar-nav"> | ||
| 258 | <li> | ||
| 259 | <a href="/qps"> | ||
| 260 | Requests statistics | ||
| 261 | </a> | ||
| 262 | </li> | ||
| 263 | <li> | ||
| 264 | |||
| 265 | <li class="dropdown"> | ||
| 266 | <a href="#" class="dropdown-toggle disabled" data-toggle="dropdown">Performance profiling<span class="caret"></span></a> | ||
| 267 | <ul class="dropdown-menu" role="menu"> | ||
| 268 | |||
| 269 | <li><a href="/prof?command=lookup goroutine">lookup goroutine</a></li> | ||
| 270 | <li><a href="/prof?command=lookup heap">lookup heap</a></li> | ||
| 271 | <li><a href="/prof?command=lookup threadcreate">lookup threadcreate</a></li> | ||
| 272 | <li><a href="/prof?command=lookup block">lookup block</a></li> | ||
| 273 | <li><a href="/prof?command=start cpuprof">start cpuprof</a></li> | ||
| 274 | <li><a href="/prof?command=stop cpuprof">stop cpuprof</a></li> | ||
| 275 | <li><a href="/prof?command=get memprof">get memprof</a></li> | ||
| 276 | <li><a href="/prof?command=gc summary">gc summary</a></li> | ||
| 277 | |||
| 278 | </ul> | ||
| 279 | </li> | ||
| 280 | |||
| 281 | <li> | ||
| 282 | <a href="/healthcheck"> | ||
| 283 | Healthcheck | ||
| 284 | </a> | ||
| 285 | </li> | ||
| 286 | |||
| 287 | <li> | ||
| 288 | <a href="/task" class="dropdown-toggle disabled" data-toggle="dropdown">Tasks</a> | ||
| 289 | </li> | ||
| 290 | |||
| 291 | <li class="dropdown"> | ||
| 292 | <a href="#" class="dropdown-toggle disabled" data-toggle="dropdown">Config Status<span class="caret"></span></a> | ||
| 293 | <ul class="dropdown-menu" role="menu"> | ||
| 294 | <li><a href="/listconf?command=conf">Configs</a></li> | ||
| 295 | <li><a href="/listconf?command=router">Routers</a></li> | ||
| 296 | <li><a href="/listconf?command=filter">Filters</a></li> | ||
| 297 | </ul> | ||
| 298 | </li> | ||
| 299 | </ul> | ||
| 300 | </nav> | ||
| 301 | </div> | ||
| 302 | </header> | ||
| 303 | |||
| 304 | <div class="container"> | ||
| 305 | {{template "content" .}} | ||
| 306 | </div> | ||
| 307 | |||
| 308 | <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> | ||
| 309 | <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> | ||
| 310 | |||
| 311 | </body> | ||
| 312 | </html> | ||
| 313 | ` |
| 1 | // Beego (http://beego.me/) | 1 | // Beego (http://beego.me/) |
| 2 | // | ||
| 3 | // @description beego is an open-source, high-performance web framework for the Go programming language. | 2 | // @description beego is an open-source, high-performance web framework for the Go programming language. |
| 4 | // | ||
| 5 | // @link http://github.com/astaxie/beego for the canonical source repository | 3 | // @link http://github.com/astaxie/beego for the canonical source repository |
| 6 | // | ||
| 7 | // @license http://github.com/astaxie/beego/blob/master/LICENSE | 4 | // @license http://github.com/astaxie/beego/blob/master/LICENSE |
| 8 | // | ||
| 9 | // @authors astaxie | 5 | // @authors astaxie |
| 10 | package toolbox | 6 | package toolbox |
| 11 | 7 | ||
| 12 | import ( | 8 | import ( |
| 13 | "fmt" | 9 | "fmt" |
| 14 | "io" | ||
| 15 | "sync" | 10 | "sync" |
| 16 | "time" | 11 | "time" |
| 17 | ) | 12 | ) |
| ... | @@ -79,17 +74,29 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri | ... | @@ -79,17 +74,29 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | // put url statistics result in io.Writer | 76 | // put url statistics result in io.Writer |
| 82 | func (m *UrlMap) GetMap(rw io.Writer) { | 77 | func (m *UrlMap) GetMap() [][]string { |
| 83 | m.lock.RLock() | 78 | m.lock.RLock() |
| 84 | defer m.lock.RUnlock() | 79 | defer m.lock.RUnlock() |
| 85 | fmt.Fprintf(rw, "| % -50s| % -10s | % -16s | % -16s | % -16s | % -16s | % -16s |\n", "requestUrl", "method", "times", "used", "max used", "min used", "avg used") | 80 | resultLists := make([][]string, 0) |
| 81 | |||
| 82 | var result = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"} | ||
| 83 | resultLists = append(resultLists, result) | ||
| 86 | for k, v := range m.urlmap { | 84 | for k, v := range m.urlmap { |
| 87 | for kk, vv := range v { | 85 | for kk, vv := range v { |
| 88 | fmt.Fprintf(rw, "| % -50s| % -10s | % -16d | % -16s | % -16s | % -16s | % -16s |\n", k, | 86 | result := []string{ |
| 89 | kk, vv.RequestNum, toS(vv.TotalTime), toS(vv.MaxTime), toS(vv.MinTime), toS(time.Duration(int64(vv.TotalTime)/vv.RequestNum)), | 87 | fmt.Sprintf("% -50s", k), |
| 90 | ) | 88 | fmt.Sprintf("% -10s", kk), |
| 89 | fmt.Sprintf("% -16d", vv.RequestNum), | ||
| 90 | fmt.Sprintf("% -16s", toS(vv.TotalTime)), | ||
| 91 | fmt.Sprintf("% -16s", toS(vv.MaxTime)), | ||
| 92 | fmt.Sprintf("% -16s", toS(vv.MinTime)), | ||
| 93 | fmt.Sprintf("% -16s", toS(time.Duration(int64(vv.TotalTime)/vv.RequestNum))), | ||
| 94 | } | ||
| 95 | resultLists = append(resultLists, result) | ||
| 91 | } | 96 | } |
| 92 | } | 97 | } |
| 98 | fmt.Println(resultLists) | ||
| 99 | return resultLists | ||
| 93 | } | 100 | } |
| 94 | 101 | ||
| 95 | // global statistics data map | 102 | // global statistics data map | ... | ... |
-
Please register or sign in to post a comment