| Index: perf/server/src/logserver/main.go
|
| diff --git a/perf/server/src/logserver/main.go b/perf/server/src/logserver/main.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7440e6d1291bd8095f1896a289b86fa326db0ac1
|
| --- /dev/null
|
| +++ b/perf/server/src/logserver/main.go
|
| @@ -0,0 +1,111 @@
|
| +// Application that serves up the contents of /tmp/glog via HTTP, giving access
|
| +// to logs w/o needing to SSH into the server.
|
| +package main
|
| +
|
| +import (
|
| + "flag"
|
| + "fmt"
|
| + "html/template"
|
| + "net/http"
|
| + "net/url"
|
| + "os"
|
| + "path"
|
| + "sort"
|
| + "strings"
|
| +
|
| + "github.com/golang/glog"
|
| +)
|
| +
|
| +var port = flag.String("port", ":8001", "HTTP service address (e.g., ':8001')")
|
| +
|
| +// FileServer returns a handler that serves HTTP requests
|
| +// with the contents of the file system rooted at root.
|
| +//
|
| +// To use the operating system's file system implementation,
|
| +// use http.Dir:
|
| +//
|
| +// http.Handle("/", FileServer(http.Dir("/tmp")))
|
| +//
|
| +// Differs from net/http FileServer by making directory listings better.
|
| +func FileServer(root http.FileSystem) http.Handler {
|
| + return &fileHandler{root}
|
| +}
|
| +
|
| +type fileHandler struct {
|
| + root http.FileSystem
|
| +}
|
| +
|
| +func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
| + upath := r.URL.Path
|
| + if !strings.HasPrefix(upath, "/") {
|
| + upath = "/" + upath
|
| + r.URL.Path = upath
|
| + }
|
| + serveFile(w, r, f.root, path.Clean(upath))
|
| +}
|
| +
|
| +// FileInfoSlice is for sorting.
|
| +type FileInfoSlice []os.FileInfo
|
| +
|
| +func (p FileInfoSlice) Len() int { return len(p) }
|
| +func (p FileInfoSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
|
| +func (p FileInfoSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
| +
|
| +func dirList(w http.ResponseWriter, f http.File) {
|
| + w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
| + fmt.Fprintf(w, "<pre>\n")
|
| + for {
|
| + dirs, err := f.Readdir(10000)
|
| + sort.Sort(FileInfoSlice(dirs))
|
| + if err != nil || len(dirs) == 0 {
|
| + break
|
| + }
|
| + for _, d := range dirs {
|
| + name := d.Name()
|
| + if d.IsDir() {
|
| + name += "/"
|
| + }
|
| + url := url.URL{Path: name}
|
| + fmt.Fprintf(w, "%s <a href=\"%s\">%s</a>\n", d.ModTime(), url.String(), template.HTMLEscapeString(name))
|
| + }
|
| + }
|
| + fmt.Fprintf(w, "</pre>\n")
|
| +}
|
| +
|
| +func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) {
|
| + f, err := fs.Open(name)
|
| + if err != nil {
|
| + http.NotFound(w, r)
|
| + return
|
| + }
|
| + defer f.Close()
|
| +
|
| + d, err1 := f.Stat()
|
| + if err1 != nil {
|
| + http.NotFound(w, r)
|
| + return
|
| + }
|
| +
|
| + url := r.URL.Path
|
| + if d.IsDir() {
|
| + if url[len(url)-1] != '/' {
|
| + w.Header().Set("Location", path.Base(url)+"/")
|
| + w.WriteHeader(http.StatusMovedPermanently)
|
| + return
|
| + }
|
| + }
|
| +
|
| + if d.IsDir() {
|
| + dirList(w, f)
|
| + return
|
| + }
|
| +
|
| + http.ServeContent(w, r, d.Name(), d.ModTime(), f)
|
| +}
|
| +
|
| +func main() {
|
| + flag.Parse()
|
| +
|
| + http.Handle("/", http.StripPrefix("/", FileServer(http.Dir("/tmp/glog"))))
|
| + glog.Fatal(http.ListenAndServe(*port, nil))
|
| +}
|
|
|