Skip to content

Commit

Permalink
Metrics API (hollow) (#6825)
Browse files Browse the repository at this point in the history
Adds an unimplemented metrics API to replace blackbox.

---------

Co-authored-by: LordME <[email protected]>
  • Loading branch information
silicons and TheLordME authored Nov 11, 2024
1 parent 6899807 commit 3af7853
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 28 deletions.
11 changes: 7 additions & 4 deletions citadel.dme
Original file line number Diff line number Diff line change
Expand Up @@ -3196,6 +3196,10 @@
#include "code\modules\language\languages\species\vulpkanin.dm"
#include "code\modules\language\languages\species\zaddat.dm"
#include "code\modules\language\languages\species\zorren.dm"
#include "code\modules\legacy_metric\activity.dm"
#include "code\modules\legacy_metric\count.dm"
#include "code\modules\legacy_metric\department.dm"
#include "code\modules\legacy_metric\metric.dm"
#include "code\modules\library\book.dm"
#include "code\modules\library\lib_items.dm"
#include "code\modules\library\lib_machines.dm"
Expand Down Expand Up @@ -3490,10 +3494,9 @@
#include "code\modules\media\media_tracks.dm"
#include "code\modules\media\mediamanager.dm"
#include "code\modules\media\walkpod.dm"
#include "code\modules\metric\activity.dm"
#include "code\modules\metric\count.dm"
#include "code\modules\metric\department.dm"
#include "code\modules\metric\metric.dm"
#include "code\modules\metrics\api.dm"
#include "code\modules\metrics\metric.dm"
#include "code\modules\metrics\metric_base.dm"
#include "code\modules\mining\mine_turfs.dm"
#include "code\modules\mining\drilling\drill.dm"
#include "code\modules\mining\drilling\scanner.dm"
Expand Down
2 changes: 1 addition & 1 deletion code/global.dm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var/gravity_is_on = 1

var/join_motd = null

var/datum/metric/metric = new() // Metric datum, used to keep track of the round.
var/datum/legacy_metric/metric = new() // Metric datum, used to keep track of the round.

var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This checks an individual player's activity level. People who have been afk for a few minutes aren't punished as much as those
// who were afk for hours, as they're most likely gone for good.
/datum/metric/proc/assess_player_activity(var/mob/M)
/datum/legacy_metric/proc/assess_player_activity(var/mob/M)
. = 100
if(!M)
. = 0
Expand All @@ -22,7 +22,7 @@
. = max(. , 0) // No negative numbers, or else people could drag other, non-afk players down.

// This checks a whole department's collective activity.
/datum/metric/proc/assess_department(var/department)
/datum/legacy_metric/proc/assess_department(var/department)
if(!department)
return
var/departmental_activity = 0
Expand All @@ -36,7 +36,7 @@
departmental_activity = departmental_activity / departmental_size // Average it out.
return departmental_activity

/datum/metric/proc/assess_all_departments(var/cutoff_number = 3, var/list/department_blacklist = list())
/datum/legacy_metric/proc/assess_all_departments(var/cutoff_number = 3, var/list/department_blacklist = list())
var/list/activity = list()
for(var/department in departments)
activity[department] = assess_department(department)
Expand All @@ -63,7 +63,7 @@
//todo: finish
return most_active_departments

/datum/metric/proc/assess_all_living_mobs() // Living refers to the type, not the stat variable.
/datum/legacy_metric/proc/assess_all_living_mobs() // Living refers to the type, not the stat variable.
. = 0
var/num = 0
for(var/mob/living/L in GLOB.player_list)
Expand All @@ -72,7 +72,7 @@
if(num)
. = round(. / num, 0.1)

/datum/metric/proc/assess_all_dead_mobs() // Ditto.
/datum/legacy_metric/proc/assess_all_dead_mobs() // Ditto.
. = 0
var/num = 0
for(var/mob/observer/dead/O in GLOB.player_list)
Expand All @@ -81,7 +81,7 @@
if(num)
. = round(. / num, 0.1)

/datum/metric/proc/assess_all_outdoor_mobs()
/datum/legacy_metric/proc/assess_all_outdoor_mobs()
. = 0
var/num = 0
for(var/mob/living/L in GLOB.player_list)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Procs for counting active players in different situations. Returns the number of active players within the given cutoff.
*/

/datum/metric/proc/count_all_outdoor_mobs(var/cutoff = 75)
/datum/legacy_metric/proc/count_all_outdoor_mobs(var/cutoff = 75)
var/num = 0
for(var/mob/living/L in GLOB.player_list)
var/turf/T = get_turf(L)
Expand All @@ -11,7 +11,7 @@
num++
return num

/datum/metric/proc/count_all_space_mobs(var/cutoff = 75, var/respect_z = TRUE)
/datum/legacy_metric/proc/count_all_space_mobs(var/cutoff = 75, var/respect_z = TRUE)
var/num = 0
for(var/mob/living/L in GLOB.player_list)
var/turf/T = get_turf(L)
Expand All @@ -24,7 +24,7 @@

// Gives a count of how many human mobs of a specific species are on the station.
// Note that `ignore_synths` makes this proc ignore posibrains and drones, but NOT cyborgs, as they are still the same species in-universe.
/datum/metric/proc/count_all_of_specific_species(species_name, ignore_synths = TRUE, cutoff = 75, respect_z = TRUE)
/datum/legacy_metric/proc/count_all_of_specific_species(species_name, ignore_synths = TRUE, cutoff = 75, respect_z = TRUE)
var/num = 0
for(var/mob/living/carbon/human/H in GLOB.player_list)
if(respect_z && !(H.z in (LEGACY_MAP_DATUM).station_levels))
Expand All @@ -37,7 +37,7 @@
return num

// Gives a count of how many FBPs of a specific type there are on the station.
/datum/metric/proc/count_all_FBPs_of_kind(desired_FBP_class, cutoff = 75, respect_z = TRUE)
/datum/legacy_metric/proc/count_all_FBPs_of_kind(desired_FBP_class, cutoff = 75, respect_z = TRUE)
var/num = 0
for(var/mob/living/carbon/human/H in GLOB.player_list)
if(respect_z && !(H.z in (LEGACY_MAP_DATUM).station_levels))
Expand All @@ -49,19 +49,19 @@
return num

// Like above, but for all FBPs.
/datum/metric/proc/count_all_FBPs(cutoff = 75, respect_z = TRUE)
/datum/legacy_metric/proc/count_all_FBPs(cutoff = 75, respect_z = TRUE)
var/num = count_all_FBPs_of_kind(FBP_CYBORG, cutoff, respect_z)
num += count_all_FBPs_of_kind(FBP_POSI, cutoff, respect_z)
num += count_all_FBPs_of_kind(FBP_DRONE, cutoff, respect_z)
return num


/datum/metric/proc/get_all_antags(cutoff = 75)
/datum/legacy_metric/proc/get_all_antags(cutoff = 75)
. = list()
for(var/mob/living/L in GLOB.player_list)
if(L.mind && player_is_antag(L.mind) && assess_player_activity(L) >= cutoff)
. += L

/datum/metric/proc/count_all_antags(cutoff = 75)
/datum/legacy_metric/proc/count_all_antags(cutoff = 75)
var/list/L = get_all_antags(cutoff)
return L.len
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

// This proc tries to find the department of an arbitrary mob.
/datum/metric/proc/guess_department(var/mob/M)
/datum/legacy_metric/proc/guess_department(var/mob/M)
var/list/found_roles = list()
. = DEPARTMENT_UNKNOWN

Expand Down Expand Up @@ -30,7 +30,7 @@
return DEPARTMENT_UNKNOWN // Welp.

// Similar to above, but gets the actual job. Note that it returns the job datum itself, or null.
/datum/metric/proc/guess_job(mob/M)
/datum/legacy_metric/proc/guess_job(mob/M)
// Like before, records are the most reliable way.
var/datum/data/record/R = find_general_record("name", M.real_name)
if(R) // They got a record, now find the job datum.
Expand All @@ -53,19 +53,19 @@

// Feed this proc the name of a job, and it will try to figure out what department they are apart of.
// Improved with the addition of SSjob, which has departments be an actual thing and not a virtual concept.
/datum/metric/proc/role_name_to_department(var/role_name)
/datum/legacy_metric/proc/role_name_to_department(var/role_name)
var/datum/role/job/J = SSjob.get_job(role_name)
if(istype(J))
if(LAZYLEN(J.departments))
return J.departments
return list(DEPARTMENT_UNKNOWN)

/datum/metric/proc/count_people_in_department(var/department, cutoff = 75)
/datum/legacy_metric/proc/count_people_in_department(var/department, cutoff = 75)
var/list/L = get_people_in_department(department, cutoff)
return L.len


/datum/metric/proc/get_people_in_department(department, cutoff = 75)
/datum/legacy_metric/proc/get_people_in_department(department, cutoff = 75)
. = list()
if(!department)
return
Expand All @@ -81,7 +81,7 @@
continue
. += M

/datum/metric/proc/get_people_with_job(job_type, cutoff = 75)
/datum/legacy_metric/proc/get_people_with_job(job_type, cutoff = 75)
. = list()
// First, get the name.
var/datum/role/job/J = SSjob.job_by_type(job_type)
Expand All @@ -99,13 +99,13 @@
continue
. += M

/datum/metric/proc/count_people_with_job(job_type, cutoff = 75)
/datum/legacy_metric/proc/count_people_with_job(job_type, cutoff = 75)
var/list/L = get_people_with_job(job_type, cutoff)
return L.len



/datum/metric/proc/get_people_with_alt_title(job_type, alt_title_type, cutoff = 75)
/datum/legacy_metric/proc/get_people_with_alt_title(job_type, alt_title_type, cutoff = 75)
. = list()

var/list/people_with_jobs = get_people_with_job(job_type, cutoff)
Expand All @@ -116,6 +116,6 @@
if(J.has_alt_title(M, null, A.title))
. += M

/datum/metric/proc/count_people_with_alt_title(job_type, alt_title_type, cutoff = 75)
/datum/legacy_metric/proc/count_people_with_alt_title(job_type, alt_title_type, cutoff = 75)
var/list/L = get_people_with_alt_title(job_type, alt_title_type, cutoff)
return L.len
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// This is a global datum used to retrieve certain information about the round, such as activity of a department or a specific
// player.

/datum/metric
/datum/legacy_metric
var/list/departments = list(
DEPARTMENT_COMMAND,
DEPARTMENT_SECURITY,
Expand Down
3 changes: 3 additions & 0 deletions code/modules/metrics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Metrics

In-dev feedback gathering system.
78 changes: 78 additions & 0 deletions code/modules/metrics/api.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//

/**
* counter metric
*
* * numerical, can only go up through a round
*/
/datum/metric/counter

/**
* increments a counter metric by an amount, defaulting to 1
*
* * The time at which this is called does matter. The recorded metric will be at the current
* time of the recording.
*
* This is what you can use for things like:
*
* * How many times an admin verb was pressed in a round
* * How many times a thing happened in a round
*/
/proc/metric_record_counter(datum/metric/counter/typepath, amount = 1)
return

/**
* records a series of values at given times
*
* * Supports a number, string, or both.
*
* This is what you can use for things like:
*
* * Time dilation tracking
*/
/datum/metric/series
/// has numerical data to graph
///
/// * doesn't limit the data, only determines if we try to pull a graph
var/graph_exists = FALSE
/// representation of numerical data in graph
///
/// * valid values are ["average", "tally"]
var/graph_collate = "tally"

/**
* records a number or a string in a series metric
*
* * The time at which this is called does matter. The recorded metric will be at the current
* time of the recording.
*/
/proc/metric_record_series(datum/metric/series/typepath, tally, comment)
return

/**
* Records an event at a specific tile of a map
*
* * Supports a single tile event with annotation of number and/or string
* * Supports a rectangular event with annotation of number and/or string
*
* This is usually used for game-map purposes, but is actually usable as an arbitrary
* spatial metric if you need it for whatever reason.
*
* This is what you can use for things like:
*
* * Tracking where people died
* * Tracking what explodes
* * Tracking what goes wrong where
*/
/datum/metric/spatial
/// Whether the spatial metric corrosponds to the actual in-game map
var/is_game_world = FALSE
/// Don't render a tally of '1'
var/elide_singular_tally = TRUE

/proc/metric_record_spatial_single(datum/metric/spatial/typepath, x, y, level_id, tally, comment)
return

/proc/metric_record_spatial_box(datum/metric/spatial/typepath, x1, y1, x2, y2, level_id, tally, comment)
return
24 changes: 24 additions & 0 deletions code/modules/metrics/metric.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//

/**
* Describes a feedback variable.
*
* * All metrics should be well-formed and described in DM-code, as the DM
* code is the root of trust for what something actually is.
*/
/datum/metric
/// id
///
/// * must be unique; this should never change
/// * changes require databaes migrations
var/id
/// fancy name
///
/// * not recorded to database; external renders/access reserve the right to use
/// their own names
var/name
/// category; string value.
///
/// * this corrosponds to database-level enums, be careful with this
var/category
28 changes: 28 additions & 0 deletions code/modules/metrics/metric_base.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//

/**
* Base metrics recorded every round.
*
* This includes things required to display metrics data, like round ID,
* server revision, and more.
*
* Any of these may be missing if we're unable to get the data. If round ID is
* missing, we should just bail on metrics reporting, as round ID is an
* identifying key in the metrics database.
*
* * Testmerges are intentionally not included as part of this. No metrics render solution
* should be performing full testmerges in general; testmerge data can always
* be recorded as a series data.
*/
/datum/metric_base
/// round ID as **string**
var/round_id
/// server revision hash
///
/// * dependent on git; at time of writing this is SHA-1
var/commit_hash
/// all valid metric ids, as a list
///
/// * this is generated via typesof()
var/list/metric_ids

0 comments on commit 3af7853

Please sign in to comment.