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