* builds with echo now instead of gin * beginning of web UI * factor out util functions
This commit is contained in:
@@ -83,6 +83,7 @@ func (f *Feta) identify() {
|
||||
}
|
||||
|
||||
func (f *Feta) setupDatabase() {
|
||||
f.dbm = database.New()
|
||||
}
|
||||
|
||||
func (f *Feta) setupLogging() {
|
||||
@@ -121,14 +122,10 @@ func (f *Feta) uptime() time.Duration {
|
||||
func (f *Feta) runForever() int {
|
||||
f.startup = time.Now()
|
||||
|
||||
//f.setupDatabase()
|
||||
|
||||
// FIXME move this channel creation into the manager's constructor
|
||||
// and add getters/setters on the manager/locator
|
||||
newInstanceHostnameNotifications := make(chan string)
|
||||
|
||||
f.dbm = database.New()
|
||||
|
||||
f.locator = locator.New()
|
||||
|
||||
f.manager = manager.New(f.dbm)
|
||||
@@ -140,6 +137,7 @@ func (f *Feta) runForever() int {
|
||||
panic("can't find home directory")
|
||||
}
|
||||
|
||||
// TODO make the ingester support multiple storage backends simultaneously
|
||||
if viper.GetBool("TootsToDB") {
|
||||
f.ingester.SetStorageBackend(f.dbm)
|
||||
} else if viper.GetBool("TootsToDisk") {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
u "git.eeqj.de/sneak/goutil"
|
||||
"github.com/flosch/pongo2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type hash map[string]interface{}
|
||||
@@ -26,7 +28,7 @@ func (a *Server) instances() []hash {
|
||||
i["successCount"] = v.SuccessCount
|
||||
i["errorCount"] = v.ErrorCount
|
||||
i["identified"] = v.Identified
|
||||
i["status"] = v.Status()
|
||||
i["status"] = v.Status() //FIXME maybe this is why
|
||||
i["software"] = "unknown"
|
||||
i["version"] = "unknown"
|
||||
if v.Identified {
|
||||
@@ -45,14 +47,15 @@ func (a *Server) instanceSummary() map[string]int {
|
||||
v.Lock()
|
||||
resp[fmt.Sprintf("STATUS_%s", v.Status())]++
|
||||
if v.ServerImplementationString != "" {
|
||||
//FIXME(sneak) sanitize this to a-z0-9, it is server-provided
|
||||
resp[fmt.Sprintf("SOFTWARE_%s", strings.ToUpper(v.ServerImplementationString))]++
|
||||
impl := strings.ToUpper(u.FilterToAlnum(v.ServerImplementationString))
|
||||
resp[fmt.Sprintf("SOFTWARE_%s", impl)]++
|
||||
}
|
||||
v.Unlock()
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
/*
|
||||
func (a *Server) getInstanceListHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -70,46 +73,38 @@ func (a *Server) getInstanceListHandler() http.HandlerFunc {
|
||||
w.Write(json)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func (a *Server) getIndexHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
index := &gin.H{
|
||||
"server": &gin.H{
|
||||
"now": time.Now().UTC().Format(time.RFC3339),
|
||||
"uptime": a.feta.uptime().String(),
|
||||
"goroutines": runtime.NumGoroutine(),
|
||||
"goversion": runtime.Version(),
|
||||
"version": a.feta.version,
|
||||
"buildarch": a.feta.buildarch,
|
||||
},
|
||||
"instanceSummary": a.instanceSummary(),
|
||||
}
|
||||
|
||||
json, err := json.Marshal(index)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(json)
|
||||
func (a *Server) indexHandler(c echo.Context) error {
|
||||
tc := pongo2.Context{
|
||||
"time": time.Now().UTC().Format(time.RFC3339Nano),
|
||||
"gitrev": a.feta.version,
|
||||
}
|
||||
return c.Render(http.StatusOK, "index.html", tc)
|
||||
}
|
||||
|
||||
func (a *Server) getHealthCheckHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := &gin.H{
|
||||
"status": "ok",
|
||||
"now": time.Now().UTC().Format(time.RFC3339),
|
||||
"uptime": a.feta.uptime().String(),
|
||||
}
|
||||
|
||||
json, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(json)
|
||||
func (a *Server) statsHandler(c echo.Context) error {
|
||||
index := &gin.H{
|
||||
"server": &gin.H{
|
||||
"now": time.Now().UTC().Format(time.RFC3339),
|
||||
"uptime": a.feta.uptime().String(),
|
||||
"goroutines": runtime.NumGoroutine(),
|
||||
"goversion": runtime.Version(),
|
||||
"version": a.feta.version,
|
||||
"buildarch": a.feta.buildarch,
|
||||
},
|
||||
"instanceSummary": a.instanceSummary(),
|
||||
}
|
||||
|
||||
return c.JSONPretty(http.StatusOK, index, " ")
|
||||
}
|
||||
|
||||
func (a *Server) healthCheckHandler(c echo.Context) error {
|
||||
resp := &gin.H{
|
||||
"status": "ok",
|
||||
"now": time.Now().UTC().Format(time.RFC3339),
|
||||
"uptime": a.feta.uptime().String(),
|
||||
}
|
||||
return c.JSONPretty(http.StatusOK, resp, " ")
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
package process
|
||||
|
||||
import "fmt"
|
||||
import "net/http"
|
||||
import "os"
|
||||
import "strconv"
|
||||
import "time"
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
import "github.com/rs/zerolog/log"
|
||||
import "github.com/gin-gonic/gin"
|
||||
import "github.com/dn365/gin-zerolog"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
gl "github.com/labstack/gommon/log"
|
||||
ep2 "github.com/mayowa/echo-pongo2"
|
||||
"github.com/ziflex/lecho"
|
||||
|
||||
//"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Server is the HTTP webserver object
|
||||
type Server struct {
|
||||
feta *Feta
|
||||
port uint
|
||||
router *gin.Engine
|
||||
server *http.Server
|
||||
debug bool
|
||||
feta *Feta
|
||||
port uint
|
||||
e *echo.Echo
|
||||
router *gin.Engine
|
||||
httpserver *http.Server
|
||||
debug bool
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// SetFeta tells the http Server where to find the Process object so that it
|
||||
@@ -28,6 +39,7 @@ func (a *Server) SetFeta(feta *Feta) {
|
||||
// Serve is the entrypoint for the Server, which should run in its own
|
||||
// goroutine (started by the Process)
|
||||
func (a *Server) Serve() {
|
||||
|
||||
if a.feta == nil {
|
||||
panic("must have feta app from which to serve stats")
|
||||
}
|
||||
@@ -47,43 +59,53 @@ func (a *Server) Serve() {
|
||||
|
||||
a.initRouter()
|
||||
a.initServer()
|
||||
err := a.server.ListenAndServe()
|
||||
a.e.Logger.Fatal(a.e.StartServer(a.httpserver))
|
||||
}
|
||||
|
||||
func (s *Server) initRouter() {
|
||||
|
||||
// Echo instance
|
||||
s.e = echo.New()
|
||||
|
||||
s.e.HideBanner = true
|
||||
|
||||
lev := gl.INFO
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
lev = gl.DEBUG
|
||||
}
|
||||
|
||||
logger := lecho.New(
|
||||
os.Stdout,
|
||||
lecho.WithLevel(lev),
|
||||
lecho.WithTimestamp(),
|
||||
lecho.WithCaller(),
|
||||
)
|
||||
s.e.Logger = logger
|
||||
s.e.Use(middleware.RequestID())
|
||||
|
||||
// Middleware
|
||||
s.e.Use(middleware.Logger())
|
||||
s.e.Use(middleware.Recover())
|
||||
|
||||
r, err := ep2.NewRenderer("view")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("webserver failure")
|
||||
return
|
||||
s.e.Logger.Fatal(err)
|
||||
}
|
||||
s.e.Renderer = r
|
||||
|
||||
// Routes
|
||||
s.e.GET("/", s.indexHandler)
|
||||
s.e.GET("/stats.json", s.statsHandler)
|
||||
s.e.GET("/.well-known/healthcheck.json", s.healthCheckHandler)
|
||||
//a.e.GET("/about", s.aboutHandler)
|
||||
|
||||
}
|
||||
|
||||
func (a *Server) initRouter() {
|
||||
func (s *Server) initServer() {
|
||||
log.Info().Uint("port", s.port).Msg("starting webserver")
|
||||
|
||||
// empty router
|
||||
r := gin.New()
|
||||
|
||||
// wrap panics:
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
// attach logger middleware
|
||||
r.Use(ginzerolog.Logger("gin"))
|
||||
|
||||
r.GET("/.well-known/healthcheck.json", gin.WrapF(a.getHealthCheckHandler()))
|
||||
r.GET("/", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "/feta") })
|
||||
r.GET("/feta", gin.WrapF(a.getIndexHandler()))
|
||||
r.GET("/feta/list/instances", gin.WrapF(a.getInstanceListHandler()))
|
||||
|
||||
a.router = r
|
||||
}
|
||||
|
||||
func (a *Server) initServer() {
|
||||
if !a.debug {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
log.Info().Uint("port", a.port).Msg("starting webserver")
|
||||
|
||||
a.server = &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", a.port),
|
||||
Handler: a.router,
|
||||
s.httpserver = &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", s.port),
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
|
||||
Reference in New Issue
Block a user