From 3048e22787af2ca3a9409da07c9cb68827487e85 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Tue, 18 Jun 2024 20:50:47 +0100 Subject: [PATCH 01/11] chore: Add Prometheus metrics for account registration and concurrent requests feat: Implement Prometheus metrics and caching for game sessions fix: Rename Prometheus metric for game modes to include namespace --- api/common.go | 2 ++ api/endpoints.go | 12 ++++++++- api/savedata/cache.go | 7 ++++++ api/savedata/prometheus.go | 16 ++++++++++++ api/savedata/update.go | 25 +++++++++++++++++++ docker-compose.Example.yml | 17 ++++++++++--- docker-compose.Local.yml | 51 ++++++++++++++++++++++++++++++++++++++ go.mod | 8 ++++++ go.sum | 20 +++++++++++++++ prometheus.yml | 12 +++++++++ rogueserver.go | 13 ++++++++++ 11 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 api/savedata/cache.go create mode 100644 api/savedata/prometheus.go create mode 100644 docker-compose.Local.yml create mode 100644 prometheus.yml diff --git a/api/common.go b/api/common.go index 0f93ca4..0bf4be4 100644 --- a/api/common.go +++ b/api/common.go @@ -27,6 +27,7 @@ import ( "github.com/pagefaultgames/rogueserver/api/account" "github.com/pagefaultgames/rogueserver/api/daily" "github.com/pagefaultgames/rogueserver/db" + "github.com/prometheus/client_golang/prometheus/promhttp" ) func Init(mux *http.ServeMux) error { @@ -73,6 +74,7 @@ func Init(mux *http.ServeMux) error { mux.HandleFunc("POST /admin/account/googleLink", handleAdminGoogleLink) mux.HandleFunc("POST /admin/account/googleUnlink", handleAdminGoogleUnlink) mux.HandleFunc("GET /admin/account/adminSearch", handleAdminSearch) + mux.Handle("GET /metrics", promhttp.Handler()) return nil } diff --git a/api/endpoints.go b/api/endpoints.go index 478b434..57263ca 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -34,6 +34,8 @@ import ( "github.com/pagefaultgames/rogueserver/api/savedata" "github.com/pagefaultgames/rogueserver/db" "github.com/pagefaultgames/rogueserver/defs" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) /* @@ -41,6 +43,14 @@ import ( Handler functions are responsible for checking the validity of this data and returning a result or error. Handlers should not return serialized JSON, instead return the struct itself. */ + +var ( + accountsRegistered = promauto.NewCounter(prometheus.CounterOpts{ + Name: "rogueserver_accounts_registered", + Help: "The total number of accounts registered", + }) +) + // account func handleAccountInfo(w http.ResponseWriter, r *http.Request) { @@ -95,7 +105,7 @@ func handleAccountRegister(w http.ResponseWriter, r *http.Request) { httpError(w, r, err, http.StatusInternalServerError) return } - + accountsRegistered.Inc() w.WriteHeader(http.StatusOK) } diff --git a/api/savedata/cache.go b/api/savedata/cache.go new file mode 100644 index 0000000..e0d30b0 --- /dev/null +++ b/api/savedata/cache.go @@ -0,0 +1,7 @@ +package savedata + +import ( + "github.com/patrickmn/go-cache" +) + +var Cache = cache.New(cache.NoExpiration, cache.NoExpiration) diff --git a/api/savedata/prometheus.go b/api/savedata/prometheus.go new file mode 100644 index 0000000..385a4d5 --- /dev/null +++ b/api/savedata/prometheus.go @@ -0,0 +1,16 @@ +package savedata + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + gameModeCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "rogueserver_game_mode_total", + Help: "The total number of classic sessions played per 5 minutes", + }, + []string{"gamemode"}, + ) +) diff --git a/api/savedata/update.go b/api/savedata/update.go index f4e633c..64f20f4 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -20,6 +20,7 @@ package savedata import ( "fmt" "log" + "time" "github.com/pagefaultgames/rogueserver/db" "github.com/pagefaultgames/rogueserver/defs" @@ -27,6 +28,7 @@ import ( // /savedata/update - update save data func Update(uuid []byte, slot int, save any) error { + err := db.UpdateAccountLastActivity(uuid) if err != nil { log.Print("failed to update account last activity") @@ -55,3 +57,26 @@ func Update(uuid []byte, slot int, save any) error { return fmt.Errorf("invalid data type") } } + +func ProcessSystemMetrics(save defs.SystemSaveData, uuid []byte) { + +} + +func ProcessSessionMetrics(save defs.SessionSaveData, uuid []byte) { + err := Cache.Add(fmt.Sprintf("session-%x-%d", uuid, save.GameMode), uuid, time.Minute*5) + if err != nil { + return + } + switch save.GameMode { + case 0: + gameModeCounter.WithLabelValues("classic").Inc() + case 1: + gameModeCounter.WithLabelValues("endless").Inc() + case 2: + gameModeCounter.WithLabelValues("spliced-endless").Inc() + case 3: + gameModeCounter.WithLabelValues("daily").Inc() + case 4: + gameModeCounter.WithLabelValues("challenge").Inc() + } +} diff --git a/docker-compose.Example.yml b/docker-compose.Example.yml index 289e074..1f1e5aa 100644 --- a/docker-compose.Example.yml +++ b/docker-compose.Example.yml @@ -10,10 +10,6 @@ services: dbname: pokeroguedb gameurl: http://localhost:8000 callbackurl: http://localhost:8001 - AWS_ACCESS_KEY_ID: - AWS_SECRET_ACCESS_KEY: - AWS_REGION: - AWS_ENDPOINT_URL_S3: depends_on: db: @@ -60,6 +56,19 @@ services: volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock + + # Prometheus monitoring stack for the server and db services above + prometheus: + image: prom/prometheus:latest + restart: unless-stopped + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + command: + - '--config.file=/etc/prometheus/prometheus.yml' + networks: + - internal volumes: database: diff --git a/docker-compose.Local.yml b/docker-compose.Local.yml new file mode 100644 index 0000000..0bbc06f --- /dev/null +++ b/docker-compose.Local.yml @@ -0,0 +1,51 @@ +services: + server: + command: --debug --dbaddr db --dbuser pokerogue --dbpass pokerogue --dbname pokeroguedb + image: rogueserver:latest + restart: unless-stopped + depends_on: + db: + condition: service_healthy + networks: + - internal + ports: + - "8001:8001" + + db: + image: mariadb:11 + restart: unless-stopped + healthcheck: + test: [ "CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized" ] + start_period: 10s + start_interval: 10s + interval: 1m + timeout: 5s + retries: 3 + environment: + MYSQL_ROOT_PASSWORD: admin + MYSQL_DATABASE: pokeroguedb + MYSQL_USER: pokerogue + MYSQL_PASSWORD: pokerogue + volumes: + - database:/var/lib/mysql + networks: + - internal + + # Prometheus monitoring stack for the server and db services above + prometheus: + image: prom/prometheus:latest + restart: unless-stopped + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + command: + - '--config.file=/etc/prometheus/prometheus.yml' + networks: + - internal + +volumes: + database: + +networks: + internal: diff --git a/go.mod b/go.mod index c21b2ee..eae4151 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,8 @@ require ( github.com/bwmarrin/discordgo v0.28.1 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/klauspost/compress v1.17.9 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/prometheus/client_golang v1.19.1 ) require ( @@ -33,6 +35,12 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect github.com/aws/smithy-go v1.22.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect golang.org/x/sys v0.19.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/go.sum b/go.sum index 6f2e494..f37136c 100644 --- a/go.sum +++ b/go.sum @@ -34,16 +34,34 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4= github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -56,3 +74,5 @@ golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/prometheus.yml b/prometheus.yml new file mode 100644 index 0000000..c264869 --- /dev/null +++ b/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: "10s" + scrape_timeout: "10s" + evaluation_interval: "1m" + +scrape_configs: + - job_name: 'rogueserver' + static_configs: + - targets: ['server:8001'] + - job_name: 'mariadb' + static_configs: + - targets: ['db:3306'] \ No newline at end of file diff --git a/rogueserver.go b/rogueserver.go index b69631d..0263828 100644 --- a/rogueserver.go +++ b/rogueserver.go @@ -29,6 +29,15 @@ import ( "github.com/pagefaultgames/rogueserver/api" "github.com/pagefaultgames/rogueserver/api/account" "github.com/pagefaultgames/rogueserver/db" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + concurrentRequests = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "rogueserver_concurrent_requests", + Help: "The number of concurrent requests being handled", + }) ) func main() { @@ -141,7 +150,9 @@ func prodHandler(router *http.ServeMux, clienturl string) http.Handler { return } + concurrentRequests.Inc() router.ServeHTTP(w, r) + concurrentRequests.Dec() }) } @@ -156,7 +167,9 @@ func debugHandler(router *http.ServeMux) http.Handler { return } + concurrentRequests.Inc() router.ServeHTTP(w, r) + concurrentRequests.Dec() }) } From 2f9ed3a0a7f4b237c0109ddb748b394c53e285ee Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:32:00 -0800 Subject: [PATCH 02/11] Starter Tracking (#1) * starterCounter? * Update api/savedata/update.go --------- Co-authored-by: frutescens Co-authored-by: Frederico Santos --- api/savedata/prometheus.go | 8 ++++++++ api/savedata/update.go | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/api/savedata/prometheus.go b/api/savedata/prometheus.go index 385a4d5..749241b 100644 --- a/api/savedata/prometheus.go +++ b/api/savedata/prometheus.go @@ -13,4 +13,12 @@ var ( }, []string{"gamemode"}, ) + + starterCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "rogueserver_starter_count", + Help: "The total number of times a specific starter was selected", + }, + []string{"starterKey"}, + ) ) diff --git a/api/savedata/update.go b/api/savedata/update.go index 64f20f4..fcacddc 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -79,4 +79,15 @@ func ProcessSessionMetrics(save defs.SessionSaveData, uuid []byte) { case 4: gameModeCounter.WithLabelValues("challenge").Inc() } + if save.WaveIndex == 1 { + for i := 0; i < len(save.Party); i++ { + formIndex = "" + if save.Party[i]["formIndex"] != 0 { + formIndex = "-"+save.Party[i]["formIndex"] + } + key = save.Party[i]["Species"] + formIndex + log.Printf("incremented starter %s", key) + starterCounter.WithLabelValues(key).Inc() + } + } } From b57eae4f0c5dbca2fd80f49378cd796cd070348d Mon Sep 17 00:00:00 2001 From: f-fsantos Date: Tue, 5 Nov 2024 23:39:25 +0000 Subject: [PATCH 03/11] fixed metrics call --- api/daily/common.go | 16 ++++++++-------- api/savedata/update.go | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/api/daily/common.go b/api/daily/common.go index 84b8167..4f6d393 100644 --- a/api/daily/common.go +++ b/api/daily/common.go @@ -91,14 +91,14 @@ func Init() error { scheduler.Start() if os.Getenv("AWS_ENDPOINT_URL_S3") != "" { - go func() { - for { - err = S3SaveMigration() - if err != nil { - return - } - } - }() + // go func() { + // for { + // err = S3SaveMigration() + // if err != nil { + // return + // } + // } + // }() } return nil diff --git a/api/savedata/update.go b/api/savedata/update.go index 64f20f4..94d8ffb 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -39,7 +39,7 @@ func Update(uuid []byte, slot int, save any) error { if save.TrainerId == 0 && save.SecretId == 0 { return fmt.Errorf("invalid system data") } - + ProcessSystemMetrics(save, uuid); err = db.UpdateAccountStats(uuid, save.GameStats, save.VoucherCounts) if err != nil { return fmt.Errorf("failed to update account stats: %s", err) @@ -51,6 +51,7 @@ func Update(uuid []byte, slot int, save any) error { if slot < 0 || slot >= defs.SessionSlotCount { return fmt.Errorf("slot id %d out of range", slot) } + ProcessSessionMetrics(save, uuid) return db.StoreSessionSaveData(uuid, save, slot) default: @@ -65,8 +66,10 @@ func ProcessSystemMetrics(save defs.SystemSaveData, uuid []byte) { func ProcessSessionMetrics(save defs.SessionSaveData, uuid []byte) { err := Cache.Add(fmt.Sprintf("session-%x-%d", uuid, save.GameMode), uuid, time.Minute*5) if err != nil { + log.Printf("already cached session") return } + log.Printf("increased game mode counter") switch save.GameMode { case 0: gameModeCounter.WithLabelValues("classic").Inc() From eefa54fe48e4396425e87520193a3e5c26c320ac Mon Sep 17 00:00:00 2001 From: f-fsantos Date: Tue, 5 Nov 2024 23:46:08 +0000 Subject: [PATCH 04/11] added username --- api/savedata/update.go | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index f36bd00..50b5bb4 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -34,6 +34,7 @@ func Update(uuid []byte, slot int, save any) error { log.Print("failed to update account last activity") } + username := db.FetchUsernameFromUUID(uuid) switch save := save.(type) { case defs.SystemSaveData: // System if save.TrainerId == 0 && save.SecretId == 0 { @@ -59,29 +60,31 @@ func Update(uuid []byte, slot int, save any) error { } } -func ProcessSystemMetrics(save defs.SystemSaveData, uuid []byte) { +func ProcessSystemMetrics(save defs.SystemSaveData, username string) { } -func ProcessSessionMetrics(save defs.SessionSaveData, uuid []byte) { - err := Cache.Add(fmt.Sprintf("session-%x-%d", uuid, save.GameMode), uuid, time.Minute*5) +func ProcessSessionMetrics(save defs.SessionSaveData, username string) { + err := Cache.Add(fmt.Sprintf("session-%s-%d", username, save.GameMode), uuid, time.Minute*5) if err != nil { - log.Printf("already cached session") + log.Printf("already cached game mode for %s", username) return + } else { + log.Printf("increased game mode counter for %s", username) + switch save.GameMode { + case 0: + gameModeCounter.WithLabelValues("classic").Inc() + case 1: + gameModeCounter.WithLabelValues("endless").Inc() + case 2: + gameModeCounter.WithLabelValues("spliced-endless").Inc() + case 3: + gameModeCounter.WithLabelValues("daily").Inc() + case 4: + gameModeCounter.WithLabelValues("challenge").Inc() + } } - log.Printf("increased game mode counter") - switch save.GameMode { - case 0: - gameModeCounter.WithLabelValues("classic").Inc() - case 1: - gameModeCounter.WithLabelValues("endless").Inc() - case 2: - gameModeCounter.WithLabelValues("spliced-endless").Inc() - case 3: - gameModeCounter.WithLabelValues("daily").Inc() - case 4: - gameModeCounter.WithLabelValues("challenge").Inc() - } + if save.WaveIndex == 1 { for i := 0; i < len(save.Party); i++ { formIndex = "" From 28c279c36d5ac403d355101028f013267cbca084 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 6 Nov 2024 00:15:03 +0000 Subject: [PATCH 05/11] fix: Update metrics processing to use username instead of UUID and improve party member type handling --- api/savedata/update.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index 50b5bb4..b0cc8da 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -34,13 +34,13 @@ func Update(uuid []byte, slot int, save any) error { log.Print("failed to update account last activity") } - username := db.FetchUsernameFromUUID(uuid) + username, _ := db.FetchUsernameFromUUID(uuid) switch save := save.(type) { case defs.SystemSaveData: // System if save.TrainerId == 0 && save.SecretId == 0 { return fmt.Errorf("invalid system data") } - ProcessSystemMetrics(save, uuid); + ProcessSystemMetrics(save, username) err = db.UpdateAccountStats(uuid, save.GameStats, save.VoucherCounts) if err != nil { return fmt.Errorf("failed to update account stats: %s", err) @@ -52,7 +52,7 @@ func Update(uuid []byte, slot int, save any) error { if slot < 0 || slot >= defs.SessionSlotCount { return fmt.Errorf("slot id %d out of range", slot) } - ProcessSessionMetrics(save, uuid) + ProcessSessionMetrics(save, username) return db.StoreSessionSaveData(uuid, save, slot) default: @@ -65,7 +65,7 @@ func ProcessSystemMetrics(save defs.SystemSaveData, username string) { } func ProcessSessionMetrics(save defs.SessionSaveData, username string) { - err := Cache.Add(fmt.Sprintf("session-%s-%d", username, save.GameMode), uuid, time.Minute*5) + err := Cache.Add(fmt.Sprintf("session-%s-%d", username, save.GameMode), username, time.Minute*5) if err != nil { log.Printf("already cached game mode for %s", username) return @@ -84,14 +84,27 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { gameModeCounter.WithLabelValues("challenge").Inc() } } - + if save.WaveIndex == 1 { for i := 0; i < len(save.Party); i++ { - formIndex = "" - if save.Party[i]["formIndex"] != 0 { - formIndex = "-"+save.Party[i]["formIndex"] + partyMember, ok := save.Party[i].(map[string]interface{}) + if !ok { + log.Printf("invalid type for party member at index %d", i) + continue } - key = save.Party[i]["Species"] + formIndex + + formIndex := "" + if formIdx, ok := partyMember["formIndex"].(int); ok && formIdx != 0 { + formIndex = fmt.Sprintf("%d", formIdx) + } + + species, ok := partyMember["Species"].(int) + if !ok { + log.Printf("invalid type for Species at index %d", i) + continue + } + + key := fmt.Sprintf("%d-%s", species, formIndex) log.Printf("incremented starter %s", key) starterCounter.WithLabelValues(key).Inc() } From 400cb28ee3f76d46d763f6ccaa5affadae5926a8 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 6 Nov 2024 00:21:38 +0000 Subject: [PATCH 06/11] fix: Enhance session metrics logging to include party member species and username --- api/savedata/update.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index b0cc8da..12c1860 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -86,6 +86,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { } if save.WaveIndex == 1 { + party := "" for i := 0; i < len(save.Party); i++ { partyMember, ok := save.Party[i].(map[string]interface{}) if !ok { @@ -98,15 +99,16 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { formIndex = fmt.Sprintf("%d", formIdx) } - species, ok := partyMember["Species"].(int) + species, ok := partyMember["species"].(int) if !ok { log.Printf("invalid type for Species at index %d", i) continue } key := fmt.Sprintf("%d-%s", species, formIndex) - log.Printf("incremented starter %s", key) + party += key + "," starterCounter.WithLabelValues(key).Inc() } + log.Printf("Incremented starters %s count for %s", party, username) } } From b7c9d6e6f1a2bfcca0bda025d5d46ac1f02b82cc Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 6 Nov 2024 00:29:47 +0000 Subject: [PATCH 07/11] fix: Update party member species handling to support float64 and improve logging --- api/savedata/update.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index 12c1860..efd1785 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -95,15 +95,16 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { } formIndex := "" - if formIdx, ok := partyMember["formIndex"].(int); ok && formIdx != 0 { - formIndex = fmt.Sprintf("%d", formIdx) + if formIdx, ok := partyMember["formIndex"].(float64); ok && formIdx != 0 { + formIndex = fmt.Sprintf("%d", int(formIdx)) } - species, ok := partyMember["species"].(int) + speciesFloat, ok := partyMember["species"].(float64) if !ok { log.Printf("invalid type for Species at index %d", i) continue } + species := int(speciesFloat) key := fmt.Sprintf("%d-%s", species, formIndex) party += key + "," From a88f8c2dc5a5c2e7bd71db1c3cbace38eb7f321e Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 6 Nov 2024 00:32:50 +0000 Subject: [PATCH 08/11] fix: Correct formIndex formatting in session metrics processing --- api/savedata/update.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index efd1785..a1c2c65 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -96,7 +96,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { formIndex := "" if formIdx, ok := partyMember["formIndex"].(float64); ok && formIdx != 0 { - formIndex = fmt.Sprintf("%d", int(formIdx)) + formIndex = fmt.Sprintf("-%d", int(formIdx)) } speciesFloat, ok := partyMember["species"].(float64) @@ -106,7 +106,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { } species := int(speciesFloat) - key := fmt.Sprintf("%d-%s", species, formIndex) + key := fmt.Sprintf("%d%s", species, formIndex) party += key + "," starterCounter.WithLabelValues(key).Inc() } From e6d55617dfa7713f454fa9473d96f6f1467c5e61 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 6 Nov 2024 00:33:25 +0000 Subject: [PATCH 09/11] fix: Update session metrics processing to exclude GameMode 3 for WaveIndex 1 --- api/savedata/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/savedata/update.go b/api/savedata/update.go index a1c2c65..6f99553 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -85,7 +85,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { } } - if save.WaveIndex == 1 { + if save.WaveIndex == 1 && save.GameMode != 3 { party := "" for i := 0; i < len(save.Party); i++ { partyMember, ok := save.Party[i].(map[string]interface{}) From 0da0283fb96661f19e2518435d8f76bd50069c6d Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:37:26 -0800 Subject: [PATCH 10/11] [Feature] Two Separate Counters for Endless and Classic Starter Choice (#2) * Revert "Remove Daily from starter tracking" This reverts commit ce4aea88de78696c76046c862cdcae2f5d6d871f. * Added separate starter counter for Endless/Endless Spliced * Added daily conditional * Changed starterCounter to also hold information about the game mode. --------- Co-authored-by: frutescens --- api/savedata/prometheus.go | 2 +- api/savedata/update.go | 32 +++++++++++++++++++------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/api/savedata/prometheus.go b/api/savedata/prometheus.go index 749241b..06ee199 100644 --- a/api/savedata/prometheus.go +++ b/api/savedata/prometheus.go @@ -19,6 +19,6 @@ var ( Name: "rogueserver_starter_count", Help: "The total number of times a specific starter was selected", }, - []string{"starterKey"}, + []string{"starterKey", "gameMode"}, ) ) diff --git a/api/savedata/update.go b/api/savedata/update.go index 6f99553..f14b813 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -71,18 +71,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { return } else { log.Printf("increased game mode counter for %s", username) - switch save.GameMode { - case 0: - gameModeCounter.WithLabelValues("classic").Inc() - case 1: - gameModeCounter.WithLabelValues("endless").Inc() - case 2: - gameModeCounter.WithLabelValues("spliced-endless").Inc() - case 3: - gameModeCounter.WithLabelValues("daily").Inc() - case 4: - gameModeCounter.WithLabelValues("challenge").Inc() - } + gameModeCounter.WithLabelValues(getGameModeKey(save.GameMode)).Inc() } if save.WaveIndex == 1 && save.GameMode != 3 { @@ -108,8 +97,25 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { key := fmt.Sprintf("%d%s", species, formIndex) party += key + "," - starterCounter.WithLabelValues(key).Inc() + starterCounter.WithLabelValues(key, getGameModeKey(save.GameMode)).Inc() + } log.Printf("Incremented starters %s count for %s", party, username) } } + +func getGameModeKey(gameMode defs.GameMode) string { + switch gameMode { + case 0: + return "classic" + case 1: + return "endless" + case 2: + return "spliced-endless" + case 3: + return "daily" + case 4: + return "challenge" + } + return "none" +} From f4e423f8c3efa9735e9277a95b0f2fbc8d572ebd Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:08:45 -0800 Subject: [PATCH 11/11] [Telemetry] Server Side Code for Run Result Logging (#4) * Revert "Remove Daily from starter tracking" This reverts commit ce4aea88de78696c76046c862cdcae2f5d6d871f. * Server-Side Run Result Logging * Removed unnecessary parameters. * Fixed up endpoint to not rely on present-in-session variables * I'm forgetful. * Fixed up logging format. * Changed somethign. * Updated endpoint variable --------- Co-authored-by: frutescens --- api/endpoints.go | 3 ++- api/savedata/newclear.go | 19 ++++++++++++++----- api/savedata/prometheus.go | 8 ++++++++ api/savedata/update.go | 2 +- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/api/endpoints.go b/api/endpoints.go index 57263ca..bae3195 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -269,7 +269,8 @@ func handleSession(w http.ResponseWriter, r *http.Request) { writeJSON(w, r, resp) case "newclear": - resp, err := savedata.NewClear(uuid, slot) + result, err := strconv.ParseBool(r.URL.Query().Get("isVictory")) + resp, err := savedata.NewClear(uuid, slot, result) if err != nil { httpError(w, r, fmt.Errorf("failed to read new clear: %s", err), http.StatusInternalServerError) return diff --git a/api/savedata/newclear.go b/api/savedata/newclear.go index 0c221c2..af3af4f 100644 --- a/api/savedata/newclear.go +++ b/api/savedata/newclear.go @@ -25,19 +25,28 @@ import ( ) // /savedata/newclear - return whether a session is a new clear for its seed -func NewClear(uuid []byte, slot int) (bool, error) { +func NewClear(uuid []byte, slot int, result bool) (bool, error) { if slot < 0 || slot >= defs.SessionSlotCount { return false, fmt.Errorf("slot id %d out of range", slot) } session, err := db.ReadSessionSaveData(uuid, slot) + if err != nil { return false, err } - - completed, err := db.ReadSeedCompleted(uuid, session.Seed) - if err != nil { - return false, fmt.Errorf("failed to read seed completed: %s", err) + gameMode := getGameModeKey(session.GameMode) + waveIndex := fmt.Sprintf("%d", session.WaveIndex) + completed := true + if result { + runResultCounter.WithLabelValues("victory", waveIndex, gameMode).Inc() + completed, err := db.ReadSeedCompleted(uuid, session.Seed) + if err != nil { + return false, fmt.Errorf("failed to read seed completed: %s", err) + } + return !completed, err + } else { + runResultCounter.WithLabelValues("loss", waveIndex, gameMode).Inc() } return !completed, nil diff --git a/api/savedata/prometheus.go b/api/savedata/prometheus.go index 06ee199..eaae15d 100644 --- a/api/savedata/prometheus.go +++ b/api/savedata/prometheus.go @@ -21,4 +21,12 @@ var ( }, []string{"starterKey", "gameMode"}, ) + + runResultCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "rogueserver_run_result_count", + Help: "The total number of victories and losses logged", + }, + []string{"result", "waveIndex", "gameMode"}, + ) ) diff --git a/api/savedata/update.go b/api/savedata/update.go index f14b813..b989318 100644 --- a/api/savedata/update.go +++ b/api/savedata/update.go @@ -74,7 +74,7 @@ func ProcessSessionMetrics(save defs.SessionSaveData, username string) { gameModeCounter.WithLabelValues(getGameModeKey(save.GameMode)).Inc() } - if save.WaveIndex == 1 && save.GameMode != 3 { + if save.WaveIndex == 1 { party := "" for i := 0; i < len(save.Party); i++ { partyMember, ok := save.Party[i].(map[string]interface{})