mirror of
https://github.com/lichess-org/lila.git
synced 2026-05-26 13:51:00 +00:00
split lila.mon from lila.common
to parallelize compilation
This commit is contained in:
+1
-1
@@ -81,7 +81,7 @@ final class LilaComponents(
|
||||
|
||||
val env: lila.app.Env =
|
||||
lila.log("boot").info(s"Start loading lila modules")
|
||||
val c = lila.common.Chronometer.sync(wire[lila.app.Env])
|
||||
val c = lila.mon.Chronometer.sync(wire[lila.app.Env])
|
||||
lila.log("boot").info(s"Loaded lila modules in ${c.showDuration}")
|
||||
c.result
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import scala.annotation.nowarn
|
||||
|
||||
import alleycats.Zero
|
||||
import play.api.libs.json.Json
|
||||
import play.api.mvc.*
|
||||
|
||||
import scala.annotation.nowarn
|
||||
|
||||
import lila.app.{ *, given }
|
||||
import lila.common.HTTPRequest
|
||||
import lila.core.id.ImageId
|
||||
@@ -15,6 +15,7 @@ import lila.core.security.FingerHash
|
||||
import lila.core.userId.ModId
|
||||
import lila.mod.{ Modlog, ModUserSearch }
|
||||
import lila.report.{ Mod as AsMod, Suspect }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class Mod(
|
||||
env: Env,
|
||||
@@ -253,26 +254,28 @@ final class Mod(
|
||||
given lila.mod.IpRender.RenderIp = env.mod.ipRender.apply
|
||||
env.game.gameRepo
|
||||
.recentPovsByUserFromSecondary(user, 80)
|
||||
.mon(_.mod.comm.segment("recentPovs"))
|
||||
.mon(lila.mon.mod.comm.segment("recentPovs"))
|
||||
.flatMap: povs =>
|
||||
(
|
||||
env.api.modTimeline.load(user, withPlayBans = false).mon(_.mod.comm.segment("modTimeline")),
|
||||
env.api.modTimeline
|
||||
.load(user, withPlayBans = false)
|
||||
.mon(lila.mon.mod.comm.segment("modTimeline")),
|
||||
priv.so:
|
||||
env.chat.api.playerChat
|
||||
.optionsByOrderedIds(povs.map(_.gameId.into(ChatId)))
|
||||
.mon(_.mod.comm.segment("playerChats"))
|
||||
.mon(lila.mon.mod.comm.segment("playerChats"))
|
||||
,
|
||||
priv.so:
|
||||
env.msg.api
|
||||
.recentByForMod(user, 30)
|
||||
.mon(_.mod.comm.segment("pms"))
|
||||
.mon(lila.mon.mod.comm.segment("pms"))
|
||||
,
|
||||
env.shutup.api
|
||||
.getPublicLines(user.id)
|
||||
.mon(_.mod.comm.segment("publicChats")),
|
||||
.mon(lila.mon.mod.comm.segment("publicChats")),
|
||||
env.report.api.inquiries
|
||||
.ofModId(me.id)
|
||||
.mon(_.mod.comm.segment("inquiries")),
|
||||
.mon(lila.mon.mod.comm.segment("inquiries")),
|
||||
env.security.userLogins(user, 100).flatMap {
|
||||
userC.loginsTableData(user, _, 100)
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import lila.study.PgnDump.WithFlags
|
||||
import lila.study.Study.WithChapter
|
||||
import lila.study.{ Who, Chapter, Orders, Settings, Study as StudyModel, StudyForm }
|
||||
import lila.tree.Node.partitionTreeWriter
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import lila.ui.Page
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class Study(
|
||||
env: Env,
|
||||
@@ -258,7 +258,7 @@ final class Study(
|
||||
}.optionFu:
|
||||
env.chat.api.userChat
|
||||
.findMine(study.id.into(ChatId))
|
||||
.mon(_.chat.fetch("study"))
|
||||
.mon(lila.mon.chat.fetch("study"))
|
||||
|
||||
def createAs = AuthBody { ctx ?=> me ?=>
|
||||
bindForm(StudyForm.importGame.form)(
|
||||
@@ -567,6 +567,7 @@ final class Study(
|
||||
bindForm(StudyForm.topicsForm)(
|
||||
_ => Redirect(routes.Study.topics),
|
||||
topics =>
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
try env.study.topicApi.userTopics(me, topics).inject(Redirect(routes.Study.topics))
|
||||
catch case e: JsonParseException => BadRequest(e.getMessage)
|
||||
)
|
||||
|
||||
@@ -2,13 +2,14 @@ package controllers
|
||||
|
||||
import play.api.libs.json.*
|
||||
import play.api.mvc.*
|
||||
import scalalib.data.Preload
|
||||
|
||||
import lila.app.{ *, given }
|
||||
import lila.common.HTTPRequest
|
||||
import lila.common.Json.given
|
||||
import scalalib.data.Preload
|
||||
import lila.gathering.Condition.GetMyTeamIds
|
||||
import lila.tournament.{ MyInfo, Tournament as Tour, TournamentForm }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class Tournament(env: Env, apiC: => Api)(using akka.stream.Materializer) extends LilaController(env):
|
||||
|
||||
@@ -119,7 +120,7 @@ final class Tournament(env: Env, apiC: => Api)(using akka.stream.Materializer) e
|
||||
yield Ok(json.add("chat" -> jsChat)).noCache
|
||||
)
|
||||
.monSuccess:
|
||||
_.tournament.apiShowPartial(partial = getBool("partial"), HTTPRequest.clientName(ctx.req))
|
||||
lila.mon.tournament.apiShowPartial(partial = getBool("partial"), HTTPRequest.clientName(ctx.req))
|
||||
|
||||
def apiShow(id: TourId) = AnonOrScoped(): ctx ?=>
|
||||
WithVisibleTournament(id): tour =>
|
||||
|
||||
@@ -18,6 +18,7 @@ import lila.rating.PerfType
|
||||
import lila.rating.UserPerfsExt.best8Perfs
|
||||
import lila.security.UserLogins
|
||||
import lila.user.WithPerfsAndEmails
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class User(
|
||||
override val env: Env,
|
||||
@@ -88,7 +89,7 @@ final class User(
|
||||
_ <- env.userInfo.preloadTeams(info)
|
||||
social <- env.socialInfo(u)
|
||||
page <- renderPage:
|
||||
lila.mon.chronoSync(_.user.segment("renderSync")):
|
||||
lila.mon.chronoSync(lila.mon.user.segment("renderSync")):
|
||||
views.user.show.page.activity(as, info, social)
|
||||
yield status(page).withCanonical(routes.User.show(u.username))
|
||||
else
|
||||
@@ -304,7 +305,7 @@ final class User(
|
||||
|
||||
private def modZoneSegment(fu: Fu[Frag], name: String, user: UserModel): Source[Frag, ?] =
|
||||
Source.futureSource:
|
||||
fu.monSuccess(_.mod.zoneSegment(name))
|
||||
fu.monSuccess(lila.mon.mod.zoneSegment(name))
|
||||
.logFailure(lila.log("modZoneSegment").branch(s"$name ${user.id}"))
|
||||
.map(Source.single)
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package lila.app
|
||||
package http
|
||||
|
||||
import play.api.mvc.*
|
||||
|
||||
import lila.app.{ *, given }
|
||||
import lila.memo.CacheApi.*
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class KeyPages(val env: Env)(using Executor)
|
||||
extends lila.web.ResponseWriter
|
||||
@@ -28,12 +30,12 @@ final class KeyPages(val env: Env)(using Executor)
|
||||
simuls = env.simul.allCreatedFeaturable.get {}.recoverDefault,
|
||||
streamerSpots = env.streamer.homepageMaxSetting.get()
|
||||
)
|
||||
.mon(_.lobby.segment("preloader.total"))
|
||||
.mon(lila.mon.lobby.segment("preloader.total"))
|
||||
.flatMap: h =>
|
||||
ctx.me.filter(_.hasTitle).foreach(env.msg.systemMsg.twoFactorReminder(_))
|
||||
ctx.me.filterNot(_.hasEmail).foreach(env.msg.systemMsg.emailReminder(_))
|
||||
renderPage:
|
||||
lila.mon.chronoSync(_.lobby.segment("renderSync")):
|
||||
lila.mon.chronoSync(lila.mon.lobby.segment("renderSync")):
|
||||
views.lobby.home(h)
|
||||
|
||||
def notFound(msg: Option[String])(using Context): Fu[Result] =
|
||||
|
||||
+12
-11
@@ -14,6 +14,7 @@ import lila.timeline.Entry
|
||||
import lila.tournament.Tournament
|
||||
import lila.ublog.UblogPost
|
||||
import lila.user.{ LightUserApi, Me, User }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class Preload(
|
||||
tv: lila.tv.Tv,
|
||||
@@ -63,19 +64,19 @@ final class Preload(
|
||||
),
|
||||
lichessMsg
|
||||
) <- lobbyApi.get
|
||||
.mon(_.lobby.segment("lobbyApi"))
|
||||
.zip(tours.mon(_.lobby.segment("tours")))
|
||||
.zip(events.mon(_.lobby.segment("events")))
|
||||
.zip(simuls.mon(_.lobby.segment("simuls")))
|
||||
.zip(tv.getBestGame.mon(_.lobby.segment("tvBestGame")))
|
||||
.zip((ctx.userId.so(timelineApi.userEntries)).mon(_.lobby.segment("timeline")))
|
||||
.zip((ctx.noBot.so(dailyPuzzle())).mon(_.lobby.segment("puzzle")))
|
||||
.mon(lila.mon.lobby.segment("lobbyApi"))
|
||||
.zip(tours.mon(lila.mon.lobby.segment("tours")))
|
||||
.zip(events.mon(lila.mon.lobby.segment("events")))
|
||||
.zip(simuls.mon(lila.mon.lobby.segment("simuls")))
|
||||
.zip(tv.getBestGame.mon(lila.mon.lobby.segment("tvBestGame")))
|
||||
.zip((ctx.userId.so(timelineApi.userEntries)).mon(lila.mon.lobby.segment("timeline")))
|
||||
.zip((ctx.noBot.so(dailyPuzzle())).mon(lila.mon.lobby.segment("puzzle")))
|
||||
.zip:
|
||||
ctx.kid.no.so:
|
||||
liveStreamApi.all
|
||||
.dmap(_.homepage(streamerSpots, ctx.acceptLanguages).withTitles(lightUserApi))
|
||||
.mon(_.lobby.segment("streams"))
|
||||
.zip((ctx.userId.so(playbanApi.currentBan)).mon(_.lobby.segment("playban")))
|
||||
.mon(lila.mon.lobby.segment("streams"))
|
||||
.zip((ctx.userId.so(playbanApi.currentBan)).mon(lila.mon.lobby.segment("playban")))
|
||||
.zip(ctx.blind.so(ctx.me).so(roundProxy.urgentGames))
|
||||
.zip(ublogApi.myCarousel)
|
||||
.zip:
|
||||
@@ -85,11 +86,11 @@ final class Preload(
|
||||
.so(unreadCount.hasLichessMsg)
|
||||
(currentGame, _) <- ctx.me
|
||||
.soUse(currentGameMyTurn(povs, lightUserApi.sync))
|
||||
.mon(_.lobby.segment("currentGame"))
|
||||
.mon(lila.mon.lobby.segment("currentGame"))
|
||||
.zip:
|
||||
lightUserApi
|
||||
.preloadMany(entries.flatMap(_.userIds).toList)
|
||||
.mon(_.lobby.segment("lightUsers"))
|
||||
.mon(lila.mon.lobby.segment("lightUsers"))
|
||||
classes <- ctx.myId.so(me => clasApi.isStudent(me).so(clasApi.clas.ofStudent(me, 4)))
|
||||
yield Homepage(
|
||||
data,
|
||||
|
||||
+23
-20
@@ -7,12 +7,13 @@ import lila.bookmark.BookmarkApi
|
||||
import lila.core.data.SafeJsonStr
|
||||
import lila.core.perf.UserWithPerfs
|
||||
import lila.core.user.User
|
||||
import lila.core.security.IsProxy
|
||||
import lila.core.perm.Granter
|
||||
import lila.forum.ForumPostApi
|
||||
import lila.game.Crosstable
|
||||
import lila.relation.RelationApi
|
||||
import lila.ublog.{ UblogApi, UblogPost }
|
||||
import lila.core.security.IsProxy
|
||||
import lila.core.perm.Granter
|
||||
import lila.mon.extensions.*
|
||||
|
||||
case class UserInfo(
|
||||
nbs: UserInfo.NbGames,
|
||||
@@ -56,10 +57,10 @@ object UserInfo:
|
||||
def apply(u: User)(using ctx: Context): Fu[Social] =
|
||||
given scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.parasitic
|
||||
(
|
||||
ctx.userId.so(relationApi.fetchRelation(_, u.id).mon(_.user.segment("relation"))),
|
||||
ctx.useMe(noteApi.getForMyPermissions(u).mon(_.user.segment("notes"))),
|
||||
ctx.isAuth.so(prefApi.followable(u.id).mon(_.user.segment("followable"))),
|
||||
ctx.userId.so(myId => relationApi.fetchBlocks(u.id, myId).mon(_.user.segment("blocks")))
|
||||
ctx.userId.so(relationApi.fetchRelation(_, u.id).mon(lila.mon.user.segment("relation"))),
|
||||
ctx.useMe(noteApi.getForMyPermissions(u).mon(lila.mon.user.segment("notes"))),
|
||||
ctx.isAuth.so(prefApi.followable(u.id).mon(lila.mon.user.segment("followable"))),
|
||||
ctx.userId.so(myId => relationApi.fetchBlocks(u.id, myId).mon(lila.mon.user.segment("blocks")))
|
||||
).mapN(Social.apply)
|
||||
|
||||
case class NbGames(
|
||||
@@ -81,11 +82,13 @@ object UserInfo:
|
||||
withCrosstable.so:
|
||||
me
|
||||
.filter(u.isnt(_))
|
||||
.traverse(me => crosstableApi.withMatchup(me.userId, u.id).mon(_.user.segment("crosstable")))
|
||||
.traverse(me =>
|
||||
crosstableApi.withMatchup(me.userId, u.id).mon(lila.mon.user.segment("crosstable"))
|
||||
)
|
||||
,
|
||||
gameCached.nbPlaying(u.id).mon(_.user.segment("nbPlaying")),
|
||||
gameCached.nbImportedBy(u.id).mon(_.user.segment("nbImported")),
|
||||
bookmarkApi.countByUser(u).mon(_.user.segment("nbBookmarks"))
|
||||
gameCached.nbPlaying(u.id).mon(lila.mon.user.segment("nbPlaying")),
|
||||
gameCached.nbImportedBy(u.id).mon(lila.mon.user.segment("nbImported")),
|
||||
bookmarkApi.countByUser(u).mon(lila.mon.user.segment("nbBookmarks"))
|
||||
).mapN(NbGames.apply)
|
||||
|
||||
final class UserInfoApi(
|
||||
@@ -112,19 +115,19 @@ object UserInfo:
|
||||
def showRatings = ctx.noBlind && ctx.pref.showRatings && isAuthOrNotProxied
|
||||
(
|
||||
perfsRepo.withPerfs(user),
|
||||
userApi.getTrophiesAndAwards(user).mon(_.user.segment("trophies")),
|
||||
(nbs.playing > 0).so(simulApi.isSimulHost(user.id).mon(_.user.segment("simul"))),
|
||||
showRatings.so(ratingChartApi(user)).mon(_.user.segment("ratingChart")),
|
||||
userApi.getTrophiesAndAwards(user).mon(lila.mon.user.segment("trophies")),
|
||||
(nbs.playing > 0).so(simulApi.isSimulHost(user.id).mon(lila.mon.user.segment("simul"))),
|
||||
showRatings.so(ratingChartApi(user)).mon(lila.mon.user.segment("ratingChart")),
|
||||
(!user.is(UserId.lichess) && !user.isBot).so:
|
||||
postApi.nbByUser(user.id).mon(_.user.segment("nbForumPosts"))
|
||||
postApi.nbByUser(user.id).mon(lila.mon.user.segment("nbForumPosts"))
|
||||
,
|
||||
withUblog.so(ublogApi.userBlogPreviewFor(user, 3)),
|
||||
studyRepo.countByOwner(user.id).recoverDefault.mon(_.user.segment("nbStudies")),
|
||||
simulApi.countHostedByUser.get(user.id).mon(_.user.segment("nbSimuls")),
|
||||
relayApi.countOwnedByUser.get(user.id).mon(_.user.segment("nbBroadcasts")),
|
||||
ctx.useMe(teamApi.joinedTeamIdsOfUserAsSeenBy(user).mon(_.user.segment("teamIds"))),
|
||||
streamerApi.isActualStreamer(user).mon(_.user.segment("streamer")),
|
||||
coachApi.isListedCoach(user).mon(_.user.segment("coach")),
|
||||
studyRepo.countByOwner(user.id).recoverDefault.mon(lila.mon.user.segment("nbStudies")),
|
||||
simulApi.countHostedByUser.get(user.id).mon(lila.mon.user.segment("nbSimuls")),
|
||||
relayApi.countOwnedByUser.get(user.id).mon(lila.mon.user.segment("nbBroadcasts")),
|
||||
ctx.useMe(teamApi.joinedTeamIdsOfUserAsSeenBy(user).mon(lila.mon.user.segment("teamIds"))),
|
||||
streamerApi.isActualStreamer(user).mon(lila.mon.user.segment("streamer")),
|
||||
coachApi.isListedCoach(user).mon(lila.mon.user.segment("coach")),
|
||||
fideIdOf(user.light),
|
||||
fuccess(Granter.opt(_.SeeInsight)) >>| (user.count.rated >= 50).so(insightShare.grant(user))
|
||||
).mapN(UserInfo(nbs, _, _, _, _, _, _, _, _, _, _, _, _, _, _))
|
||||
|
||||
@@ -5,6 +5,7 @@ import scalalib.StringUtils.escapeHtmlRaw
|
||||
import lila.app.UiEnv.{ *, given }
|
||||
import lila.common.String.html.safeJsonValue
|
||||
import lila.ui.{ RenderedPage, PageFlags }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
object page:
|
||||
|
||||
|
||||
@@ -98,6 +98,11 @@ lazy val coreI18n = module("coreI18n",
|
||||
Seq(scalatags) ++ scalalib.bundle
|
||||
)
|
||||
|
||||
lazy val mon = module("mon",
|
||||
Seq(core),
|
||||
Seq(kamon.core, kamon.influxdb)
|
||||
)
|
||||
|
||||
lazy val common = module("common",
|
||||
Seq(core),
|
||||
Seq(
|
||||
@@ -111,7 +116,7 @@ lazy val db = module("db",
|
||||
)
|
||||
|
||||
lazy val memo = module("memo",
|
||||
Seq(db),
|
||||
Seq(db, mon),
|
||||
Seq(scaffeine, bloomFilter) ++ playWs.bundle
|
||||
)
|
||||
|
||||
@@ -130,7 +135,7 @@ lazy val i18n = module("i18n",
|
||||
)
|
||||
|
||||
lazy val rating = module("rating",
|
||||
Seq(db, ui),
|
||||
Seq(db, ui, mon),
|
||||
tests.bundle ++ Seq(apacheMath)
|
||||
).dependsOn(common % "test->test")
|
||||
|
||||
@@ -346,7 +351,7 @@ lazy val security = module("security",
|
||||
)
|
||||
|
||||
lazy val shutup = module("shutup",
|
||||
Seq(db),
|
||||
Seq(db, mon),
|
||||
tests.bundle
|
||||
)
|
||||
|
||||
@@ -401,17 +406,17 @@ lazy val playban = module("playban",
|
||||
)
|
||||
|
||||
lazy val push = module("push",
|
||||
Seq(db),
|
||||
Seq(db, mon),
|
||||
playWs.bundle ++ Seq(googleOAuth)
|
||||
)
|
||||
|
||||
lazy val irc = module("irc",
|
||||
Seq(common),
|
||||
Seq(common, mon),
|
||||
playWs.bundle
|
||||
)
|
||||
|
||||
lazy val mailer = module("mailer",
|
||||
Seq(memo, coreI18n, ui),
|
||||
Seq(memo, ui),
|
||||
Seq(hasher, play.mailer)
|
||||
)
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@ package lila.activity
|
||||
|
||||
import play.api.i18n.Lang
|
||||
import scalalib.HeapSort
|
||||
import chess.Speed.Correspondence
|
||||
|
||||
import lila.core.chess.Rank
|
||||
import lila.core.game.LightPov
|
||||
import lila.core.swiss.IdName as SwissIdName
|
||||
import lila.db.AsyncCollFailingSilently
|
||||
import lila.db.dsl.*
|
||||
import chess.Speed.Correspondence
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class ActivityReadApi(
|
||||
coll: AsyncCollFailingSilently,
|
||||
@@ -37,12 +38,12 @@ final class ActivityReadApi(
|
||||
.cursor[Activity]()
|
||||
.list(Activity.recentNb)
|
||||
).dmap(_.filterNot(_.isEmpty))
|
||||
.mon(_.user.segment("activity.raws"))
|
||||
.mon(lila.mon.user.segment("activity.raws"))
|
||||
practiceStudies <- activities
|
||||
.exists(_.practice.isDefined)
|
||||
.optionFu(getPracticeStudies())
|
||||
views <- activities.sequentially: a =>
|
||||
one(practiceStudies, a).mon(_.user.segment("activity.view"))
|
||||
one(practiceStudies, a).mon(lila.mon.user.segment("activity.view"))
|
||||
_ <- preloadAll(views)
|
||||
yield addSignup(u.createdAt, views)
|
||||
|
||||
@@ -56,7 +57,7 @@ final class ActivityReadApi(
|
||||
allForumPosts <- a.forumPosts.traverse: p =>
|
||||
forumPostApi
|
||||
.miniViews(p.value)
|
||||
.mon(_.user.segment("activity.posts"))
|
||||
.mon(lila.mon.user.segment("activity.posts"))
|
||||
hiddenForumTeamIds <- teamApi.filterHideForum(
|
||||
(~allForumPosts).flatMap(_.topic.possibleTeamId).distinct
|
||||
)
|
||||
@@ -67,7 +68,7 @@ final class ActivityReadApi(
|
||||
.traverse: p =>
|
||||
ublogApi
|
||||
.liveLightsByIds(p.value)
|
||||
.mon(_.user.segment("activity.ublogs"))
|
||||
.mon(lila.mon.user.segment("activity.ublogs"))
|
||||
.dmap(_.filter(_.nonEmpty))
|
||||
practice =
|
||||
for
|
||||
@@ -117,7 +118,7 @@ final class ActivityReadApi(
|
||||
)
|
||||
)
|
||||
)
|
||||
.mon(_.user.segment("activity.tours"))
|
||||
.mon(lila.mon.user.segment("activity.tours"))
|
||||
swisses <-
|
||||
a.swisses.so: swisses =>
|
||||
toSwissesView(swisses.value).dmap(_.nonEmptyOption)
|
||||
|
||||
@@ -6,6 +6,7 @@ import lila.common.Json.given
|
||||
import lila.core.perf.{ UserPerfs, UserWithPerfs }
|
||||
import lila.lobby.LobbySocket
|
||||
import lila.rating.UserPerfsExt.perfsList
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class LobbyApi(
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
@@ -16,7 +17,7 @@ final class LobbyApi(
|
||||
|
||||
def get(using me: Option[UserWithPerfs]): Fu[(JsObject, List[Pov])] =
|
||||
me.so(gameProxyRepo.urgentGames)
|
||||
.mon(_.lobby.segment("urgentGames"))
|
||||
.mon(lila.mon.lobby.segment("urgentGames"))
|
||||
.flatMap: povs =>
|
||||
val displayedPovs = povs.take(9)
|
||||
for _ <- lightUserApi.preloadMany(displayedPovs.flatMap(_.opponent.userId))
|
||||
|
||||
@@ -19,6 +19,7 @@ import lila.swiss.GameView as SwissView
|
||||
import lila.tournament.GameView as TourView
|
||||
import lila.tree.{ ExportOptions, Tree }
|
||||
import lila.game.GameExt.timeForFirstMove
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private[api] class RoundApi(
|
||||
jsonView: JsonView,
|
||||
@@ -66,7 +67,7 @@ final private[api] class RoundApi(
|
||||
.compose(withForecastCount(forecast.map(_.steps.size)))
|
||||
.compose(withOpponentSignal(pov))
|
||||
)(json)
|
||||
}.mon(_.round.api.player)
|
||||
}.mon(lila.mon.round.api.player)
|
||||
|
||||
def watcher(
|
||||
pov: Pov,
|
||||
@@ -94,7 +95,7 @@ final private[api] class RoundApi(
|
||||
.compose(withBookmark(bookmarked))
|
||||
.compose(withSteps(pov, initialFen))
|
||||
)(json)
|
||||
}.mon(_.round.api.watcher)
|
||||
}.mon(lila.mon.round.api.watcher)
|
||||
|
||||
private def ctxFlags(using ctx: Context) =
|
||||
ExportOptions(
|
||||
@@ -144,7 +145,7 @@ final private[api] class RoundApi(
|
||||
.compose(withPuzzleOpening(puzzleOpening))
|
||||
)(json)
|
||||
.flatMap(externalEngineApi.withExternalEngines)
|
||||
.mon(_.round.api.watcher)
|
||||
.mon(lila.mon.round.api.watcher)
|
||||
|
||||
def userAnalysisJson(
|
||||
pov: Pov,
|
||||
|
||||
@@ -115,7 +115,7 @@ final class ChallengeApi(
|
||||
maxSize = Max(64),
|
||||
timeout = 5.seconds,
|
||||
"challengeAccept",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def accept(
|
||||
|
||||
@@ -35,7 +35,7 @@ final class ChallengeBulkApi(
|
||||
expiration = 10.minutes,
|
||||
timeout = 10.seconds,
|
||||
name = "challenge.bulk",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def scheduledBy(me: User): Fu[List[ScheduledBulk]] =
|
||||
|
||||
@@ -6,6 +6,7 @@ import play.api.i18n.Lang
|
||||
|
||||
import lila.common.Form.{ cleanNonEmptyText, cleanText, into }
|
||||
import lila.clas.Student.RealName
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class ClasForm(
|
||||
lightUserAsync: lila.core.LightUser.Getter,
|
||||
|
||||
@@ -8,6 +8,7 @@ import reactivemongo.api.bson.BSONNull
|
||||
import play.api.Mode
|
||||
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class ClasUserFilters(using Executor, Materializer, Scheduler)(colls: ClasColls)(using mode: Mode):
|
||||
|
||||
@@ -84,7 +85,7 @@ private final class ClasUserCache(name: String)(
|
||||
lila.mon.clas.bloomFilter(name).count.update(nb)
|
||||
bloomFilter.dispose()
|
||||
bloomFilter = nextBloom
|
||||
.monSuccess(_.clas.bloomFilter(name).fu)
|
||||
.monSuccess(lila.mon.clas.bloomFilter(name).fu)
|
||||
|
||||
scheduler.scheduleWithFixedDelay(initialDelay, 7.days): () =>
|
||||
rebuildBloomFilter()
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package lila.common
|
||||
|
||||
import scalalib.actor.{ AsyncActorBounded, AsyncActorSequencer }
|
||||
|
||||
// provides values of A one by one
|
||||
// but generates them in batches
|
||||
final class BatchProvider[A](name: String, timeout: FiniteDuration)(generateBatch: () => Fu[List[A]])(using
|
||||
final class BatchProvider[A](name: String, timeout: FiniteDuration, monitor: AsyncActorBounded.Monitor)(
|
||||
generateBatch: () => Fu[List[A]]
|
||||
)(using
|
||||
Executor,
|
||||
Scheduler
|
||||
):
|
||||
@@ -11,7 +15,7 @@ final class BatchProvider[A](name: String, timeout: FiniteDuration)(generateBatc
|
||||
maxSize = Max(4096),
|
||||
timeout = timeout,
|
||||
name = s"$name.batchProvider.workQueue",
|
||||
lila.log.asyncActorMonitor.full
|
||||
monitor = monitor
|
||||
)
|
||||
|
||||
private var reserve = List.empty[A]
|
||||
|
||||
@@ -51,7 +51,7 @@ object Form:
|
||||
def stringIn[A](choices: Seq[A])(key: A => String): Mapping[A] =
|
||||
stringIn(choices.map(key).toSet).transform[A](str => choices.find(c => str == key(c)).get, key)
|
||||
|
||||
def id[Id](size: Int, fixed: Option[Id])(exists: Id => Fu[Boolean])(using
|
||||
def idWithSyncUniqueCheck[Id](size: Int, fixed: Option[Id])(exists: Id => Fu[Boolean])(using
|
||||
sr: StringRuntime[Id],
|
||||
rs: SameRuntime[String, Id]
|
||||
): Mapping[Id] =
|
||||
@@ -59,9 +59,12 @@ object Form:
|
||||
.verifying("IDs must be made of ASCII letters and numbers", id => """(?i)^[a-z\d]+$""".r.matches(id))
|
||||
.into[Id]
|
||||
fixed match
|
||||
case Some(fixedId) => field.verifying("The ID cannot be changed now", id => id == fixedId)
|
||||
case Some(fixedId) => field.verifying("The ID cannot be changed now", _ == fixedId)
|
||||
case None =>
|
||||
field.verifying("This ID is already in use", id => !exists(id).await(1.second, "unique ID"))
|
||||
field.verifying(
|
||||
"This ID is already in use",
|
||||
id => !scala.concurrent.Await.result(exists(id), 1.second)
|
||||
)
|
||||
|
||||
def empty[T]: FieldMapping[Option[T]] =
|
||||
given Formatter[Option[T]] = new:
|
||||
|
||||
@@ -13,7 +13,6 @@ object Lilakka:
|
||||
val msg = s"$phase $name"
|
||||
cs.addTask(phase, name): () =>
|
||||
shutdownLogger.info(msg)
|
||||
Chronometer(f())
|
||||
.log(shutdownLogger)(_ => msg)
|
||||
.result
|
||||
.inject(akka.Done)
|
||||
f().dmap: _ =>
|
||||
shutdownLogger.info(s"$msg done")
|
||||
akka.Done
|
||||
|
||||
@@ -104,19 +104,14 @@ final class MarkdownRender(
|
||||
Markdown(RawHtml.atUsernameRegex.replaceAllIn(markdown.value, "[@$1](/@/$1)"))
|
||||
|
||||
def apply(key: MarkdownRender.Key)(text: Markdown): Html = Html:
|
||||
Chronometer
|
||||
.sync:
|
||||
try
|
||||
val saferText = MarkdownRender.preventStackOverflow(text)
|
||||
val withMentions = if sourceMap then saferText else mentionsToLinks(saferText)
|
||||
renderer.render(parser.parse(withMentions.value))
|
||||
catch
|
||||
case e: StackOverflowError =>
|
||||
logger.branch(key).error("StackOverflowError", e)
|
||||
text.value
|
||||
.mon(_.markdown.time)
|
||||
.logIfSlow(50, logger.branch(key))(_ => s"slow markdown size:${text.value.size}")
|
||||
.result
|
||||
try
|
||||
val saferText = MarkdownRender.preventStackOverflow(text)
|
||||
val withMentions = if sourceMap then saferText else mentionsToLinks(saferText)
|
||||
renderer.render(parser.parse(withMentions.value))
|
||||
catch
|
||||
case e: StackOverflowError =>
|
||||
logger.branch(key).error("StackOverflowError", e)
|
||||
text.value
|
||||
|
||||
object MarkdownRender:
|
||||
|
||||
|
||||
@@ -12,22 +12,3 @@ object log:
|
||||
|
||||
def http(status: Int, body: String) =
|
||||
s"$status ${body.linesIterator.take(1).toList.headOption.getOrElse("-")}"
|
||||
|
||||
object asyncActorMonitor:
|
||||
lazy val full = scalalib.actor.AsyncActorBounded.Monitor(
|
||||
overflow = name =>
|
||||
lila.mon.asyncActor.overflow(name).increment()
|
||||
lila.log("asyncActor").warn(s"[$name] queue is full")
|
||||
,
|
||||
queueSize = (name, size) => lila.mon.asyncActor.queueSize(name).record(size),
|
||||
unhandled = (name, msg) => lila.log("asyncActor").warn(s"[$name] unhandled msg: $msg")
|
||||
)
|
||||
|
||||
lazy val highCardinality = full.copy(
|
||||
queueSize = (_, _) => ()
|
||||
)
|
||||
|
||||
lazy val unhandled = full.copy(
|
||||
overflow = _ => (),
|
||||
queueSize = (_, _) => ()
|
||||
)
|
||||
|
||||
@@ -1,759 +0,0 @@
|
||||
package lila
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache as CaffeineCache
|
||||
import kamon.metric.{ Counter, Timer }
|
||||
import kamon.tag.TagSet
|
||||
import chess.variant.Variant
|
||||
|
||||
import lila.core.id.*
|
||||
import lila.core.net.*
|
||||
import lila.core.userId.{ UserId, UserName }
|
||||
import lila.core.perf.PerfKey
|
||||
|
||||
object mon:
|
||||
|
||||
import kamon.Kamon.{ timer, gauge, counter, histogram }
|
||||
|
||||
// https://github.com/kamon-io/Kamon/issues/752
|
||||
extension (s: String)
|
||||
def escape: String =
|
||||
val builder = java.lang.StringBuilder(s.length)
|
||||
for c <- s.toCharArray do
|
||||
if c != '"' && c != '\n' && c != '\\'
|
||||
then builder.append(c)
|
||||
builder.toString
|
||||
|
||||
private def tags(elems: (String, Any)*): Map[String, Any] = Map.from(elems)
|
||||
|
||||
object http:
|
||||
private val reqTime = timer("http.time")
|
||||
private val reqCount = counter("http.count")
|
||||
private val mobCount = counter("http.mobile.count")
|
||||
|
||||
def time(action: String) = reqTime.withTag("action", action)
|
||||
|
||||
def count(action: String, client: String, method: String, code: Int) =
|
||||
reqCount.withTags:
|
||||
tags("action" -> action, "client" -> client, "method" -> method, "code" -> code.toLong)
|
||||
|
||||
def errorCount(action: String, client: String, method: String, code: Int) =
|
||||
counter("http.error").withTags:
|
||||
tags("action" -> action, "client" -> client, "method" -> method, "code" -> code.toLong)
|
||||
|
||||
def mobileCount(action: String, version: String, auth: Boolean, os: String) =
|
||||
mobCount.withTags:
|
||||
tags(
|
||||
"action" -> action,
|
||||
"version" -> version,
|
||||
"auth" -> (if auth then "auth" else "anon"),
|
||||
"os" -> os
|
||||
)
|
||||
|
||||
def path(p: String) = counter("http.path.count").withTag("path", p.escape)
|
||||
val userGamesCost = counter("http.userGames.cost").withoutTags()
|
||||
def csrfError(tpe: String, action: String, client: String) =
|
||||
counter("http.csrf.error").withTags(tags("type" -> tpe, "action" -> action, "client" -> client))
|
||||
val fingerPrint = timer("http.fingerPrint.time").withoutTags()
|
||||
object syncache:
|
||||
def miss(name: String) = counter("syncache.miss").withTag("name", name)
|
||||
def timeout(name: String) = counter("syncache.timeout").withTag("name", name)
|
||||
def compute(name: String) = timer("syncache.compute").withTag("name", name)
|
||||
def wait(name: String) = timer("syncache.wait").withTag("name", name)
|
||||
def caffeineStats(cache: CaffeineCache[?, ?], name: String): Unit =
|
||||
val stats = cache.stats
|
||||
gauge("caffeine.request").withTags(tags("name" -> name, "hit" -> true)).update(stats.hitCount.toDouble)
|
||||
gauge("caffeine.request").withTags(tags("name" -> name, "hit" -> false)).update(stats.missCount.toDouble)
|
||||
histogram("caffeine.hit.rate").withTag("name", name).record((stats.hitRate * 100000).toLong)
|
||||
if stats.totalLoadTime > 0 then
|
||||
gauge("caffeine.load.count")
|
||||
.withTags(tags("name" -> name, "success" -> "success"))
|
||||
.update(stats.loadSuccessCount.toDouble)
|
||||
gauge("caffeine.load.count")
|
||||
.withTags(tags("name" -> name, "success" -> "failure"))
|
||||
.update(stats.loadFailureCount.toDouble)
|
||||
gauge("caffeine.loadTime.cumulated")
|
||||
.withTag("name", name)
|
||||
.update(stats.totalLoadTime / 1000000d) // in millis; too much nanos for Kamon to handle)
|
||||
timer("caffeine.loadTime.penalty").withTag("name", name).record(stats.averageLoadPenalty.toLong)
|
||||
gauge("caffeine.eviction.count").withTag("name", name).update(stats.evictionCount.toDouble)
|
||||
gauge("caffeine.entry.count").withTag("name", name).update(cache.estimatedSize.toDouble)
|
||||
object mongoCache:
|
||||
def request(name: String, hit: Boolean) =
|
||||
counter("mongocache.request").withTags:
|
||||
tags(
|
||||
"name" -> name,
|
||||
"hit" -> hit
|
||||
)
|
||||
def compute(name: String) = timer("mongocache.compute").withTag("name", name)
|
||||
object evalCache:
|
||||
private val r = counter("evalCache.request")
|
||||
def request(ply: Int, isHit: Boolean) =
|
||||
r.withTags(tags("ply" -> (if ply < 15 then ply.toString else "15+"), "hit" -> isHit))
|
||||
object upgrade:
|
||||
val count = counter("evalCache.upgrade.count").withoutTags()
|
||||
val members = gauge("evalCache.upgrade.members").withoutTags()
|
||||
val evals = gauge("evalCache.upgrade.evals").withoutTags()
|
||||
val expirable = gauge("evalCache.upgrade.expirable").withoutTags()
|
||||
object lobby:
|
||||
object hook:
|
||||
val create = counter("lobby.hook.create").withoutTags()
|
||||
val join = counter("lobby.hook.join").withoutTags()
|
||||
val size = histogram("lobby.hook.size").withoutTags()
|
||||
def apiCreate(client: String) = counter("lobby.hook.apiCreate").withTag("client", client)
|
||||
object seek:
|
||||
val create = counter("lobby.seek.create").withoutTags()
|
||||
val join = counter("lobby.seek.join").withoutTags()
|
||||
object socket:
|
||||
val getSris = timer("lobby.socket.getSris").withoutTags()
|
||||
val member = gauge("lobby.socket.member").withoutTags()
|
||||
val idle = gauge("lobby.socket.idle").withoutTags()
|
||||
val hookSubscribers = gauge("lobby.socket.hookSubscribers").withoutTags()
|
||||
object pool:
|
||||
object wave:
|
||||
def scheduled(id: String) = counter("lobby.pool.wave.scheduled").withTag("pool", id)
|
||||
def full(id: String) = counter("lobby.pool.wave.full").withTag("pool", id)
|
||||
def candidates(id: String) = histogram("lobby.pool.wave.candidates").withTag("pool", id)
|
||||
def paired(id: String) = histogram("lobby.pool.wave.paired").withTag("pool", id)
|
||||
def missed(id: String) = histogram("lobby.pool.wave.missed").withTag("pool", id)
|
||||
def ratingDiff(id: String) = histogram("lobby.pool.wave.ratingDiff").withTag("pool", id)
|
||||
def withRange(id: String) = histogram("lobby.pool.wave.withRange").withTag("pool", id)
|
||||
object thieve:
|
||||
def stolen(id: String) = histogram("lobby.pool.thieve.stolen").withTag("pool", id)
|
||||
private val lobbySegment = timer("lobby.segment")
|
||||
def segment(seg: String) = lobbySegment.withTag("segment", seg)
|
||||
object rating:
|
||||
def distribution(perfKey: PerfKey, rating: Int) =
|
||||
gauge("rating.distribution").withTags(tags("perf" -> perfKey, "rating" -> rating.toLong))
|
||||
object regulator:
|
||||
def micropoints(perfKey: PerfKey) = histogram("rating.regulator").withTag("perf", perfKey.value)
|
||||
object perfStat:
|
||||
def indexTime = timer("perfStat.indexTime").withoutTags()
|
||||
|
||||
object round:
|
||||
object api:
|
||||
val player = timer("round.api").withTag("endpoint", "player")
|
||||
val watcher = timer("round.api").withTag("endpoint", "watcher")
|
||||
object forecast:
|
||||
val create = counter("round.forecast.create").withoutTags()
|
||||
object move:
|
||||
object lag:
|
||||
val compDeviation = histogram("round.move.lag.comp_deviation").withoutTags()
|
||||
def uncomped(key: String) = histogram("round.move.lag.uncomped_ms").withTag("key", key)
|
||||
def uncompStdDev(key: String) = histogram("round.move.lag.uncomp_stdev_ms").withTag("key", key)
|
||||
val stdDev = histogram("round.move.lag.stddev_ms").withoutTags()
|
||||
val mean = histogram("round.move.lag.mean_ms").withoutTags()
|
||||
val coefVar = histogram("round.move.lag.coef_var_1000").withoutTags()
|
||||
val compEstStdErr = histogram("round.move.lag.comp_est_stderr_1000").withoutTags()
|
||||
val compEstOverErr = histogram("round.move.lag.avg_over_error_ms").withoutTags()
|
||||
val moveComp = timer("round.move.lag.comped").withoutTags()
|
||||
val time = timer("round.move.time").withoutTags()
|
||||
object error:
|
||||
val client = counter("round.error").withTag("from", "client")
|
||||
val fishnet = counter("round.error").withTag("from", "fishnet")
|
||||
val glicko = counter("round.error").withTag("from", "glicko")
|
||||
val other = counter("round.error").withTag("from", "other")
|
||||
object titivate:
|
||||
val time = future("round.titivate.time")
|
||||
val game = histogram("round.titivate.game").withoutTags() // how many games were processed
|
||||
val total = histogram("round.titivate.total").withoutTags() // how many games should have been processed
|
||||
val old = histogram("round.titivate.old").withoutTags() // how many old games remain
|
||||
def broken(error: String) = counter("round.titivate.broken").withTag("error", error) // broken game
|
||||
object alarm:
|
||||
val time = timer("round.alarm.time").withoutTags()
|
||||
object expiration:
|
||||
val count = counter("round.expiration.count").withoutTags()
|
||||
val asyncActorCount = gauge("round.asyncActor.count").withoutTags()
|
||||
object correspondenceEmail:
|
||||
val emails = histogram("round.correspondenceEmail.emails").withoutTags()
|
||||
val time = future("round.correspondenceEmail.time")
|
||||
object farming:
|
||||
val bot = counter("round.farming.bot").withoutTags()
|
||||
val provisional = counter("round.farming.provisional").withoutTags()
|
||||
object playban:
|
||||
def outcome(out: String) = counter("playban.outcome").withTag("outcome", out)
|
||||
object ban:
|
||||
val count = counter("playban.ban.count").withoutTags()
|
||||
val mins = histogram("playban.ban.mins").withoutTags()
|
||||
object explorer:
|
||||
object index:
|
||||
def count(success: Boolean) = counter("explorer.index.count").withTag("success", successTag(success))
|
||||
val time = timer("explorer.index.time").withoutTags()
|
||||
object timeline:
|
||||
val notification = counter("timeline.notification").withoutTags()
|
||||
object insight:
|
||||
val user = future("insight.request.time", "user")
|
||||
val peers = future("insight.request.time", "peer")
|
||||
val index = future("insight.index.time")
|
||||
object tutor:
|
||||
def buildSegment(segment: String) = future("tutor.build.segment", segment)
|
||||
val buildFull = future("tutor.build.full")
|
||||
val askMine = askAs("mine")
|
||||
val askPeer = askAs("peer")
|
||||
val buildTimeout = counter("tutor.build.timeout").withoutTags()
|
||||
def peerMatch(hit: Boolean, perf: PerfKey) = counter("tutor.peerMatch").withTags:
|
||||
tags("hit" -> hitTag(hit), "perf" -> perf)
|
||||
val parallelism = gauge("tutor.build.parallelism").withoutTags()
|
||||
val fishnetMissing = histogram("tutor.fishnet.missing").withoutTags()
|
||||
private def askAs(as: "mine" | "peer")(question: String, perf: PerfKey | "all") =
|
||||
future("tutor.insight.ask", tags("question" -> question, "perf" -> perf, "as" -> as))
|
||||
object search:
|
||||
def time(op: "search" | "count", index: String, success: Boolean) =
|
||||
timer("search.client.time").withTags:
|
||||
tags(
|
||||
"op" -> op,
|
||||
"index" -> index,
|
||||
"success" -> successTag(success)
|
||||
)
|
||||
object asyncActor:
|
||||
def overflow(name: String) = counter("asyncActor.overflow").withTag("name", name)
|
||||
def queueSize(name: String) = histogram("asyncActor.queueSize").withTag("name", name)
|
||||
object irc:
|
||||
object zulip:
|
||||
def say(stream: String) = future("irc.zulip.say", tags("stream" -> stream.escape))
|
||||
object user:
|
||||
val online = gauge("user.online").withoutTags()
|
||||
object register:
|
||||
def count(
|
||||
confirm: String,
|
||||
ipSusp: Boolean,
|
||||
fp: Boolean,
|
||||
proxy: Option[String],
|
||||
country: String,
|
||||
client: String
|
||||
) =
|
||||
counter("user.register.count").withTags:
|
||||
tags(
|
||||
"confirm" -> confirm,
|
||||
"ipSusp" -> ipSusp,
|
||||
"fp" -> fp,
|
||||
"proxy" -> proxy.getOrElse("no"),
|
||||
"country" -> country.escape,
|
||||
"client" -> client
|
||||
)
|
||||
def result(client: String, result: String) =
|
||||
counter("user.register.result").withTags:
|
||||
tags("client" -> client, "result" -> result)
|
||||
def mustConfirmEmail(v: String) = counter("user.register.mustConfirmEmail").withTag("type", v)
|
||||
def confirmEmailResult(success: Boolean) =
|
||||
counter("user.register.confirmEmail").withTag("success", successTag(success))
|
||||
def modConfirmEmail(by: "mod" | "worker", result: String) =
|
||||
counter("user.register.modConfirmEmail").withTags:
|
||||
tags("by" -> by, "result" -> result)
|
||||
object auth:
|
||||
val bcFullMigrate = counter("user.auth.bcFullMigrate").withoutTags()
|
||||
val hashTime = timer("user.auth.hashTime").withoutTags()
|
||||
def count(success: Boolean) = counter("user.auth.count").withTag("success", successTag(success))
|
||||
|
||||
def passwordResetRequest(s: String) = counter("user.auth.passwordResetRequest").withTag("type", s)
|
||||
def passwordResetConfirm(s: String) = counter("user.auth.passwordResetConfirm").withTag("type", s)
|
||||
|
||||
def reopenRequest(s: String) = counter("user.auth.reopenRequest").withTag("type", s)
|
||||
def reopenConfirm(s: String) = counter("user.auth.reopenConfirm").withTag("type", s)
|
||||
object oauth:
|
||||
def request(success: Boolean) = counter("user.oauth.request").withTags:
|
||||
tags("success" -> successTag(success))
|
||||
private val userSegment = timer("user.segment")
|
||||
def segment(seg: String) = userSegment.withTag("segment", seg)
|
||||
def leaderboardCompute = future("user.leaderboard.compute")
|
||||
def weeklyStableRanking(perf: PerfKey) = future("user.weeklyStableRanking", perf.value)
|
||||
object actor:
|
||||
def queueSize(name: String) = gauge("trouper.queueSize").withTag("name", name)
|
||||
object mod:
|
||||
object report:
|
||||
val highest = gauge("mod.report.highest").withoutTags()
|
||||
val close = counter("mod.report.close").withoutTags()
|
||||
def create(reason: String, score: Int) =
|
||||
counter("mod.report.create").withTags:
|
||||
tags("reason" -> reason, "score" -> score)
|
||||
object automod:
|
||||
val request = future("mod.report.automod.request")
|
||||
def assessment(a: String) = counter("mod.report.automod.assessment").withTag("assessment", a)
|
||||
val imageRequest = future("mod.report.automod.image.request")
|
||||
def imageFlagged(v: Boolean) = counter("mod.report.automod.image.flagged").withTag("flagged", v)
|
||||
object log:
|
||||
val create = counter("mod.log.create").withoutTags()
|
||||
object irwin:
|
||||
val report = counter("mod.report.irwin.report").withoutTags()
|
||||
val mark = counter("mod.report.irwin.mark").withoutTags()
|
||||
def ownerReport(name: String) = counter("mod.irwin.ownerReport").withTag("name", name)
|
||||
def streamEventType(name: String) = counter("mod.irwin.stream.eventType").withTag("name", name)
|
||||
object kaladin:
|
||||
def request(by: String) = counter("mod.kaladin.request").withTag("by", by)
|
||||
def insufficientMoves(by: String) = counter("mod.kaladin.insufficientMoves").withTag("by", by)
|
||||
def queue(priority: Int) = gauge("mod.kaladin.queue").withTag("priority", priority)
|
||||
def error(errKind: String) = counter("mod.kaladin.error").withTag("error", errKind)
|
||||
val activation = histogram("mod.report.kaladin.activation").withoutTags()
|
||||
val report = counter("mod.report.kaladin.report").withoutTags()
|
||||
val mark = counter("mod.report.kaladin.mark").withoutTags()
|
||||
object comm:
|
||||
def segment(seg: String) = timer("mod.comm.segmentLat").withTag("segment", seg)
|
||||
def zoneSegment(name: String) = future("mod.zone.segment", name)
|
||||
object relay:
|
||||
private def by(official: Boolean) = if official then "official" else "user"
|
||||
private def relay(official: Boolean, id: RelayTourId, slug: String) =
|
||||
tags("by" -> by(official), "slug" -> s"$slug/$id")
|
||||
def ongoing(official: Boolean) = gauge("relay.ongoing").withTag("by", by(official))
|
||||
val crowdMonitor = gauge("relay.crowdMonitor").withoutTags()
|
||||
def moves(official: Boolean, id: RelayTourId, slug: String) =
|
||||
counter("relay.moves").withTags(relay(official, id, slug))
|
||||
def fetchTime(official: Boolean, id: RelayTourId, slug: String) =
|
||||
timer("relay.fetch.time").withTags(relay(official, id, slug))
|
||||
def syncTime(official: Boolean, id: RelayTourId, slug: String) =
|
||||
timer("relay.sync.time").withTags(relay(official, id, slug))
|
||||
def httpGet(code: Int, host: String, etag: String, proxy: Option[String]) =
|
||||
timer("relay.http.get").withTags:
|
||||
tags(
|
||||
"code" -> code.toLong,
|
||||
"host" -> host.escape,
|
||||
"etag" -> etag.escape,
|
||||
"proxy" -> proxy.getOrElse("none")
|
||||
)
|
||||
val dedup = counter("relay.fetch.dedup").withoutTags()
|
||||
def push(name: String, user: UserName, client: String)(games: Int, moves: Int, errors: Int) =
|
||||
val histogramTags = tags("name" -> name.escape, "user" -> user, "client" -> client.escape)
|
||||
val counterTags = tags("name" -> name.escape, "user" -> user)
|
||||
histogram("relay.push.games").withTags(histogramTags).record(games)
|
||||
histogram("relay.push.moves").withTags(histogramTags).record(moves)
|
||||
histogram("relay.push.errors").withTags(histogramTags).record(errors)
|
||||
counter("relay.push.games.nb").withTags(counterTags).increment(games)
|
||||
counter("relay.push.moves.nb").withTags(counterTags).increment(moves)
|
||||
|
||||
object bot:
|
||||
def moves(username: String) = counter("bot.moves").withTag("name", username)
|
||||
def chats(username: String) = counter("bot.chats").withTag("name", username)
|
||||
def gameStream(event: "start" | "stop") = counter("bot.gameStream").withTag("event", event)
|
||||
object cheat:
|
||||
def selfReport(wildName: String, auth: Boolean) =
|
||||
val name = if wildName.startsWith("soc: ") then "soc" else wildName.takeWhile(' ' !=)
|
||||
counter("cheat.selfReport").withTags(tags("name" -> name.escape, "auth" -> auth))
|
||||
val holdAlert = counter("cheat.holdAlert").withoutTags()
|
||||
def autoAnalysis(reason: String) = counter("cheat.autoAnalysis").withTag("reason", reason)
|
||||
val autoMark = counter("cheat.autoMark.count").withoutTags()
|
||||
val autoReport = counter("cheat.autoReport.count").withoutTags()
|
||||
object email:
|
||||
object send:
|
||||
private val c = counter("email.send")
|
||||
val resetPassword = c.withTag("type", "resetPassword")
|
||||
val magicLink = c.withTag("type", "magicLink")
|
||||
val reopen = c.withTag("type", "reopen")
|
||||
val fix = c.withTag("type", "fix")
|
||||
val change = c.withTag("type", "change")
|
||||
val confirmation = c.withTag("type", "confirmation")
|
||||
val welcome = c.withTag("type", "welcome")
|
||||
def time(mailer: String) = future("email.send.time", tags("mailer" -> mailer))
|
||||
val disposableDomain = gauge("email.disposableDomain").withoutTags()
|
||||
object security:
|
||||
val torNodes = gauge("security.tor.node").withoutTags()
|
||||
object firewall:
|
||||
val block = counter("security.firewall.block").withoutTags()
|
||||
val ip = gauge("security.firewall.ip").withoutTags()
|
||||
val prints = gauge("security.firewall.prints").withoutTags()
|
||||
object proxy:
|
||||
val request = future("security.proxy.time")
|
||||
def result(r: Option[String]) = counter("security.proxy.result").withTag("result", r.getOrElse("none"))
|
||||
def hit(prox: String, action: String) =
|
||||
counter("security.proxy.hit").withTags(tags("proxy" -> prox, "action" -> action))
|
||||
def rateLimit(key: String) = counter("security.rateLimit.count").withTag("key", key)
|
||||
def concurrencyLimit(key: String) = counter("security.concurrencyLimit.count").withTag("key", key)
|
||||
object dnsApi:
|
||||
val mx = future("security.dnsApi.mx.time")
|
||||
object verifyMailApi:
|
||||
def fetch(success: Boolean, ok: Boolean) =
|
||||
timer("verifyMail.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
|
||||
object mailcheckApi:
|
||||
def fetch(success: Boolean, ok: Boolean) =
|
||||
timer("mailcheck.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
|
||||
object turnstile:
|
||||
def hit(client: String, action: String, result: String) =
|
||||
counter("turnstile.hit").withTags(tags("client" -> client, "action" -> action, "result" -> result))
|
||||
object pwned:
|
||||
def get(res: Boolean) = timer("security.pwned.result").withTag("res", res)
|
||||
object geoip:
|
||||
val epoch = gauge("security.geoip.epoch").withoutTags()
|
||||
val loadTime = gauge("security.geoip.loadTime").withoutTags()
|
||||
object login:
|
||||
def attempt(byEmail: Boolean, pwned: Boolean, result: Boolean) =
|
||||
counter("security.login.attempt").withTags:
|
||||
tags(
|
||||
"by" -> (if byEmail then "email" else "name"),
|
||||
"pwned" -> pwned,
|
||||
"result" -> result
|
||||
)
|
||||
def proxy(tpe: String) = counter("security.login.proxy").withTag("proxy", tpe)
|
||||
def secretScanning(tokenType: String, source: String, hit: Boolean) =
|
||||
counter("security.githubSecretScanning.hit").withTags(
|
||||
tags("type" -> tokenType, "source" -> source.escape, "hit" -> hit)
|
||||
)
|
||||
def userTrust(trust: Boolean, cause: String) =
|
||||
counter("security.userTrust").withTags(tags("trust" -> trust, "cause" -> cause)).increment()
|
||||
object shutup:
|
||||
def analyzer = timer("shutup.analyzer.time").withoutTags()
|
||||
object tv:
|
||||
object selector:
|
||||
def candidates(channel: String) = histogram("tv.selector.candidates").withTag("channel", channel)
|
||||
def cheats(channel: String) = histogram("tv.selector.cheats").withTag("channel", channel)
|
||||
def rating(channel: String) = histogram("tv.selector.rating").withTag("channel", channel)
|
||||
object streamer:
|
||||
def online = gauge("tv.streamer.count").withoutTags()
|
||||
def present(n: String) = gauge("tv.streamer.present").withTag("name", n.escape)
|
||||
object relation:
|
||||
private val c = counter("relation.action")
|
||||
val follow = c.withTag("type", "follow")
|
||||
val unfollow = c.withTag("type", "unfollow")
|
||||
val block = c.withTag("type", "block")
|
||||
val unblock = c.withTag("type", "unblock")
|
||||
object clas:
|
||||
object student:
|
||||
def create(teacher: UserId) = counter("clas.student.create").withTag("teacher", teacher)
|
||||
def invite(teacher: UserId) = counter("clas.student.invite").withTag("teacher", teacher)
|
||||
final class bloomFilter(name: String):
|
||||
def count = gauge(s"clas.${name}.bloomFilter.count").withoutTags()
|
||||
def fu = future(s"clas.${name}.bloomFilter.future")
|
||||
object tournament:
|
||||
object pairing:
|
||||
val batchSize = histogram("tournament.pairing.batchSize").withoutTags()
|
||||
val create = future("tournament.pairing.create")
|
||||
val createRanking = timer("tournament.pairing.create.ranking").withoutTags()
|
||||
val createPairings = timer("tournament.pairing.create.pairings").withoutTags()
|
||||
val createPlayerMap = timer("tournament.pairing.create.playerMap").withoutTags()
|
||||
val createInserts = timer("tournament.pairing.create.inserts").withoutTags()
|
||||
val createFeature = timer("tournament.pairing.create.feature").withoutTags()
|
||||
val createAutoPairing = timer("tournament.pairing.create.autoPairing").withoutTags()
|
||||
val prep = future("tournament.pairing.prep")
|
||||
val wmmatching = timer("tournament.pairing.wmmatching").withoutTags()
|
||||
val created = gauge("tournament.count").withTag("type", "created")
|
||||
val started = gauge("tournament.count").withTag("type", "started")
|
||||
val waitingPlayers = histogram("tournament.waitingPlayers").withoutTags()
|
||||
object startedOrganizer:
|
||||
val tick = future("tournament.startedOrganizer.tick")
|
||||
val waitingUsers = future("tournament.startedOrganizer.waitingUsers")
|
||||
object createdOrganizer:
|
||||
val tick = future("tournament.createdOrganizer.tick")
|
||||
object lilaHttp:
|
||||
val tick = future("tournament.lilaHttp.tick")
|
||||
val fullSize = histogram("tournament.lilaHttp.fullSize").withoutTags()
|
||||
val nbTours = gauge("tournament.lilaHttp.nbTours").withoutTags()
|
||||
def apiShowPartial(partial: Boolean, client: String)(success: Boolean) =
|
||||
timer("tournament.api.show").withTags:
|
||||
tags(
|
||||
"partial" -> partial,
|
||||
"success" -> successTag(success),
|
||||
"client" -> client
|
||||
)
|
||||
def withdrawableIds(reason: String) = future("tournament.withdrawableIds", reason)
|
||||
def action(tourId: String, action: String) =
|
||||
timer("tournament.api.action").withTags(tags("tourId" -> tourId, "action" -> action))
|
||||
object notifier:
|
||||
def tournaments = counter("tournament.notify.tournaments").withoutTags()
|
||||
def players = counter("tournament.notify.players").withoutTags()
|
||||
object featuring:
|
||||
def forTeams(page: "index" | "homepage") = future("tournament.featuring.forTeams", page)
|
||||
object swiss:
|
||||
val tick = future("swiss.tick")
|
||||
val bbpairing = timer("swiss.bbpairing").withoutTags()
|
||||
val scoringGet = future("swiss.scoring.get")
|
||||
val scoringRecompute = future("swiss.scoring.recompute")
|
||||
val startRound = future("swiss.director.startRound")
|
||||
def games(status: String) = histogram("swiss.ongoingGames").withTag("status", status)
|
||||
val json = future("swiss.json")
|
||||
object plan:
|
||||
object paypalLegacy:
|
||||
val amount = histogram("plan.amount").withTag("service", "paypal")
|
||||
object paypalCheckout:
|
||||
val amount = histogram("plan.amount").withTag("service", "paypalCheckout")
|
||||
val fetchAccessToken = future("plan.paypal.accessToken")
|
||||
val stripe = histogram("plan.amount").withTag("service", "stripe")
|
||||
val goal = gauge("plan.goal").withoutTags()
|
||||
val current = gauge("plan.current").withoutTags()
|
||||
val percent = gauge("plan.percent").withoutTags()
|
||||
def webhook(service: String, tpe: String) =
|
||||
counter("plan.webhook").withTags(tags("service" -> service, "tpe" -> tpe))
|
||||
def intent(service: String, currency: java.util.Currency, coverFees: Boolean) =
|
||||
counter("plan.intent").withTags:
|
||||
tags("service" -> service, "currency" -> currency.getCurrencyCode, "coverFees" -> coverFees)
|
||||
object charge:
|
||||
def first(service: String) = counter("plan.charge.first").withTag("service", service)
|
||||
def countryCents(country: String, currency: java.util.Currency, service: String, gift: Boolean) =
|
||||
histogram("plan.charge.country.cents").withTags:
|
||||
tags(
|
||||
"country" -> country.escape,
|
||||
"currency" -> currency.getCurrencyCode,
|
||||
"service" -> service,
|
||||
"gift" -> gift
|
||||
)
|
||||
object forum:
|
||||
object post:
|
||||
val create = counter("forum.post.create").withoutTags()
|
||||
object topic:
|
||||
val view = counter("forum.topic.view").withoutTags()
|
||||
def reaction(r: String) = counter("forum.reaction").withTag("reaction", r)
|
||||
object msg:
|
||||
def post(verdict: String, isNew: Boolean, multi: Boolean) = counter("msg.post").withTags(
|
||||
tags("verdict" -> verdict, "isNew" -> isNew, "multi" -> multi)
|
||||
)
|
||||
val teamBulk = histogram("msg.bulk.team").withoutTags()
|
||||
def clasBulk(clasId: ClasId) = histogram("msg.bulk.clas").withTag("id", clasId.value)
|
||||
object puzzle:
|
||||
object selector:
|
||||
object user:
|
||||
def time(categ: String) = timer("puzzle.selector.user.puzzle").withTag("categ", categ)
|
||||
def retries(categ: String) = histogram("puzzle.selector.user.retries").withTag("categ", categ)
|
||||
val vote = histogram("puzzle.selector.user.vote").withoutTags()
|
||||
def tier(t: String, categ: String, difficulty: String) =
|
||||
counter("puzzle.selector.user.tier").withTags:
|
||||
tags("tier" -> t, "categ" -> categ, "difficulty" -> difficulty)
|
||||
def batch(nb: Int) = timer("puzzle.selector.user.batch").withTag("nb", nb)
|
||||
object anon:
|
||||
val time = timer("puzzle.selector.anon.puzzle").withoutTags()
|
||||
def batch(nb: Int) = timer("puzzle.selector.anon.batch").withTag("nb", nb)
|
||||
val vote = histogram("puzzle.selector.anon.vote").withoutTags()
|
||||
def nextPuzzleResult(result: String) =
|
||||
timer("puzzle.selector.user.puzzleResult").withTag("result", result)
|
||||
def nextPathFor(categ: String, requester: String) =
|
||||
timer("puzzle.path.nextFor").withTags(tags("categ" -> categ, "requester" -> requester))
|
||||
|
||||
object batch:
|
||||
object selector:
|
||||
val count = counter("puzzle.batch.selector.count").withoutTags()
|
||||
val time = timer("puzzle.batch.selector").withoutTags()
|
||||
val solve = counter("puzzle.batch.solve").withoutTags()
|
||||
object round:
|
||||
def attempt(user: Boolean, theme: String, rated: Boolean) =
|
||||
counter("puzzle.attempt.count").withTags(tags("user" -> user, "theme" -> theme, "rated" -> rated))
|
||||
object vote:
|
||||
def count(up: Boolean, win: Boolean) =
|
||||
counter("puzzle.vote.count").withTags:
|
||||
tags(
|
||||
"up" -> up,
|
||||
"win" -> win
|
||||
)
|
||||
def theme(key: String, up: Option[Boolean], win: Boolean) =
|
||||
counter("puzzle.vote.theme").withTags:
|
||||
tags(
|
||||
"up" -> up.fold("cancel")(_.toString),
|
||||
"theme" -> key,
|
||||
"win" -> win
|
||||
)
|
||||
val future = mon.future("puzzle.vote.future")
|
||||
val crazyGlicko = counter("puzzle.crazyGlicko").withoutTags()
|
||||
object storm:
|
||||
object selector:
|
||||
val time = future("storm.selector.time")
|
||||
val sets = histogram("storm.selector.sets").withoutTags()
|
||||
val count = histogram("storm.selector.count").withoutTags()
|
||||
val rating = histogram("storm.selector.rating").withoutTags()
|
||||
def ratingSlice(index: Int) = histogram("storm.selector.ratingSlice").withTag("index", index)
|
||||
object run:
|
||||
def score(auth: Boolean) = histogram("storm.run.score").withTag("auth", auth)
|
||||
def sign(cause: String) = counter("storm.run.sign").withTag("cause", cause)
|
||||
object racer:
|
||||
private def tpe(lobby: Boolean) = if lobby then "lobby" else "friend"
|
||||
def race(lobby: Boolean) = counter("racer.lobby.race").withTag("tpe", tpe(lobby))
|
||||
def players(lobby: Boolean) =
|
||||
histogram("racer.lobby.players").withTag("tpe", tpe(lobby))
|
||||
def score(lobby: Boolean, auth: Boolean) =
|
||||
histogram("racer.player.score").withTags:
|
||||
tags(
|
||||
"tpe" -> tpe(lobby),
|
||||
"auth" -> auth
|
||||
)
|
||||
object streak:
|
||||
object selector:
|
||||
val time = timer("streak.selector.time").withoutTags()
|
||||
val count = histogram("streak.selector.count").withoutTags()
|
||||
val rating = histogram("streak.selector.rating").withoutTags()
|
||||
def ratingSlice(index: Int) = histogram("streak.selector.ratingSlice").withTag("index", index)
|
||||
object run:
|
||||
def score(auth: String) = histogram("streak.run.score").withTag("auth", auth)
|
||||
object game:
|
||||
import chess.{ Speed, Rated, Status }
|
||||
import lila.core.game.Source
|
||||
def finish(variant: Variant, speed: Speed, source: Option[Source], mode: Rated, status: Status) =
|
||||
counter("game.finish").withTags:
|
||||
tags(
|
||||
"variant" -> variant.key,
|
||||
"speed" -> speed.key,
|
||||
"source" -> source.fold("unknown")(_.name),
|
||||
"mode" -> mode.name,
|
||||
"status" -> status.name
|
||||
)
|
||||
val fetch = counter("game.fetch.count").withoutTags()
|
||||
val loadClockHistory = counter("game.loadClockHistory.count").withoutTags()
|
||||
object pgn:
|
||||
def encode(format: String) = timer("game.pgn.encode").withTag("format", format)
|
||||
def decode(format: String) = timer("game.pgn.decode").withTag("format", format)
|
||||
val idCollision = counter("game.idCollision").withoutTags()
|
||||
def idGenerator(collisions: Int) = timer("game.idGenerator").withTags(tags("collisions" -> collisions))
|
||||
object streamByOauthOrigin:
|
||||
def event(tpe: String) = counter("game.streamByOauthOrigin.event").withTag("type", tpe)
|
||||
def users(sel: String) = gauge("game.streamByOauthOrigin.users").withTag("selector", sel)
|
||||
def streams(ua: UserAgent) = gauge("game.streamByOauthOrigin.streams").withTag("ua", ua.value)
|
||||
val bloomFP = counter("game.streamByOauthOrigin.bloomFP").withoutTags()
|
||||
object chat:
|
||||
private val msgCounter = counter("chat.message")
|
||||
def message(parent: String, troll: Boolean) =
|
||||
msgCounter.withTags(tags("parent" -> parent, "troll" -> troll))
|
||||
def fetch(parent: String) = timer("chat.fetch").withTag("parent", parent)
|
||||
object push:
|
||||
object register:
|
||||
def in(platform: String) = counter("push.register").withTag("platform", platform)
|
||||
val out = counter("push.register.out").withoutTags()
|
||||
object web:
|
||||
def post = future("push.web.post")
|
||||
object send:
|
||||
private def send(tpe: String)(platform: String, success: Boolean, count: Int): Unit =
|
||||
counter("push.send")
|
||||
.withTags:
|
||||
tags(
|
||||
"type" -> tpe,
|
||||
"platform" -> platform,
|
||||
"success" -> successTag(success)
|
||||
)
|
||||
.increment(count)
|
||||
()
|
||||
val move = send("move")
|
||||
val takeback = send("takeback")
|
||||
val draw = send("draw")
|
||||
val corresAlarm = send("corresAlarm")
|
||||
val finish = send("finish")
|
||||
val message = send("message")
|
||||
val tourSoon = send("tourSoon")
|
||||
val forumMention = send("forumMention")
|
||||
val invitedStudy = send("invitedStudy")
|
||||
val streamStart = send("streamStart")
|
||||
val broadcastRound = send("broadcastRound")
|
||||
|
||||
object challenge:
|
||||
val create = send("challengeCreate")
|
||||
val accept = send("challengeAccept")
|
||||
val googleTokenTime = timer("push.send.googleToken").withoutTags()
|
||||
def firebaseStatus(project: String, typ: String, status: Int) =
|
||||
counter("push.firebase.status").withTags(tags("status" -> status, "project" -> project, "type" -> typ))
|
||||
object fishnet:
|
||||
object client:
|
||||
object result:
|
||||
private val c = counter("fishnet.client.result")
|
||||
private def apply(r: String)(client: UserId) =
|
||||
c.withTags(tags("client" -> client, "result" -> r))
|
||||
val success = apply("success")
|
||||
val failure = apply("failure")
|
||||
val timeout = apply("timeout")
|
||||
val notFound = apply("notFound")
|
||||
val notAcquired = apply("notAcquired")
|
||||
val abort = apply("abort")
|
||||
def status(enabled: Boolean) = gauge("fishnet.client.status").withTag("enabled", enabled)
|
||||
def version(v: String) = gauge("fishnet.client.version").withTag("version", v.escape)
|
||||
def queueTime(sender: "system" | "user") = timer("fishnet.queue.db").withTag("sender", sender)
|
||||
val acquire = future("fishnet.acquire")
|
||||
def work(typ: String, as: "system" | "user") =
|
||||
gauge("fishnet.work").withTags(tags("type" -> typ, "for" -> as))
|
||||
def oldest(as: "system" | "user") = gauge("fishnet.oldest").withTag("for", as)
|
||||
object analysis:
|
||||
object by:
|
||||
def movetime(client: UserId) = histogram("fishnet.analysis.movetime").withTag("client", client)
|
||||
def node(client: UserId) = histogram("fishnet.analysis.node").withTag("client", client)
|
||||
def nps(client: UserId) = histogram("fishnet.analysis.nps").withTag("client", client)
|
||||
def depth(client: UserId) = histogram("fishnet.analysis.depth").withTag("client", client)
|
||||
def pvSize(client: UserId) = histogram("fishnet.analysis.pvSize").withTag("client", client)
|
||||
def pv(client: UserId, isLong: Boolean) =
|
||||
counter("fishnet.analysis.pvs").withTags(tags("client" -> client, "long" -> isLong))
|
||||
def totalMeganode(client: UserId) =
|
||||
counter("fishnet.analysis.total.meganode").withTag("client", client)
|
||||
def totalSecond(client: UserId) =
|
||||
counter("fishnet.analysis.total.second").withTag("client", client)
|
||||
def requestCount(tpe: "game" | "study") = counter("fishnet.analysis.request").withTag("type", tpe)
|
||||
val evalCacheHits = histogram("fishnet.analysis.evalCacheHits").withoutTags()
|
||||
val skipPositionsGame = future("fishnet.analysis.skipPositions.game")
|
||||
val skipPositionsStudy = future("fishnet.analysis.skipPositions.study")
|
||||
object http:
|
||||
def request(hit: Boolean) = counter("fishnet.http.acquire").withTag("hit", hit)
|
||||
def move(level: Int) = counter("fishnet.move.time").withTag("level", level)
|
||||
def openingBook(variant: Variant, hit: Boolean) =
|
||||
timer("fishnet.opening.hit").withTags:
|
||||
tags("variant" -> variant.key, "hit" -> hitTag(hit))
|
||||
object opening:
|
||||
def searchTime = timer("opening.search.time").withoutTags()
|
||||
object explorer:
|
||||
def stats = future("opening.explorer.stats")
|
||||
object study:
|
||||
object tree:
|
||||
val read = timer("study.tree.read").withoutTags()
|
||||
val write = timer("study.tree.write").withoutTags()
|
||||
object sequencer:
|
||||
val chapterTime = timer("study.sequencer.chapter.time").withoutTags()
|
||||
object api:
|
||||
val users = counter("api.cost").withTag("endpoint", "users")
|
||||
val activity = counter("api.cost").withTag("endpoint", "activity")
|
||||
object challenge:
|
||||
object bulk:
|
||||
def scheduleNb(by: UserId) = counter("api.challenge.bulk.schedule.nb").withTag("by", by)
|
||||
def createNb(by: UserId) = counter("api.challenge.bulk.create.nb").withTag("by", by)
|
||||
object `export`:
|
||||
object png:
|
||||
val game = counter("export.png").withTag("type", "game")
|
||||
val puzzle = counter("export.png").withTag("type", "puzzle")
|
||||
object bus:
|
||||
val classifiers = gauge("bus.classifiers").withoutTags()
|
||||
object blocking:
|
||||
def time(name: String) = timer("blocking.time").withTag("name", name)
|
||||
def timeout(name: String) = counter("blocking.timeout").withTag("name", name)
|
||||
object workQueue:
|
||||
def offerFail(name: String, result: String) =
|
||||
counter("workQueue.offerFail").withTags:
|
||||
tags("name" -> name, "result" -> result)
|
||||
def timeout(name: String) = counter("workQueue.timeout").withTag("name", name)
|
||||
class parallelQueue(name: String):
|
||||
val parallelism = gauge("parallelQueue.parallelism").withTag("name", name)
|
||||
val computeTimeout = counter("parallelQueue.buildTimeout").withTag("name", name)
|
||||
object markdown:
|
||||
val time = timer("markdown.time").withoutTags()
|
||||
def pgnsFromText = future("markdown.pgnsFromText")
|
||||
object ublog:
|
||||
def create(user: UserId) = counter("ublog.create").withTag("user", user)
|
||||
def view = counter("ublog.view").withoutTags()
|
||||
object automod:
|
||||
val request = future("ublog.automod.request")
|
||||
def quality(q: String) = counter("ublog.automod.quality").withTag("quality", q)
|
||||
def flagged(f: Boolean) = counter("ublog.automod.flagged").withTag("flagged", f)
|
||||
object picfit:
|
||||
def uploadTime(user: UserId) = future("picfit.upload.time", tags("user" -> user))
|
||||
def uploadSize(user: UserId) = histogram("picfit.upload.size").withTag("user", user)
|
||||
object fideSync:
|
||||
val time = future("fide.sync.time")
|
||||
val players = gauge("fide.sync.players").withoutTags()
|
||||
val updated = gauge("fide.sync.updated").withoutTags()
|
||||
object recap:
|
||||
val games = future("recap.build.games.time")
|
||||
val puzzles = future("recap.build.puzzles.time")
|
||||
|
||||
object jvm:
|
||||
def threads() =
|
||||
val perState = gauge("jvm.threads.group")
|
||||
val total = gauge("jvm.threads.group.total")
|
||||
for
|
||||
group <- scalalib.Jvm.threadGroups()
|
||||
_ = total.withTags(tags("name" -> group.name)).update(group.total)
|
||||
(state, count) <- group.states
|
||||
yield perState.withTags(tags("name" -> group.name, "state" -> state.toString)).update(count)
|
||||
|
||||
object prometheus:
|
||||
val lines = gauge("prometheus.lines").withoutTags()
|
||||
|
||||
def chronoSync[A] = lila.common.Chronometer.syncMon[A]
|
||||
|
||||
type TimerPath = lila.mon.type => Timer
|
||||
type CounterPath = lila.mon.type => Counter
|
||||
|
||||
private def future(name: String) = (success: Boolean) => timer(name).withTag("success", successTag(success))
|
||||
private def future(name: String, tags: Map[String, Any]) = (success: Boolean) =>
|
||||
timer(name).withTags(tags + ("success" -> successTag(success)))
|
||||
private def future(name: String, segment: String)(success: Boolean) =
|
||||
timer(name).withTags:
|
||||
tags("success" -> successTag(success), "segment" -> segment)
|
||||
|
||||
private def successTag(success: Boolean) = if success then "success" else "failure"
|
||||
private def hitTag(hit: Boolean) = if hit then "hit" else "miss"
|
||||
|
||||
import scala.language.implicitConversions
|
||||
private given Conversion[UserId, String] = _.value
|
||||
private given Conversion[Map[String, Any], TagSet] = TagSet.from
|
||||
@@ -5,7 +5,6 @@ import scalalib.data.LazyFu
|
||||
export lila.core.lilaism.Lilaism.{ *, given }
|
||||
|
||||
object extensions:
|
||||
export Chronometer.futureExtension.*
|
||||
// replaces Product.unapply in play forms
|
||||
def unapply[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): Option[m.MirroredElemTypes] =
|
||||
Some(Tuple.fromProductTyped(p))
|
||||
|
||||
@@ -2,7 +2,6 @@ package lila.db
|
||||
|
||||
import reactivemongo.api.*
|
||||
|
||||
import lila.common.Chronometer
|
||||
import lila.core.config.CollName
|
||||
import lila.db.dsl.Coll
|
||||
|
||||
@@ -37,16 +36,18 @@ final class Db(
|
||||
|
||||
private val logger = lila.db.logger.branch(name)
|
||||
|
||||
private lazy val db: DB = Chronometer.syncEffect(
|
||||
MongoConnection
|
||||
.fromString(uri)
|
||||
.flatMap: parsedUri =>
|
||||
driver
|
||||
.connect(parsedUri, name.some)
|
||||
.flatMap(_.database(parsedUri.db.getOrElse("lichess")))
|
||||
.await(5.seconds, s"db:$name")
|
||||
) { lap =>
|
||||
logger.info(s"MongoDB connected to $uri in ${lap.showDuration}")
|
||||
}
|
||||
private lazy val db: DB =
|
||||
logger.info(s"MongoDB connecting to $uri")
|
||||
val connected = scala.concurrent.Await.result(
|
||||
MongoConnection
|
||||
.fromString(uri)
|
||||
.flatMap: parsedUri =>
|
||||
driver
|
||||
.connect(parsedUri, name.some)
|
||||
.flatMap(_.database(parsedUri.db.getOrElse("lichess"))),
|
||||
5.seconds
|
||||
)
|
||||
logger.info(s"MongoDB connected to $uri")
|
||||
connected
|
||||
|
||||
def apply(name: CollName): Coll = db.collection(name.value)
|
||||
|
||||
@@ -9,6 +9,7 @@ import reactivemongo.api.bson.*
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.time.YearMonth
|
||||
|
||||
import lila.mon.extensions.*
|
||||
import lila.core.fide.Federation
|
||||
import lila.db.dsl.{ *, given }
|
||||
|
||||
@@ -121,7 +122,7 @@ final private class FidePlayerSync(repo: FideRepo, ws: StandaloneWSClient)(using
|
||||
.map(_.toList)
|
||||
.mapAsync(1)(saveIfChanged)
|
||||
.runWith(lila.common.LilaStream.sinkSum)
|
||||
.monSuccess(_.fideSync.time)
|
||||
.monSuccess(lila.mon.fideSync.time)
|
||||
nbAll <- repo.player.countAll
|
||||
yield
|
||||
lila.mon.fideSync.updated.update(nbUpdated)
|
||||
|
||||
@@ -3,6 +3,7 @@ package lila.fishnet
|
||||
import chess.Ply
|
||||
import scalalib.cache.OnceEvery
|
||||
|
||||
import lila.mon.extensions.*
|
||||
import lila.analyse.AnalysisRepo
|
||||
import lila.core.id
|
||||
import lila.fishnet.Work.{ Origin, Sender }
|
||||
@@ -68,7 +69,7 @@ final class Analyser(
|
||||
lila.mon.fishnet.analysis.requestCount("game").increment()
|
||||
evalCache
|
||||
.skipPositions(work.game)
|
||||
.monSuccess(_.fishnet.analysis.skipPositionsGame)
|
||||
.monSuccess(lila.mon.fishnet.analysis.skipPositionsGame)
|
||||
.flatMap: skipPositions =>
|
||||
lila.mon.fishnet.analysis.evalCacheHits.record(skipPositions.size)
|
||||
repo.addAnalysis(work.copy(skipPositions = skipPositions))
|
||||
@@ -119,7 +120,7 @@ final class Analyser(
|
||||
lila.mon.fishnet.analysis.requestCount("study").increment()
|
||||
evalCache
|
||||
.skipPositions(work.game)
|
||||
.monSuccess(_.fishnet.analysis.skipPositionsStudy)
|
||||
.monSuccess(lila.mon.fishnet.analysis.skipPositionsStudy)
|
||||
.withTimeout(2.seconds, s"study analysis skipPositions $work")
|
||||
.recoverDefault
|
||||
.flatMap: skipPositions =>
|
||||
|
||||
@@ -7,6 +7,7 @@ import scala.util.{ Failure, Success, Try }
|
||||
|
||||
import lila.core.lilaism.LilaNoStackTrace
|
||||
import lila.core.net.IpAddress
|
||||
import lila.mon.extensions.*
|
||||
import lila.db.dsl.{ *, given }
|
||||
|
||||
import Client.Skill
|
||||
@@ -30,7 +31,7 @@ final class FishnetApi(
|
||||
maxSize = Max(256),
|
||||
timeout = 5.seconds,
|
||||
name = "fishnetApi",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def keyExists(key: Client.Key) = repo.getEnabledClient(key).map(_.isDefined)
|
||||
@@ -50,7 +51,7 @@ final class FishnetApi(
|
||||
.match
|
||||
case Skill.Move => fufail(s"Can't acquire a move directly on lichess! $client")
|
||||
case Skill.Analysis | Skill.All => acquireAnalysis(client, slow)
|
||||
.monSuccess(_.fishnet.acquire)
|
||||
.monSuccess(lila.mon.fishnet.acquire)
|
||||
.recover { case e: Exception =>
|
||||
logger.error("Fishnet.acquire", e)
|
||||
none
|
||||
|
||||
@@ -9,6 +9,7 @@ import play.api.libs.ws.StandaloneWSClient
|
||||
import scalalib.ThreadLocalRandom
|
||||
|
||||
import lila.common.Json.given
|
||||
import lila.mon.extensions.*
|
||||
import lila.memo.SettingStore
|
||||
|
||||
final private class FishnetOpeningBook(
|
||||
@@ -51,7 +52,7 @@ final private class FishnetOpeningBook(
|
||||
none
|
||||
}
|
||||
.monTry: res =>
|
||||
_.fishnet.openingBook(
|
||||
lila.mon.fishnet.openingBook(
|
||||
variant = game.variant,
|
||||
hit = res.toOption.exists(_.isDefined)
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import lila.analyse.Annotator
|
||||
import lila.core.config.NetDomain
|
||||
import lila.core.game.Player
|
||||
import lila.core.id.GamePlayerId
|
||||
import lila.mon.extensions.*
|
||||
|
||||
import JsonApi.*
|
||||
import readers.given
|
||||
|
||||
@@ -8,6 +8,7 @@ import scala.util.Success
|
||||
|
||||
import lila.core.captcha.{ Captcha, CaptchaApi as ICaptchaApi, Solutions, WithCaptcha }
|
||||
import lila.core.game.Game
|
||||
import lila.mon.extensions.*
|
||||
|
||||
// only works with standard chess (not chess960)
|
||||
final private class CaptchaApi(gameRepo: GameRepo)(using Executor) extends ICaptchaApi:
|
||||
|
||||
@@ -5,23 +5,25 @@ import scalalib.SecureRandom
|
||||
import lila.core.game.{ Game, NewGame }
|
||||
import lila.core.id.GameId
|
||||
import lila.common.BatchProvider
|
||||
import lila.mon.extensions.*
|
||||
import lila.db.dsl.{ *, given }
|
||||
|
||||
final class IdGenerator(gameRepo: GameRepo)(using Executor, Scheduler) extends lila.core.game.IdGenerator:
|
||||
|
||||
import lila.core.game.IdGenerator.*
|
||||
|
||||
private val batchProvider = BatchProvider[GameId]("idGenerator", timeout = 3.seconds): () =>
|
||||
// must NOT use `games(nb)` for it would cause a deadlock
|
||||
// due to `games` calling `game` which calls `batchProvider.one`
|
||||
val ids = List.fill(256)(uncheckedGame).distinct
|
||||
gameRepo.coll
|
||||
.distinctEasy[GameId, List]("_id", $inIds(ids))
|
||||
.monValue: collisions =>
|
||||
_.game.idGenerator(collisions.size)
|
||||
.map:
|
||||
case Nil => ids
|
||||
case collisions => ids.filterNot(collisions.contains)
|
||||
private val batchProvider =
|
||||
BatchProvider[GameId]("idGenerator", timeout = 3.seconds, lila.mon.asyncActorMonitor.full): () =>
|
||||
// must NOT use `games(nb)` for it would cause a deadlock
|
||||
// due to `games` calling `game` which calls `batchProvider.one`
|
||||
val ids = List.fill(256)(uncheckedGame).distinct
|
||||
gameRepo.coll
|
||||
.distinctEasy[GameId, List]("_id", $inIds(ids))
|
||||
.monValue: collisions =>
|
||||
lila.mon.game.idGenerator(collisions.size)
|
||||
.map:
|
||||
case Nil => ids
|
||||
case collisions => ids.filterNot(collisions.contains)
|
||||
|
||||
def game: Fu[GameId] = batchProvider.one
|
||||
|
||||
@@ -34,7 +36,7 @@ final class IdGenerator(gameRepo: GameRepo)(using Executor, Scheduler) extends l
|
||||
gameRepo.coll
|
||||
.distinctEasy[GameId, Set]("_id", $inIds(ids))
|
||||
.monValue: collisions =>
|
||||
_.game.idGenerator(collisions.size)
|
||||
lila.mon.game.idGenerator(collisions.size)
|
||||
.flatMap: collisions =>
|
||||
games(collisions.size).dmap { _ ++ (ids.diff(collisions)) }
|
||||
.map(_.toList)
|
||||
|
||||
@@ -8,15 +8,17 @@ import lila.db.ByteArray
|
||||
|
||||
private object PgnStorage:
|
||||
|
||||
import lila.mon.Chronometer.syncMon as monitor
|
||||
|
||||
object OldBin:
|
||||
|
||||
def encode(sans: Vector[SanStr]) =
|
||||
ByteArray:
|
||||
monitor(_.game.pgn.encode("old")):
|
||||
monitor(lila.mon.game.pgn.encode("old")):
|
||||
format.pgn.Binary.writeMoves(sans).get
|
||||
|
||||
def decode(bytes: ByteArray, plies: Ply): Vector[SanStr] =
|
||||
monitor(_.game.pgn.decode("old")):
|
||||
monitor(lila.mon.game.pgn.decode("old")):
|
||||
format.pgn.Binary.readMoves(bytes.value.toList, plies.value).get.toVector
|
||||
|
||||
object Huffman:
|
||||
@@ -25,11 +27,11 @@ private object PgnStorage:
|
||||
|
||||
def encode(sans: Vector[SanStr]) =
|
||||
ByteArray:
|
||||
monitor(_.game.pgn.encode("huffman")):
|
||||
monitor(lila.mon.game.pgn.encode("huffman")):
|
||||
Encoder.encode(SanStr.raw(sans.toArray))
|
||||
|
||||
def decode(bytes: ByteArray, plies: Ply, id: GameId): Decoded =
|
||||
monitor(_.game.pgn.decode("huffman")):
|
||||
monitor(lila.mon.game.pgn.decode("huffman")):
|
||||
val decoded =
|
||||
try Encoder.decode(bytes.value, plies.value)
|
||||
catch
|
||||
@@ -72,6 +74,3 @@ private object PgnStorage:
|
||||
castles: Castles, // irrelevant after game ends
|
||||
halfMoveClock: HalfMoveClock // irrelevant after game ends
|
||||
)
|
||||
|
||||
private def monitor[A](mon: lila.mon.TimerPath)(f: => A): A =
|
||||
lila.common.Chronometer.syncMon(mon)(f)
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.io.ObjectInputStream
|
||||
import java.util.Map as JMap
|
||||
import scala.jdk.CollectionConverters.*
|
||||
|
||||
import lila.common.Chronometer
|
||||
import lila.core.i18n.{ I18nKey, defaultLang }
|
||||
|
||||
object Registry:
|
||||
@@ -26,11 +25,8 @@ object Registry:
|
||||
.zipWithIndex
|
||||
.foreach: (langs, i) =>
|
||||
scheduler.scheduleOnce(i.seconds):
|
||||
val lap = Chronometer.sync:
|
||||
langs.foreach: lang =>
|
||||
register(lang, loadSerialized(lang))
|
||||
if i < 1 || mode.isProd
|
||||
then logger.info(s"Loaded ${langs.size} languages in ${lap.showDuration}")
|
||||
langs.foreach: lang =>
|
||||
register(lang, loadSerialized(lang))
|
||||
|
||||
// for tests
|
||||
private[i18n] def getAll(lang: Lang): Option[MessageMap] = all.get(lang)
|
||||
|
||||
@@ -3,6 +3,7 @@ package lila.insight
|
||||
import scalalib.HeapSort.botN
|
||||
|
||||
import lila.game.GameRepo
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class InsightApi(
|
||||
storage: InsightStorage,
|
||||
@@ -41,14 +42,14 @@ final class InsightApi(
|
||||
gameRepo.userPovsByGameIds(clusters.flatMap(_.gameIds).botN(4), user)
|
||||
.map { Answer(question, clusters, _) }
|
||||
}
|
||||
.monSuccess(_.insight.user)
|
||||
.monSuccess(lila.mon.insight.user)
|
||||
|
||||
def askPeers[X](question: Question[X], rating: MeanRating, nbGames: Max): Fu[Answer[X]] =
|
||||
pipeline
|
||||
.aggregate(question, Right(PeersRatingRange.of(rating)), withPovs = false, nbGames = nbGames)
|
||||
.map: aggDocs =>
|
||||
Answer(question, AggregationClusters(question, aggDocs), Nil)
|
||||
.monSuccess(_.insight.peers)
|
||||
.monSuccess(lila.mon.insight.peers)
|
||||
|
||||
def userStatus(user: User): Fu[UserStatus] =
|
||||
indexer
|
||||
@@ -65,7 +66,7 @@ final class InsightApi(
|
||||
case _ => UserStatus.Fresh
|
||||
|
||||
def indexAll(user: User, force: Boolean): Funit =
|
||||
for _ <- indexer.all(user, force).monSuccess(_.insight.index)
|
||||
for _ <- indexer.all(user, force).monSuccess(lila.mon.insight.index)
|
||||
yield userCache.put(user.id, computeUser(user.id))
|
||||
|
||||
def updateGame(g: Game) =
|
||||
|
||||
@@ -19,7 +19,7 @@ final private class InsightIndexer(
|
||||
maxSize = Max(256),
|
||||
timeout = 1.minute,
|
||||
name = "insightIndexer",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def all(user: User, force: Boolean): Funit =
|
||||
|
||||
@@ -7,6 +7,7 @@ import play.api.libs.ws.JsonBodyReadables.*
|
||||
import play.api.libs.ws.{ StandaloneWSClient, WSAuthScheme }
|
||||
|
||||
import lila.common.String.urlencode
|
||||
import lila.mon.extensions.*
|
||||
import lila.core.config.Secret
|
||||
|
||||
final private class ZulipClient(ws: StandaloneWSClient, config: ZulipClient.Config)(using
|
||||
@@ -54,7 +55,7 @@ final private class ZulipClient(ws: StandaloneWSClient, config: ZulipClient.Conf
|
||||
case JsSuccess(result, _) => fuccess(result.some)
|
||||
case JsError(err) => fufail(s"[zulip]: $err, $msg ${res.status} ${res.body}")
|
||||
case res => fufail(s"[zulip] $msg ${res.status} ${res.body}")
|
||||
.monSuccess(_.irc.zulip.say(msg.stream))
|
||||
.monSuccess(lila.mon.irc.zulip.say(msg.stream))
|
||||
.logFailure(lila.log("zulip"))
|
||||
.recoverDefault
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ final class KaladinApi(
|
||||
maxSize = Max(512),
|
||||
timeout = 2.minutes,
|
||||
name = "kaladinApi",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
private def sequence[A <: Matchable](user: Suspect)(f: Option[KaladinUser] => Fu[A]): Fu[A] =
|
||||
|
||||
@@ -5,6 +5,7 @@ import scalalib.actor.SyncActor
|
||||
import lila.common.Bus
|
||||
import lila.core.pool.{ HookThieve, IsClockCompatible }
|
||||
import lila.core.socket.{ Sri, Sris }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class LobbySyncActor(
|
||||
seekApi: SeekApi,
|
||||
@@ -98,7 +99,7 @@ final private class LobbySyncActor(
|
||||
.chronometer
|
||||
.logIfSlow(100, logger): r =>
|
||||
s"GetSris size=${r.sris.size}"
|
||||
.mon(_.lobby.socket.getSris)
|
||||
.mon(lila.mon.lobby.socket.getSris)
|
||||
.result
|
||||
.logFailure(logger, err => s"broom cannot get sris from socket: $err")
|
||||
.foreach { this ! WithPromise(_, promise) }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package lila.mailer
|
||||
|
||||
import scala.concurrent.blocking
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import play.api.ConfigLoader
|
||||
import play.api.libs.mailer.{ Email, SMTPConfiguration, SMTPMailer }
|
||||
@@ -7,8 +9,7 @@ import scalatags.Text.all.{ html as htmlTag, * }
|
||||
import scalatags.Text.tags2.title as titleTag
|
||||
import org.apache.commons.mail.EmailException
|
||||
|
||||
import scala.concurrent.blocking
|
||||
|
||||
import lila.mon.extensions.*
|
||||
import lila.common.String.html.nl2br
|
||||
import lila.common.autoconfig.*
|
||||
import lila.core.i18n.I18nKey.emails as trans
|
||||
@@ -71,7 +72,7 @@ final class Mailer(
|
||||
)
|
||||
blocking:
|
||||
client.mailer.send(email)
|
||||
.monSuccess(_.email.send.time(client.toString))
|
||||
.monSuccess(lila.mon.email.send.time(client.toString))
|
||||
.recoverWith:
|
||||
case _: EmailException if msg.to.normalize.value != msg.to.value =>
|
||||
logger.warn(s"Email ${msg.to} is invalid, trying ${msg.to.normalize}")
|
||||
|
||||
@@ -3,6 +3,7 @@ package lila.memo
|
||||
import scalalib.future.TimeoutException
|
||||
|
||||
import lila.common.{ Bus, Markdown, MarkdownRender, MarkdownToastUi }
|
||||
import lila.mon.extensions.*
|
||||
import lila.core.config
|
||||
import lila.core.misc.lpv.{ LpvEmbed, Lpv as LpvBus }
|
||||
|
||||
@@ -66,7 +67,7 @@ final class MarkdownCache(
|
||||
.logIfSlow(300, logger): result =>
|
||||
s"AllPgnsFromText for markdown $key - found ${result.size} embeds"
|
||||
.result
|
||||
.monSuccess(_.markdown.pgnsFromText)
|
||||
.monSuccess(lila.mon.markdown.pgnsFromText)
|
||||
.andThen:
|
||||
case scala.util.Success(pgns) => cache.putAll(pgns)
|
||||
.recoverWith:
|
||||
@@ -93,9 +94,14 @@ final class MarkdownCache(
|
||||
)
|
||||
)
|
||||
|
||||
private def bodyProcessor(key: RenderKey, opts: MarkdownOptions): Markdown => Html =
|
||||
if opts.toastUi then toastUiProcessor(key, opts)
|
||||
else getRenderer(opts)(key)
|
||||
private def bodyProcessor(key: RenderKey, opts: MarkdownOptions)(text: Markdown): Html =
|
||||
lila.mon.Chronometer
|
||||
.sync:
|
||||
if opts.toastUi then toastUiProcessor(key, opts)(text)
|
||||
else getRenderer(opts)(key)(text)
|
||||
.mon(lila.mon.markdown.time)
|
||||
.logIfSlow(50, logger.branch(key))(_ => s"slow markdown size:${text.value.size}")
|
||||
.result
|
||||
|
||||
private def toastUiProcessor(key: RenderKey, opts: MarkdownOptions): Markdown => Html =
|
||||
MarkdownToastUi.unescapeAtUsername.apply
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.github.blemale.scaffeine.AsyncLoadingCache
|
||||
import reactivemongo.api.bson.*
|
||||
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
import CacheApi.*
|
||||
|
||||
@@ -36,7 +37,7 @@ final class MongoCache[K, V: BSONHandler] private (
|
||||
)
|
||||
.inject(v)
|
||||
}
|
||||
.mon(_.mongoCache.compute(name))
|
||||
.mon(lila.mon.mongoCache.compute(name))
|
||||
case Some(entry) =>
|
||||
lila.mon.mongoCache.request(name, hit = true).increment()
|
||||
fuccess(entry.v)
|
||||
|
||||
@@ -29,7 +29,7 @@ final class MongoRateLimit[K](
|
||||
expiration = 1.minute,
|
||||
timeout = 10.seconds,
|
||||
name = s"$name.sequencer",
|
||||
lila.log.asyncActorMonitor.highCardinality
|
||||
lila.mon.asyncActorMonitor.highCardinality
|
||||
)
|
||||
|
||||
private def makeDbKey(k: K) = s"ratelimit:$name:${keyToString(k)}"
|
||||
|
||||
@@ -50,7 +50,7 @@ final class ParallelMongoQueue[A: BSONHandler](
|
||||
maxSize = Max(256),
|
||||
timeout = 5.seconds,
|
||||
s"$name.workQueue",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
/* Read the oldest <parallelism()> entries from the queue
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit
|
||||
import scala.util.Success
|
||||
|
||||
import lila.common.Uptime
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/** A synchronous cache from asynchronous computations. It will attempt to serve cached responses
|
||||
* synchronously. If none is available, it starts an async computation, and either waits for the result or
|
||||
@@ -37,7 +38,7 @@ final class Syncache[K, V](
|
||||
new CacheLoader[K, Fu[V]]:
|
||||
def load(k: K) =
|
||||
compute(k)
|
||||
.mon(_ => recCompute) // monitoring: record async time
|
||||
.mon(recCompute) // monitoring: record async time
|
||||
.recover { case e: Exception =>
|
||||
logger.branch(s"syncache $name").warn(s"key=$k", e)
|
||||
cache.invalidate(k)
|
||||
@@ -79,15 +80,15 @@ final class Syncache[K, V](
|
||||
|
||||
private def waitForResult(k: K, fu: Fu[V], duration: FiniteDuration): V =
|
||||
try
|
||||
lila.common.Chronometer.syncMon(_ => recWait):
|
||||
lila.mon.Chronometer.syncMon(recWait):
|
||||
fu.await(duration, s"syncache:$name")
|
||||
catch
|
||||
case _: java.util.concurrent.TimeoutException =>
|
||||
incTimeout()
|
||||
default(k)
|
||||
|
||||
private val incMiss = (() => lila.mon.syncache.miss(name).increment())
|
||||
private val incTimeout = (() => lila.mon.syncache.timeout(name).increment())
|
||||
private val incMiss = () => lila.mon.syncache.miss(name).increment()
|
||||
private val incTimeout = () => lila.mon.syncache.timeout(name).increment()
|
||||
private val recWait = lila.mon.syncache.wait(name)
|
||||
private val recCompute = lila.mon.syncache.compute(name)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import scala.util.matching.Regex.quote
|
||||
import scalalib.paginator.AdapterLike
|
||||
|
||||
import lila.common.Bus
|
||||
import lila.mon.extensions.*
|
||||
import lila.core.id.ImageId
|
||||
import lila.db.dsl.{ *, given }
|
||||
|
||||
@@ -182,7 +183,7 @@ final class PicfitApi(
|
||||
if image.size > 0 then lila.mon.picfit.uploadSize(image.user).record(image.size)
|
||||
funit
|
||||
}
|
||||
.monSuccess(_.picfit.uploadTime(image.user))
|
||||
.monSuccess(lila.mon.picfit.uploadTime(image.user))
|
||||
|
||||
def delete(image: PicfitImage): Funit =
|
||||
ws.url(s"${config.endpointPost}/${image.id}")
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package lila.mon
|
||||
|
||||
import play.api.Logger
|
||||
|
||||
object asyncActorMonitor:
|
||||
|
||||
private lazy val logger = Logger("asyncActor")
|
||||
|
||||
lazy val full = scalalib.actor.AsyncActorBounded.Monitor(
|
||||
overflow = name =>
|
||||
lila.mon.asyncActor.overflow(name).increment()
|
||||
logger.warn(s"[$name] queue is full")
|
||||
,
|
||||
queueSize = (name, size) => lila.mon.asyncActor.queueSize(name).record(size),
|
||||
unhandled = (name, msg) => logger.warn(s"[$name] unhandled msg: $msg")
|
||||
)
|
||||
|
||||
lazy val highCardinality = full.copy(
|
||||
queueSize = (_, _) => ()
|
||||
)
|
||||
|
||||
lazy val unhandled = full.copy(
|
||||
overflow = _ => (),
|
||||
queueSize = (_, _) => ()
|
||||
)
|
||||
+27
-20
@@ -1,4 +1,11 @@
|
||||
package lila.common
|
||||
package lila.mon
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import kamon.metric.Timer
|
||||
import play.api.LoggerLike
|
||||
|
||||
import lila.core.lilaism.Lilaism.*
|
||||
|
||||
object Chronometer:
|
||||
|
||||
@@ -8,7 +15,7 @@ object Chronometer:
|
||||
extension [A](fua: Future[A])
|
||||
|
||||
def await(duration: FiniteDuration, name: String): A =
|
||||
Chronometer.syncMon(_.blocking.time(name)):
|
||||
Chronometer.syncMon(lila.mon.blocking.time(name)):
|
||||
try Await.result(fua, duration)
|
||||
catch
|
||||
case e: Exception =>
|
||||
@@ -21,15 +28,15 @@ object Chronometer:
|
||||
def chronometer = Chronometer(fua)
|
||||
def chronometerTry = Chronometer.lapTry(fua)
|
||||
|
||||
def mon(path: lila.mon.TimerPath): Fu[A] = chronometer.mon(path).result
|
||||
def monTry(path: scala.util.Try[A] => lila.mon.TimerPath): Fu[A] =
|
||||
chronometerTry.mon(r => path(r)(lila.mon)).result
|
||||
def monSuccess(path: lila.mon.type => Boolean => kamon.metric.Timer): Fu[A] =
|
||||
def mon(path: Timer): Fu[A] = chronometer.mon(path).result
|
||||
def monTry(path: scala.util.Try[A] => Timer): Fu[A] =
|
||||
chronometerTry.mon(r => path(r)).result
|
||||
def monSuccess(path: Boolean => kamon.metric.Timer): Fu[A] =
|
||||
chronometerTry
|
||||
.mon: r =>
|
||||
path(lila.mon)(r.isSuccess)
|
||||
path(r.isSuccess)
|
||||
.result
|
||||
def monValue(path: A => lila.mon.TimerPath): Fu[A] = chronometer.monValue(path).result
|
||||
def monValue(path: A => Timer): Fu[A] = chronometer.monValue(path).result
|
||||
|
||||
def logTime(name: String): Fu[A] = chronometer.pp(name)
|
||||
def logTimeIfGt(name: String, duration: FiniteDuration): Fu[A] = chronometer.ppIfGt(name, duration)
|
||||
@@ -41,19 +48,19 @@ object Chronometer:
|
||||
def micros = (nanos / 1000).toInt
|
||||
def seconds = (millis / 1000).toInt
|
||||
|
||||
def logIfSlow(threshold: Int, logger: lila.log.Logger)(msg: A => String) =
|
||||
def logIfSlow(threshold: Int, logger: LoggerLike)(msg: A => String) =
|
||||
if millis >= threshold then log(logger)(msg)
|
||||
else this
|
||||
def log(logger: lila.log.Logger)(msg: A => String) =
|
||||
def log(logger: LoggerLike)(msg: A => String) =
|
||||
logger.info(s"<${millis}ms> ${msg(result)}")
|
||||
this
|
||||
|
||||
def mon(path: lila.mon.TimerPath) =
|
||||
path(lila.mon).record(nanos)
|
||||
def mon(path: Timer) =
|
||||
path.record(nanos)
|
||||
this
|
||||
|
||||
def monValue(path: A => lila.mon.TimerPath) =
|
||||
path(result)(lila.mon).record(nanos)
|
||||
def monValue(path: A => Timer) =
|
||||
path(result).record(nanos)
|
||||
this
|
||||
|
||||
def pp: A =
|
||||
@@ -74,19 +81,19 @@ object Chronometer:
|
||||
|
||||
case class FuLap[A](lap: Fu[Lap[A]]) extends AnyVal:
|
||||
|
||||
def logIfSlow(threshold: Int, logger: lila.log.Logger)(msg: A => String) =
|
||||
def logIfSlow(threshold: Int, logger: LoggerLike)(msg: A => String) =
|
||||
lap.dforeach(_.logIfSlow(threshold, logger)(msg))
|
||||
this
|
||||
|
||||
def mon(path: lila.mon.TimerPath) =
|
||||
def mon(path: Timer) =
|
||||
lap.dforeach(_.mon(path))
|
||||
this
|
||||
|
||||
def monValue(path: A => lila.mon.TimerPath) =
|
||||
def monValue(path: A => Timer) =
|
||||
lap.dforeach(_.monValue(path))
|
||||
this
|
||||
|
||||
def log(logger: lila.log.Logger)(msg: A => String) =
|
||||
def log(logger: LoggerLike)(msg: A => String) =
|
||||
lap.dforeach(_.log(logger)(msg))
|
||||
this
|
||||
|
||||
@@ -133,8 +140,8 @@ object Chronometer:
|
||||
effect(lap)
|
||||
lap.result
|
||||
|
||||
def syncMon[A](path: lila.mon.TimerPath)(f: => A): A =
|
||||
val timer = path(lila.mon).start()
|
||||
def syncMon[A](path: Timer)(f: => A): A =
|
||||
val timer = path.start()
|
||||
val res = f
|
||||
timer.stop()
|
||||
res
|
||||
@@ -0,0 +1,753 @@
|
||||
package lila.mon
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache as CaffeineCache
|
||||
import kamon.metric.Timer
|
||||
import kamon.tag.TagSet
|
||||
import kamon.Kamon.{ timer, gauge, counter, histogram }
|
||||
import chess.variant.Variant
|
||||
|
||||
import lila.core.id.*
|
||||
import lila.core.net.*
|
||||
import lila.core.userId.{ UserId, UserName }
|
||||
import lila.core.perf.PerfKey
|
||||
|
||||
// https://github.com/kamon-io/Kamon/issues/752
|
||||
extension (s: String)
|
||||
def escape: String =
|
||||
val builder = java.lang.StringBuilder(s.length)
|
||||
for c <- s.toCharArray do
|
||||
if c != '"' && c != '\n' && c != '\\'
|
||||
then builder.append(c)
|
||||
builder.toString
|
||||
|
||||
private def tags(elems: (String, Any)*): Map[String, Any] = Map.from(elems)
|
||||
|
||||
object http:
|
||||
private val reqTime = timer("http.time")
|
||||
private val reqCount = counter("http.count")
|
||||
private val mobCount = counter("http.mobile.count")
|
||||
|
||||
def time(action: String) = reqTime.withTag("action", action)
|
||||
|
||||
def count(action: String, client: String, method: String, code: Int) =
|
||||
reqCount.withTags:
|
||||
tags("action" -> action, "client" -> client, "method" -> method, "code" -> code.toLong)
|
||||
|
||||
def errorCount(action: String, client: String, method: String, code: Int) =
|
||||
counter("http.error").withTags:
|
||||
tags("action" -> action, "client" -> client, "method" -> method, "code" -> code.toLong)
|
||||
|
||||
def mobileCount(action: String, version: String, auth: Boolean, os: String) =
|
||||
mobCount.withTags:
|
||||
tags(
|
||||
"action" -> action,
|
||||
"version" -> version,
|
||||
"auth" -> (if auth then "auth" else "anon"),
|
||||
"os" -> os
|
||||
)
|
||||
|
||||
def path(p: String) = counter("http.path.count").withTag("path", p.escape)
|
||||
val userGamesCost = counter("http.userGames.cost").withoutTags()
|
||||
def csrfError(tpe: String, action: String, client: String) =
|
||||
counter("http.csrf.error").withTags(tags("type" -> tpe, "action" -> action, "client" -> client))
|
||||
val fingerPrint = timer("http.fingerPrint.time").withoutTags()
|
||||
object syncache:
|
||||
def miss(name: String) = counter("syncache.miss").withTag("name", name)
|
||||
def timeout(name: String) = counter("syncache.timeout").withTag("name", name)
|
||||
def compute(name: String) = timer("syncache.compute").withTag("name", name)
|
||||
def wait(name: String) = timer("syncache.wait").withTag("name", name)
|
||||
def caffeineStats(cache: CaffeineCache[?, ?], name: String): Unit =
|
||||
val stats = cache.stats
|
||||
gauge("caffeine.request").withTags(tags("name" -> name, "hit" -> true)).update(stats.hitCount.toDouble)
|
||||
gauge("caffeine.request").withTags(tags("name" -> name, "hit" -> false)).update(stats.missCount.toDouble)
|
||||
histogram("caffeine.hit.rate").withTag("name", name).record((stats.hitRate * 100000).toLong)
|
||||
if stats.totalLoadTime > 0 then
|
||||
gauge("caffeine.load.count")
|
||||
.withTags(tags("name" -> name, "success" -> "success"))
|
||||
.update(stats.loadSuccessCount.toDouble)
|
||||
gauge("caffeine.load.count")
|
||||
.withTags(tags("name" -> name, "success" -> "failure"))
|
||||
.update(stats.loadFailureCount.toDouble)
|
||||
gauge("caffeine.loadTime.cumulated")
|
||||
.withTag("name", name)
|
||||
.update(stats.totalLoadTime / 1000000d) // in millis; too much nanos for Kamon to handle)
|
||||
timer("caffeine.loadTime.penalty").withTag("name", name).record(stats.averageLoadPenalty.toLong)
|
||||
gauge("caffeine.eviction.count").withTag("name", name).update(stats.evictionCount.toDouble)
|
||||
gauge("caffeine.entry.count").withTag("name", name).update(cache.estimatedSize.toDouble)
|
||||
object mongoCache:
|
||||
def request(name: String, hit: Boolean) =
|
||||
counter("mongocache.request").withTags:
|
||||
tags(
|
||||
"name" -> name,
|
||||
"hit" -> hit
|
||||
)
|
||||
def compute(name: String) = timer("mongocache.compute").withTag("name", name)
|
||||
object evalCache:
|
||||
private val r = counter("evalCache.request")
|
||||
def request(ply: Int, isHit: Boolean) =
|
||||
r.withTags(tags("ply" -> (if ply < 15 then ply.toString else "15+"), "hit" -> isHit))
|
||||
object upgrade:
|
||||
val count = counter("evalCache.upgrade.count").withoutTags()
|
||||
val members = gauge("evalCache.upgrade.members").withoutTags()
|
||||
val evals = gauge("evalCache.upgrade.evals").withoutTags()
|
||||
val expirable = gauge("evalCache.upgrade.expirable").withoutTags()
|
||||
object lobby:
|
||||
object hook:
|
||||
val create = counter("lobby.hook.create").withoutTags()
|
||||
val join = counter("lobby.hook.join").withoutTags()
|
||||
val size = histogram("lobby.hook.size").withoutTags()
|
||||
def apiCreate(client: String) = counter("lobby.hook.apiCreate").withTag("client", client)
|
||||
object seek:
|
||||
val create = counter("lobby.seek.create").withoutTags()
|
||||
val join = counter("lobby.seek.join").withoutTags()
|
||||
object socket:
|
||||
val getSris = timer("lobby.socket.getSris").withoutTags()
|
||||
val member = gauge("lobby.socket.member").withoutTags()
|
||||
val idle = gauge("lobby.socket.idle").withoutTags()
|
||||
val hookSubscribers = gauge("lobby.socket.hookSubscribers").withoutTags()
|
||||
object pool:
|
||||
object wave:
|
||||
def scheduled(id: String) = counter("lobby.pool.wave.scheduled").withTag("pool", id)
|
||||
def full(id: String) = counter("lobby.pool.wave.full").withTag("pool", id)
|
||||
def candidates(id: String) = histogram("lobby.pool.wave.candidates").withTag("pool", id)
|
||||
def paired(id: String) = histogram("lobby.pool.wave.paired").withTag("pool", id)
|
||||
def missed(id: String) = histogram("lobby.pool.wave.missed").withTag("pool", id)
|
||||
def ratingDiff(id: String) = histogram("lobby.pool.wave.ratingDiff").withTag("pool", id)
|
||||
def withRange(id: String) = histogram("lobby.pool.wave.withRange").withTag("pool", id)
|
||||
object thieve:
|
||||
def stolen(id: String) = histogram("lobby.pool.thieve.stolen").withTag("pool", id)
|
||||
private val lobbySegment = timer("lobby.segment")
|
||||
def segment(seg: String) = lobbySegment.withTag("segment", seg)
|
||||
object rating:
|
||||
def distribution(perfKey: PerfKey, rating: Int) =
|
||||
gauge("rating.distribution").withTags(tags("perf" -> perfKey, "rating" -> rating.toLong))
|
||||
object regulator:
|
||||
def micropoints(perfKey: PerfKey) = histogram("rating.regulator").withTag("perf", perfKey.value)
|
||||
object perfStat:
|
||||
def indexTime = timer("perfStat.indexTime").withoutTags()
|
||||
|
||||
object round:
|
||||
object api:
|
||||
val player = timer("round.api").withTag("endpoint", "player")
|
||||
val watcher = timer("round.api").withTag("endpoint", "watcher")
|
||||
object forecast:
|
||||
val create = counter("round.forecast.create").withoutTags()
|
||||
object move:
|
||||
object lag:
|
||||
val compDeviation = histogram("round.move.lag.comp_deviation").withoutTags()
|
||||
def uncomped(key: String) = histogram("round.move.lag.uncomped_ms").withTag("key", key)
|
||||
def uncompStdDev(key: String) = histogram("round.move.lag.uncomp_stdev_ms").withTag("key", key)
|
||||
val stdDev = histogram("round.move.lag.stddev_ms").withoutTags()
|
||||
val mean = histogram("round.move.lag.mean_ms").withoutTags()
|
||||
val coefVar = histogram("round.move.lag.coef_var_1000").withoutTags()
|
||||
val compEstStdErr = histogram("round.move.lag.comp_est_stderr_1000").withoutTags()
|
||||
val compEstOverErr = histogram("round.move.lag.avg_over_error_ms").withoutTags()
|
||||
val moveComp = timer("round.move.lag.comped").withoutTags()
|
||||
val time = timer("round.move.time").withoutTags()
|
||||
object error:
|
||||
val client = counter("round.error").withTag("from", "client")
|
||||
val fishnet = counter("round.error").withTag("from", "fishnet")
|
||||
val glicko = counter("round.error").withTag("from", "glicko")
|
||||
val other = counter("round.error").withTag("from", "other")
|
||||
object titivate:
|
||||
val time = future("round.titivate.time")
|
||||
val game = histogram("round.titivate.game").withoutTags() // how many games were processed
|
||||
val total = histogram("round.titivate.total").withoutTags() // how many games should have been processed
|
||||
val old = histogram("round.titivate.old").withoutTags() // how many old games remain
|
||||
def broken(error: String) = counter("round.titivate.broken").withTag("error", error) // broken game
|
||||
object alarm:
|
||||
val time = timer("round.alarm.time").withoutTags()
|
||||
object expiration:
|
||||
val count = counter("round.expiration.count").withoutTags()
|
||||
val asyncActorCount = gauge("round.asyncActor.count").withoutTags()
|
||||
object correspondenceEmail:
|
||||
val emails = histogram("round.correspondenceEmail.emails").withoutTags()
|
||||
val time = future("round.correspondenceEmail.time")
|
||||
object farming:
|
||||
val bot = counter("round.farming.bot").withoutTags()
|
||||
val provisional = counter("round.farming.provisional").withoutTags()
|
||||
object playban:
|
||||
def outcome(out: String) = counter("playban.outcome").withTag("outcome", out)
|
||||
object ban:
|
||||
val count = counter("playban.ban.count").withoutTags()
|
||||
val mins = histogram("playban.ban.mins").withoutTags()
|
||||
object explorer:
|
||||
object index:
|
||||
def count(success: Boolean) = counter("explorer.index.count").withTag("success", successTag(success))
|
||||
val time = timer("explorer.index.time").withoutTags()
|
||||
object timeline:
|
||||
val notification = counter("timeline.notification").withoutTags()
|
||||
object insight:
|
||||
val user = future("insight.request.time", "user")
|
||||
val peers = future("insight.request.time", "peer")
|
||||
val index = future("insight.index.time")
|
||||
object tutor:
|
||||
def buildSegment(segment: String) = future("tutor.build.segment", segment)
|
||||
val buildFull = future("tutor.build.full")
|
||||
val askMine = askAs("mine")
|
||||
val askPeer = askAs("peer")
|
||||
val buildTimeout = counter("tutor.build.timeout").withoutTags()
|
||||
def peerMatch(hit: Boolean, perf: PerfKey) = counter("tutor.peerMatch").withTags:
|
||||
tags("hit" -> hitTag(hit), "perf" -> perf)
|
||||
val parallelism = gauge("tutor.build.parallelism").withoutTags()
|
||||
val fishnetMissing = histogram("tutor.fishnet.missing").withoutTags()
|
||||
private def askAs(as: "mine" | "peer")(question: String, perf: PerfKey | "all") =
|
||||
future("tutor.insight.ask", tags("question" -> question, "perf" -> perf, "as" -> as))
|
||||
object search:
|
||||
def time(op: "search" | "count", index: String, success: Boolean) =
|
||||
timer("search.client.time").withTags:
|
||||
tags(
|
||||
"op" -> op,
|
||||
"index" -> index,
|
||||
"success" -> successTag(success)
|
||||
)
|
||||
object asyncActor:
|
||||
def overflow(name: String) = counter("asyncActor.overflow").withTag("name", name)
|
||||
def queueSize(name: String) = histogram("asyncActor.queueSize").withTag("name", name)
|
||||
object irc:
|
||||
object zulip:
|
||||
def say(stream: String) = future("irc.zulip.say", tags("stream" -> stream.escape))
|
||||
object user:
|
||||
val online = gauge("user.online").withoutTags()
|
||||
object register:
|
||||
def count(
|
||||
confirm: String,
|
||||
ipSusp: Boolean,
|
||||
fp: Boolean,
|
||||
proxy: Option[String],
|
||||
country: String,
|
||||
client: String
|
||||
) =
|
||||
counter("user.register.count").withTags:
|
||||
tags(
|
||||
"confirm" -> confirm,
|
||||
"ipSusp" -> ipSusp,
|
||||
"fp" -> fp,
|
||||
"proxy" -> proxy.getOrElse("no"),
|
||||
"country" -> country.escape,
|
||||
"client" -> client
|
||||
)
|
||||
def result(client: String, result: String) =
|
||||
counter("user.register.result").withTags:
|
||||
tags("client" -> client, "result" -> result)
|
||||
def mustConfirmEmail(v: String) = counter("user.register.mustConfirmEmail").withTag("type", v)
|
||||
def confirmEmailResult(success: Boolean) =
|
||||
counter("user.register.confirmEmail").withTag("success", successTag(success))
|
||||
def modConfirmEmail(by: "mod" | "worker", result: String) =
|
||||
counter("user.register.modConfirmEmail").withTags:
|
||||
tags("by" -> by, "result" -> result)
|
||||
object auth:
|
||||
val bcFullMigrate = counter("user.auth.bcFullMigrate").withoutTags()
|
||||
val hashTime = timer("user.auth.hashTime").withoutTags()
|
||||
def count(success: Boolean) = counter("user.auth.count").withTag("success", successTag(success))
|
||||
|
||||
def passwordResetRequest(s: String) = counter("user.auth.passwordResetRequest").withTag("type", s)
|
||||
def passwordResetConfirm(s: String) = counter("user.auth.passwordResetConfirm").withTag("type", s)
|
||||
|
||||
def reopenRequest(s: String) = counter("user.auth.reopenRequest").withTag("type", s)
|
||||
def reopenConfirm(s: String) = counter("user.auth.reopenConfirm").withTag("type", s)
|
||||
object oauth:
|
||||
def request(success: Boolean) = counter("user.oauth.request").withTags:
|
||||
tags("success" -> successTag(success))
|
||||
private val userSegment = timer("user.segment")
|
||||
def segment(seg: String) = userSegment.withTag("segment", seg)
|
||||
def leaderboardCompute = future("user.leaderboard.compute")
|
||||
def weeklyStableRanking(perf: PerfKey) = future("user.weeklyStableRanking", perf.value)
|
||||
object actor:
|
||||
def queueSize(name: String) = gauge("trouper.queueSize").withTag("name", name)
|
||||
object mod:
|
||||
object report:
|
||||
val highest = gauge("mod.report.highest").withoutTags()
|
||||
val close = counter("mod.report.close").withoutTags()
|
||||
def create(reason: String, score: Int) =
|
||||
counter("mod.report.create").withTags:
|
||||
tags("reason" -> reason, "score" -> score)
|
||||
object automod:
|
||||
val request = future("mod.report.automod.request")
|
||||
def assessment(a: String) = counter("mod.report.automod.assessment").withTag("assessment", a)
|
||||
val imageRequest = future("mod.report.automod.image.request")
|
||||
def imageFlagged(v: Boolean) = counter("mod.report.automod.image.flagged").withTag("flagged", v)
|
||||
object log:
|
||||
val create = counter("mod.log.create").withoutTags()
|
||||
object irwin:
|
||||
val report = counter("mod.report.irwin.report").withoutTags()
|
||||
val mark = counter("mod.report.irwin.mark").withoutTags()
|
||||
def ownerReport(name: String) = counter("mod.irwin.ownerReport").withTag("name", name)
|
||||
def streamEventType(name: String) = counter("mod.irwin.stream.eventType").withTag("name", name)
|
||||
object kaladin:
|
||||
def request(by: String) = counter("mod.kaladin.request").withTag("by", by)
|
||||
def insufficientMoves(by: String) = counter("mod.kaladin.insufficientMoves").withTag("by", by)
|
||||
def queue(priority: Int) = gauge("mod.kaladin.queue").withTag("priority", priority)
|
||||
def error(errKind: String) = counter("mod.kaladin.error").withTag("error", errKind)
|
||||
val activation = histogram("mod.report.kaladin.activation").withoutTags()
|
||||
val report = counter("mod.report.kaladin.report").withoutTags()
|
||||
val mark = counter("mod.report.kaladin.mark").withoutTags()
|
||||
object comm:
|
||||
def segment(seg: String) = timer("mod.comm.segmentLat").withTag("segment", seg)
|
||||
def zoneSegment(name: String) = future("mod.zone.segment", name)
|
||||
object relay:
|
||||
private def by(official: Boolean) = if official then "official" else "user"
|
||||
private def relay(official: Boolean, id: RelayTourId, slug: String) =
|
||||
tags("by" -> by(official), "slug" -> s"$slug/$id")
|
||||
def ongoing(official: Boolean) = gauge("relay.ongoing").withTag("by", by(official))
|
||||
val crowdMonitor = gauge("relay.crowdMonitor").withoutTags()
|
||||
def moves(official: Boolean, id: RelayTourId, slug: String) =
|
||||
counter("relay.moves").withTags(relay(official, id, slug))
|
||||
def fetchTime(official: Boolean, id: RelayTourId, slug: String) =
|
||||
timer("relay.fetch.time").withTags(relay(official, id, slug))
|
||||
def syncTime(official: Boolean, id: RelayTourId, slug: String) =
|
||||
timer("relay.sync.time").withTags(relay(official, id, slug))
|
||||
def httpGet(code: Int, host: String, etag: String, proxy: Option[String]) =
|
||||
timer("relay.http.get").withTags:
|
||||
tags(
|
||||
"code" -> code.toLong,
|
||||
"host" -> host.escape,
|
||||
"etag" -> etag.escape,
|
||||
"proxy" -> proxy.getOrElse("none")
|
||||
)
|
||||
val dedup = counter("relay.fetch.dedup").withoutTags()
|
||||
def push(name: String, user: UserName, client: String)(games: Int, moves: Int, errors: Int) =
|
||||
val histogramTags = tags("name" -> name.escape, "user" -> user, "client" -> client.escape)
|
||||
val counterTags = tags("name" -> name.escape, "user" -> user)
|
||||
histogram("relay.push.games").withTags(histogramTags).record(games)
|
||||
histogram("relay.push.moves").withTags(histogramTags).record(moves)
|
||||
histogram("relay.push.errors").withTags(histogramTags).record(errors)
|
||||
counter("relay.push.games.nb").withTags(counterTags).increment(games)
|
||||
counter("relay.push.moves.nb").withTags(counterTags).increment(moves)
|
||||
|
||||
object bot:
|
||||
def moves(username: String) = counter("bot.moves").withTag("name", username)
|
||||
def chats(username: String) = counter("bot.chats").withTag("name", username)
|
||||
def gameStream(event: "start" | "stop") = counter("bot.gameStream").withTag("event", event)
|
||||
object cheat:
|
||||
def selfReport(wildName: String, auth: Boolean) =
|
||||
val name = if wildName.startsWith("soc: ") then "soc" else wildName.takeWhile(' ' !=)
|
||||
counter("cheat.selfReport").withTags(tags("name" -> name.escape, "auth" -> auth))
|
||||
val holdAlert = counter("cheat.holdAlert").withoutTags()
|
||||
def autoAnalysis(reason: String) = counter("cheat.autoAnalysis").withTag("reason", reason)
|
||||
val autoMark = counter("cheat.autoMark.count").withoutTags()
|
||||
val autoReport = counter("cheat.autoReport.count").withoutTags()
|
||||
object email:
|
||||
object send:
|
||||
private val c = counter("email.send")
|
||||
val resetPassword = c.withTag("type", "resetPassword")
|
||||
val magicLink = c.withTag("type", "magicLink")
|
||||
val reopen = c.withTag("type", "reopen")
|
||||
val fix = c.withTag("type", "fix")
|
||||
val change = c.withTag("type", "change")
|
||||
val confirmation = c.withTag("type", "confirmation")
|
||||
val welcome = c.withTag("type", "welcome")
|
||||
def time(mailer: String) = future("email.send.time", tags("mailer" -> mailer))
|
||||
val disposableDomain = gauge("email.disposableDomain").withoutTags()
|
||||
object security:
|
||||
val torNodes = gauge("security.tor.node").withoutTags()
|
||||
object firewall:
|
||||
val block = counter("security.firewall.block").withoutTags()
|
||||
val ip = gauge("security.firewall.ip").withoutTags()
|
||||
val prints = gauge("security.firewall.prints").withoutTags()
|
||||
object proxy:
|
||||
val request = future("security.proxy.time")
|
||||
def result(r: Option[String]) = counter("security.proxy.result").withTag("result", r.getOrElse("none"))
|
||||
def hit(prox: String, action: String) =
|
||||
counter("security.proxy.hit").withTags(tags("proxy" -> prox, "action" -> action))
|
||||
def rateLimit(key: String) = counter("security.rateLimit.count").withTag("key", key)
|
||||
def concurrencyLimit(key: String) = counter("security.concurrencyLimit.count").withTag("key", key)
|
||||
object dnsApi:
|
||||
val mx = future("security.dnsApi.mx.time")
|
||||
object verifyMailApi:
|
||||
def fetch(success: Boolean, ok: Boolean) =
|
||||
timer("verifyMail.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
|
||||
object mailcheckApi:
|
||||
def fetch(success: Boolean, ok: Boolean) =
|
||||
timer("mailcheck.fetch").withTags(tags("success" -> successTag(success), "ok" -> ok))
|
||||
object turnstile:
|
||||
def hit(client: String, action: String, result: String) =
|
||||
counter("turnstile.hit").withTags(tags("client" -> client, "action" -> action, "result" -> result))
|
||||
object pwned:
|
||||
def get(res: Boolean) = timer("security.pwned.result").withTag("res", res)
|
||||
object geoip:
|
||||
val epoch = gauge("security.geoip.epoch").withoutTags()
|
||||
val loadTime = gauge("security.geoip.loadTime").withoutTags()
|
||||
object login:
|
||||
def attempt(byEmail: Boolean, pwned: Boolean, result: Boolean) =
|
||||
counter("security.login.attempt").withTags:
|
||||
tags(
|
||||
"by" -> (if byEmail then "email" else "name"),
|
||||
"pwned" -> pwned,
|
||||
"result" -> result
|
||||
)
|
||||
def proxy(tpe: String) = counter("security.login.proxy").withTag("proxy", tpe)
|
||||
def secretScanning(tokenType: String, source: String, hit: Boolean) =
|
||||
counter("security.githubSecretScanning.hit").withTags(
|
||||
tags("type" -> tokenType, "source" -> source.escape, "hit" -> hit)
|
||||
)
|
||||
def userTrust(trust: Boolean, cause: String) =
|
||||
counter("security.userTrust").withTags(tags("trust" -> trust, "cause" -> cause)).increment()
|
||||
object shutup:
|
||||
def analyzer = timer("shutup.analyzer.time").withoutTags()
|
||||
object tv:
|
||||
object selector:
|
||||
def candidates(channel: String) = histogram("tv.selector.candidates").withTag("channel", channel)
|
||||
def cheats(channel: String) = histogram("tv.selector.cheats").withTag("channel", channel)
|
||||
def rating(channel: String) = histogram("tv.selector.rating").withTag("channel", channel)
|
||||
object streamer:
|
||||
def online = gauge("tv.streamer.count").withoutTags()
|
||||
def present(n: String) = gauge("tv.streamer.present").withTag("name", n.escape)
|
||||
object relation:
|
||||
private val c = counter("relation.action")
|
||||
val follow = c.withTag("type", "follow")
|
||||
val unfollow = c.withTag("type", "unfollow")
|
||||
val block = c.withTag("type", "block")
|
||||
val unblock = c.withTag("type", "unblock")
|
||||
object clas:
|
||||
object student:
|
||||
def create(teacher: UserId) = counter("clas.student.create").withTag("teacher", teacher)
|
||||
def invite(teacher: UserId) = counter("clas.student.invite").withTag("teacher", teacher)
|
||||
final class bloomFilter(name: String):
|
||||
def count = gauge(s"clas.${name}.bloomFilter.count").withoutTags()
|
||||
def fu = future(s"clas.${name}.bloomFilter.future")
|
||||
object tournament:
|
||||
object pairing:
|
||||
val batchSize = histogram("tournament.pairing.batchSize").withoutTags()
|
||||
val create = future("tournament.pairing.create")
|
||||
val createRanking = timer("tournament.pairing.create.ranking").withoutTags()
|
||||
val createPairings = timer("tournament.pairing.create.pairings").withoutTags()
|
||||
val createPlayerMap = timer("tournament.pairing.create.playerMap").withoutTags()
|
||||
val createInserts = timer("tournament.pairing.create.inserts").withoutTags()
|
||||
val createFeature = timer("tournament.pairing.create.feature").withoutTags()
|
||||
val createAutoPairing = timer("tournament.pairing.create.autoPairing").withoutTags()
|
||||
val prep = future("tournament.pairing.prep")
|
||||
val wmmatching = timer("tournament.pairing.wmmatching").withoutTags()
|
||||
val created = gauge("tournament.count").withTag("type", "created")
|
||||
val started = gauge("tournament.count").withTag("type", "started")
|
||||
val waitingPlayers = histogram("tournament.waitingPlayers").withoutTags()
|
||||
object startedOrganizer:
|
||||
val tick = future("tournament.startedOrganizer.tick")
|
||||
val waitingUsers = future("tournament.startedOrganizer.waitingUsers")
|
||||
object createdOrganizer:
|
||||
val tick = future("tournament.createdOrganizer.tick")
|
||||
object lilaHttp:
|
||||
val tick = future("tournament.lilaHttp.tick")
|
||||
val fullSize = histogram("tournament.lilaHttp.fullSize").withoutTags()
|
||||
val nbTours = gauge("tournament.lilaHttp.nbTours").withoutTags()
|
||||
def apiShowPartial(partial: Boolean, client: String)(success: Boolean) =
|
||||
timer("tournament.api.show").withTags:
|
||||
tags(
|
||||
"partial" -> partial,
|
||||
"success" -> successTag(success),
|
||||
"client" -> client
|
||||
)
|
||||
def withdrawableIds(reason: String) = future("tournament.withdrawableIds", reason)
|
||||
def action(tourId: String, action: String) =
|
||||
timer("tournament.api.action").withTags(tags("tourId" -> tourId, "action" -> action))
|
||||
object notifier:
|
||||
def tournaments = counter("tournament.notify.tournaments").withoutTags()
|
||||
def players = counter("tournament.notify.players").withoutTags()
|
||||
object featuring:
|
||||
def forTeams(page: "index" | "homepage") = future("tournament.featuring.forTeams", page)
|
||||
object swiss:
|
||||
val tick = future("swiss.tick")
|
||||
val bbpairing = timer("swiss.bbpairing").withoutTags()
|
||||
val scoringGet = future("swiss.scoring.get")
|
||||
val scoringRecompute = future("swiss.scoring.recompute")
|
||||
val startRound = future("swiss.director.startRound")
|
||||
def games(status: String) = histogram("swiss.ongoingGames").withTag("status", status)
|
||||
val json = future("swiss.json")
|
||||
object plan:
|
||||
object paypalLegacy:
|
||||
val amount = histogram("plan.amount").withTag("service", "paypal")
|
||||
object paypalCheckout:
|
||||
val amount = histogram("plan.amount").withTag("service", "paypalCheckout")
|
||||
val fetchAccessToken = future("plan.paypal.accessToken")
|
||||
val stripe = histogram("plan.amount").withTag("service", "stripe")
|
||||
val goal = gauge("plan.goal").withoutTags()
|
||||
val current = gauge("plan.current").withoutTags()
|
||||
val percent = gauge("plan.percent").withoutTags()
|
||||
def webhook(service: String, tpe: String) =
|
||||
counter("plan.webhook").withTags(tags("service" -> service, "tpe" -> tpe))
|
||||
def intent(service: String, currency: java.util.Currency, coverFees: Boolean) =
|
||||
counter("plan.intent").withTags:
|
||||
tags("service" -> service, "currency" -> currency.getCurrencyCode, "coverFees" -> coverFees)
|
||||
object charge:
|
||||
def first(service: String) = counter("plan.charge.first").withTag("service", service)
|
||||
def countryCents(country: String, currency: java.util.Currency, service: String, gift: Boolean) =
|
||||
histogram("plan.charge.country.cents").withTags:
|
||||
tags(
|
||||
"country" -> country.escape,
|
||||
"currency" -> currency.getCurrencyCode,
|
||||
"service" -> service,
|
||||
"gift" -> gift
|
||||
)
|
||||
object forum:
|
||||
object post:
|
||||
val create = counter("forum.post.create").withoutTags()
|
||||
object topic:
|
||||
val view = counter("forum.topic.view").withoutTags()
|
||||
def reaction(r: String) = counter("forum.reaction").withTag("reaction", r)
|
||||
object msg:
|
||||
def post(verdict: String, isNew: Boolean, multi: Boolean) = counter("msg.post").withTags(
|
||||
tags("verdict" -> verdict, "isNew" -> isNew, "multi" -> multi)
|
||||
)
|
||||
val teamBulk = histogram("msg.bulk.team").withoutTags()
|
||||
def clasBulk(clasId: ClasId) = histogram("msg.bulk.clas").withTag("id", clasId.value)
|
||||
object puzzle:
|
||||
object selector:
|
||||
object user:
|
||||
def time(categ: String) = timer("puzzle.selector.user.puzzle").withTag("categ", categ)
|
||||
def retries(categ: String) = histogram("puzzle.selector.user.retries").withTag("categ", categ)
|
||||
val vote = histogram("puzzle.selector.user.vote").withoutTags()
|
||||
def tier(t: String, categ: String, difficulty: String) =
|
||||
counter("puzzle.selector.user.tier").withTags:
|
||||
tags("tier" -> t, "categ" -> categ, "difficulty" -> difficulty)
|
||||
def batch(nb: Int) = timer("puzzle.selector.user.batch").withTag("nb", nb)
|
||||
object anon:
|
||||
val time = timer("puzzle.selector.anon.puzzle").withoutTags()
|
||||
def batch(nb: Int) = timer("puzzle.selector.anon.batch").withTag("nb", nb)
|
||||
val vote = histogram("puzzle.selector.anon.vote").withoutTags()
|
||||
def nextPuzzleResult(result: String) =
|
||||
timer("puzzle.selector.user.puzzleResult").withTag("result", result)
|
||||
def nextPathFor(categ: String, requester: String) =
|
||||
timer("puzzle.path.nextFor").withTags(tags("categ" -> categ, "requester" -> requester))
|
||||
|
||||
object batch:
|
||||
object selector:
|
||||
val count = counter("puzzle.batch.selector.count").withoutTags()
|
||||
val time = timer("puzzle.batch.selector").withoutTags()
|
||||
val solve = counter("puzzle.batch.solve").withoutTags()
|
||||
object round:
|
||||
def attempt(user: Boolean, theme: String, rated: Boolean) =
|
||||
counter("puzzle.attempt.count").withTags(tags("user" -> user, "theme" -> theme, "rated" -> rated))
|
||||
object vote:
|
||||
def count(up: Boolean, win: Boolean) =
|
||||
counter("puzzle.vote.count").withTags:
|
||||
tags(
|
||||
"up" -> up,
|
||||
"win" -> win
|
||||
)
|
||||
def theme(key: String, up: Option[Boolean], win: Boolean) =
|
||||
counter("puzzle.vote.theme").withTags:
|
||||
tags(
|
||||
"up" -> up.fold("cancel")(_.toString),
|
||||
"theme" -> key,
|
||||
"win" -> win
|
||||
)
|
||||
val future = lila.mon.future("puzzle.vote.future")
|
||||
val crazyGlicko = counter("puzzle.crazyGlicko").withoutTags()
|
||||
object storm:
|
||||
object selector:
|
||||
val time = future("storm.selector.time")
|
||||
val sets = histogram("storm.selector.sets").withoutTags()
|
||||
val count = histogram("storm.selector.count").withoutTags()
|
||||
val rating = histogram("storm.selector.rating").withoutTags()
|
||||
def ratingSlice(index: Int) = histogram("storm.selector.ratingSlice").withTag("index", index)
|
||||
object run:
|
||||
def score(auth: Boolean) = histogram("storm.run.score").withTag("auth", auth)
|
||||
def sign(cause: String) = counter("storm.run.sign").withTag("cause", cause)
|
||||
object racer:
|
||||
private def tpe(lobby: Boolean) = if lobby then "lobby" else "friend"
|
||||
def race(lobby: Boolean) = counter("racer.lobby.race").withTag("tpe", tpe(lobby))
|
||||
def players(lobby: Boolean) =
|
||||
histogram("racer.lobby.players").withTag("tpe", tpe(lobby))
|
||||
def score(lobby: Boolean, auth: Boolean) =
|
||||
histogram("racer.player.score").withTags:
|
||||
tags(
|
||||
"tpe" -> tpe(lobby),
|
||||
"auth" -> auth
|
||||
)
|
||||
object streak:
|
||||
object selector:
|
||||
val time = timer("streak.selector.time").withoutTags()
|
||||
val count = histogram("streak.selector.count").withoutTags()
|
||||
val rating = histogram("streak.selector.rating").withoutTags()
|
||||
def ratingSlice(index: Int) = histogram("streak.selector.ratingSlice").withTag("index", index)
|
||||
object run:
|
||||
def score(auth: String) = histogram("streak.run.score").withTag("auth", auth)
|
||||
object game:
|
||||
import chess.{ Speed, Rated, Status }
|
||||
import lila.core.game.Source
|
||||
def finish(variant: Variant, speed: Speed, source: Option[Source], mode: Rated, status: Status) =
|
||||
counter("game.finish").withTags:
|
||||
tags(
|
||||
"variant" -> variant.key,
|
||||
"speed" -> speed.key,
|
||||
"source" -> source.fold("unknown")(_.name),
|
||||
"mode" -> mode.name,
|
||||
"status" -> status.name
|
||||
)
|
||||
val fetch = counter("game.fetch.count").withoutTags()
|
||||
val loadClockHistory = counter("game.loadClockHistory.count").withoutTags()
|
||||
object pgn:
|
||||
def encode(format: String) = timer("game.pgn.encode").withTag("format", format)
|
||||
def decode(format: String) = timer("game.pgn.decode").withTag("format", format)
|
||||
val idCollision = counter("game.idCollision").withoutTags()
|
||||
def idGenerator(collisions: Int) = timer("game.idGenerator").withTags(tags("collisions" -> collisions))
|
||||
object streamByOauthOrigin:
|
||||
def event(tpe: String) = counter("game.streamByOauthOrigin.event").withTag("type", tpe)
|
||||
def users(sel: String) = gauge("game.streamByOauthOrigin.users").withTag("selector", sel)
|
||||
def streams(ua: UserAgent) = gauge("game.streamByOauthOrigin.streams").withTag("ua", ua.value)
|
||||
val bloomFP = counter("game.streamByOauthOrigin.bloomFP").withoutTags()
|
||||
object chat:
|
||||
private val msgCounter = counter("chat.message")
|
||||
def message(parent: String, troll: Boolean) =
|
||||
msgCounter.withTags(tags("parent" -> parent, "troll" -> troll))
|
||||
def fetch(parent: String) = timer("chat.fetch").withTag("parent", parent)
|
||||
object push:
|
||||
object register:
|
||||
def in(platform: String) = counter("push.register").withTag("platform", platform)
|
||||
val out = counter("push.register.out").withoutTags()
|
||||
object web:
|
||||
def post = future("push.web.post")
|
||||
object send:
|
||||
private def send(tpe: String)(platform: String, success: Boolean, count: Int): Unit =
|
||||
counter("push.send")
|
||||
.withTags:
|
||||
tags(
|
||||
"type" -> tpe,
|
||||
"platform" -> platform,
|
||||
"success" -> successTag(success)
|
||||
)
|
||||
.increment(count)
|
||||
()
|
||||
val move = send("move")
|
||||
val takeback = send("takeback")
|
||||
val draw = send("draw")
|
||||
val corresAlarm = send("corresAlarm")
|
||||
val finish = send("finish")
|
||||
val message = send("message")
|
||||
val tourSoon = send("tourSoon")
|
||||
val forumMention = send("forumMention")
|
||||
val invitedStudy = send("invitedStudy")
|
||||
val streamStart = send("streamStart")
|
||||
val broadcastRound = send("broadcastRound")
|
||||
|
||||
object challenge:
|
||||
val create = send("challengeCreate")
|
||||
val accept = send("challengeAccept")
|
||||
val googleTokenTime = timer("push.send.googleToken").withoutTags()
|
||||
def firebaseStatus(project: String, typ: String, status: Int) =
|
||||
counter("push.firebase.status").withTags(tags("status" -> status, "project" -> project, "type" -> typ))
|
||||
object fishnet:
|
||||
object client:
|
||||
object result:
|
||||
private val c = counter("fishnet.client.result")
|
||||
private def apply(r: String)(client: UserId) =
|
||||
c.withTags(tags("client" -> client, "result" -> r))
|
||||
val success = apply("success")
|
||||
val failure = apply("failure")
|
||||
val timeout = apply("timeout")
|
||||
val notFound = apply("notFound")
|
||||
val notAcquired = apply("notAcquired")
|
||||
val abort = apply("abort")
|
||||
def status(enabled: Boolean) = gauge("fishnet.client.status").withTag("enabled", enabled)
|
||||
def version(v: String) = gauge("fishnet.client.version").withTag("version", v.escape)
|
||||
def queueTime(sender: "system" | "user") = timer("fishnet.queue.db").withTag("sender", sender)
|
||||
val acquire = future("fishnet.acquire")
|
||||
def work(typ: String, as: "system" | "user") =
|
||||
gauge("fishnet.work").withTags(tags("type" -> typ, "for" -> as))
|
||||
def oldest(as: "system" | "user") = gauge("fishnet.oldest").withTag("for", as)
|
||||
object analysis:
|
||||
object by:
|
||||
def movetime(client: UserId) = histogram("fishnet.analysis.movetime").withTag("client", client)
|
||||
def node(client: UserId) = histogram("fishnet.analysis.node").withTag("client", client)
|
||||
def nps(client: UserId) = histogram("fishnet.analysis.nps").withTag("client", client)
|
||||
def depth(client: UserId) = histogram("fishnet.analysis.depth").withTag("client", client)
|
||||
def pvSize(client: UserId) = histogram("fishnet.analysis.pvSize").withTag("client", client)
|
||||
def pv(client: UserId, isLong: Boolean) =
|
||||
counter("fishnet.analysis.pvs").withTags(tags("client" -> client, "long" -> isLong))
|
||||
def totalMeganode(client: UserId) =
|
||||
counter("fishnet.analysis.total.meganode").withTag("client", client)
|
||||
def totalSecond(client: UserId) =
|
||||
counter("fishnet.analysis.total.second").withTag("client", client)
|
||||
def requestCount(tpe: "game" | "study") = counter("fishnet.analysis.request").withTag("type", tpe)
|
||||
val evalCacheHits = histogram("fishnet.analysis.evalCacheHits").withoutTags()
|
||||
val skipPositionsGame = future("fishnet.analysis.skipPositions.game")
|
||||
val skipPositionsStudy = future("fishnet.analysis.skipPositions.study")
|
||||
object http:
|
||||
def request(hit: Boolean) = counter("fishnet.http.acquire").withTag("hit", hit)
|
||||
def move(level: Int) = counter("fishnet.move.time").withTag("level", level)
|
||||
def openingBook(variant: Variant, hit: Boolean) =
|
||||
timer("fishnet.opening.hit").withTags:
|
||||
tags("variant" -> variant.key, "hit" -> hitTag(hit))
|
||||
object opening:
|
||||
def searchTime = timer("opening.search.time").withoutTags()
|
||||
object explorer:
|
||||
def stats = future("opening.explorer.stats")
|
||||
object study:
|
||||
object tree:
|
||||
val read = timer("study.tree.read").withoutTags()
|
||||
val write = timer("study.tree.write").withoutTags()
|
||||
object sequencer:
|
||||
val chapterTime = timer("study.sequencer.chapter.time").withoutTags()
|
||||
object api:
|
||||
val users = counter("api.cost").withTag("endpoint", "users")
|
||||
val activity = counter("api.cost").withTag("endpoint", "activity")
|
||||
object challenge:
|
||||
object bulk:
|
||||
def scheduleNb(by: UserId) = counter("api.challenge.bulk.schedule.nb").withTag("by", by)
|
||||
def createNb(by: UserId) = counter("api.challenge.bulk.create.nb").withTag("by", by)
|
||||
object `export`:
|
||||
object png:
|
||||
val game = counter("export.png").withTag("type", "game")
|
||||
val puzzle = counter("export.png").withTag("type", "puzzle")
|
||||
object bus:
|
||||
val classifiers = gauge("bus.classifiers").withoutTags()
|
||||
object blocking:
|
||||
def time(name: String) = timer("blocking.time").withTag("name", name)
|
||||
def timeout(name: String) = counter("blocking.timeout").withTag("name", name)
|
||||
object workQueue:
|
||||
def offerFail(name: String, result: String) =
|
||||
counter("workQueue.offerFail").withTags:
|
||||
tags("name" -> name, "result" -> result)
|
||||
def timeout(name: String) = counter("workQueue.timeout").withTag("name", name)
|
||||
class parallelQueue(name: String):
|
||||
val parallelism = gauge("parallelQueue.parallelism").withTag("name", name)
|
||||
val computeTimeout = counter("parallelQueue.buildTimeout").withTag("name", name)
|
||||
object markdown:
|
||||
val time = timer("markdown.time").withoutTags()
|
||||
def pgnsFromText = future("markdown.pgnsFromText")
|
||||
object ublog:
|
||||
def create(user: UserId) = counter("ublog.create").withTag("user", user)
|
||||
def view = counter("ublog.view").withoutTags()
|
||||
object automod:
|
||||
val request = future("ublog.automod.request")
|
||||
def quality(q: String) = counter("ublog.automod.quality").withTag("quality", q)
|
||||
def flagged(f: Boolean) = counter("ublog.automod.flagged").withTag("flagged", f)
|
||||
object picfit:
|
||||
def uploadTime(user: UserId) = future("picfit.upload.time", tags("user" -> user))
|
||||
def uploadSize(user: UserId) = histogram("picfit.upload.size").withTag("user", user)
|
||||
object fideSync:
|
||||
val time = future("fide.sync.time")
|
||||
val players = gauge("fide.sync.players").withoutTags()
|
||||
val updated = gauge("fide.sync.updated").withoutTags()
|
||||
object recap:
|
||||
val games = future("recap.build.games.time")
|
||||
val puzzles = future("recap.build.puzzles.time")
|
||||
|
||||
object jvm:
|
||||
def threads() =
|
||||
val perState = gauge("jvm.threads.group")
|
||||
val total = gauge("jvm.threads.group.total")
|
||||
for
|
||||
group <- scalalib.Jvm.threadGroups()
|
||||
_ = total.withTags(tags("name" -> group.name)).update(group.total)
|
||||
(state, count) <- group.states
|
||||
yield perState.withTags(tags("name" -> group.name, "state" -> state.toString)).update(count)
|
||||
|
||||
object prometheus:
|
||||
val lines = gauge("prometheus.lines").withoutTags()
|
||||
|
||||
def chronoSync[A] = Chronometer.syncMon[A]
|
||||
|
||||
private def future(name: String) = (success: Boolean) => timer(name).withTag("success", successTag(success))
|
||||
private def future(name: String, tags: Map[String, Any]) = (success: Boolean) =>
|
||||
timer(name).withTags(tags + ("success" -> successTag(success)))
|
||||
private def future(name: String, segment: String)(success: Boolean) =
|
||||
timer(name).withTags:
|
||||
tags("success" -> successTag(success), "segment" -> segment)
|
||||
|
||||
private def successTag(success: Boolean) = if success then "success" else "failure"
|
||||
private def hitTag(hit: Boolean) = if hit then "hit" else "miss"
|
||||
|
||||
import scala.language.implicitConversions
|
||||
private given Conversion[UserId, String] = _.value
|
||||
private given Conversion[Map[String, Any], TagSet] = TagSet.from
|
||||
@@ -0,0 +1,4 @@
|
||||
package lila.mon
|
||||
|
||||
object extensions:
|
||||
export Chronometer.futureExtension.*
|
||||
@@ -11,6 +11,7 @@ import scala.util.{ Failure, Success, Try }
|
||||
|
||||
import lila.core.net.Crawler
|
||||
import lila.core.config.Secret
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class OpeningExplorer(
|
||||
ws: StandaloneWSClient,
|
||||
@@ -47,7 +48,7 @@ final private class OpeningExplorer(
|
||||
err => fufail(s"Couldn't parse $err"),
|
||||
data => fuccess(data.some)
|
||||
)
|
||||
.monSuccess(_.opening.explorer.stats)
|
||||
.monSuccess(lila.mon.opening.explorer.stats)
|
||||
.map(Success(_))
|
||||
.recover:
|
||||
case e: Exception =>
|
||||
|
||||
@@ -6,7 +6,7 @@ import scalalib.HeapSort.topN
|
||||
|
||||
import java.text.Normalizer
|
||||
|
||||
import lila.common.Chronometer
|
||||
import lila.mon.Chronometer
|
||||
import lila.memo.CacheApi
|
||||
|
||||
case class OpeningSearchResult(opening: Opening):
|
||||
@@ -114,7 +114,7 @@ private object OpeningSearch:
|
||||
|
||||
private given Ordering[Match] = Ordering.by { case Match(_, score) => score }
|
||||
|
||||
def apply(str: String, max: Int): List[Opening] = Chronometer.syncMon(_.opening.searchTime):
|
||||
def apply(str: String, max: Int): List[Opening] = Chronometer.syncMon(lila.mon.opening.searchTime):
|
||||
val query = makeQuery(str)
|
||||
index
|
||||
.flatMap: entry =>
|
||||
|
||||
@@ -2,6 +2,7 @@ package lila.perfStat
|
||||
|
||||
import lila.rating.PerfType
|
||||
import lila.rating.PerfType.GamePerf
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class PerfStatIndexer(
|
||||
gameRepo: lila.core.game.GameRepo,
|
||||
@@ -12,7 +13,7 @@ final class PerfStatIndexer(
|
||||
maxSize = Max(64),
|
||||
timeout = 10.seconds,
|
||||
name = "perfStatIndexer",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
private[perfStat] def userPerf(user: UserId, perf: GamePerf): Fu[PerfStat] =
|
||||
@@ -30,7 +31,7 @@ final class PerfStatIndexer(
|
||||
else perfStat
|
||||
.flatMap: ps =>
|
||||
storage.insert(ps).recover(lila.db.ignoreDuplicateKey).inject(ps)
|
||||
.mon(_.perfStat.indexTime)
|
||||
.mon(lila.mon.perfStat.indexTime)
|
||||
|
||||
def addGame(game: Game): Funit =
|
||||
game.players.toList.sequentiallyVoid: player =>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package lila.plan
|
||||
|
||||
import java.util.Currency
|
||||
|
||||
import play.api.ConfigLoader
|
||||
import play.api.i18n.Lang
|
||||
import play.api.libs.json.*
|
||||
@@ -9,8 +11,7 @@ import play.api.libs.ws.JsonBodyReadables.*
|
||||
import play.api.libs.ws.JsonBodyWritables.*
|
||||
import play.api.libs.ws.{ StandaloneWSClient, StandaloneWSResponse, WSAuthScheme }
|
||||
|
||||
import java.util.Currency
|
||||
|
||||
import lila.mon.extensions.*
|
||||
import lila.common.Json.given
|
||||
import lila.common.autoconfig.*
|
||||
import lila.common.config.given
|
||||
@@ -236,7 +237,7 @@ final private class PayPalClient(
|
||||
(res.body[JsValue] \ "access_token").validate[String] match
|
||||
case JsError(err) => fufail(s"PayPal access token ${err} ${res.body[String].take(200)}")
|
||||
case JsSuccess(token, _) => fuccess(AccessToken(token))
|
||||
.monSuccess(_.plan.paypalCheckout.fetchAccessToken)
|
||||
.monSuccess(lila.mon.plan.paypalCheckout.fetchAccessToken)
|
||||
|
||||
object PayPalClient:
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package lila.plan
|
||||
|
||||
import java.util.Currency
|
||||
|
||||
import play.api.data.*
|
||||
import play.api.data.Forms.*
|
||||
import play.api.data.validation.Constraints
|
||||
|
||||
import java.util.Currency
|
||||
import lila.mon.extensions.*
|
||||
|
||||
case class PlanCheckout(
|
||||
email: Option[String],
|
||||
|
||||
@@ -18,7 +18,7 @@ final private class GameStarter(
|
||||
maxSize = Max(64),
|
||||
timeout = 10.seconds,
|
||||
name = "gameStarter",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def apply(pool: PoolConfig, couples: Vector[MatchMaking.Couple]): Funit =
|
||||
|
||||
@@ -8,7 +8,7 @@ import play.api.libs.ws.StandaloneWSClient
|
||||
import scalalib.cache.FrequencyThreshold
|
||||
import scalalib.data.LazyFu
|
||||
|
||||
import lila.common.Chronometer
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class FirebasePush(
|
||||
deviceApi: DeviceApi,
|
||||
@@ -26,7 +26,7 @@ final private class FirebasePush(
|
||||
maxSize = Max(512),
|
||||
timeout = 10.seconds,
|
||||
name = "firebasePush",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def apply(userId: UserId, data: LazyFu[PushApi.Data]): Funit =
|
||||
@@ -55,10 +55,10 @@ final private class FirebasePush(
|
||||
// access token has 1h lifetime and is requested only if expired
|
||||
token <- workQueue {
|
||||
Future:
|
||||
Chronometer.syncMon(_.blocking.time("firebase")):
|
||||
lila.mon.Chronometer.syncMon(lila.mon.blocking.time("firebase")):
|
||||
creds.refreshIfExpired()
|
||||
creds.getAccessToken()
|
||||
}.chronometer.mon(_.push.googleTokenTime).result
|
||||
}.chronometer.mon(lila.mon.push.googleTokenTime).result
|
||||
_ <- send(token, device, config, data)
|
||||
yield ()
|
||||
yield ()
|
||||
|
||||
@@ -9,6 +9,7 @@ import scalalib.data.LazyFu
|
||||
|
||||
import lila.common.Json.given
|
||||
import lila.common.autoconfig.*
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class WebPush(
|
||||
webSubscriptionApi: WebSubscriptionApi,
|
||||
@@ -77,7 +78,7 @@ final private class WebPush(
|
||||
.map: n =>
|
||||
logger.info(s"[push] web: $n/${staleEndpoints.size} stale endpoints unsubscribed")
|
||||
case res => fufail(s"[push] web: ${res.status} ${res.body}")
|
||||
.monSuccess(_.push.web.post)
|
||||
.monSuccess(lila.mon.push.web.post)
|
||||
|
||||
private object WebPush:
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import scalalib.ThreadLocalRandom
|
||||
|
||||
import lila.db.dsl.*
|
||||
import lila.memo.CacheApi
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class PuzzleAnon(
|
||||
colls: PuzzleColls,
|
||||
@@ -18,7 +19,7 @@ final class PuzzleAnon(
|
||||
pool
|
||||
.get(angle -> diff)
|
||||
.map(color.fold[Vector[Puzzle] => Option[Puzzle]](ThreadLocalRandom.oneOf)(selectWithColor))
|
||||
.mon(_.puzzle.selector.anon.time)
|
||||
.mon(lila.mon.puzzle.selector.anon.time)
|
||||
.addEffect:
|
||||
_.foreach: puzzle =>
|
||||
lila.mon.puzzle.selector.anon.vote.record(100 + math.round(puzzle.vote * 100))
|
||||
@@ -31,7 +32,7 @@ final class PuzzleAnon(
|
||||
nextTry(1)
|
||||
|
||||
def getBatchFor(angle: PuzzleAngle, diff: PuzzleDifficulty, nb: Int): Fu[Vector[Puzzle]] =
|
||||
pool.get(angle -> diff).map(_.take(nb)).mon(_.puzzle.selector.anon.batch(nb))
|
||||
pool.get(angle -> diff).map(_.take(nb)).mon(lila.mon.puzzle.selector.anon.batch(nb))
|
||||
|
||||
private val poolSize = 150
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import scalalib.paginator.Paginator
|
||||
import lila.core.i18n.I18nKey
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.db.paginator.Adapter
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class PuzzleApi(
|
||||
colls: PuzzleColls,
|
||||
@@ -66,7 +67,7 @@ final class PuzzleApi(
|
||||
expiration = 1.minute,
|
||||
timeout = 3.seconds,
|
||||
name = "puzzle.vote",
|
||||
monitor = lila.log.asyncActorMonitor.highCardinality
|
||||
monitor = lila.mon.asyncActorMonitor.highCardinality
|
||||
)
|
||||
|
||||
def update(id: PuzzleId, user: User, vote: Boolean): Funit =
|
||||
@@ -86,7 +87,7 @@ final class PuzzleApi(
|
||||
})
|
||||
.void
|
||||
}
|
||||
.monSuccess(_.puzzle.vote.future)
|
||||
.monSuccess(lila.mon.puzzle.vote.future)
|
||||
.recoverDefault
|
||||
|
||||
private def updatePuzzle(puzzleId: PuzzleId, newVote: Int, prevVote: Option[Int]): Funit =
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lila.puzzle
|
||||
|
||||
import lila.db.dsl.*
|
||||
import lila.mon.extensions.*
|
||||
|
||||
// mobile app
|
||||
final class PuzzleBatch(
|
||||
@@ -55,4 +56,4 @@ final class PuzzleBatch(
|
||||
)
|
||||
.map:
|
||||
_.view.flatMap(puzzleReader.readOpt).toVector
|
||||
.mon(_.puzzle.selector.user.batch(nb = nb))
|
||||
.mon(lila.mon.puzzle.selector.user.batch(nb = nb))
|
||||
|
||||
@@ -25,7 +25,7 @@ final private[puzzle] class PuzzleFinisher(
|
||||
expiration = 5.minutes,
|
||||
timeout = 5.seconds,
|
||||
name = "puzzle.finish",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
private val calculator = GlickoCalculator()
|
||||
@@ -130,7 +130,7 @@ final private[puzzle] class PuzzleFinisher(
|
||||
date = now
|
||||
)
|
||||
val userPerf = perf
|
||||
.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userGlicko, now)
|
||||
.addOrReset(lila.mon.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userGlicko, now)
|
||||
.pipe: p =>
|
||||
p.copy(glicko = ponder.player(angle, win, perf.glicko -> p.glicko, puzzle.glicko))
|
||||
(round, newPuzzleGlicko, userPerf)
|
||||
|
||||
@@ -5,6 +5,7 @@ import reactivemongo.akkastream.cursorProducer
|
||||
|
||||
import lila.common.{ LilaOpeningFamily, LilaStream, SimpleOpening }
|
||||
import lila.core.i18n.I18nKey
|
||||
import lila.mon.extensions.*
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.memo.{ CacheApi, MongoCache }
|
||||
import lila.memo.CacheApi.buildAsyncTimeout
|
||||
|
||||
@@ -3,6 +3,7 @@ package lila.puzzle
|
||||
import scalalib.Iso
|
||||
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
object PuzzlePath:
|
||||
|
||||
@@ -65,7 +66,7 @@ h":"5B7ADA38","planCacheKey":"7FF0C349","queryFramework":"classic","reslen":286,
|
||||
nextFor(requester)(angle, actualTier, difficulty, previousPaths, compromise + 1)
|
||||
case _ => fuccess(none)
|
||||
}.mon:
|
||||
_.puzzle.nextPathFor(angle.categ, requester)
|
||||
lila.mon.puzzle.nextPathFor(angle.categ, requester)
|
||||
|
||||
def select(angle: PuzzleAngle, tier: PuzzleTier, rating: Range) = $doc(
|
||||
"min".$lte(f"${angle.key}${sep}${tier}${sep}${rating.max}%04d"),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lila.puzzle
|
||||
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class PuzzleSelector(
|
||||
colls: PuzzleColls,
|
||||
@@ -43,7 +44,7 @@ final class PuzzleSelector(
|
||||
,
|
||||
some
|
||||
)
|
||||
.mon(_.puzzle.selector.user.time(angle.categ))
|
||||
.mon(lila.mon.puzzle.selector.user.time(angle.categ))
|
||||
|
||||
private def findNextPuzzleFor(angle: PuzzleAngle, retries: Int)(using me: Me, perf: Perf): Fu[Puzzle] =
|
||||
sessionApi
|
||||
@@ -140,4 +141,4 @@ final class PuzzleSelector(
|
||||
PuzzleAlreadyPlayed(puzzle)
|
||||
else PuzzleFound(puzzle)
|
||||
.monValue: result =>
|
||||
_.puzzle.selector.nextPuzzleResult(result.name)
|
||||
lila.mon.puzzle.selector.nextPuzzleResult(result.name)
|
||||
|
||||
@@ -3,6 +3,7 @@ package lila.puzzle
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.memo.CacheApi
|
||||
import lila.memo.CacheApi.buildAsyncTimeout
|
||||
import lila.mon.extensions.*
|
||||
|
||||
case class PuzzleStreak(ids: String, first: Puzzle)
|
||||
|
||||
@@ -75,7 +76,7 @@ final class PuzzleStreakApi(colls: PuzzleColls, cacheApi: CacheApi)(using Execut
|
||||
)
|
||||
.map:
|
||||
_.flatMap(puzzleReader.readOpt)
|
||||
.mon(_.streak.selector.time)
|
||||
.mon(lila.mon.streak.selector.time)
|
||||
.addEffect(monitor)
|
||||
.map: puzzles =>
|
||||
puzzles.headOption.map:
|
||||
|
||||
@@ -5,6 +5,7 @@ import reactivemongo.akkastream.cursorProducer
|
||||
|
||||
import lila.common.LilaStream
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class PuzzleTagger(colls: PuzzleColls, openingApi: PuzzleOpeningApi)(using
|
||||
ec: Executor,
|
||||
|
||||
@@ -52,7 +52,7 @@ final class RacerApi(
|
||||
maxSize = Max(32),
|
||||
timeout = 20.seconds,
|
||||
name = "racer.rematch",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def rematch(race: RacerRace, player: RacerPlayer.Id): Fu[RacerRace.Id] = race.rematch.flatMap(get) match
|
||||
|
||||
@@ -16,7 +16,7 @@ final class RacerLobby(api: RacerApi)(using Executor)(using scheduler: Scheduler
|
||||
maxSize = Max(128),
|
||||
timeout = 20.seconds,
|
||||
name = "racer.lobby",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
private val fallbackRace = RacerRace.make(RacerPlayer.lichess, Nil, 10)
|
||||
|
||||
@@ -13,7 +13,7 @@ object PerfExt:
|
||||
|
||||
extension (p: Perf)
|
||||
|
||||
def addOrReset(monitor: lila.mon.CounterPath, msg: => String)(player: Glicko, date: Instant): Perf =
|
||||
def addOrReset(counter: kamon.metric.Counter, msg: => String)(player: Glicko, date: Instant): Perf =
|
||||
val newGlicko = player.copy(
|
||||
rating = player.rating
|
||||
.atMost(p.glicko.rating + lila.rating.Glicko.maxRatingDelta)
|
||||
@@ -30,7 +30,7 @@ object PerfExt:
|
||||
if newGlicko.sanityCheck then append(newGlicko)
|
||||
else
|
||||
lila.log("rating").error(s"Crazy Glicko2 $msg")
|
||||
monitor(lila.mon).increment()
|
||||
counter.increment()
|
||||
append(lila.rating.Glicko.default)
|
||||
|
||||
def refund(points: Int): Perf =
|
||||
|
||||
@@ -10,6 +10,7 @@ import lila.common.SimpleOpening
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.game.Query
|
||||
import lila.core.game.Source
|
||||
import lila.mon.extensions.*
|
||||
|
||||
private final class RecapBuilder(
|
||||
repo: RecapRepo,
|
||||
@@ -51,7 +52,7 @@ private final class RecapBuilder(
|
||||
nbs = NbWin(total = nb, win = wins - fixes),
|
||||
votes = PuzzleVotes(nb = votes, themes = themes)
|
||||
)
|
||||
.monSuccess(_.recap.puzzles)
|
||||
.monSuccess(lila.mon.recap.puzzles)
|
||||
|
||||
private def makeGameRecap(scan: GameScan): RecapGames =
|
||||
RecapGames(
|
||||
@@ -85,7 +86,7 @@ private final class RecapBuilder(
|
||||
.sortedCursor(query, Query.sortChronological)
|
||||
.documentSource()
|
||||
.runFold(GameScan())(_.addGame(userId)(_))
|
||||
.monSuccess(_.recap.games)
|
||||
.monSuccess(lila.mon.recap.games)
|
||||
|
||||
private case class GameScan(
|
||||
nbs: NbWin = NbWin(),
|
||||
|
||||
@@ -6,6 +6,7 @@ import play.api.libs.ws.*
|
||||
import play.shaded.ahc.org.asynchttpclient.util.HttpUtils.extractContentTypeCharsetAttribute
|
||||
|
||||
import lila.core.lilaism.LilaException
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/* Extra generic features for play WS client,
|
||||
* without any knowledge of broadcast specifics.
|
||||
@@ -73,7 +74,7 @@ private final class HttpClient(
|
||||
req
|
||||
.get()
|
||||
.monValue: res =>
|
||||
_.relay.httpGet(
|
||||
lila.mon.relay.httpGet(
|
||||
res.status,
|
||||
url.host.toString,
|
||||
etag = monitorEtagHit(req, res),
|
||||
|
||||
@@ -13,6 +13,7 @@ import lila.game.{ GameRepo, PgnDump }
|
||||
import lila.memo.CacheApi
|
||||
import lila.relay.RelayRound.Sync
|
||||
import lila.study.{ MultiPgn, StudyPgnImport }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class RelayFetch(
|
||||
sync: RelaySync,
|
||||
@@ -83,7 +84,7 @@ final private class RelayFetch(
|
||||
else
|
||||
val syncFu = for
|
||||
allGamesInSourceNoLimit <- fetchGames(rt).mon:
|
||||
_.relay.fetchTime(rt.tour.official, rt.tour.id, rt.tour.slug)
|
||||
lila.mon.relay.fetchTime(rt.tour.official, rt.tour.id, rt.tour.slug)
|
||||
allGamesInSource = allGamesInSourceNoLimit.take(maxGamesToRead(rt.tour.official).value)
|
||||
filtered = RelayGame.filter(rt.round.sync.onlyRound)(allGamesInSource)
|
||||
sliced = RelayGame.Slices.filterAndOrder(~rt.round.sync.slices)(filtered)
|
||||
@@ -98,7 +99,7 @@ final private class RelayFetch(
|
||||
res <- sync
|
||||
.updateStudyChapters(rt, reordered)
|
||||
.withTimeoutError(7.seconds, SyncResult.Timeout)
|
||||
.mon(_.relay.syncTime(rt.tour.official, rt.tour.id, rt.tour.slug))
|
||||
.mon(lila.mon.relay.syncTime(rt.tour.official, rt.tour.id, rt.tour.slug))
|
||||
games = res.plan.input.games
|
||||
_ <- notifyAdmin.orphanBoards.inspectPlan(rt, res.plan)
|
||||
nbGamesFinished = games.count(_.points.isDefined)
|
||||
|
||||
@@ -26,7 +26,7 @@ final class RelayPush(
|
||||
expiration = 1.minute,
|
||||
timeout = 10.seconds,
|
||||
name = "relay.push",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def apply(rt: RelayRound.WithTour, pgn: PgnStr)(using Me, UserAgent): Fu[Results] =
|
||||
|
||||
@@ -12,6 +12,7 @@ import lila.common.Json.given
|
||||
import lila.core.config.Secret
|
||||
import lila.core.data.Text
|
||||
import lila.core.id.ImageId
|
||||
import lila.mon.extensions.*
|
||||
import lila.memo.{ ImageAutomod, ImageAutomodRequest, Dimensions }
|
||||
import lila.memo.SettingStore.Text.given
|
||||
|
||||
@@ -128,7 +129,7 @@ final class Automod(
|
||||
lila.mon.mod.report.automod.imageFlagged(flagged).increment()
|
||||
flagged.option:
|
||||
res.str("reason") | "No reason provided"
|
||||
.monSuccess(_.mod.report.automod.imageRequest)
|
||||
.monSuccess(lila.mon.mod.report.automod.imageRequest)
|
||||
.recover:
|
||||
case err =>
|
||||
logger.error(err.getMessage, err)
|
||||
|
||||
@@ -11,6 +11,7 @@ import lila.db.dsl.{ *, given }
|
||||
import lila.memo.CacheApi.*
|
||||
import lila.memo.SettingStore.Text.given
|
||||
import lila.report.Room.Scores
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class ReportApi(
|
||||
val coll: Coll,
|
||||
@@ -336,7 +337,7 @@ final class ReportApi(
|
||||
systemPrompt = commsPromptSetting.get(),
|
||||
model = commsModelSetting.get()
|
||||
)
|
||||
.monSuccess(_.mod.report.automod.request)
|
||||
.monSuccess(lila.mon.mod.report.automod.request)
|
||||
val candidate = for
|
||||
(images, textResponse) <- automodApi.markdownImages(Markdown(userText)).zip(assessText)
|
||||
flaggedImages = images.flatMap(_.automod).flatMap(_.flagged)
|
||||
@@ -623,7 +624,7 @@ final class ReportApi(
|
||||
maxSize = Max(32),
|
||||
timeout = 20.seconds,
|
||||
name = "report.inquiries",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
def allBySuspect: Fu[Map[UserId, Report.Inquiry]] =
|
||||
|
||||
@@ -8,6 +8,7 @@ import lila.common.Form.cleanNonEmptyText
|
||||
import lila.core.LightUser
|
||||
import lila.core.config.NetDomain
|
||||
import lila.core.report.SuspectId
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private[report] class ReportForm(lightUserAsync: LightUser.Getter)(using domain: NetDomain):
|
||||
val cheatLinkConstraint: Constraint[ReportSetup] = Constraint("constraints.cheatgamelink"): setup =>
|
||||
|
||||
@@ -7,6 +7,7 @@ import reactivemongo.api.bson.*
|
||||
import lila.common.{ Bus, LilaScheduler, LilaStream }
|
||||
import lila.core.user.LightUserApi
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class CorresAlarm(
|
||||
coll: Coll,
|
||||
@@ -71,5 +72,5 @@ final private class CorresAlarm(
|
||||
case (alarm, None) => deleteAlarm(alarm._id)
|
||||
.toMat(LilaStream.sinkCount)(Keep.right)
|
||||
.run()
|
||||
.mon(_.round.alarm.time)
|
||||
.mon(lila.mon.round.alarm.time)
|
||||
.void
|
||||
|
||||
@@ -9,6 +9,7 @@ import lila.core.misc.mailer.*
|
||||
import lila.core.notify.NotifyApi
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.user.UserRepo
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class CorrespondenceEmail(gameRepo: GameRepo, userRepo: UserRepo, notifyApi: NotifyApi)(using
|
||||
Executor,
|
||||
@@ -26,7 +27,7 @@ final private class CorrespondenceEmail(gameRepo: GameRepo, userRepo: UserRepo,
|
||||
.map { Bus.pub(_) }
|
||||
.runWith(LilaStream.sinkCount)
|
||||
.addEffect(lila.mon.round.correspondenceEmail.emails.record(_))
|
||||
.monSuccess(_.round.correspondenceEmail.time)
|
||||
.monSuccess(lila.mon.round.correspondenceEmail.time)
|
||||
|
||||
private def opponentStream =
|
||||
notifyApi.prefColl
|
||||
|
||||
@@ -80,7 +80,7 @@ final class PerfsUpdater(
|
||||
val newPerfs = perfs
|
||||
.focusKey(perfKey)
|
||||
.modify:
|
||||
_.addOrReset(_.round.error.glicko, s"game ${game.id}")(player, game.movedAt)
|
||||
_.addOrReset(lila.mon.round.error.glicko, s"game ${game.id}")(player, game.movedAt)
|
||||
if game.ratingVariant.standard
|
||||
then updateStandard(newPerfs)
|
||||
else newPerfs
|
||||
|
||||
@@ -11,6 +11,7 @@ import lila.game.GameExt.*
|
||||
import lila.game.{ Event, GameRepo, Player as GamePlayer, Progress }
|
||||
import lila.room.RoomSocket.{ Protocol as RP, * }
|
||||
import lila.round.RoundGame.*
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class RoundAsyncActor(
|
||||
dependencies: RoundAsyncActor.Dependencies,
|
||||
@@ -195,7 +196,7 @@ final private class RoundAsyncActor(
|
||||
case RoundBus.FishnetPlay(uci, hash) =>
|
||||
handle: game =>
|
||||
player.fishnet(game, hash, uci)
|
||||
.mon(_.round.move.time)
|
||||
.mon(lila.mon.round.move.time)
|
||||
|
||||
case RoundBus.Abort(playerId) =>
|
||||
handle(playerId): pov =>
|
||||
|
||||
@@ -15,6 +15,7 @@ import lila.core.net.IpAddress
|
||||
import lila.core.round.*
|
||||
import lila.core.socket.{ protocol as P, * }
|
||||
import lila.room.RoomSocket.{ Protocol as RP, * }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class RoundSocket(
|
||||
socketKit: ParallelSocketKit,
|
||||
|
||||
@@ -8,6 +8,7 @@ import lila.core.round.{ Abandon, RoundBus }
|
||||
import lila.db.dsl.*
|
||||
import lila.game.GameExt.abandoned
|
||||
import lila.game.{ GameRepo, Query }
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/*
|
||||
* Cleans up unfinished games
|
||||
@@ -54,7 +55,7 @@ final private class Titivate(
|
||||
yield lila.mon.round.titivate.old.record(old)
|
||||
|
||||
run
|
||||
.monSuccess(_.round.titivate.time)
|
||||
.monSuccess(lila.mon.round.titivate.time)
|
||||
.logFailure(logBranch)
|
||||
.addEffectAnyway(scheduleNext())
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package lila.search
|
||||
|
||||
import lila.search.client.SearchClient
|
||||
import lila.search.spec.*
|
||||
import lila.mon.extensions.*
|
||||
|
||||
class LilaSearchClient(client: SearchClient, cacheApi: lila.memo.CacheApi)(using Executor)
|
||||
extends SearchClient:
|
||||
@@ -29,7 +30,7 @@ class LilaSearchClient(client: SearchClient, cacheApi: lila.memo.CacheApi)(using
|
||||
SearchOutput(Nil)
|
||||
|
||||
private def monitor[A](op: "search" | "count", index: String)(f: Fu[A]) =
|
||||
f.monTry(res => _.search.time(op, index, res.isSuccess))
|
||||
f.monTry(res => lila.mon.search.time(op, index, res.isSuccess))
|
||||
|
||||
extension (query: Query)
|
||||
def index: String = query match
|
||||
|
||||
@@ -7,6 +7,7 @@ import play.api.libs.ws.StandaloneWSClient
|
||||
import lila.core.lilaism.LilaException
|
||||
import lila.core.net.Domain
|
||||
import lila.db.dsl.given
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final private class DnsApi(
|
||||
ws: StandaloneWSClient,
|
||||
@@ -36,7 +37,7 @@ final private class DnsApi(
|
||||
}
|
||||
.flatten
|
||||
}
|
||||
}.monSuccess(_.security.dnsApi.mx)
|
||||
}.monSuccess(lila.mon.security.dnsApi.mx)
|
||||
}
|
||||
|
||||
private def fetch[A](domain: Domain.Lower, tpe: String)(f: List[JsObject] => A): Fu[A] =
|
||||
|
||||
@@ -5,6 +5,7 @@ import play.api.data.validation.*
|
||||
import lila.core.net.Domain
|
||||
import lila.user.{ User, UserRepo }
|
||||
import lila.core.email.NormalizedEmailAddress
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/** Validate and normalize emails
|
||||
*/
|
||||
|
||||
@@ -58,7 +58,7 @@ final class Env(
|
||||
lazy val passwordHasher = PasswordHasher(
|
||||
secret = config.passwordBPassSecret,
|
||||
logRounds = 10,
|
||||
hashTimer = lila.common.Chronometer.syncMon(_.user.auth.hashTime)
|
||||
hashTimer = lila.mon.Chronometer.syncMon(lila.mon.user.auth.hashTime)
|
||||
)
|
||||
|
||||
lazy val authenticator = wire[Authenticator]
|
||||
|
||||
@@ -19,7 +19,7 @@ final class GeoIP(config: GeoIP.Config, scheduler: Scheduler)(using Executor):
|
||||
private def loadFromFile(): Unit =
|
||||
if config.file.nonEmpty then
|
||||
try
|
||||
val time = lila.common.Chronometer.sync:
|
||||
val time = lila.mon.Chronometer.sync:
|
||||
reader = DatabaseReader.Builder(java.io.File(config.file)).fileMode(FileMode.MEMORY).build.some
|
||||
reader.foreach: r =>
|
||||
val meta = r.getMetadata
|
||||
|
||||
@@ -8,6 +8,7 @@ import play.api.libs.ws.StandaloneWSClient
|
||||
import lila.core.net.IpAddress
|
||||
import lila.core.security.{ Ip2ProxyApi, IsProxy }
|
||||
import lila.common.HTTPRequest
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class Ip2ProxySkip extends Ip2ProxyApi:
|
||||
def ofReq(req: RequestHeader): Fu[IsProxy] = fuccess(IsProxy.empty)
|
||||
@@ -89,7 +90,7 @@ final class Ip2ProxyServer(
|
||||
.withTimeout(200.millis, "Ip2Proxy.fetch")
|
||||
.dmap(_.body[JsValue])
|
||||
.dmap(readProxyName)
|
||||
.monSuccess(_.security.proxy.request)
|
||||
.monSuccess(lila.mon.security.proxy.request)
|
||||
.addEffect: result =>
|
||||
lila.mon.security.proxy.result(result.name).increment()
|
||||
.recoverDefault(IsProxy.empty)
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.roundeights.hasher.Implicits.*
|
||||
import play.api.libs.ws.DefaultBodyReadables.*
|
||||
import play.api.libs.ws.StandaloneWSClient
|
||||
|
||||
import lila.mon.extensions.*
|
||||
|
||||
opaque type IsPwned = Boolean
|
||||
object IsPwned extends YesNo[IsPwned]
|
||||
|
||||
@@ -24,5 +26,5 @@ final class PwnedApi(ws: StandaloneWSClient, rangeUrl: String)(using Executor):
|
||||
logger.warn(s"Pwnd ${url} ${res.status} ${res.body[String].take(200)}")
|
||||
IsPwned(false)
|
||||
.monValue: result =>
|
||||
_.security.pwned.get(result.yes)
|
||||
lila.mon.security.pwned.get(result.yes)
|
||||
.recoverDefault(IsPwned(false))
|
||||
|
||||
@@ -11,6 +11,7 @@ import lila.core.security.ClearPassword
|
||||
import lila.user.TotpSecret.{ base32, verify }
|
||||
import lila.user.{ TotpSecret, TotpToken }
|
||||
import lila.oauth.OAuthSignedClient.SimpleSignup
|
||||
import lila.mon.extensions.*
|
||||
|
||||
final class SecurityForm(
|
||||
userRepo: lila.user.UserRepo,
|
||||
|
||||
@@ -6,6 +6,7 @@ import play.api.libs.ws.JsonBodyReadables.*
|
||||
import play.api.libs.ws.StandaloneWSClient
|
||||
|
||||
import lila.core.net.Domain
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/* An expensive API detecting disposable email.
|
||||
* Only hit after trying everything else (DnsApi)
|
||||
@@ -77,7 +78,7 @@ final private class VerifyMail(
|
||||
ok
|
||||
).getOrElse:
|
||||
throw lila.core.lilaism.LilaException(s"$url ${res.status} ${res.body[String].take(200)}")
|
||||
.monTry(res => _.security.mailcheckApi.fetch(res.isSuccess, res.getOrElse(true)))
|
||||
.monTry(res => lila.mon.security.mailcheckApi.fetch(res.isSuccess, res.getOrElse(true)))
|
||||
|
||||
private def fetchPaid(domain: Domain.Lower): Fu[Boolean] =
|
||||
val url = s"https://verifymail.io/api/$domain"
|
||||
@@ -99,4 +100,4 @@ final private class VerifyMail(
|
||||
ok
|
||||
).getOrElse:
|
||||
throw lila.core.lilaism.LilaException(s"$url ${res.status} ${res.body[String].take(200)}")
|
||||
.monTry(res => _.security.verifyMailApi.fetch(res.isSuccess, res.getOrElse(true)))
|
||||
.monTry(res => lila.mon.security.verifyMailApi.fetch(res.isSuccess, res.getOrElse(true)))
|
||||
|
||||
@@ -4,14 +4,14 @@ import lila.common.constants.bannedYoutubeIds
|
||||
|
||||
object Analyser extends lila.core.shutup.TextAnalyser:
|
||||
|
||||
def apply(raw: String): TextAnalysis = lila.common.Chronometer
|
||||
def apply(raw: String): TextAnalysis = lila.mon.Chronometer
|
||||
.sync:
|
||||
val lower = raw.take(2000).toLowerCase
|
||||
val processable = removeDiacriticalCombination(removeSlash(lower))
|
||||
val matches = latinBigRegex.findAllMatchIn(latinify(processable)).toList :::
|
||||
ruBigRegex.findAllMatchIn(lower).toList
|
||||
TextAnalysis(lower, matches.map(_.toString))
|
||||
.mon(_.shutup.analyzer)
|
||||
.mon(lila.mon.shutup.analyzer)
|
||||
.logIfSlow(100, logger)(_ => s"Slow shutup analyser ${raw.take(400)}")
|
||||
.result
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ final class SimulApi(
|
||||
expiration = 10.minutes,
|
||||
timeout = 10.seconds,
|
||||
name = "simulApi",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
export repo.{ find, byIds }
|
||||
|
||||
@@ -7,6 +7,7 @@ import lila.db.dsl.{ *, given }
|
||||
import lila.memo.CacheApi
|
||||
import lila.puzzle.PuzzleColls
|
||||
import lila.common.BatchProvider
|
||||
import lila.mon.extensions.*
|
||||
|
||||
/* The difficulty of storm should remain constant!
|
||||
* Be very careful when adjusting the selector.
|
||||
@@ -46,7 +47,7 @@ final class StormSelector(colls: PuzzleColls, cacheApi: CacheApi)(using Executor
|
||||
private val setSize = ratingBuckets._2F.sum // 137
|
||||
|
||||
private val batchProvider =
|
||||
BatchProvider[PuzzleSet]("stormSelector", timeout = 15.seconds): () =>
|
||||
BatchProvider[PuzzleSet]("stormSelector", timeout = 15.seconds, lila.mon.asyncActorMonitor.full): () =>
|
||||
aggregateMultipleSets:
|
||||
if lila.common.Uptime.startedSinceMinutes(2) then setsPerAggregation else 1
|
||||
|
||||
@@ -92,7 +93,7 @@ final class StormSelector(colls: PuzzleColls, cacheApi: CacheApi)(using Executor
|
||||
logger.warn:
|
||||
s"selector: $setSize x $nbSets. ${docs.size} docs, ${puzzles.size} puzzles, ${setsToMake} sets, ${groups.size} groups: $showGroups"
|
||||
.logTimeIfGt(s"storm selector x$nbSets", 8.seconds)
|
||||
.monSuccess(_.storm.selector.time)
|
||||
.monSuccess(lila.mon.storm.selector.time)
|
||||
.recoverWith:
|
||||
case e: IllegalArgumentException if nbSets > 1 =>
|
||||
val retryNbSets = nbSets / 2
|
||||
|
||||
@@ -2,7 +2,7 @@ package lila.study
|
||||
|
||||
import chess.format.UciPath
|
||||
|
||||
import lila.common.Chronometer
|
||||
import lila.mon.Chronometer.syncMon
|
||||
import lila.db.dsl.*
|
||||
import lila.tree.{ Branch, Branches, NewBranch, NewRoot, NewTree, Root }
|
||||
|
||||
@@ -23,7 +23,7 @@ private object StudyFlatTree:
|
||||
object reader:
|
||||
|
||||
def rootChildren(flatTree: Bdoc): Branches =
|
||||
Chronometer.syncMon(_.study.tree.read):
|
||||
syncMon(lila.mon.study.tree.read):
|
||||
traverse:
|
||||
flatTree.elements.toList
|
||||
.collect:
|
||||
@@ -32,7 +32,7 @@ private object StudyFlatTree:
|
||||
.sortBy(-_.depth)
|
||||
|
||||
def newRoot(flatTree: Bdoc): Option[NewTree] =
|
||||
Chronometer.syncMon(_.study.tree.read):
|
||||
syncMon(lila.mon.study.tree.read):
|
||||
traverseN:
|
||||
flatTree.elements.toList
|
||||
.collect:
|
||||
@@ -72,11 +72,11 @@ private object StudyFlatTree:
|
||||
object writer:
|
||||
|
||||
def rootChildren(root: Root): List[(String, Bdoc)] =
|
||||
Chronometer.syncMon(_.study.tree.write):
|
||||
syncMon(lila.mon.study.tree.write):
|
||||
root.children.toList.flatMap { traverse(_, UciPath.root) }
|
||||
|
||||
def newRootChildren(root: NewRoot): List[(String, Bdoc)] =
|
||||
Chronometer.syncMon(_.study.tree.write):
|
||||
syncMon(lila.mon.study.tree.write):
|
||||
root.tree.so:
|
||||
_.mapAccuml_(UciPath.root)((acc, branch) =>
|
||||
val path = acc + branch.id
|
||||
|
||||
@@ -13,7 +13,7 @@ final private class StudySequencer(
|
||||
expiration = 1.minute,
|
||||
timeout = 10.seconds,
|
||||
name = "study",
|
||||
lila.log.asyncActorMonitor.highCardinality
|
||||
lila.mon.asyncActorMonitor.highCardinality
|
||||
)
|
||||
|
||||
def sequenceStudy[A <: Matchable: Zero](studyId: StudyId)(f: Study => Fu[A]): Fu[A] =
|
||||
|
||||
@@ -117,7 +117,7 @@ final class StudyTopicApi(topicRepo: StudyTopicRepo, userTopicRepo: StudyUserTop
|
||||
maxSize = Max(1),
|
||||
timeout = 61.seconds,
|
||||
name = "studyTopicAggregation",
|
||||
lila.log.asyncActorMonitor.unhandled
|
||||
lila.mon.asyncActorMonitor.unhandled
|
||||
)
|
||||
|
||||
private[study] def recompute(): Unit =
|
||||
|
||||
@@ -27,7 +27,7 @@ final private class PairingSystem(trf: SwissTrf, executable: String)(using
|
||||
val command = s"$executable --$flavour $file -p"
|
||||
val stdout = new collection.mutable.ListBuffer[String]
|
||||
val stderr = new StringBuilder
|
||||
val status = lila.common.Chronometer.syncMon(_.swiss.bbpairing):
|
||||
val status = lila.mon.Chronometer.syncMon(lila.mon.swiss.bbpairing):
|
||||
blocking:
|
||||
command ! ProcessLogger(stdout append _, stderr append _)
|
||||
if status != 0 then
|
||||
|
||||
@@ -14,6 +14,7 @@ import lila.core.LightUser
|
||||
import lila.core.round.RoundBus
|
||||
import lila.core.swiss.{ IdName, SwissFinish }
|
||||
import lila.core.userId.UserSearch
|
||||
import lila.mon.extensions.*
|
||||
import lila.db.dsl.{ *, given }
|
||||
import lila.gathering.Condition.WithVerdicts
|
||||
import lila.gathering.GreatPlayer
|
||||
@@ -41,7 +42,7 @@ final class SwissApi(
|
||||
expiration = 20.minutes,
|
||||
timeout = 10.seconds,
|
||||
name = "swiss.api",
|
||||
lila.log.asyncActorMonitor.full
|
||||
lila.mon.asyncActorMonitor.full
|
||||
)
|
||||
|
||||
import BsonHandlers.{ *, given }
|
||||
@@ -607,7 +608,7 @@ final class SwissApi(
|
||||
)
|
||||
yield cache.swissCache.clear(swiss.id)
|
||||
} >> recomputeAndUpdateAll(id)
|
||||
.monSuccess(_.swiss.tick)
|
||||
.monSuccess(lila.mon.swiss.tick)
|
||||
|
||||
private def countPresentPlayers(swiss: Swiss) = SwissPlayer.fields: f =>
|
||||
mongo.player.countSel($doc(f.swissId -> swiss.id, f.absent.$ne(true)))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user