d314d12c by Lei Cao

Added the UI for Admin monitor page

1 parent 14cd9e51
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.
......
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,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"/>
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
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!