Cockatrice 2026-10-19-Development-3.1.2-beta.2
A virtual tabletop for multiplayer card games
Loading...
Searching...
No Matches
MetricsRegistry Class Reference

Lock-free accumulation of command processing statistics. More...

#include <metrics_registry.h>

Collaboration diagram for MetricsRegistry:
[legend]

Classes

struct  ActiveTypeStats
struct  GameStartSnapshot
struct  TypeStats

Public Member Functions

void observeCommand (int typeId, qint64 elapsedMs)
void observeGameStartDurationMs (qint64 elapsedMs)
qint64 totalCommands () const
 Total number of observed commands across all types.
qint64 totalTimeMs () const
 Cumulative processing milliseconds across all types.
int activeTypeCount () const
 Number of distinct type slots that have seen at least one sample.
QList< ActiveTypeStats > collectActiveStats () const
GameStartSnapshot getGameStartSnapshot () const

Static Public Member Functions

static int typeIdFor (int kindIndex, int extensionNumber)
 Guard against typeIdFor() overflowing into the neighbouring kind's slots.

Static Public Attributes

static constexpr int KindStride = 1280
static constexpr int NumKinds = 6
static constexpr const char * KindNames [NumKinds] = {"session", "room", "game", "moderator", "admin", "developer"}
static constexpr int MaxTypes = NumKinds * KindStride
 Upper bound on distinct command type ids (see typeIdFor).

Private Member Functions

TypeStats & slotFor (int typeId)
const TypeStats & slotFor (int typeId) const

Private Attributes

std::array< TypeStats, MaxTypes > typeSlots {}
TypeStats gameStartStats {}
std::atomic< qint64 > totalCommandsCounter {0}
std::atomic< qint64 > totalTimeCounter {0}

Detailed Description

Lock-free accumulation of command processing statistics.

observeCommand() is called once per processed command from whichever socket thread handled it. It uses relaxed atomic adds on preallocated storage only, so it introduces no locks, allocations, or shared cache-line ping-pong beyond the unavoidable counter updates.

Reading happens rarely (metrics scraping), accepts momentary tears between related counters, and therefore also needs no synchronization.

Only counts and totals are retained. An earlier Prometheus-style cumulative histogram (per-type, time-bucketed) was cut because nothing in the server ever wrote it out; it belongs to the future /metrics exporter that needs it.

Member Function Documentation

◆ activeTypeCount()

int MetricsRegistry::activeTypeCount ( ) const

Number of distinct type slots that have seen at least one sample.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ collectActiveStats()

QList< MetricsRegistry::ActiveTypeStats > MetricsRegistry::collectActiveStats ( ) const

Returns stats for every type slot that has seen at least one sample. Callers resolve the numeric type id to a human-readable label via typeIdFor()/KindNames as needed.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getGameStartSnapshot()

MetricsRegistry::GameStartSnapshot MetricsRegistry::getGameStartSnapshot ( ) const
Here is the caller graph for this function:

◆ observeCommand()

void MetricsRegistry::observeCommand ( int typeId,
qint64 elapsedMs )
Here is the call graph for this function:
Here is the caller graph for this function:

◆ observeGameStartDurationMs()

void MetricsRegistry::observeGameStartDurationMs ( qint64 elapsedMs)

Records how long one game start took to bring every player's zones online. Kept separate from command timings because it is triggered by the server itself and can dwarf any single command when decks are huge.

Here is the caller graph for this function:

◆ slotFor() [1/2]

MetricsRegistry::TypeStats & MetricsRegistry::slotFor ( int typeId)
private
Here is the caller graph for this function:

◆ slotFor() [2/2]

const MetricsRegistry::TypeStats & MetricsRegistry::slotFor ( int typeId) const
private

◆ totalCommands()

qint64 MetricsRegistry::totalCommands ( ) const
inline

Total number of observed commands across all types.

Here is the caller graph for this function:

◆ totalTimeMs()

qint64 MetricsRegistry::totalTimeMs ( ) const
inline

Cumulative processing milliseconds across all types.

Here is the caller graph for this function:

◆ typeIdFor()

int MetricsRegistry::typeIdFor ( int kindIndex,
int extensionNumber )
inlinestatic

Guard against typeIdFor() overflowing into the neighbouring kind's slots.

Here is the caller graph for this function:

Member Data Documentation

◆ gameStartStats

TypeStats MetricsRegistry::gameStartStats {}
private

◆ KindNames

const char* MetricsRegistry::KindNames[NumKinds] = {"session", "room", "game", "moderator", "admin", "developer"}
staticconstexpr

◆ KindStride

int MetricsRegistry::KindStride = 1280
staticconstexpr

Extension numbers are only unique per command kind, so recorded ids combine the kind index with the protobuf extension number.

The stride is only as wide as it needs to be: 1280 is the first round number above the largest extension actually in use (ModeratorCommand = 1206) and keeps the preallocated TypeStats array small. Bump it if a new command exceeds it.

◆ MaxTypes

int MetricsRegistry::MaxTypes = NumKinds * KindStride
staticconstexpr

Upper bound on distinct command type ids (see typeIdFor).

◆ NumKinds

int MetricsRegistry::NumKinds = 6
staticconstexpr

◆ totalCommandsCounter

std::atomic<qint64> MetricsRegistry::totalCommandsCounter {0}
private

◆ totalTimeCounter

std::atomic<qint64> MetricsRegistry::totalTimeCounter {0}
private

◆ typeSlots

std::array<TypeStats, MaxTypes> MetricsRegistry::typeSlots {}
private

The documentation for this class was generated from the following files: