Compare commits
9 Commits
042ddf0e34
...
0.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
21dd601325
|
|||
|
b7b9c89dc2
|
|||
|
a209843caa
|
|||
|
2907101a42
|
|||
|
20400a0929
|
|||
|
e907eeecfd
|
|||
|
6cf4297ab9
|
|||
|
5d30b1931c
|
|||
|
c687d1a3f1
|
68
7cavChat.txt
68
7cavChat.txt
@@ -1,68 +0,0 @@
|
||||
Jarvis — Today at 8:23 PM
|
||||
@EagleTrooper let's use this instead
|
||||
to save blowing up the recruiters notifications
|
||||
on recruitment
|
||||
EagleTrooper — Today at 8:23 PM
|
||||
Yeah keep the recruitment clean. I understand Im a recruiter / NCO / admin for the community in involved in.
|
||||
Alright,
|
||||
I am working on developing a dashboard that gives historical stats with our server as well as our missions that run Performance / FPS / Memory Usage / etc. During my research i came across your groups Repo and it appears that you are doing something very similar to what I wanted to do. I did read through just to get an idea unfortunately there was some gaps in the implementation and i was hoping to speak to someone about how it was done with your group as well as if they would be so kind as to provide pointers and insight so that I may implement something very similar.
|
||||
Jarvis — Today at 8:26 PM
|
||||
Do you know how to setup a Grafana/InfluxDB stack?
|
||||
EagleTrooper — Today at 8:27 PM
|
||||
Already have it setup (Background in IT and Cloud Network Engineering).
|
||||
Sweetwater.I — Today at 8:27 PM
|
||||
u can see our dashboard here if u wanna see what cavmetrics extension is outputting.
|
||||
https://metrics.7cav.us/d/NED-gV3Mz/arma3?orgId=1&refresh=10s
|
||||
Jarvis — Today at 8:28 PM
|
||||
It's basically just arma -> influx -> grafana
|
||||
Sweetwater.I — Today at 8:28 PM
|
||||
but yeah, influxdb+grafana is what we do
|
||||
Jarvis — Today at 8:28 PM
|
||||
The cavmetrics addon you see is the arma extension
|
||||
EagleTrooper — Today at 8:28 PM
|
||||
Yep understood the workflow and that was very clear. I believe the piece im missing or dont understand is the dll creation / implementation
|
||||
Jarvis — Today at 8:28 PM
|
||||
If you know influx/grafana, you're 2/3rds of the way there
|
||||
|
||||
Just git clone the cavmetrics repo
|
||||
EagleTrooper — Today at 8:29 PM
|
||||
I believe it was the Arma-Influx?
|
||||
That was the piece that i was not clear on. Unless i was misunderstanding it still required a compiled DLL
|
||||
Jarvis — Today at 8:29 PM
|
||||
the a3_influx dll is inside of the git repo
|
||||
so == a DLL but linux
|
||||
we run our servers on linux
|
||||
EagleTrooper — Today at 8:30 PM
|
||||
Unfortuantly it looks like its a .so
|
||||
Sweetwater.I — Today at 8:30 PM
|
||||
use the arma-influx repo to build the extension
|
||||
EagleTrooper — Today at 8:30 PM
|
||||
Yeah we have windows :/
|
||||
Sweetwater.I — Today at 8:30 PM
|
||||
cavmetrics is what we called the packaged extension.
|
||||
on the repo
|
||||
Jarvis — Today at 8:30 PM
|
||||
https://github.com/7Cav/Arma-Influx
|
||||
GitHub
|
||||
GitHub - 7Cav/Arma-Influx: Arma Extension for sending metrics to In...
|
||||
Arma Extension for sending metrics to InfluxDB. Contribute to 7Cav/Arma-Influx development by creating an account on GitHub.
|
||||
|
||||
Just compile that for dll
|
||||
it's an arma ext written in go
|
||||
Liber.N — Today at 8:31 PM
|
||||
Cavmetrics is an arma addon thats calls to arma influx extension
|
||||
Jarvis — Today at 8:31 PM
|
||||
you'll need to change the makefile on that repo tho
|
||||
EagleTrooper — Today at 8:32 PM
|
||||
does it need to be labeld armago? or a3influx?
|
||||
If that is what your referring to then it appears i do have an understanding of it and something else is missing outside of my imediate understanding and may not have anything you can provide input on. I will review the implementation again and see if I can get any further.
|
||||
I do appreciate the input and help.
|
||||
Jarvis — Today at 8:35 PM
|
||||
no probs, it's a long road but found it worth it in the end
|
||||
|
||||
https://metrics.7cav.us/
|
||||
Specifically - https://metrics.7cav.us/d/NED-gV3Mz/arma3?orgId=1&refresh=10s
|
||||
EagleTrooper — Today at 8:36 PM
|
||||
I will take a look! Keep on Keeping on and again I appreciate the friendly response!
|
||||
Jarvis — Today at 8:36 PM
|
||||
You'll need to update these for your influx db host - https://github.com/7Cav/cav_metrics/blob/dev/%40CavMetrics/addons/CavMetrics/functions/fn_send.sqf#L9-L12
|
||||
@@ -2,7 +2,7 @@ class CfgPatches {
|
||||
class RangerMetrics {
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
requiredVersion = 0.1;
|
||||
requiredVersion = 2.10;
|
||||
requiredAddons[] = {};
|
||||
author[] = {"EagleTrooper","Gary","IndigoFox"};
|
||||
authorUrl = "http://example.com";
|
||||
@@ -10,6 +10,13 @@ class CfgPatches {
|
||||
};
|
||||
|
||||
class CfgFunctions {
|
||||
class RangerMetrics_callback {
|
||||
class functions {
|
||||
file = "\RangerMetrics\functions\callbackHandlers";
|
||||
class callbackHandler {};
|
||||
class loadSettings {};
|
||||
};
|
||||
};
|
||||
class RangerMetrics_event {
|
||||
class functions {
|
||||
file = "\RangerMetrics\functions\capture\EHOnly";
|
||||
@@ -23,7 +30,7 @@ class CfgFunctions {
|
||||
class MarkerUpdated {};
|
||||
class milsim_serverEfficiency {};
|
||||
};
|
||||
}
|
||||
};
|
||||
class RangerMetrics_cDefinitions {
|
||||
class functions {
|
||||
file = "\RangerMetrics\functions\captureDefinitions";
|
||||
@@ -62,10 +69,10 @@ class CfgFunctions {
|
||||
class log {};
|
||||
class queue {};
|
||||
class send {};
|
||||
class callbackHandler {};
|
||||
class sendClientPoll {};
|
||||
class startServerPoll {};
|
||||
class classHandlers {};
|
||||
class initCapture {};
|
||||
};
|
||||
class helpers {
|
||||
file = "\RangerMetrics\functions\helpers";
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
params ["_name", "_function", "_data"];
|
||||
if !(_name == "RangerMetrics") exitWith {};
|
||||
|
||||
// Validate data param
|
||||
if (isNil "_data") then {_data = ""};
|
||||
|
||||
if (_data isEqualTo "") exitWith {
|
||||
[
|
||||
format ["Callback empty data: %1", _function],
|
||||
"WARN"
|
||||
] call RangerMetrics_fnc_log;
|
||||
false;
|
||||
};
|
||||
|
||||
// Parse response from string array
|
||||
private "_response";
|
||||
try {
|
||||
// diag_log format ["Raw callback: %1: %2", _function, _data];
|
||||
if (_function find "JSON" > -1) then {
|
||||
_response = [_data, 2] call CBA_fnc_parseJSON;
|
||||
} else {
|
||||
_response = parseSimpleArray _data;
|
||||
};
|
||||
} catch {
|
||||
[
|
||||
format ["Callback invalid data: %1: %2", _function, _data],
|
||||
"WARN"
|
||||
] call RangerMetrics_fnc_log;
|
||||
};
|
||||
|
||||
|
||||
switch (_function) do {
|
||||
case "deinitExtension": {
|
||||
// Our first call is deinitExtension. When we received a single "true" value, we can then run init processes for the extension connections.
|
||||
if ((_response select 0) isEqualTo true) then {
|
||||
"RangerMetrics" callExtension "initExtension";
|
||||
} else {
|
||||
_response call RangerMetrics_fnc_log;
|
||||
};
|
||||
};
|
||||
case "loadSettingsJSON": {
|
||||
[_function, _response] call RangerMetrics_callback_fnc_loadSettings;
|
||||
};
|
||||
case "loadSettings": {
|
||||
// Load settings
|
||||
[_function, _response] call RangerMetrics_callback_fnc_loadSettings;
|
||||
};
|
||||
case "extensionReady": {
|
||||
// deinitialize existing captures
|
||||
if (!isNil "RangerMetrics_allMEH") then {
|
||||
{
|
||||
private _handle = missionNamespace getVariable _x;
|
||||
if (isNil "_handle") then {continue};
|
||||
private _EHName = (_x splitString "_") select 2;
|
||||
removeMissionEventHandler [_EHName, _handle];
|
||||
missionNamespace setVariable [_x, nil];
|
||||
} forEach RangerMetrics_allMEH;
|
||||
};
|
||||
|
||||
if (!isNil "RangerMetrics_allCBA") then {
|
||||
{
|
||||
private _handle = missionNamespace getVariable _x;
|
||||
if (isNil "_handle") then {continue};
|
||||
private _EHName = (_x splitString "_") select 2;
|
||||
[_EHName, _handle] call CBA_fnc_removeEventHandler;
|
||||
missionNamespace setVariable [_x, nil];
|
||||
} forEach RangerMetrics_allCBA;
|
||||
};
|
||||
|
||||
if (!isNil "RangerMetrics_allServerPoll") then {
|
||||
{
|
||||
private _handle = missionNamespace getVariable _x;
|
||||
if (isNil "_handle") then {continue};
|
||||
terminate _handle;
|
||||
missionNamespace setVariable [_x, nil];
|
||||
} forEach RangerMetrics_allServerPoll;
|
||||
};
|
||||
|
||||
call RangerMetrics_fnc_initCapture;
|
||||
};
|
||||
default {
|
||||
_response call RangerMetrics_fnc_log;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
params ["_function", "_data"];
|
||||
|
||||
|
||||
if (_function isEqualTo "loadSettingsJSON") exitWith {
|
||||
RangerMetrics_settings = _data;
|
||||
RangerMetrics_recordingSettings = _data get "recordingSettings";
|
||||
|
||||
RangerMetrics_debug = RangerMetrics_settings get "arma3" get "debug";
|
||||
|
||||
[
|
||||
format [
|
||||
"Settings loaded: %1",
|
||||
_data
|
||||
],
|
||||
"INFO"
|
||||
] call RangerMetrics_fnc_log;
|
||||
|
||||
if (isServer) then {
|
||||
missionNamespace setVariable [
|
||||
"RangerMetrics_serverProfileName",
|
||||
profileName,
|
||||
true
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
switch (_data select 0) do {
|
||||
case "CREATED SETTINGS": {
|
||||
[
|
||||
"settings.json did not exist and has been created - you will need to update it with your own settings before the addon will initialize further.",
|
||||
"ERROR"
|
||||
] call RangerMetrics_fnc_log;
|
||||
};
|
||||
|
||||
case "loadSettings": {
|
||||
[
|
||||
format [
|
||||
"Setting loaded: %1",
|
||||
_data
|
||||
],
|
||||
"INFO"
|
||||
] call RangerMetrics_fnc_log;
|
||||
|
||||
};
|
||||
|
||||
default {
|
||||
[
|
||||
_data select 0,
|
||||
"INFO"
|
||||
] call RangerMetrics_fnc_log;
|
||||
};
|
||||
};
|
||||
@@ -15,7 +15,7 @@ private _fields = [
|
||||
["bool", "forcedDisplay", _forcedDisplay],
|
||||
["bool", "isPlayerMessage", _isPlayerMessage],
|
||||
["int", "sentenceType", _sentenceType],
|
||||
["int", "chatMessageType", _chatMessageType]
|
||||
["int", "chatMessageType", _chatMessageType toFixed 0]
|
||||
];
|
||||
|
||||
// we need special processing to ensure the object is valid and we have a playerUid. Line protocol doesn't support empty string
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
params ["_fields", []];
|
||||
params [["_fields", []]];
|
||||
|
||||
// Example:
|
||||
// [
|
||||
// ["float", "milsim_raw_cps", "3207.98"],
|
||||
// ["float", "milsim_cps", "1"]
|
||||
// ]
|
||||
// ["milsim_serverEfficiency", [[
|
||||
// ["float", "milsim_raw_cps", "3207.98"],
|
||||
// ["float", "milsim_cps", "1"]
|
||||
// ]]] call CBA_fnc_serverEvent;
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "CBAEventHandlers" get "milsimServerEfficiency";
|
||||
|
||||
[
|
||||
"server_state",
|
||||
"server_efficiency",
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil,
|
||||
_fields,
|
||||
["server"]
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "entityCount";
|
||||
|
||||
|
||||
private _allUnits = allUnits;
|
||||
private _allDeadMen = allDeadMen;
|
||||
private _allGroups = allGroups;
|
||||
@@ -9,92 +12,104 @@ private _allPlayers = call BIS_fnc_listPlayers;
|
||||
private _thisSide = _x;
|
||||
private _thisSideStr = _thisSide call BIS_fnc_sideNameUnlocalized;
|
||||
// Number of remote units
|
||||
["server_state", "entities_remote", [
|
||||
["string", "side", _thisSideStr]
|
||||
], [
|
||||
["int", "units_alive", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allUnits],
|
||||
["int", "units_dead", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allDeadMen],
|
||||
["int", "groups_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allGroups],
|
||||
["int", "vehicles_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x) &&
|
||||
!(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "vehicles_weaponholder", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x) &&
|
||||
(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
|
||||
// Number of local units
|
||||
["server_state", "entities_local", [
|
||||
["string", "side", _thisSideStr]
|
||||
], [
|
||||
["int", "units_alive", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allUnits],
|
||||
["int", "units_dead", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allDeadMen],
|
||||
["int", "groups_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allGroups],
|
||||
["int", "vehicles_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x &&
|
||||
!(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "vehicles_weaponholder", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x &&
|
||||
(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
|
||||
// Number of global units - only track on server
|
||||
if (isServer) then {
|
||||
["server_state", "entities_global", [
|
||||
[
|
||||
_settings get "bucket",
|
||||
"entities_remote",
|
||||
[
|
||||
["string", "side", _thisSideStr]
|
||||
], [
|
||||
["int", "units_alive", {
|
||||
side _x isEqualTo _thisSide
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allUnits],
|
||||
["int", "units_dead", {
|
||||
side _x isEqualTo _thisSide
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allDeadMen],
|
||||
["int", "groups_total", {
|
||||
side _x isEqualTo _thisSide
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x)
|
||||
} count _allGroups],
|
||||
["int", "vehicles_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x) &&
|
||||
!(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "vehicles_weaponholder", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
not (local _x) &&
|
||||
(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles]
|
||||
]
|
||||
] call RangerMetrics_fnc_queue;
|
||||
|
||||
// Number of local units
|
||||
[
|
||||
_settings get "bucket",
|
||||
"entities_local",
|
||||
[
|
||||
["string", "side", _thisSideStr]
|
||||
], [
|
||||
["int", "units_alive", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allUnits],
|
||||
["int", "units_dead", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allDeadMen],
|
||||
["int", "groups_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x
|
||||
} count _allGroups],
|
||||
["int", "vehicles_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
local _x &&
|
||||
!(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "players_alive", {
|
||||
["int", "vehicles_weaponholder", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
alive _x
|
||||
} count _allPlayers],
|
||||
["int", "players_dead", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
!alive _x
|
||||
} count _allPlayers]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
local _x &&
|
||||
(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles]
|
||||
]
|
||||
] call RangerMetrics_fnc_queue;
|
||||
|
||||
// Number of global units - only track on server
|
||||
if (isServer) then {
|
||||
[
|
||||
_settings get "bucket",
|
||||
"entities_global",
|
||||
[
|
||||
["string", "side", _thisSideStr]
|
||||
], [
|
||||
["int", "units_alive", {
|
||||
side _x isEqualTo _thisSide
|
||||
} count _allUnits],
|
||||
["int", "units_dead", {
|
||||
side _x isEqualTo _thisSide
|
||||
} count _allDeadMen],
|
||||
["int", "groups_total", {
|
||||
side _x isEqualTo _thisSide
|
||||
} count _allGroups],
|
||||
["int", "vehicles_total", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
!(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "vehicles_weaponholder", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
(_x isKindOf "WeaponHolderSimulated")
|
||||
} count _vehicles],
|
||||
["int", "players_alive", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
alive _x
|
||||
} count _allPlayers],
|
||||
["int", "players_dead", {
|
||||
side _x isEqualTo _thisSide &&
|
||||
!alive _x
|
||||
} count _allPlayers]
|
||||
]
|
||||
] call RangerMetrics_fnc_queue;
|
||||
};
|
||||
|
||||
} forEach [east, west, independent, civilian];
|
||||
@@ -3,11 +3,12 @@ if (!RangerMetrics_run) exitWith {};
|
||||
params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit", ["_jip", false]];
|
||||
// _networkInfo params ["_avgPing", "_avgBandwidth", "_desync"];
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "playerIdentity";
|
||||
|
||||
|
||||
private _fields = [
|
||||
["string", "playerID", _playerID],
|
||||
["string", "ownerId", _ownerId],
|
||||
["int", "ownerId", _ownerId],
|
||||
["string", "playerUID", _playerUID],
|
||||
["string", "profileName", _profileName],
|
||||
["string", "displayName", _displayName],
|
||||
@@ -43,7 +44,7 @@ try {
|
||||
];
|
||||
} forEach _squadInfoDataFormat;
|
||||
|
||||
_unitInfoDataFormat =[
|
||||
_unitInfoDataFormat = [
|
||||
"unitUid",
|
||||
"unitName",
|
||||
"unitFullName",
|
||||
@@ -72,8 +73,8 @@ if (_roleDescription isNotEqualTo "") then {
|
||||
};
|
||||
|
||||
[
|
||||
"player_state",
|
||||
"player_identity",
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
[
|
||||
["string", "playerUID", _playerUID]
|
||||
],
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "playerPerformance";
|
||||
|
||||
{
|
||||
_x params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"];
|
||||
_networkInfo params ["_avgPing", "_avgBandwidth", "_desync"];
|
||||
|
||||
if (_unit == objNull || _isHC) then {
|
||||
continue;
|
||||
};
|
||||
|
||||
[
|
||||
"player_state",
|
||||
"player_performance",
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
[["string", "playerUID", _playerUID]],
|
||||
[
|
||||
["float", "avgPing", _avgPing],
|
||||
|
||||
@@ -3,7 +3,11 @@ if (!RangerMetrics_run) exitWith {};
|
||||
params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"];
|
||||
// _networkInfo params ["_avgPing", "_avgBandwidth", "_desync"];
|
||||
|
||||
["player_state", "player_status",
|
||||
private _settings = RangerMetrics_recordingSettings get "playerStatus";
|
||||
|
||||
[
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
[["string", "playerUID", _playerUID]],
|
||||
[
|
||||
["int", "clientStateNumber", _clientState],
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
// Mission name
|
||||
private _settings = RangerMetrics_recordingSettings get "runningMission";
|
||||
|
||||
[
|
||||
"server_state", // bucket to store the data
|
||||
"running_mission", // measurement classifier inside of bucket
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil, // tags
|
||||
[ // fields
|
||||
["string","briefing_name", briefingName],
|
||||
["string","mission_name", missionName],
|
||||
["string","mission_name_source", missionNameSource],
|
||||
[
|
||||
"string",
|
||||
"onLoadName",
|
||||
"on_load_name",
|
||||
getMissionConfigValue ["onLoadName", ""]
|
||||
],
|
||||
["string","briefingName", briefingName],
|
||||
["string","missionName", missionName],
|
||||
["string","missionNameSource", missionNameSource]
|
||||
["string","author", getMissionConfigValue ["author", ""]],
|
||||
["string","server_name",serverName]
|
||||
],
|
||||
["profile", "server", "world"] // context
|
||||
] call RangerMetrics_fnc_queue;
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
["server_state", "running_scripts", nil, [
|
||||
["int", "spawn", diag_activeScripts select 0],
|
||||
["int", "execVM", diag_activeScripts select 1],
|
||||
["int", "exec", diag_activeScripts select 2],
|
||||
["int", "execFSM", diag_activeScripts select 3],
|
||||
["int", "pfh", if (RangerMetrics_cbaPresent) then {count CBA_common_perFrameHandlerArray} else {0}]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
private _settings = RangerMetrics_recordingSettings get "runningScripts";
|
||||
|
||||
[
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil,
|
||||
[
|
||||
["int", "spawn", diag_activeScripts select 0],
|
||||
["int", "execVM", diag_activeScripts select 1],
|
||||
["int", "exec", diag_activeScripts select 2],
|
||||
["int", "execFSM", diag_activeScripts select 3],
|
||||
["int", "pfh",
|
||||
if (RangerMetrics_cbaPresent) then {
|
||||
count CBA_common_perFrameHandlerArray
|
||||
} else {0}
|
||||
]
|
||||
]
|
||||
] call RangerMetrics_fnc_queue;
|
||||
@@ -1,6 +1,11 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
["server_state", "server_performance", nil, [
|
||||
private _settings = RangerMetrics_recordingSettings get "serverPerformance";
|
||||
|
||||
[
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil, [
|
||||
["float", "fps_avg", diag_fps toFixed 2],
|
||||
["float", "fps_min", diag_fpsMin toFixed 2]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
@@ -1,8 +1,15 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
["server_state", "server_time", nil, [
|
||||
["float", "diag_tickTime", diag_tickTime toFixed 2],
|
||||
["float", "serverTime", time toFixed 2],
|
||||
["float", "timeMultiplier", timeMultiplier toFixed 2],
|
||||
["float", "accTime", accTime toFixed 2]
|
||||
]] call RangerMetrics_fnc_queue;
|
||||
private _settings = RangerMetrics_recordingSettings get "serverTime";
|
||||
|
||||
[
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil,
|
||||
[
|
||||
["float", "diag_tickTime", diag_tickTime toFixed 2],
|
||||
["float", "serverTime", time toFixed 2],
|
||||
["float", "timeMultiplier", timeMultiplier toFixed 2],
|
||||
["float", "accTime", accTime toFixed 2]
|
||||
]
|
||||
] call RangerMetrics_fnc_queue;
|
||||
@@ -1,8 +1,10 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "viewDistance";
|
||||
|
||||
[
|
||||
"server_state",
|
||||
"view_distance",
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil,
|
||||
[
|
||||
["float", "objectViewDistance", getObjectViewDistance # 0],
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "weather";
|
||||
|
||||
[
|
||||
"server_state", // bucket to store the data
|
||||
"weather", // measurement classifier inside of bucket
|
||||
_settings get "bucket",
|
||||
_settings get "measurement",
|
||||
nil, // tags
|
||||
[ // fields
|
||||
["float", "fog", fog],
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
[
|
||||
["ace_unconscious", RangerMetrics_event_fnc_ace_unconscious],
|
||||
["milsim_serverEfficiency", RangerMetrics_event_fnc_milsim_serverEfficiency]
|
||||
// ["ace_unconscious", RangerMetrics_event_fnc_ace_unconscious],
|
||||
[
|
||||
"milsimServerEfficiency",
|
||||
"milsim_serverEfficiency",
|
||||
RangerMetrics_event_fnc_milsim_serverEfficiency
|
||||
]
|
||||
]
|
||||
@@ -29,14 +29,14 @@
|
||||
}],
|
||||
["PlayerConnected", {
|
||||
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
|
||||
private _userInfo = (getUserInfo _networkId);
|
||||
private _userInfo = (getUserInfo _idstr);
|
||||
_userInfo call RangerMetrics_capture_fnc_player_identity;
|
||||
_userInfo call RangerMetrics_capture_fnc_player_status;
|
||||
[_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
// [_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
["server_events", "PlayerConnected", [
|
||||
["string", "playerUID", _userInfo#2]
|
||||
["string", "playerUID", _uid]
|
||||
], [
|
||||
["int", "id", _id],
|
||||
["string", "id", _id toFixed 0],
|
||||
["string", "uid", _uid],
|
||||
["string", "name", _name],
|
||||
["bool", "jip", _jip],
|
||||
@@ -47,13 +47,13 @@
|
||||
}],
|
||||
["PlayerDisconnected", {
|
||||
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
|
||||
private _userInfo = (getUserInfo _networkId);
|
||||
private _userInfo = (getUserInfo _idstr);
|
||||
_userInfo call RangerMetrics_capture_fnc_player_identity;
|
||||
_userInfo call RangerMetrics_capture_fnc_player_status;
|
||||
["server_events", "PlayerDisconnected", [
|
||||
["string", "playerUID", _userInfo#2]
|
||||
["string", "playerUID", _uid]
|
||||
], [
|
||||
["int", "id", _id],
|
||||
["string", "id", _id toFixed 0],
|
||||
["string", "uid", _uid],
|
||||
["string", "name", _name],
|
||||
["bool", "jip", _jip],
|
||||
@@ -136,16 +136,16 @@
|
||||
) exitWith {};
|
||||
_this call RangerMetrics_event_fnc_EntityKilled;
|
||||
call RangerMetrics_capture_fnc_entity_count;
|
||||
[_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
[_entity] call RangerMetrics_capture_fnc_unit_state;
|
||||
// [_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
// [_entity] call RangerMetrics_capture_fnc_unit_state;
|
||||
|
||||
[format["(EventHandler) EntityKilled fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}],
|
||||
["EntityRespawned", {
|
||||
params ["_newEntity", "_oldEntity"];
|
||||
call RangerMetrics_capture_fnc_entity_count;
|
||||
[_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
[_entity] call RangerMetrics_capture_fnc_unit_state;
|
||||
// [_entity] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
// [_entity] call RangerMetrics_capture_fnc_unit_state;
|
||||
[format["(EventHandler) EntityRespawned fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}],
|
||||
["GroupCreated", {
|
||||
@@ -157,38 +157,38 @@
|
||||
params ["_group"];
|
||||
call RangerMetrics_capture_fnc_entity_count;
|
||||
[format["(EventHandler) GroupDeleted fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}],
|
||||
["MarkerCreated", {
|
||||
params ["_marker", "_channelNumber", "_owner", "_local"];
|
||||
if (markerType _marker isEqualTo "") exitWith {};
|
||||
_this call RangerMetrics_event_fnc_MarkerCreated;
|
||||
[format["(EventHandler) MarkerCreated fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}],
|
||||
["MarkerDeleted", {
|
||||
params ["_marker", "_channelNumber", "_owner", "_local"];
|
||||
if (markerType _marker isEqualTo "") exitWith {};
|
||||
_this call RangerMetrics_event_fnc_MarkerDeleted;
|
||||
[format["(EventHandler) MarkerDeleted fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}],
|
||||
}]
|
||||
// ["MarkerCreated", {
|
||||
// params ["_marker", "_channelNumber", "_owner", "_local"];
|
||||
// if (markerType _marker isEqualTo "") exitWith {};
|
||||
// _this call RangerMetrics_event_fnc_MarkerCreated;
|
||||
// [format["(EventHandler) MarkerCreated fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
// }],
|
||||
// ["MarkerDeleted", {
|
||||
// params ["_marker", "_channelNumber", "_owner", "_local"];
|
||||
// if (markerType _marker isEqualTo "") exitWith {};
|
||||
// _this call RangerMetrics_event_fnc_MarkerDeleted;
|
||||
// [format["(EventHandler) MarkerDeleted fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
// }],
|
||||
// ["MarkerUpdated", {
|
||||
// params ["_marker", "_local"];
|
||||
// if (markerType _marker isEqualTo "") exitWith {};
|
||||
// _this call RangerMetrics_event_fnc_MarkerUpdated;
|
||||
// }],
|
||||
["Service", {
|
||||
params ["_serviceVehicle", "_servicedVehicle", "_serviceType", "_needsService", "_autoSupply"];
|
||||
[
|
||||
"server_events",
|
||||
"Service",
|
||||
[
|
||||
["string", "serviceVehicle", typeOf _serviceVehicle],
|
||||
["string", "servicedVehicle", typeOf _servicedVehicle],
|
||||
["int", "serviceType", _serviceType],
|
||||
["bool", "needsService", _needsService],
|
||||
["bool", "autoSupply", _autoSupply]
|
||||
],
|
||||
nil
|
||||
] call RangerMetrics_fnc_queue;
|
||||
[format["(EventHandler) Service fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
}]
|
||||
// ["Service", {
|
||||
// params ["_serviceVehicle", "_servicedVehicle", "_serviceType", "_needsService", "_autoSupply"];
|
||||
// [
|
||||
// "server_events",
|
||||
// "Service",
|
||||
// [
|
||||
// ["string", "serviceVehicle", typeOf _serviceVehicle],
|
||||
// ["string", "servicedVehicle", typeOf _servicedVehicle],
|
||||
// ["int", "serviceType", _serviceType],
|
||||
// ["bool", "needsService", _needsService],
|
||||
// ["bool", "autoSupply", _autoSupply]
|
||||
// ],
|
||||
// nil
|
||||
// ] call RangerMetrics_fnc_queue;
|
||||
// [format["(EventHandler) Service fired: %1", _this], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
// }]
|
||||
]
|
||||
@@ -1,67 +1,42 @@
|
||||
[
|
||||
[
|
||||
1, // interval
|
||||
[ // functions to run
|
||||
[
|
||||
["server", "hc"],
|
||||
RangerMetrics_capture_fnc_server_performance
|
||||
]
|
||||
]
|
||||
"serverPerformance",
|
||||
RangerMetrics_capture_fnc_server_performance
|
||||
],
|
||||
[
|
||||
3,
|
||||
[
|
||||
[
|
||||
["server", "hc"],
|
||||
RangerMetrics_capture_fnc_running_scripts
|
||||
],
|
||||
[
|
||||
["server", "hc"],
|
||||
RangerMetrics_capture_fnc_player_performance
|
||||
]
|
||||
]
|
||||
"runningScripts",
|
||||
RangerMetrics_capture_fnc_running_scripts
|
||||
],
|
||||
[
|
||||
15,
|
||||
[
|
||||
[
|
||||
["server", "hc"],
|
||||
RangerMetrics_capture_fnc_server_time
|
||||
],
|
||||
[
|
||||
["hc"],
|
||||
RangerMetrics_capture_fnc_entity_count
|
||||
]
|
||||
]
|
||||
"entityCount",
|
||||
RangerMetrics_capture_fnc_entity_count
|
||||
],
|
||||
[
|
||||
120,
|
||||
[
|
||||
[
|
||||
["server"],
|
||||
{
|
||||
{
|
||||
[_x] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
} count (call BIS_fnc_listPlayers);
|
||||
}
|
||||
]
|
||||
]
|
||||
"playerPerformance",
|
||||
RangerMetrics_capture_fnc_player_performance
|
||||
],
|
||||
[
|
||||
300,
|
||||
[
|
||||
[
|
||||
["server"],
|
||||
RangerMetrics_capture_fnc_weather
|
||||
],
|
||||
[
|
||||
["server"],
|
||||
RangerMetrics_capture_fnc_view_distance
|
||||
],
|
||||
[
|
||||
["server"],
|
||||
RangerMetrics_capture_fnc_running_mission
|
||||
]
|
||||
]
|
||||
"runningMission",
|
||||
RangerMetrics_capture_fnc_running_mission
|
||||
],
|
||||
[
|
||||
"serverTime",
|
||||
RangerMetrics_capture_fnc_server_time
|
||||
],
|
||||
[
|
||||
"weather",
|
||||
RangerMetrics_capture_fnc_weather
|
||||
],
|
||||
[
|
||||
"viewDistance",
|
||||
RangerMetrics_capture_fnc_view_distance
|
||||
]
|
||||
// [
|
||||
// "playerInventory",
|
||||
// {
|
||||
// {
|
||||
// [_x] call RangerMetrics_capture_fnc_unit_inventory;
|
||||
// } count (call BIS_fnc_listPlayers);
|
||||
// }
|
||||
// ],
|
||||
]
|
||||
@@ -1,14 +0,0 @@
|
||||
params ["_name", "_function", "_data"];
|
||||
if (_name == "RangerMetrics") then {
|
||||
if (isNil "_data") then {_data = ""};
|
||||
try {
|
||||
if (_data isEqualType "") exitWith {
|
||||
_data = parseSimpleArray _data;
|
||||
_data call RangerMetrics_fnc_log;
|
||||
};
|
||||
|
||||
diag_log format ["Callback unsupported type: %1: %2", _function, _data];
|
||||
} catch {
|
||||
_data = format ["%1", _data];
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
// MISSION EH
|
||||
{
|
||||
if (!isServer) exitWith {};
|
||||
_x params ["_ehName", "_code"];
|
||||
|
||||
_handle = (addMissionEventHandler [_ehName, _code]);
|
||||
if (isNil "_handle") then {
|
||||
[format["Failed to add Mission event handler: %1", _x], "ERROR"] call RangerMetrics_fnc_log;
|
||||
false;
|
||||
} else {
|
||||
missionNamespace setVariable [
|
||||
("RangerMetrics" + "_MEH_" + _ehName),
|
||||
_handle
|
||||
];
|
||||
true;
|
||||
};
|
||||
} forEach (call RangerMetrics_cDefinitions_fnc_server_missionEH);
|
||||
|
||||
// SERVER POLLS
|
||||
{
|
||||
// for each definition in SQF, pair it to the settings imported from settings.json
|
||||
// and then call the function to create the metric
|
||||
|
||||
// get the definition
|
||||
_x params ["_name", "_code"];
|
||||
|
||||
// get the settings
|
||||
private _settings = RangerMetrics_recordingSettings get _name;
|
||||
if (isNil "_settings") exitWith {};
|
||||
if (count (keys _settings) == 0) exitWith {};
|
||||
|
||||
if (
|
||||
(_settings get "enabled") isNotEqualTo true ||
|
||||
(
|
||||
!isServer &&
|
||||
(_settings get "serverOnly") isNotEqualTo false
|
||||
) ||
|
||||
(hasInterface && !isServer)
|
||||
) exitWith {};
|
||||
|
||||
// set up pfh
|
||||
_x call RangerMetrics_fnc_startServerPoll;
|
||||
|
||||
} forEach (call RangerMetrics_cDefinitions_fnc_server_poll);
|
||||
|
||||
|
||||
// CBA EVENTS
|
||||
{
|
||||
private "_handle";
|
||||
_x params ["_settingName", "_handleName", "_code"];
|
||||
|
||||
private _settings = RangerMetrics_recordingSettings get "CBAEventHandlers" get _settingName;
|
||||
if (isNil "_settings") exitWith {};
|
||||
if (count (keys _settings) == 0) exitWith {};
|
||||
|
||||
if (
|
||||
(_settings get "enabled") isNotEqualTo true ||
|
||||
(
|
||||
!isServer &&
|
||||
(_settings get "serverOnly") isNotEqualTo false
|
||||
) ||
|
||||
(hasInterface && !isServer)
|
||||
) exitWith {};
|
||||
|
||||
_handle = ([_handleName, _code] call CBA_fnc_addEventHandlerArgs);
|
||||
|
||||
if (isNil "_handle") then {
|
||||
[format["Failed to add CBA event handler: %1", _x], "ERROR"] call RangerMetrics_fnc_log;
|
||||
false;
|
||||
} else {
|
||||
missionNamespace setVariable [
|
||||
("RangerMetrics" + "_CBAEH_" + _handleName),
|
||||
_handle
|
||||
];
|
||||
true;
|
||||
};
|
||||
} forEach (call RangerMetrics_cDefinitions_fnc_server_CBA);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RangerMetrics_allMEH = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_MEH_") == 0
|
||||
};
|
||||
RangerMetrics_allCBA = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_CBAEH_") == 0
|
||||
};
|
||||
RangerMetrics_allServerPoll = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_serverPoll_") == 0
|
||||
};
|
||||
|
||||
[format ["Mission event handlers: %1", RangerMetrics_allMEH]] call RangerMetrics_fnc_log;
|
||||
[format ["CBA event handlers: %1", RangerMetrics_allCBA]] call RangerMetrics_fnc_log;
|
||||
[format ["Server poll handles: %1", RangerMetrics_allServerPoll]] call RangerMetrics_fnc_log;
|
||||
|
||||
|
||||
missionNamespace setVariable ["RangerMetrics_initialized", true, true];
|
||||
missionNamespace setVariable ["RangerMetrics_run", true, true];
|
||||
|
||||
|
||||
|
||||
// start sending
|
||||
[{
|
||||
params ["_args", "_idPFH"];
|
||||
if (scriptDone RangerMetrics_sendBatchHandle) then {
|
||||
RangerMetrics_sendBatchHandle = [] spawn RangerMetrics_fnc_send;
|
||||
};
|
||||
// call RangerMetrics_fnc_send;
|
||||
}, 2, []] call CBA_fnc_addPerFrameHandler;
|
||||
@@ -1,4 +1,4 @@
|
||||
params [["_text","Log text invalid"], ["_type","INFO"]];
|
||||
params [["_text","Log text invalid"], ["_logType","DEBUG"]];
|
||||
|
||||
if (typeName _this != "ARRAY") exitWith {
|
||||
diag_log format ["RangerMetrics: Invalid log params: %1", _this];
|
||||
@@ -6,18 +6,19 @@ if (typeName _this != "ARRAY") exitWith {
|
||||
if (typeName _text != "STRING") exitWith {
|
||||
diag_log format ["RangerMetrics: Invalid log text: %1", _this];
|
||||
};
|
||||
if (typeName _type != "STRING") exitWith {
|
||||
if (typeName _logType != "STRING") exitWith {
|
||||
diag_log format ["RangerMetrics: Invalid log type: %1", _this];
|
||||
};
|
||||
|
||||
if (_type isEqualTo "DEBUG") then {
|
||||
if (!RangerMetrics_debug) exitWith {};
|
||||
};
|
||||
if (
|
||||
_logType == "DEBUG" &&
|
||||
!(missionNamespace getVariable ["RangerMetrics_debug", false])
|
||||
) exitWith {};
|
||||
|
||||
private _textFormatted = format [
|
||||
"[%1] %2: %3",
|
||||
RangerMetrics_logPrefix,
|
||||
_type,
|
||||
_logType,
|
||||
_text];
|
||||
|
||||
if(isServer) then {
|
||||
|
||||
@@ -15,184 +15,38 @@ RangerMetrics_messageQueue = createHashMap;
|
||||
// RangerMetrics_messageQueue apply {[_x, count _y]};
|
||||
RangerMetrics_sendBatchHandle = scriptNull;
|
||||
|
||||
RangerMetrics_settings = createHashMap;
|
||||
RangerMetrics_recordingSettings = createHashMap;
|
||||
|
||||
[format ["Instance name: %1", profileName]] call RangerMetrics_fnc_log;
|
||||
[format ["CBA detected: %1", RangerMetrics_cbaPresent]] call RangerMetrics_fnc_log;
|
||||
["Initializing v0.1"] call RangerMetrics_fnc_log;
|
||||
["Initializing v0.0.2"] call RangerMetrics_fnc_log;
|
||||
|
||||
|
||||
// load settings from extension / settings.json
|
||||
private _settingsLoaded = "RangerMetrics" callExtension "loadSettings";
|
||||
// if (isNil "_settingsLoaded") exitWith {
|
||||
// ["Extension not found, disabling"] call RangerMetrics_fnc_log;
|
||||
// RangerMetrics_run = false;
|
||||
// };
|
||||
if (_settingsLoaded isEqualTo [] || _settingsLoaded isEqualTo "") exitWith {
|
||||
["Failed to load settings, exiting", "ERROR"] call RangerMetrics_fnc_log;
|
||||
};
|
||||
_settingsLoaded = parseSimpleArray (_settingsLoaded);
|
||||
[format["Settings loaded: %1", _settingsLoaded]] call RangerMetrics_fnc_log;
|
||||
RangerMetrics_settings = createHashMap;
|
||||
RangerMetrics_settings set [
|
||||
"influxDB",
|
||||
createHashMapFromArray [
|
||||
["host", _settingsLoaded#1],
|
||||
["org", _settingsLoaded#2]
|
||||
]
|
||||
];
|
||||
RangerMetrics_settings set [
|
||||
"arma3",
|
||||
createHashMapFromArray [
|
||||
["refreshRateMs", _settingsLoaded#3]
|
||||
]
|
||||
// Create listener - extension calls are async, so we need to listen for the response
|
||||
addMissionEventHandler [
|
||||
"ExtensionCallback",
|
||||
RangerMetrics_callback_fnc_callbackHandler
|
||||
];
|
||||
|
||||
|
||||
// connect to DB, extension is now ready
|
||||
private _dbConnection = "RangerMetrics" callExtension "connectToInflux";
|
||||
if (_dbConnection isEqualTo "") exitWith {
|
||||
["Failed to connect to InfluxDB, disabling"] call RangerMetrics_fnc_log;
|
||||
};
|
||||
|
||||
_response = parseSimpleArray _dbConnection;
|
||||
(_response) call RangerMetrics_fnc_log;
|
||||
systemChat str _response;
|
||||
|
||||
// send server profile name to all clients with JIP, so HC or player reporting knows what server it's connected to
|
||||
if (isServer) then {
|
||||
["RangerMetrics_serverProfileName", profileName] remoteExecCall ["setVariable", 0, true];
|
||||
RangerMetrics_serverProfileName = profileName;
|
||||
};
|
||||
|
||||
|
||||
// define the metrics to capture by sideloading definition files
|
||||
// this keeps the main file clean and easy to read
|
||||
// the definition files are in the format of a hashmap, where the key is the category and the value is an array of arrays, where each sub-array is a capture definition
|
||||
RangerMetrics_captureDefinitions = createHashMapFromArray [
|
||||
[
|
||||
"ServerEvent",
|
||||
createHashMapFromArray [
|
||||
[
|
||||
"MissionEventHandlers",
|
||||
call RangerMetrics_cDefinitions_fnc_server_missionEH
|
||||
]
|
||||
]],
|
||||
["ClientEvent", []],
|
||||
[
|
||||
"ServerPoll",
|
||||
call RangerMetrics_cDefinitions_fnc_server_poll
|
||||
],
|
||||
[
|
||||
"ClientPoll",
|
||||
call RangerMetrics_cDefinitions_fnc_client_poll
|
||||
],
|
||||
[
|
||||
"CBAEvent",
|
||||
call RangerMetrics_cDefinitions_fnc_server_CBA
|
||||
]
|
||||
];
|
||||
// Deinit to start fresh. See callback handler for the remainder of async init code
|
||||
"RangerMetrics" callExtension "deinitExtension";
|
||||
|
||||
|
||||
|
||||
// add missionEventHandlers on server only
|
||||
{_x params ["_handleName", "_code"];
|
||||
if (!isServer) exitWith {};
|
||||
// try {
|
||||
_handle = (addMissionEventHandler [_handleName, _code]);
|
||||
// } catch {
|
||||
// _handle = nil;
|
||||
// };
|
||||
if (isNil "_handle") then {
|
||||
[format["Failed to add Mission event handler: %1", [_handleName]], "ERROR"] call RangerMetrics_fnc_log;
|
||||
} else {
|
||||
missionNamespace setVariable [
|
||||
("RangerMetrics" + "_MEH_" + _handleName),
|
||||
_handle
|
||||
];
|
||||
true;
|
||||
};
|
||||
} forEach ((RangerMetrics_captureDefinitions get "ServerEvent") get "MissionEventHandlers");
|
||||
|
||||
|
||||
|
||||
|
||||
// begin server polling
|
||||
{
|
||||
_x call RangerMetrics_fnc_startServerPoll;
|
||||
} forEach (RangerMetrics_captureDefinitions get "ServerPoll");
|
||||
|
||||
// remoteExec client polling - send data to start handles
|
||||
{
|
||||
_x call RangerMetrics_fnc_sendClientPoll;
|
||||
} forEach (RangerMetrics_captureDefinitions get "ClientPoll");
|
||||
|
||||
// {
|
||||
|
||||
// } forEach (call RangerMetrics_captureDefinitions_fnc_clientEvent);
|
||||
|
||||
// begin client polling
|
||||
|
||||
|
||||
// set up CBA event listeners
|
||||
{_x params ["_handleName", "_code"];
|
||||
private "_handle";
|
||||
// try {
|
||||
_handle = ([_handleName, _code] call CBA_fnc_addEventHandlerArgs);
|
||||
// } catch {
|
||||
// _handle = nil;
|
||||
// };
|
||||
|
||||
if (isNil "_handle") then {
|
||||
[format["Failed to add CBA event handler: %1", [_handleName, _code]], "ERROR"] call RangerMetrics_fnc_log;
|
||||
} else {
|
||||
missionNamespace setVariable [
|
||||
("RangerMetrics" + "_CBAEH_" + _handleName),
|
||||
_handle
|
||||
];
|
||||
true;
|
||||
};
|
||||
} forEach (RangerMetrics_captureDefinitions get "CBAEvent");
|
||||
|
||||
|
||||
if (true) exitWith {};
|
||||
|
||||
|
||||
[] spawn {
|
||||
sleep 1;
|
||||
isNil {
|
||||
addMissionEventHandler [
|
||||
"ExtensionCallback",
|
||||
RangerMetrics_fnc_callbackHandler
|
||||
];
|
||||
|
||||
|
||||
// set up CBA class inits if CBA loaded
|
||||
call RangerMetrics_fnc_classHandlers;
|
||||
|
||||
private _meh = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_MEH_") == 0
|
||||
};
|
||||
private _cba = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_CBAEH_") == 0
|
||||
};
|
||||
private _serverPoll = allVariables missionNamespace select {
|
||||
_x find (toLower "RangerMetrics_captureBatchHandle_") == 0
|
||||
};
|
||||
|
||||
[format ["Mission event handlers: %1", _meh]] call RangerMetrics_fnc_log;
|
||||
[format ["CBA event handlers: %1", _cba]] call RangerMetrics_fnc_log;
|
||||
[format ["Server poll handles: %1", _serverPoll]] call RangerMetrics_fnc_log;
|
||||
|
||||
RangerMetrics_initialized = true;
|
||||
RangerMetrics_run = true;
|
||||
["RangerMetrics_run", true] remoteExecCall ["setVariable", 0];
|
||||
|
||||
|
||||
// start sending
|
||||
[{
|
||||
params ["_args", "_idPFH"];
|
||||
if (scriptDone RangerMetrics_sendBatchHandle) then {
|
||||
RangerMetrics_sendBatchHandle = [] spawn RangerMetrics_fnc_send;
|
||||
};
|
||||
// call RangerMetrics_fnc_send;
|
||||
}, 2, []] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,17 @@ if (_tagContext find "world" > -1) then {
|
||||
_tags pushBack ["string", "world", toLower worldName];
|
||||
};
|
||||
if (_tagContext find "server" > -1) then {
|
||||
_tags pushBack ["string", "connectedServer", RangerMetrics_serverProfileName];
|
||||
private _serverProfile = missionNamespace getVariable [
|
||||
"RangerMetrics_serverProfileName",
|
||||
""
|
||||
];
|
||||
if (_serverProfile isNotEqualTo "") then {
|
||||
_tags pushBack [
|
||||
"string",
|
||||
"connectedServer",
|
||||
_serverProfile
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
private _outTags = _tags apply {
|
||||
|
||||
@@ -1,84 +1,52 @@
|
||||
params [
|
||||
["_interval", 5, [0]],
|
||||
["_functions", [], [[]]]
|
||||
];
|
||||
params ["_refName", "_code"];
|
||||
|
||||
private _captureHandleName = format ["RangerMetrics_captureBatchHandle_%1", _interval];
|
||||
private _intervalMs = RangerMetrics_recordingSettings get _refName get "intervalMs";
|
||||
if (isNil "_intervalMs") exitWith {
|
||||
[format["No intervalMs found for serverPoll %1", _name]] call RangerMetrics_fnc_log;
|
||||
};
|
||||
|
||||
if (RangerMetrics_cbaPresent) then { // CBA is running, use PFH
|
||||
private _interval = _intervalMs / 1000; // convert to seconds
|
||||
|
||||
/*
|
||||
// if interval is 0, just run once now at init
|
||||
if (_interval == 0) exitWith {
|
||||
[_code] call CBA_fnc_execNextFrame;
|
||||
};
|
||||
|
||||
This capture method is dynamic.
|
||||
Every 5 seconds, two script handles are checked. One is for capturing, one is for sending.
|
||||
The capturing script will go through and capture data, getting nanosecond precision timestamps from the extension to go alongside each data point, then saving it to a queue. It will go through all assigned interval-based checks then exit, and on the next interval of this parent PFH, the capturing script will be spawned again.
|
||||
The queue is a hashmap where keys are buckets and values are arrays of data points in [string] line protocol format.
|
||||
The sending script will go through and send data, sending it in batches per bucket and per 2000 data points, as the max extension call with args is 2048 elements.
|
||||
The sending script will also check if the queue is empty, and if it is, it will exit. This means scriptDone will be true, and on the next interval of this parent PFH, the sending script will be spawned again.
|
||||
|
||||
|
||||
This system means that capture and sending are occurring in the scheduled environment, not blocking the server, while maintaining the timestamps of when each point was captured. The cycles of each will only occur at most once per 2 seconds, leaving plenty of time, and there will never be more than one call for each at a time.
|
||||
*/
|
||||
private _handle = [{
|
||||
params ["_args", "_idPFH"];
|
||||
_args params ["_captureHandleName", "_functions"];
|
||||
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
|
||||
// use spawn
|
||||
// if (scriptDone _captureHandleName) then {
|
||||
// missionNamespace setVariable [
|
||||
// _captureHandleName,
|
||||
// [_functions] spawn {
|
||||
// {
|
||||
// call _x;
|
||||
// } forEach _this;
|
||||
// }
|
||||
// ];
|
||||
// };
|
||||
|
||||
// call direct
|
||||
[format["Running %1 functions for %2", count _functions, _captureHandleName], "DEBUG"] call RangerMetrics_fnc_log;
|
||||
{
|
||||
_x params ["_whereToRun", "_scriptBlock"];
|
||||
if (
|
||||
_whereToRun find "server" == -1 &&
|
||||
!isServer
|
||||
) exitWith {false};
|
||||
|
||||
if (
|
||||
_whereToRun find "hc" == -1 &&
|
||||
(!hasInterface && !isDedicated)
|
||||
) exitWith {false};
|
||||
|
||||
[] spawn _scriptBlock;
|
||||
} forEach _functions;
|
||||
}, _interval, [_captureHandleName, _functions]] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
missionNamespace setVariable [_captureHandleName, _handle];
|
||||
|
||||
|
||||
} else { // CBA isn't running, use sleep
|
||||
[_interval, _functions] spawn {
|
||||
params ["_interval", "_functions"];
|
||||
while {true} do {
|
||||
if (!RangerMetrics_run) exitWith {};
|
||||
{
|
||||
_x params ["_whereToRun", "_scriptBlock"];
|
||||
if (
|
||||
_whereToRun find "server" == -1 &&
|
||||
!isServer
|
||||
) exitWith {false};
|
||||
|
||||
if (
|
||||
_whereToRun find "hc" == -1 &&
|
||||
(!hasInterface && !isDedicated)
|
||||
) exitWith {false};
|
||||
|
||||
[] spawn _scriptBlock;
|
||||
} forEach _functions;
|
||||
|
||||
sleep (_interval * 2);
|
||||
// run a constant scheduled loop
|
||||
private _runnerVar = "RangerMetrics" + "_serverPollRunner_" + _refName;
|
||||
missionNamespace setVariable [_runnerVar, scriptNull];
|
||||
private _spawnParams = [_refName, _code, _interval, _runnerVar];
|
||||
private _handle = _spawnParams spawn {
|
||||
params ["_refName", "_code", "_interval", "_runnerVar"];
|
||||
while {true} do {
|
||||
if (scriptDone (
|
||||
missionNamespace getVariable _runnerVar
|
||||
)) then {
|
||||
private _handle = [] spawn _code;
|
||||
missionNamespace setVariable [
|
||||
_runnerVar,
|
||||
_handle
|
||||
];
|
||||
};
|
||||
// sleep _interval;
|
||||
sleep 2;
|
||||
};
|
||||
};
|
||||
missionNamespace setVariable [
|
||||
"RangerMetrics" + "_serverPoll_" + _refName,
|
||||
_handle
|
||||
];
|
||||
|
||||
// USE PFH
|
||||
// private _handle = [{
|
||||
// params ["_args", "_idPFH"];
|
||||
// _args params ["_refName", "_code"];
|
||||
|
||||
// [_code] call CBA_fnc_execNextFrame;
|
||||
|
||||
// }, _interval, _this] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
// missionNamespace setVariable [
|
||||
// "RangerMetrics" + "_serverPoll_" + _refName,
|
||||
// _handle
|
||||
// ];
|
||||
@@ -13,9 +13,9 @@ if !(_str isEqualType "") exitWith {
|
||||
"RangerMetrics_fnc_stringReplace: _str is not a string. %1",
|
||||
_str
|
||||
],
|
||||
"ERROR"
|
||||
"WARN"
|
||||
] call RangerMetrics_fnc_log;
|
||||
"";
|
||||
str _str;
|
||||
};
|
||||
|
||||
if (!(_find isEqualType [])) then {
|
||||
|
||||
@@ -10,6 +10,7 @@ classDiagram
|
||||
Measurement PlayerDisconnected
|
||||
Measurement OnUserClientStateChanged
|
||||
Measurement OnUserAdminStateChanged
|
||||
Measurement OnUserKicked
|
||||
Meausrement HandleChatMessage
|
||||
Measurement MPEnded
|
||||
Measurement EntityCreated
|
||||
@@ -19,11 +20,13 @@ classDiagram
|
||||
Measurement MarkerCreated
|
||||
Measurement MarkerDeleted
|
||||
Measurement MarkerUpdated
|
||||
Measurement Service
|
||||
}
|
||||
|
||||
server_state --> running_mission
|
||||
class running_mission {
|
||||
capture: ServerPoll, 60s
|
||||
capture: MissionEH, MPEnded
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field string onLoadName
|
||||
@@ -43,28 +46,34 @@ classDiagram
|
||||
|
||||
server_state --> server_time
|
||||
class server_time {
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field float diag_tickTime
|
||||
field int serverTime
|
||||
field float timeMultiplier
|
||||
field int accTime
|
||||
capture: ServerPoll, 3s
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field float diag_tickTime
|
||||
field int serverTime
|
||||
field float timeMultiplier
|
||||
field int accTime
|
||||
}
|
||||
|
||||
server_state --> running_scripts
|
||||
class running_scripts {
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field int spawn_total
|
||||
field int execVM_total
|
||||
field int exec_total
|
||||
field int execFSM_total
|
||||
field int pfh_total
|
||||
capture: ServerPoll, 3s
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field int spawn_total
|
||||
field int execVM_total
|
||||
field int exec_total
|
||||
field int execFSM_total
|
||||
field int pfh_total
|
||||
}
|
||||
|
||||
server_state --> entities_local
|
||||
class entities_local {
|
||||
capture: ServerPoll, 1s (customizable)
|
||||
capture: ServerPoll, 30s
|
||||
capture: MissionEH, EntityKilled
|
||||
capture: MissionEH, EntityCreated
|
||||
capture: MissionEH, GroupCreated
|
||||
capture: MissionEH, GroupDeleted
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field int units_alive
|
||||
@@ -74,7 +83,11 @@ classDiagram
|
||||
}
|
||||
server_state --> entities_global
|
||||
class entities_global {
|
||||
capture: ServerPoll, 1s (customizable)
|
||||
capture: ServerPoll, 30s
|
||||
capture: MissionEH, EntityKilled
|
||||
capture: MissionEH, EntityCreated
|
||||
capture: MissionEH, GroupCreated
|
||||
capture: MissionEH, GroupDeleted
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field int units_alive
|
||||
@@ -84,7 +97,11 @@ classDiagram
|
||||
}
|
||||
server_state --> entities_remote
|
||||
class entities_remote {
|
||||
capture: ServerPoll, 1s (customizable)
|
||||
capture: ServerPoll, 30s
|
||||
capture: MissionEH, EntityKilled
|
||||
capture: MissionEH, EntityCreated
|
||||
capture: MissionEH, GroupCreated
|
||||
capture: MissionEH, GroupDeleted
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field int units_alive
|
||||
@@ -95,7 +112,7 @@ classDiagram
|
||||
|
||||
server_state --> server_performance
|
||||
class server_performance {
|
||||
capture: ServerPoll, 1s (customizable)
|
||||
capture: ServerPoll, 1s
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field string fps_avg
|
||||
@@ -128,7 +145,6 @@ classDiagram
|
||||
Measurement mission_config_file
|
||||
Measurement addon_options
|
||||
Measurement mission_parameters
|
||||
Measurement visual_settings
|
||||
}
|
||||
|
||||
config_state --> mission_config_file
|
||||
@@ -254,15 +270,6 @@ classDiagram
|
||||
field string missionGroup
|
||||
}
|
||||
|
||||
|
||||
config_state --> visual_settings
|
||||
class visual_settings {
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field string getTIParameters
|
||||
field string objectViewDistance
|
||||
}
|
||||
|
||||
class player_state
|
||||
|
||||
|
||||
@@ -272,8 +279,9 @@ classDiagram
|
||||
capture: MissionEH, OnUserDisconnected
|
||||
capture: MissionEH, PlayerConnected
|
||||
capture: MissionEH, PlayerDisconnected
|
||||
tag string profileName
|
||||
capture: MissionEH, OnUserKicked
|
||||
tag string connectedServer
|
||||
tag string playerUID
|
||||
field string playerID
|
||||
field string ownerId
|
||||
field string playerUID
|
||||
@@ -293,9 +301,9 @@ classDiagram
|
||||
capture: MissionEH, PlayerDisconnected
|
||||
capture: MissionEH, OnUserClientStateChanged
|
||||
capture: MissionEH, OnUserAdminStateChanged
|
||||
tag string profileName
|
||||
capture: MissionEH, OnUserKicked
|
||||
tag string connectedServer
|
||||
field string playerUID
|
||||
tag string playerUID
|
||||
field int clientStateNumber
|
||||
field int adminState
|
||||
}
|
||||
@@ -303,20 +311,19 @@ classDiagram
|
||||
player_state --> player_performance
|
||||
class player_performance {
|
||||
capture: ServerPoll
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field string playerUID
|
||||
tag string playerUID
|
||||
field float avgPing
|
||||
field float avgBandwidth
|
||||
field float desync
|
||||
}
|
||||
|
||||
player_state --> unit_loadout
|
||||
class unit_loadout {
|
||||
player_state --> unit_inventory
|
||||
class unit_inventory {
|
||||
capture: InventoryClosedEH
|
||||
tag string profileName
|
||||
tag string connectedServer
|
||||
field string playerUID
|
||||
tag string playerUID
|
||||
field string currentWeapon
|
||||
field string uniform
|
||||
field string vest
|
||||
field string backpack
|
||||
@@ -333,6 +340,8 @@ classDiagram
|
||||
|
||||
player_state --> unit_state
|
||||
class unit_state {
|
||||
capture: UnitEH, GetInMan
|
||||
capture: UnitEH, GetOutMan
|
||||
tag string connectedServer
|
||||
tag string playerUID
|
||||
field float health
|
||||
@@ -342,6 +351,9 @@ classDiagram
|
||||
field bool in_vehicle
|
||||
field string vehicle_role
|
||||
field float speed_kmh
|
||||
field string unitTraitX
|
||||
field bool unitTraitY
|
||||
field int unitTraitZ
|
||||
}
|
||||
|
||||
class player_events
|
||||
@@ -400,4 +412,24 @@ player_events --> Dammaged
|
||||
field int score
|
||||
field string object
|
||||
field string objectclass
|
||||
}
|
||||
|
||||
player_events --> InventoryClosed
|
||||
class InventoryClosed {
|
||||
capture: UnitEH, InventoryClosed
|
||||
tag string connectedServer
|
||||
tag string playerUID
|
||||
field string currentWeaponClass
|
||||
field string uniformClass
|
||||
field string vestClass
|
||||
field string backpackClass
|
||||
field string headgearClass
|
||||
field string gogglesClass
|
||||
field string hmdClass
|
||||
field string primaryWeaponClass
|
||||
field string primaryWeaponMagazineClass
|
||||
field string secondaryWeaponClass
|
||||
field string secondaryWeaponMagazineClass
|
||||
field string handgunWeaponClass
|
||||
field string handgunMagazineClass
|
||||
}
|
||||
101
@RangerMetrics/settings.example.json
Normal file
101
@RangerMetrics/settings.example.json
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"influxdb": {
|
||||
"enabled": true,
|
||||
"host": "http://INFLUX_URL:8086",
|
||||
"token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX_AUTH_TOKEN_XXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"org": "ORG_NAME"
|
||||
},
|
||||
"timescaledb": {
|
||||
"enabled": false,
|
||||
"connectionUrl": "postgresql://user:pass@host.com:5432",
|
||||
"databaseName": "ranger_metrics",
|
||||
"description": "TimescaleDB is an open-source time-series database built on Postgres. The extension will connect to the maintenance database (postgres) first and create the database it will control with desired name, then shift connections to the newly created database to create the schema and conduct write operations."
|
||||
},
|
||||
"arma3": {
|
||||
"refreshRateMs": 1000,
|
||||
"debug": false
|
||||
},
|
||||
"recordingSettings": {
|
||||
"serverPolls": [
|
||||
{
|
||||
"name": "serverPerformance",
|
||||
"enabled": true,
|
||||
"serverOnly": false,
|
||||
"intervalMs": 1000,
|
||||
"bucket": "server_performance",
|
||||
"measurement": "fps",
|
||||
"description": "SERVER/HC POLL. Tracks average and minimum FPS. Polled on server (and HC) at specified interval."
|
||||
},
|
||||
{
|
||||
"name": "runningScripts",
|
||||
"enabled": true,
|
||||
"serverOnly": false,
|
||||
"intervalMs": 1000,
|
||||
"bucket": "server_performance",
|
||||
"measurement": "running_scripts",
|
||||
"description": "SERVER/HC POLL. Tracks the number of scripts running on the server (and HC). Polled on specified interval."
|
||||
},
|
||||
{
|
||||
"name": "entityCount",
|
||||
"enabled": true,
|
||||
"serverOnly": false,
|
||||
"intervalMs": 20000,
|
||||
"bucket": "server_performance",
|
||||
"measurement": "n/a",
|
||||
"description": "SERVER/HC POLL. Tracks the number of entities on the server. Polled on server (and HC) at specified interval as well as on EntityCreated/EntityRespawned/EntityKilled events. Measurement is static, [entities_local, entities_remote, entities_global]."
|
||||
},
|
||||
{
|
||||
"name": "playerPerformance",
|
||||
"enabled": true,
|
||||
"serverOnly": true,
|
||||
"intervalMs": 1000,
|
||||
"bucket": "player_performance",
|
||||
"measurement": "network",
|
||||
"description": "SERVER POLL. User network performance. Tracks average ping, average bandwidth, and desync. Polled by the server at specified interval. Not tracked from headless client."
|
||||
},
|
||||
{
|
||||
"name": "serverTime",
|
||||
"enabled": true,
|
||||
"serverOnly": true,
|
||||
"intervalMs": 10000,
|
||||
"bucket": "mission_data",
|
||||
"measurement": "server_time",
|
||||
"description": "SERVER POLL. Tracks the server time. Always server-only. Runs at specified interval."
|
||||
},
|
||||
{
|
||||
"name": "weather",
|
||||
"enabled": true,
|
||||
"serverOnly": true,
|
||||
"intervalMs": 120000,
|
||||
"bucket": "mission_data",
|
||||
"measurement": "weather",
|
||||
"description": "SERVER POLL. Tracks the weather on the server. Always server-only. Runs at specified interval."
|
||||
},
|
||||
{
|
||||
"name": "viewDistance",
|
||||
"enabled": true,
|
||||
"serverOnly": true,
|
||||
"intervalMs": 120000,
|
||||
"bucket": "mission_data",
|
||||
"measurement": "view_distance",
|
||||
"description": "SERVER POSTINIT, MPEnded. Tracks the view distance on the server. Always server-only. Runs at specified interval."
|
||||
},
|
||||
{
|
||||
"name": "runningMission",
|
||||
"enabled": true,
|
||||
"serverOnly": true,
|
||||
"intervalMs": 0,
|
||||
"bucket": "mission_data",
|
||||
"measurement": "running_mission",
|
||||
"description": "SERVER POSTINIT, MPEnded. Tracks the name of the mission running on the server. Always server-only. Runs at the start (and tries at end) of the mission."
|
||||
}
|
||||
],
|
||||
"CBAEventHandlers": [
|
||||
{
|
||||
"name": "milsimServerEfficiency",
|
||||
"enabled": true,
|
||||
"description": "EVENTHANDLER. Tracks the efficiency of the server."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"host" : "http://INFLUX_URL:8086",
|
||||
"token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX_AUTH_TOKEN_XXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"org" : "ORG_NAME",
|
||||
"bucket" : "BUCKET_NAME",
|
||||
}
|
||||
52
InfluxDB/bucketsTemplate.json
Normal file
52
InfluxDB/bucketsTemplate.json
Normal file
@@ -0,0 +1,52 @@
|
||||
[
|
||||
{
|
||||
"apiVersion": "influxdata.com/v2alpha1",
|
||||
"kind": "Bucket",
|
||||
"metadata": {
|
||||
"name": "alerting-chaum-a8c001"
|
||||
},
|
||||
"spec": {
|
||||
"name": "config_state"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "influxdata.com/v2alpha1",
|
||||
"kind": "Bucket",
|
||||
"metadata": {
|
||||
"name": "hardcore-hodgkin-a8c005"
|
||||
},
|
||||
"spec": {
|
||||
"name": "player_state"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "influxdata.com/v2alpha1",
|
||||
"kind": "Bucket",
|
||||
"metadata": {
|
||||
"name": "objective-curie-a8c003"
|
||||
},
|
||||
"spec": {
|
||||
"name": "player_events"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "influxdata.com/v2alpha1",
|
||||
"kind": "Bucket",
|
||||
"metadata": {
|
||||
"name": "romantic-blackwell-a8c009"
|
||||
},
|
||||
"spec": {
|
||||
"name": "server_state"
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "influxdata.com/v2alpha1",
|
||||
"kind": "Bucket",
|
||||
"metadata": {
|
||||
"name": "thirsty-leakey-a8c007"
|
||||
},
|
||||
"spec": {
|
||||
"name": "server_events"
|
||||
}
|
||||
}
|
||||
]
|
||||
3
InfluxDB/exportToTemplate.ps1
Normal file
3
InfluxDB/exportToTemplate.ps1
Normal file
@@ -0,0 +1,3 @@
|
||||
# Requires Influx CLI to be installed. Used to quickly generate a template of buckets to import to an instance for pre-setup.
|
||||
# https://docs.influxdata.com/influxdb/v2.7/reference/cli/influx/export/
|
||||
influx export all -f "bucketsTemplate.json" --filter=resourceKind=Bucket
|
||||
58
README.md
58
README.md
@@ -1,3 +1,57 @@
|
||||
# RangerMetrics based off of CAV-Metrics
|
||||
# RangerMetrics - Arma3 InfluxDB Metrics
|
||||
|
||||
Ranger Metrics is used to submit information from the Arma3 Instance to the Influx Database. This uses the ArmaInflux Version complied to a DLL to communicate.
|
||||
Ranger Metrics is used to submit information from the Arma3 Instance to the Influx Database. This uses the ArmaInflux Version complied to a DLL to communicate.
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
### Settings.json
|
||||
|
||||
Configure the options in settings.json.
|
||||
|
||||
As of v0.0.2, metrics are captured on a recurring loop in the scheduled environment with a two second pause to allow time. Whether to use CBA Per Frame Handlers that run metric collection less often and in the unscheduled environment has yet to be decided on, as it does lead to longer intervals that are more difficult to graph precisely.
|
||||
|
||||
### InfluxDB
|
||||
|
||||
InfluxDB is a time series database. It is used to store data points with a timestamp.
|
||||
|
||||
#### Required Buckets
|
||||
|
||||
- mission_data
|
||||
- player_data
|
||||
- player_performance
|
||||
- server_events
|
||||
- server_performance
|
||||
|
||||
### Grafana
|
||||
|
||||
Grafana is a dashboarding tool. It is used to display the data from InfluxDB. Import the dashboard from the json file in the root of this addon and set up your datasources appropriately.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Ingame
|
||||
|
||||
#### Toggle Capture On/Off
|
||||
|
||||
Running the following commands in Server Exec will toggle the capture on or off for the server and any Headless Clients. Capture loops will still occur but will exit almost immediately.
|
||||
|
||||
Change the last parameter to false to ONLY target the server when run as Server Exec.
|
||||
|
||||
*This may not apply to raw Event Handler data which goes under `server_events`*
|
||||
|
||||
```sqf
|
||||
// ON
|
||||
missionNamespace setVariable ["RangerMetrics_run", true, true];
|
||||
|
||||
// OFF
|
||||
missionNamespace setVariable ["RangerMetrics_run", false, true];
|
||||
```
|
||||
|
||||
#### Reload Settings.json and recreate all capture loops
|
||||
|
||||
To reload everything while in a game, run `"RangerMetrics" callExtension "deinitExtension";` in Global Exec. This will disconnect any database connections and reset state. Running it Global Exec will cause any client with the addon to run it, which includes Headless Clients.
|
||||
|
||||
When the extension is finished, it will notify Arma via a callback. The addon will then __automatically__ run `"RangerMetrics" callExtension "initExtension";` to reinitialize the extension, to include fetching the new settings, tearing down existing captures, and re-setting up captures with the new settings.
|
||||
|
||||
3237
grafana_dashboard.json
Normal file
3237
grafana_dashboard.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user