feat: custom gesture & room metrics

This commit is contained in:
efim 2023-12-02 11:26:00 +00:00
parent 42c73c5902
commit acd9f4fc62
5 changed files with 77 additions and 13 deletions

View File

@ -35,7 +35,7 @@
some-automoderation = pkgs.buildGoModule { some-automoderation = pkgs.buildGoModule {
inherit pname version; inherit pname version;
src = pkgs.nix-gitignore.gitignoreSource [ ] ./.; src = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
vendorHash = "sha256-FOIDFJNBViicvcpDG3T1KYABmI5Xyrv+IdQvT2Elhjg="; vendorHash = "sha256-ID0WG0pa9DkXTJ7aB9VywGO3R85FWkpXaaIuugnG6mg=";
preBuild = '' preBuild = ''
${pkgs.nodePackages.tailwindcss}/bin/tailwindcss -i routes/in.css -o routes/static/out.css ${pkgs.nodePackages.tailwindcss}/bin/tailwindcss -i routes/in.css -o routes/static/out.css

16
main.go
View File

@ -10,6 +10,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"sunshine.industries/some-automoderation/metrics"
"sunshine.industries/some-automoderation/rooms" "sunshine.industries/some-automoderation/rooms"
"sunshine.industries/some-automoderation/routes" "sunshine.industries/some-automoderation/routes"
"sunshine.industries/some-automoderation/sessions" "sunshine.industries/some-automoderation/sessions"
@ -26,7 +27,10 @@ func main() {
flag.IntVar(&redisPort, "redisPort", 7777, "Port on which server should connect to redis db") flag.IntVar(&redisPort, "redisPort", 7777, "Port on which server should connect to redis db")
flag.Parse() flag.Parse()
promHandler := promhttp.Handler() metrics := metrics.SetupMetrics()
promhttp.Handler()
promHandler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{})
promMux := http.NewServeMux() promMux := http.NewServeMux()
promMux.Handle("/metrics", promHandler) promMux.Handle("/metrics", promHandler)
@ -35,16 +39,16 @@ func main() {
}() }()
rdb := redis.NewClient(&redis.Options{ rdb := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("localhost:%d", redisPort), Addr: fmt.Sprintf("localhost:%d", redisPort),
Password: "", Password: "",
DB: 0, DB: 0,
}) })
roomsM := rooms.RedisRM { Rdb: rdb, } roomsM := rooms.RedisRM{Rdb: rdb}
sessions := sessions.RedisSM{ Rdb: rdb, } sessions := sessions.RedisSM{Rdb: rdb}
log.Printf("Server will start on port: %d; /metrics on %d; listening to redis on: %d\n", port, metricsPort, redisPort) log.Printf("Server will start on port: %d; /metrics on %d; listening to redis on: %d\n", port, metricsPort, redisPort)
routes.RegisterRoutes(sessions, roomsM) routes.RegisterRoutes(sessions, roomsM, &metrics)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
} }

43
metrics/metrics.go Normal file
View File

@ -0,0 +1,43 @@
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
)
type MetricsContainer struct {
Registry *prometheus.Registry
LiveConnectionsGauge prometheus.Gauge
RaiseGestureCounter *prometheus.CounterVec
SpeakerCounter *prometheus.CounterVec
}
const GestureNameLabel string = "gestureString"
func SetupMetrics() MetricsContainer {
registry := prometheus.NewRegistry()
liveConnectionsGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "live_connections_total",
Help: "Total amount of live SSE subscriptions to room state",
})
raiseGestureCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "raise_gesture_total",
Help: "Total amount of raised hands",
}, []string{GestureNameLabel})
speakerCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "speaker_total",
Help: "Total amount of speaker turns",
}, []string{GestureNameLabel})
registry.MustRegister(liveConnectionsGauge, raiseGestureCounter, speakerCounter,
collectors.NewGoCollector(),
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
)
return MetricsContainer{
Registry: registry,
LiveConnectionsGauge: liveConnectionsGauge,
RaiseGestureCounter: raiseGestureCounter,
SpeakerCounter: speakerCounter,
}
}

View File

@ -10,6 +10,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"sunshine.industries/some-automoderation/metrics"
"sunshine.industries/some-automoderation/rooms" "sunshine.industries/some-automoderation/rooms"
"sunshine.industries/some-automoderation/sessions" "sunshine.industries/some-automoderation/sessions"
) )
@ -23,6 +24,7 @@ func registerPageRoutes(
templateFs *embed.FS, templateFs *embed.FS,
sessionSM sessions.SessionManagement, sessionSM sessions.SessionManagement,
roomsM rooms.RoomManager, roomsM rooms.RoomManager,
metrics *metrics.MetricsContainer,
) { ) {
http.Handle(roomPath, // ending in / captures all following path sections, i.e room name http.Handle(roomPath, // ending in / captures all following path sections, i.e room name
http.StripPrefix(roomPath, roomPageRoute(templateFs, roomsM, sessionSM))) http.StripPrefix(roomPath, roomPageRoute(templateFs, roomsM, sessionSM)))
@ -30,15 +32,15 @@ func registerPageRoutes(
http.Handle(raiseHandPath, // ending in / captures all following path sections, i.e gesture num http.Handle(raiseHandPath, // ending in / captures all following path sections, i.e gesture num
authedPageMiddleware( authedPageMiddleware(
sessionSM, sessionSM,
http.StripPrefix(raiseHandPath, raiseGestureHandRoute(roomsM)))) http.StripPrefix(raiseHandPath, raiseGestureHandRoute(roomsM, metrics))))
http.Handle("/rooms/releaseHand", http.Handle("/rooms/releaseHand",
authedPageMiddleware(sessionSM, releaseHandRoute(roomsM))) authedPageMiddleware(sessionSM, releaseHandRoute(roomsM, metrics)))
http.Handle(subscribeRoomPath, http.Handle(subscribeRoomPath,
authedPageMiddleware( authedPageMiddleware(
sessionSM, sessionSM,
http.StripPrefix(subscribeRoomPath, streamingRoomStates(templateFs, roomsM)))) http.StripPrefix(subscribeRoomPath, streamingRoomStates(templateFs, roomsM, metrics))))
http.HandleFunc("/rooms/preview-templates", roomTemplatesPreview(templateFs)) http.HandleFunc("/rooms/preview-templates", roomTemplatesPreview(templateFs))
@ -48,8 +50,11 @@ func registerPageRoutes(
func streamingRoomStates( func streamingRoomStates(
templateFs *embed.FS, templateFs *embed.FS,
roomsM rooms.RoomManager, roomsM rooms.RoomManager,
metrics *metrics.MetricsContainer,
) http.HandlerFunc { ) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
metrics.LiveConnectionsGauge.Inc()
defer metrics.LiveConnectionsGauge.Dec()
r.ParseForm() r.ParseForm()
roomName := r.FormValue("roomName") roomName := r.FormValue("roomName")
defer log.Printf("/rooms/subscribe/%s stream ended\n", roomName) defer log.Printf("/rooms/subscribe/%s stream ended\n", roomName)
@ -112,6 +117,7 @@ func streamingRoomStates(
// TODO should return control for raised state // TODO should return control for raised state
func raiseGestureHandRoute( func raiseGestureHandRoute(
roomsM rooms.RoomManager, roomsM rooms.RoomManager,
metrics *metrics.MetricsContainer,
) http.HandlerFunc { ) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
gestureInd, err := strconv.Atoi(r.URL.Path) gestureInd, err := strconv.Atoi(r.URL.Path)
@ -120,6 +126,7 @@ func raiseGestureHandRoute(
log.Printf("/rooms/raiseGesture error %s gettin hand symbol index from path %s\n", err, r.URL.Path) log.Printf("/rooms/raiseGesture error %s gettin hand symbol index from path %s\n", err, r.URL.Path)
return return
} }
metrics.RaiseGestureCounter.WithLabelValues(selectedGesture.String()).Inc()
log.Printf("/rooms/raiseGesture successfully got gesture %d : %s", selectedGesture, selectedGesture.String()) log.Printf("/rooms/raiseGesture successfully got gesture %d : %s", selectedGesture, selectedGesture.String())
session, found := getContextSession(r.Context()) session, found := getContextSession(r.Context())
if !found { if !found {
@ -129,6 +136,10 @@ func raiseGestureHandRoute(
} }
var room rooms.Room var room rooms.Room
err = roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) { err = roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) {
if fromRoom.CurrentSpeaker == rooms.PersonId(0) {
// room had no speaker, need count new speaker turn
metrics.SpeakerCounter.WithLabelValues(selectedGesture.String()).Inc()
}
toRoom = fromRoom.RaiseHand(session.PersonId, selectedGesture) toRoom = fromRoom.RaiseHand(session.PersonId, selectedGesture)
room = toRoom room = toRoom
return toRoom return toRoom
@ -167,6 +178,7 @@ func raiseGestureHandRoute(
// TODO should return lowered control for passed hand gesture, i guess optional // TODO should return lowered control for passed hand gesture, i guess optional
func releaseHandRoute( func releaseHandRoute(
roomsM rooms.RoomManager, roomsM rooms.RoomManager,
metrics *metrics.MetricsContainer,
) http.HandlerFunc { ) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, found := getContextSession(r.Context()) session, found := getContextSession(r.Context())
@ -179,6 +191,10 @@ func releaseHandRoute(
err := roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) { err := roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) {
toRoom = fromRoom toRoom = fromRoom
toRoom.ReleaseHand(session.PersonId) toRoom.ReleaseHand(session.PersonId)
if fromRoom.CurrentSpeaker != toRoom.CurrentSpeaker && toRoom.CurrentSpeaker != rooms.PersonId(0) {
gesture := toRoom.ParticipantHands[toRoom.CurrentSpeaker]
metrics.SpeakerCounter.WithLabelValues(gesture.String()).Inc()
}
return toRoom return toRoom
}) })
if err != nil { if err != nil {
@ -268,7 +284,7 @@ func roomPageRoute(
} }
data := pageData{ data := pageData{
Base: baseData{ Base: baseData{
Title: fmt.Sprintf("Some Automoderation: discussion in '%s'", room.Name), Title: fmt.Sprintf("Some Automoderation: discussion in '%s'", room.Name),
LoggedIn: true, LoggedIn: true,
}, },
Content: contentData, Content: contentData,

View File

@ -4,6 +4,7 @@ import (
"embed" "embed"
"net/http" "net/http"
"sunshine.industries/some-automoderation/metrics"
"sunshine.industries/some-automoderation/rooms" "sunshine.industries/some-automoderation/rooms"
"sunshine.industries/some-automoderation/sessions" "sunshine.industries/some-automoderation/sessions"
) )
@ -14,7 +15,7 @@ var templateFs embed.FS
//go:embed static //go:embed static
var staticFilesFs embed.FS var staticFilesFs embed.FS
func RegisterRoutes(sessionsM sessions.SessionManagement, rooms rooms.RoomManager) { func RegisterRoutes(sessionsM sessions.SessionManagement, rooms rooms.RoomManager, metrics *metrics.MetricsContainer) {
// login page // login page
registerLoginRoutes(&templateFs, sessionsM, rooms) registerLoginRoutes(&templateFs, sessionsM, rooms)
@ -22,7 +23,7 @@ func RegisterRoutes(sessionsM sessions.SessionManagement, rooms rooms.RoomManage
http.Handle("/", indexPageRoute(&templateFs, sessionsM, rooms)) http.Handle("/", indexPageRoute(&templateFs, sessionsM, rooms))
// main conversation room page // main conversation room page
registerPageRoutes(&templateFs, sessionsM, rooms) registerPageRoutes(&templateFs, sessionsM, rooms, metrics)
// static resources route // static resources route
http.Handle("/static/", http.Handle("/static/",