Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Prometheus support #60

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down
16 changes: 8 additions & 8 deletions api/daily/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@

scheduler.Start()

if os.Getenv("AWS_ENDPOINT_URL_S3") != "" {

Check failure on line 93 in api/daily/common.go

View workflow job for this annotation

GitHub Actions / Build (linux)

SA9003: empty branch (staticcheck)

Check failure on line 93 in api/daily/common.go

View workflow job for this annotation

GitHub Actions / Build (windows)

SA9003: empty branch (staticcheck)
go func() {
for {
err = S3SaveMigration()
if err != nil {
return
}
}
}()
// go func() {
// for {
// err = S3SaveMigration()
// if err != nil {
// return
// }
// }
// }()
}

return nil
Expand Down
15 changes: 13 additions & 2 deletions api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,23 @@
"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"
)

/*
The caller of endpoint handler functions are responsible for extracting the necessary data from the request.
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) {
Expand Down Expand Up @@ -95,7 +105,7 @@
httpError(w, r, err, http.StatusInternalServerError)
return
}

accountsRegistered.Inc()
w.WriteHeader(http.StatusOK)
}

Expand Down Expand Up @@ -165,7 +175,7 @@
}

func handleGameClassicSessionCount(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(strconv.Itoa(classicSessionCount)))

Check failure on line 178 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (linux)

Error return value of `w.Write` is not checked (errcheck)

Check failure on line 178 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (windows)

Error return value of `w.Write` is not checked (errcheck)
}

func handleSession(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -259,7 +269,8 @@

writeJSON(w, r, resp)
case "newclear":
resp, err := savedata.NewClear(uuid, slot)
result, err := strconv.ParseBool(r.URL.Query().Get("isVictory"))

Check failure on line 272 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (linux)

ineffectual assignment to err (ineffassign)

Check failure on line 272 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (windows)

ineffectual assignment to err (ineffassign)
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
Expand Down Expand Up @@ -562,7 +573,7 @@
httpError(w, r, err, http.StatusInternalServerError)
}

w.Write([]byte(strconv.Itoa(count)))

Check failure on line 576 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (linux)

Error return value of `w.Write` is not checked (errcheck)

Check failure on line 576 in api/endpoints.go

View workflow job for this annotation

GitHub Actions / Build (windows)

Error return value of `w.Write` is not checked (errcheck)
}

// redirect link after authorizing application link
Expand Down
7 changes: 7 additions & 0 deletions api/savedata/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package savedata

import (
"github.com/patrickmn/go-cache"
)

var Cache = cache.New(cache.NoExpiration, cache.NoExpiration)
19 changes: 14 additions & 5 deletions api/savedata/newclear.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions api/savedata/prometheus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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"},
)

starterCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "rogueserver_starter_count",
Help: "The total number of times a specific starter was selected",
},
[]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"},
)
)
66 changes: 65 additions & 1 deletion api/savedata/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,27 @@ package savedata
import (
"fmt"
"log"
"time"

"github.com/pagefaultgames/rogueserver/db"
"github.com/pagefaultgames/rogueserver/defs"
)

// /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")
}

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, username)
err = db.UpdateAccountStats(uuid, save.GameStats, save.VoucherCounts)
if err != nil {
return fmt.Errorf("failed to update account stats: %s", err)
Expand All @@ -49,9 +52,70 @@ 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, username)
return db.StoreSessionSaveData(uuid, save, slot)

default:
return fmt.Errorf("invalid data type")
}
}

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), username, time.Minute*5)
if err != nil {
log.Printf("already cached game mode for %s", username)
return
} else {
log.Printf("increased game mode counter for %s", username)
gameModeCounter.WithLabelValues(getGameModeKey(save.GameMode)).Inc()
}

if save.WaveIndex == 1 {
party := ""
for i := 0; i < len(save.Party); i++ {
partyMember, ok := save.Party[i].(map[string]interface{})
if !ok {
log.Printf("invalid type for party member at index %d", i)
continue
}

formIndex := ""
if formIdx, ok := partyMember["formIndex"].(float64); ok && formIdx != 0 {
formIndex = fmt.Sprintf("-%d", int(formIdx))
}

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 + ","
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"
}
17 changes: 13 additions & 4 deletions docker-compose.Example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ services:
dbname: pokeroguedb
gameurl: http://localhost:8000
callbackurl: http://localhost:8001
AWS_ACCESS_KEY_ID: <access>
AWS_SECRET_ACCESS_KEY: <secret>
AWS_REGION: <region>
AWS_ENDPOINT_URL_S3: <endpoint>

depends_on:
db:
Expand Down Expand Up @@ -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:
Expand Down
51 changes: 51 additions & 0 deletions docker-compose.Local.yml
Original file line number Diff line number Diff line change
@@ -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:
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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
)
Loading
Loading