github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/witch/witch.go (about) 1 package witch 2 3 import "net/http" 4 import ( 5 "bytes" 6 "github.com/rakyll/statik/fs" 7 "github.com/v2pro/plz/countlog" 8 _ "github.com/v2pro/plz/witch/statik" 9 "io/ioutil" 10 "github.com/v2pro/plz/countlog/output" 11 "github.com/v2pro/plz/countlog/output/json" 12 "expvar" 13 "path" 14 "runtime" 15 "reflect" 16 ) 17 18 var files = []string{ 19 "ide.html", 20 "log-viewer.html", "filters.html", "data-sources.html", "columns.html", 21 "state-viewer.html", "snapshots.html", 22 "viz.html", "viz-item.html", "viz-value.html", 23 "viz-struct.html", "viz-array.html", 24 "viz-plain.html", "viz-ptr.html"} 25 26 //go:generate $GOPATH/bin/statik -src $PWD/webroot 27 28 var viewerHtml []byte 29 30 var Mux = &http.ServeMux{} 31 32 func init() { 33 Mux.HandleFunc("/witch/more-events", moreEvents) 34 Mux.Handle("/witch/expvar", expvar.Handler()) 35 Mux.HandleFunc("/witch/", homepage) 36 } 37 38 func initViewerHtml() error { 39 if viewerHtml != nil { 40 return nil 41 } 42 statikFS, err := fs.New() 43 if err != nil { 44 countlog.Error("event!witch.failed to load witch viewer web resource", "err", err) 45 return err 46 } 47 indexHtmlFile, err := statikFS.Open("/index.html") 48 if err != nil { 49 countlog.Error("event!witch.failed to open index.html", "err", err) 50 return err 51 } 52 indexHtml, err := ioutil.ReadAll(indexHtmlFile) 53 if err != nil { 54 countlog.Error("event!witch.failed to read index.html", "err", err) 55 return err 56 } 57 components := []byte{} 58 for _, file := range files { 59 f, err := statikFS.Open("/" + file) 60 if err != nil { 61 countlog.Error("event!witch.failed to open file", "err", err, "file", file) 62 return err 63 } 64 fileHtml, err := ioutil.ReadAll(f) 65 if err != nil { 66 countlog.Error("event!witch.failed to read file html", "err", err, "file", file) 67 return err 68 } 69 components = append(components, fileHtml...) 70 } 71 viewerHtml = bytes.Replace(indexHtml, []byte("{{ COMPONENTS }}"), components, -1) 72 return nil 73 } 74 75 var isDebug = true 76 var thisFile string 77 78 func init() { 79 pc := reflect.ValueOf(loadDebugViewerHtml).Pointer() 80 thisFile, _ = runtime.FuncForPC(pc).FileLine(pc) 81 } 82 83 func loadDebugViewerHtml() ([]byte, error) { 84 dir := path.Join(path.Dir(thisFile), "webroot") 85 indexHtml, err := ioutil.ReadFile(path.Join(dir, "index.html")) 86 if err != nil { 87 countlog.Error("event!witch.failed to read index.html", "err", err) 88 return nil, err 89 } 90 components := []byte{} 91 for _, file := range files { 92 fileHtml, err := ioutil.ReadFile(path.Join(dir, file)) 93 if err != nil { 94 countlog.Error("event!witch.failed to read file", "err", err, "file", file) 95 return nil, err 96 } 97 components = append(components, fileHtml...) 98 } 99 components = append(components, ` 100 <script> 101 window.isDebug = true; 102 </script> 103 `...) 104 return bytes.Replace(indexHtml, []byte("{{ COMPONENTS }}"), components, -1), nil 105 } 106 107 func Start(addr string) { 108 err := initViewerHtml() 109 if err != nil { 110 countlog.Error("event!witch.failed to init viewer html", "err", err) 111 return 112 } 113 countlog.Info("event!witch.viewer started", "addr", addr) 114 countlog.EventWriter = output.NewEventWriter(output.EventWriterConfig{ 115 Format: &json.Format{}, 116 Writer: theEventQueue, 117 }) 118 if addr != "" { 119 go func() { 120 setCurrentGoRoutineIsKoala() 121 http.ListenAndServe(addr, Mux) 122 }() 123 } 124 } 125 126 func homepage(respWriter http.ResponseWriter, req *http.Request) { 127 setCurrentGoRoutineIsKoala() 128 if !isDebug { 129 respWriter.Write(viewerHtml) 130 return 131 } 132 debugViewerHtml, err := loadDebugViewerHtml() 133 if err != nil { 134 respWriter.Write([]byte(err.Error())) 135 } else { 136 respWriter.Write(debugViewerHtml) 137 } 138 }