feat: initial commit
This commit is contained in:
61
site/handler.go
Normal file
61
site/handler.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type counter struct {
|
||||
hits map[string]int
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger *slog.Logger
|
||||
requestsCounter *counter
|
||||
}
|
||||
|
||||
func newHandler(logger *slog.Logger) *handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
requestsCounter: &counter{hits: make(map[string]int)},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) LoggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Received request", "path", r.URL.Path)
|
||||
next.ServeHTTP(w, r)
|
||||
h.logger.Debug("Finished Request", "path", r.URL.Path)
|
||||
})
|
||||
}
|
||||
|
||||
func (h *handler) RequestsCounterMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.requestsCounter.mu.Lock()
|
||||
h.requestsCounter.hits[r.URL.Path] += 1
|
||||
h.requestsCounter.mu.Unlock()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (h *handler) Ping(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Pong")
|
||||
}
|
||||
|
||||
func (h *handler) Metrics(w http.ResponseWriter, r *http.Request) {
|
||||
h.requestsCounter.mu.Lock()
|
||||
defer h.requestsCounter.mu.Unlock()
|
||||
for path, hits := range h.requestsCounter.hits {
|
||||
fmt.Fprintf(w, "http_requests_total{handler=\"%s\"} %d\n", path, hits)
|
||||
}
|
||||
}
|
||||
func (h *handler) Healthz(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "Ok")
|
||||
}
|
||||
|
||||
func (h *handler) NotFound(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Page Not Found", http.StatusNotFound)
|
||||
}
|
||||
32
site/router.go
Normal file
32
site/router.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package site
|
||||
|
||||
import "net/http"
|
||||
|
||||
func middlewares(h *handler, next http.Handler) http.Handler {
|
||||
return h.LoggingMiddleware(h.RequestsCounterMiddleware(next))
|
||||
}
|
||||
|
||||
func createRoutes(h *handler) map[string]http.Handler {
|
||||
routes := map[string]http.Handler{
|
||||
"/ping": middlewares(h, http.HandlerFunc(h.Ping)),
|
||||
"/metrics": middlewares(h, http.HandlerFunc(h.Metrics)),
|
||||
"/healthz": middlewares(h, http.HandlerFunc(h.Healthz)),
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
func newRouter(handler *handler) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
for pattern, handler := range createRoutes(handler) {
|
||||
mux.Handle(pattern, handler)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if h, pattern := mux.Handler(r); pattern != "" {
|
||||
h.ServeHTTP(w, r)
|
||||
} else {
|
||||
middlewares(handler, http.HandlerFunc(handler.NotFound)).ServeHTTP(w, r)
|
||||
http.Error(w, "Boo", http.StatusNotFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
26
site/site.go
Normal file
26
site/site.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Logger *slog.Logger
|
||||
Port int
|
||||
}
|
||||
|
||||
func NewConfig(logLevel slog.Level, port int) Config {
|
||||
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||
return Config{
|
||||
Logger: logger,
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
func Run(c Config) error {
|
||||
h := newHandler(c.Logger)
|
||||
return http.ListenAndServe(fmt.Sprintf(":%d", c.Port), newRouter(h))
|
||||
}
|
||||
Reference in New Issue
Block a user