Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
import org.emulinker.config.RuntimeFlags
import org.emulinker.kaillera.master.StatsCollector
import org.emulinker.monitoring.JfrEvent
import org.emulinker.util.TaskScheduler

class MasterListUpdater(
Expand Down Expand Up @@ -34,14 +35,26 @@ class MasterListUpdater(
initialDelay = 10.seconds,
period = LIST_REPORTING_INTERVAL,
) {
if (flags.touchEmulinker) emuLinkerMasterUpdateTask.reportStatus()
if (flags.touchKaillera) kailleraMasterUpdateTask.reportStatus()
val e = JfrEvent.MasterListCheckin()
e.begin()
try {
if (flags.touchEmulinker) emuLinkerMasterUpdateTask.reportStatus()
if (flags.touchKaillera) kailleraMasterUpdateTask.reportStatus()
} finally {
e.commit()
}
statsCollector.clearStartedGamesList()
}
}
serverCheckinJob =
taskScheduler.scheduleRepeating(initialDelay = 10.seconds, period = CHECKIN_INTERVAL) {
serverCheckinTask.reportStatus()
val e = JfrEvent.ElkCheckin()
e.begin()
try {
serverCheckinTask.reportStatus()
} finally {
e.commit()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import java.net.URL
import java.util.Locale
import java.util.concurrent.TimeUnit.HOURS
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.emulinker.config.RuntimeFlags
import org.emulinker.kaillera.master.PublicServerInformation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.emulinker.kaillera.model.event.UserQuitEvent
import org.emulinker.kaillera.model.event.UserQuitGameEvent
import org.emulinker.kaillera.model.exception.*
import org.emulinker.kaillera.model.impl.KailleraGameImpl
import org.emulinker.monitoring.JfrEvent
import org.emulinker.util.CircularVariableSizeByteArrayBuffer
import org.emulinker.util.EmuLang
import org.emulinker.util.TimeOffsetCache
Expand All @@ -45,6 +46,9 @@ class KailleraUser(
) {
var inStealthMode = false

private val loginJfrEvent: JfrEvent.UserLogin =
JfrEvent.UserLogin(userId = id, ip = connectSocketAddress.toString()).also { it.begin() }

/** Example: "Project 64k 0.13 (01 Aug 2003)" */
var clientType: String? = null
set(clientType) {
Expand Down Expand Up @@ -250,7 +254,11 @@ class KailleraUser(
@Synchronized
fun login(): Result<Unit> {
updateLastActivity()
return server.login(this)
val result = server.login(this)
loginJfrEvent.username = name ?: ""
loginJfrEvent.successful = result.isSuccess
loginJfrEvent.commit()
return result
}

@Throws(ChatException::class, FloodException::class)
Expand All @@ -271,25 +279,28 @@ class KailleraUser(
}

@Throws(CreateGameException::class, FloodException::class)
fun createGame(romName: String?): KailleraGame? {
updateLastActivity()
if (server.getUser(id) == null) {
logger.atSevere().log("%s create game failed: User don't exist!", this)
return null
}
if (status == UserStatus.PLAYING) {
logger.atWarning().log("%s create game failed: User status is Playing!", this)
throw CreateGameException(EmuLang.getString("KailleraUserImpl.CreateGameErrorAlreadyInGame"))
} else if (status == UserStatus.CONNECTING) {
logger.atWarning().log("%s create game failed: User status is Connecting!", this)
throw CreateGameException(
EmuLang.getString("KailleraUserImpl.CreateGameErrorNotFullyConnected")
)
fun createGame(romName: String?): KailleraGame? =
JfrEvent.CreateGame().record {
updateLastActivity()
if (server.getUser(id) == null) {
logger.atSevere().log("%s create game failed: User don't exist!", this)
return null
}
if (status == UserStatus.PLAYING) {
logger.atWarning().log("%s create game failed: User status is Playing!", this)
throw CreateGameException(
EmuLang.getString("KailleraUserImpl.CreateGameErrorAlreadyInGame")
)
} else if (status == UserStatus.CONNECTING) {
logger.atWarning().log("%s create game failed: User status is Connecting!", this)
throw CreateGameException(
EmuLang.getString("KailleraUserImpl.CreateGameErrorNotFullyConnected")
)
}
val game = server.createGame(this, romName)
lastCreateGameTime = System.currentTimeMillis()
return game
}
val game = server.createGame(this, romName)
lastCreateGameTime = System.currentTimeMillis()
return game
}

@Synchronized
@Throws(
Expand All @@ -298,11 +309,12 @@ class KailleraUser(
QuitGameException::class,
CloseGameException::class,
)
fun quit(message: String?) {
updateLastActivity()
server.quit(this, message)
loggedIn = false
}
fun quit(message: String?) =
JfrEvent.QuitServer().record {
updateLastActivity()
server.quit(this, message)
loggedIn = false
}

fun lagAttributedToUser(): Duration =
(totalDriftNs - (totalDriftCache.getDelayedValue() ?: 0)).nanoseconds.absoluteValue
Expand Down Expand Up @@ -418,16 +430,17 @@ class KailleraUser(

@Synchronized
@Throws(StartGameException::class)
fun startGame() {
resetLag()
updateLastActivity()
val game = this.game
if (game == null) {
logger.atWarning().log("%s start game failed: Not in a game", this)
throw StartGameException(EmuLang.getString("KailleraUserImpl.StartGameErrorNotInGame"))
fun startGame() =
JfrEvent.GameStart(gameId = id).record {
resetLag()
updateLastActivity()
val game = this.game
if (game == null) {
logger.atWarning().log("%s start game failed: Not in a game", this)
throw StartGameException(EmuLang.getString("KailleraUserImpl.StartGameErrorNotInGame"))
}
game.start(this)
}
game.start(this)
}

@Synchronized
@Throws(UserReadyException::class)
Expand Down
56 changes: 56 additions & 0 deletions emulinker/src/main/java/org/emulinker/monitoring/JfrEvents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.emulinker.monitoring

import jdk.jfr.Description
import jdk.jfr.Event
import jdk.jfr.Label
import jdk.jfr.Name

sealed class JfrEvent : Event() {

inline fun <T> record(block: () -> T): T {
begin()
return try {
block()
} finally {
commit()
}
}

@Name("User Login")
@Description("A user joined the server")
class UserLogin(
@field:Label("User ID") var userId: Int,
@field:Label("User IP Address") val ip: String,
) : JfrEvent() {

@Label("Username") var username: String = ""

@Label("Successful") var successful: Boolean = false
}

@Name("Server Lists Check-in")
@Description("Reported server status for public game lists")
class MasterListCheckin : JfrEvent()

@Name("ELK Check-in")
@Description("Checked in with central EmuLinker-K server")
class ElkCheckin : JfrEvent()

@Name("Create Game")
@Description("A user created a new game in the server")
class CreateGame : JfrEvent()

@Name("Stop Game")
@Description("A user created a new game in the server")
class StopGame : JfrEvent()

class DropGame : JfrEvent()

@Name("Game Start") class GameStart(@field:Label("Game ID") var gameId: Int) : JfrEvent()

class QuitServer : JfrEvent()

class GameChat : JfrEvent()

class ServerChat : JfrEvent()
}
Loading