5 Commits

Author SHA1 Message Date
489db10506 version 2023-10-12 16:20:29 -07:00
31fa09e478 Merge branch 'develop' 2023-10-12 16:20:15 -07:00
3c43a2bc20 finalize for release 2023-10-12 16:17:25 -07:00
85ed597711 fixes for prod 2023-10-12 16:14:05 -07:00
40b5a3d26f small reorg, some improvements, readme updates
- fix hemtt config to copy example
- add measurements table in Readme
- ENTITY COUNTS
  - re add side tags
  - use `side group _x` for units and players
  - fix players_connected and add headless_clients
- get `_allUserInfos = allUsers apply {getUserInfo _x} select {count _x > 0};` from main loop and use in entity counts and player performance
2023-10-10 18:17:18 -07:00
15 changed files with 131 additions and 30 deletions

3
.gitignore vendored
View File

@@ -8,5 +8,6 @@
ifxmetrics.config.json ifxmetrics.config.json
.hemttout .hemttout
influxdb influxdb/data
influxdb/config
releases releases

View File

@@ -9,7 +9,8 @@ git_hash=6 # Default: 8
[files] [files]
include=[ include=[
"ifxmetrics.config.json", "ifxmetrics.config.example.json",
# "ifxmetrics.config.json", # used for copying during debugging
"LICENSE", "LICENSE",
"README.md", "README.md",
"mod.cpp", "mod.cpp",

View File

@@ -105,6 +105,58 @@ Grafana is a dashboarding tool. It is used to display the data from InfluxDB. A
--- ---
## CORE METRICS
These metrics will be gathered by default every `refreshRateMs` milliseconds.
| Bucket | Measurement | Tags | Field |
| --- | --- | --- | --- |
| server_performance | fps | profile=`profileName` world=`worldName` server=`serverName` | fps_avg=`diag_fps` |
| server_performance | fps | ... | fps_min=`diag_fpsMin` |
| server_performance | running_scripts | ... | spawn=`diag_activeScripts#0` |
| server_performance | running_scripts | ... | execVM=`diag_activeScripts#1` |
| server_performance | running_scripts | ... | exec=`diag_activeScripts#2` |
| server_performance | running_scripts | ... | execFSM=`diag_activeScripts#3` |
| server_performance | running_scripts | ... | pfh=`count CBA_common_perFrameHandlerArray \|\| 0` |
| server_performance | entities_remote | ... + side=`WEST`,`EAST`, etc | units_alive=`{side group _x isEqualTo _thisSide && not (local _x)} count _allUnits` |
| server_performance | entities_remote | ... + side=`WEST`,`EAST`, etc | units_dead=`{side group _x isEqualTo _thisSide && not (local _x)} count _allDeadMen` |
| server_performance | entities_remote | ... + side=`WEST`,`EAST`, etc | groups_total=`{side _x isEqualTo _thisSide && not (local _x)} count _allGroups` |
| server_performance | entities_remote | ... + side=`WEST`,`EAST`, etc | vehicles_total=`{side _x isEqualTo _thisSide && not (local _x) && !(_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_remote | ... + side=`WEST`,`EAST`, etc | vehicles_weaponholder=`{side _x isEqualTo _thisSide && not (local _x) && (_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_local | ... + side=`WEST`,`EAST`, etc | units_alive=`{side group _x isEqualTo _thisSide && (local _x)} count _allUnits` |
| server_performance | entities_local | ... + side=`WEST`,`EAST`, etc | units_dead=`{side group _x isEqualTo _thisSide && (local _x)} count _allDeadMen` |
| server_performance | entities_local | ... + side=`WEST`,`EAST`, etc | groups_total=`{side _x isEqualTo _thisSide && (local _x)} count _allGroups` |
| server_performance | entities_local | ... + side=`WEST`,`EAST`, etc | vehicles_total=`{side _x isEqualTo _thisSide && (local _x) && !(_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_local | ... + side=`WEST`,`EAST`, etc | vehicles_weaponholder=`{side _x isEqualTo _thisSide && (local _x) && (_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | units_alive=`{side group _x isEqualTo _thisSide} count _allUnits` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | units_dead=`{side group _x isEqualTo _thisSide} count _allDeadMen` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | groups_total=`{side _x isEqualTo _thisSide} count _allGroups` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | vehicles_total=`{side _x isEqualTo _thisSide && !(_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | vehicles_weaponholder=`{side _x isEqualTo _thisSide && (_x isKindOf "WeaponHolderSimulated")} count _vehicles` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | players_alive=`{side group _x isEqualTo _thisSide && alive _x} count (call BIS_fnc_listPlayers)` |
| server_performance | entities_global | ... + side=`WEST`,`EAST`, etc | players_dead=`{side group _x isEqualTo _thisSide && !alive _x} count (call BIS_fnc_listPlayers)` |
| server_performance | player_count | ... | players_connected=`count (_allUserInfos select {_x#7 isEqualTo false})` |
| server_performance | player_count | ... | headless_clients_connected=`count (_allUserInfos select {_x#7 isEqualTo true})` |
| player_performance | network | ... + playerUID=`getUserInfo#2`, playerName=`getUserInfo#3` | avgPing=`getUserInfo#9#0` |
| player_performance | network | ... + playerUID=`getUserInfo#2`, playerName=`getUserInfo#3` | avgBandwidth=`getUserInfo#9#1` |
| player_performance | network | ... + playerUID=`getUserInfo#2`, playerName=`getUserInfo#3` | desync=`getUserInfo#9#2` |
| mission_data | server_time | ... | diag_tickTime=`diag_tickTime` |
| mission_data | server_time | ... | serverTime=`time` |
| mission_data | server_time | ... | timeMultiplier=`timeMultiplier` |
| mission_data | server_time | ... | accTime=`accTime` |
| mission_data | weather | ... | fog=`fog` |
| mission_data | weather | ... | overcast=`overcast` |
| mission_data | weather | ... | rain=`rain` |
| mission_data | weather | ... | humidity=`humidity` |
| mission_data | weather | ... | waves=`waves` |
| mission_data | weather | ... | windDir=`windDir` |
| mission_data | weather | ... | windStr=`windStr` |
| mission_data | weather | ... | gusts=`gusts` |
| mission_data | weather | ... | lightnings=`lightnings` |
| mission_data | weather | ... | moonIntensity=`moonIntensity` |
| mission_data | weather | ... | moonPhase=`moonPhase` |
| mission_data | weather | ... | sunOrMoon=`sunOrMoon` |
## BUILDING ## BUILDING
Set an environment variable in your terminal with the desired extension build version. It defaults to "DEVELOPMENT". Set an environment variable in your terminal with the desired extension build version. It defaults to "DEVELOPMENT".
@@ -127,13 +179,19 @@ Run this from the project root.
docker pull x1unix/go-mingw:1.20 docker pull x1unix/go-mingw:1.20
# Compile x64 Windows DLL # Compile x64 Windows DLL
docker run --rm -it -v ${PWD}:/go/work -w /go/work -e GOARCH=amd64 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./ifxmetrics_x64.dll -buildmode=c-shared -ldflags "-w -s -X main.EXTENSION_VERSION=`"$IFXMETRICS_BUILD_VER`"" ./extension/cmd docker run --rm -it -v ${PWD}/extension/IFXMetrics:/go/work -w /go/work -e GOARCH=amd64 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./dist/ifxmetrics_x64.dll -buildmode=c-shared -ldflags "-w -s -X main.EXTENSION_VERSION=$IFXMETRICS_BUILD_VER" ./cmd
Move-Item -Path ./extension/IFXMetrics/dist/ifxmetrics_x64.dll -Destination ./ifxmetrics_x64.dll -Force
# Compile x86 Windows DLL # Compile x86 Windows DLL
docker run --rm -it -v ${PWD}:/go/work -w /go/work -e GOARCH=386 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./ifxmetrics.dll -buildmode=c-shared -ldflags "-w -s -X main.EXTENSION_VERSION=`"$IFXMETRICS_BUILD_VER`"" ./extension/cmd docker run --rm -it -v ${PWD}/extension/IFXMetrics:/go/work -w /go/work -e GOARCH=386 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./dist/ifxmetrics.dll -buildmode=c-shared -ldflags "-w -s -X main.EXTENSION_VERSION=$IFXMETRICS_BUILD_VER" ./cmd
Move-Item -Path ./extension/IFXMetrics/dist/ifxmetrics.dll -Destination ./ifxmetrics.dll -Force
# Compile x64 Windows EXE # Compile x64 Windows EXE
docker run --rm -it -v ${PWD}:/go/work -w /go/work -e GOARCH=amd64 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./ifxmetrics_x64.exe -ldflags "-w -s -X main.EXTENSION_VERSION=`"$IFXMETRICS_BUILD_VER`"" ./extension/cmd docker run --rm -it -v ${PWD}/extension/IFXMetrics:/go/work -w /go/work -e GOARCH=amd64 -e CGO_ENABLED=1 x1unix/go-mingw:1.20 go build -o ./dist/ifxmetrics_x64.exe -ldflags "-w -s -X main.EXTENSION_VERSION=$IFXMETRICS_BUILD_VER" ./cmd
Move-Item -Path ./extension/IFXMetrics/dist/ifxmetrics_x64.exe -Destination ./ifxmetrics_x64.exe -Force
``` ```
### EXTENSION: COMPILING FOR LINUX ### EXTENSION: COMPILING FOR LINUX
@@ -144,10 +202,15 @@ Run this from the project root.
docker build -t indifox926/build-a3go:linux-so -f ./build/Dockerfile.build . docker build -t indifox926/build-a3go:linux-so -f ./build/Dockerfile.build .
# Compile x64 Linux .so # Compile x64 Linux .so
docker run --rm -it -v ${PWD}:/app -e GOOS=linux -e GOARCH=amd64 -e CGO_ENABLED=1 indifox926/build-a3go:linux-so go build -o ./ifxmetrics_x64.so -linkshared -ldflags "-w -s -X main.EXTENSION_VERSION=${IFXMETRICS_BUILD_VER}" ./extension/cmd docker run --rm -it -v ${PWD}/extension/IFXMetrics:/app -e GOOS=linux -e GOARCH=amd64 -e CGO_ENABLED=1 indifox926/build-a3go:linux-so go build -o ./dist/ifxmetrics_x64.so -linkshared -ldflags "-w -s -X main.EXTENSION_VERSION=${IFXMETRICS_BUILD_VER}" ./cmd
Move-Item -Path ./extension/IFXMetrics/dist/ifxmetrics_x64.so -Destination ./ifxmetrics_x64.so -Force
# Compile x86 Linux .so # Compile x86 Linux .so
docker run --rm -it -v ${PWD}:/app -e GOOS=linux -e GOARCH=386 -e CGO_ENABLED=1 indifox926/build-a3go:linux-so go build -o ./ifxmetrics.so -linkshared -ldflags "-w -s -X main.EXTENSION_VERSION=${IFXMETRICS_BUILD_VER}" ./extension/cmd docker run --rm -it -v ${PWD}/extension/IFXMetrics:/app -e GOOS=linux -e GOARCH=386 -e CGO_ENABLED=1 indifox926/build-a3go:linux-so go build -o ./dist/ifxmetrics.so -linkshared -ldflags "-w -s -X main.EXTENSION_VERSION=${IFXMETRICS_BUILD_VER}" ./cmd
Move-Item -Path ./extension/IFXMetrics/dist/ifxmetrics.so -Destination ./ifxmetrics.so -Force
``` ```
### ADDON: COMPILE USING HEMTT ### ADDON: COMPILE USING HEMTT

View File

@@ -1,5 +1,9 @@
#include "script_component.hpp" #include "script_component.hpp"
params [
["_allUserInfos", [], [[]]]
];
private _hashesOut = []; private _hashesOut = [];
private _allUnits = allUnits; private _allUnits = allUnits;
@@ -10,18 +14,20 @@ private _allPlayers = call BIS_fnc_listPlayers;
{ {
private _thisSide = _x; private _thisSide = _x;
private _thisSideStr = _thisSide call BIS_fnc_sideNameUnlocalized; private _thisSideStr = _thisSide call BIS_fnc_sideNameUnlocalized;
private _tags = +GVARMAIN(standardTags);
_tags pushBack ["side", _thisSideStr];
// Number of remote units // Number of remote units
_hashesOut pushBack ([ _hashesOut pushBack ([
["bucket", "server_performance"], ["bucket", "server_performance"],
["measurement", "entities_remote"], ["measurement", "entities_remote"],
["tags", GVARMAIN(standardTags)], ["tags", _tags],
["fields", [ ["fields", [
["units_alive", { ["units_alive", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
not (local _x) not (local _x)
} count _allUnits], } count _allUnits],
["units_dead", { ["units_dead", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
not (local _x) not (local _x)
} count _allDeadMen], } count _allDeadMen],
["groups_total", { ["groups_total", {
@@ -45,14 +51,14 @@ private _allPlayers = call BIS_fnc_listPlayers;
_hashesOut pushBack ([ _hashesOut pushBack ([
["bucket", "server_performance"], ["bucket", "server_performance"],
["measurement", "entities_local"], ["measurement", "entities_local"],
["tags", GVARMAIN(standardTags)], ["tags", _tags],
["fields", [ ["fields", [
["units_alive", { ["units_alive", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
local _x local _x
} count _allUnits], } count _allUnits],
["units_dead", { ["units_dead", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
local _x local _x
} count _allDeadMen], } count _allDeadMen],
["groups_total", { ["groups_total", {
@@ -78,13 +84,13 @@ private _allPlayers = call BIS_fnc_listPlayers;
_hashesOut pushBack ([ _hashesOut pushBack ([
["bucket", "server_performance"], ["bucket", "server_performance"],
["measurement", "entities_global"], ["measurement", "entities_global"],
["tags", GVARMAIN(standardTags)], ["tags", _tags],
["fields", [ ["fields", [
["units_alive", { ["units_alive", {
side _x isEqualTo _thisSide side group _x isEqualTo _thisSide
} count _allUnits], } count _allUnits],
["units_dead", { ["units_dead", {
side _x isEqualTo _thisSide side group _x isEqualTo _thisSide
} count _allDeadMen], } count _allDeadMen],
["groups_total", { ["groups_total", {
side _x isEqualTo _thisSide side _x isEqualTo _thisSide
@@ -98,11 +104,11 @@ private _allPlayers = call BIS_fnc_listPlayers;
(_x isKindOf "WeaponHolderSimulated") (_x isKindOf "WeaponHolderSimulated")
} count _vehicles], } count _vehicles],
["players_alive", { ["players_alive", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
alive _x alive _x
} count _allPlayers], } count _allPlayers],
["players_dead", { ["players_dead", {
side _x isEqualTo _thisSide && side group _x isEqualTo _thisSide &&
!alive _x !alive _x
} count _allPlayers] } count _allPlayers]
]] ]]
@@ -116,12 +122,8 @@ if (isServer) then {
["measurement", "player_count"], ["measurement", "player_count"],
["tags", GVARMAIN(standardTags)], ["tags", GVARMAIN(standardTags)],
["fields", [ ["fields", [
["players_connected", { ["players_connected", count (_allUserInfos select {_x#7 isEqualTo false})],
private _info = getUserInfo (getPlayerId _x); ["headless_clients_connected", count (_allUserInfos select {_x#7 isEqualTo true})]
if (!isNil "_info" && {count _info >= 6}) then {
_info select 7
} else {false}
} count _allPlayers]
]] ]]
]); ]);
}; };

View File

@@ -1,5 +1,9 @@
#include "script_component.hpp" #include "script_component.hpp"
params [
["_allUserInfos", [], [[]]]
];
private _hashesOut = []; private _hashesOut = [];
{ {
_x params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"]; _x params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"];
@@ -23,6 +27,6 @@ private _hashesOut = [];
["desync", _desync] ["desync", _desync]
]] ]]
]); ]);
} forEach (allUsers apply {getUserInfo _x}); } forEach _allUserInfos;
_hashesOut; _hashesOut;

View File

@@ -5,7 +5,11 @@ class CfgPatches {
units[] = {}; units[] = {};
weapons[] = {}; weapons[] = {};
requiredVersion = 2.10; requiredVersion = 2.10;
requiredAddons[] = {}; requiredAddons[] = {
"cba_main",
"cba_xeh",
"cba_settings"
};
author[] = {"IndigoFox"}; author[] = {"IndigoFox"};
authorUrl = "https://github.com/indig0fox/IFXMetrics"; authorUrl = "https://github.com/indig0fox/IFXMetrics";
}; };

View File

@@ -24,19 +24,22 @@ GVARMAIN(captureLoop) = [
] ]
]; ];
// getUserInfo for all users
private _allUserInfos = allUsers apply {getUserInfo _x} select {count _x > 0};
// entity_count returns an array of hashMap // entity_count returns an array of hashMap
{ {
GVARMAIN(extensionName) callExtension [ GVARMAIN(extensionName) callExtension [
":INFLUX:WRITE:", ":INFLUX:WRITE:",
[_x] [_x]
]; ];
} forEach (call EFUNC(capture,entity_count)); } forEach ([_allUserInfos] call EFUNC(capture,entity_count));
{ {
GVARMAIN(extensionName) callExtension [ GVARMAIN(extensionName) callExtension [
":INFLUX:WRITE:", ":INFLUX:WRITE:",
[_x] [_x]
]; ];
} forEach (call EFUNC(capture,player_performance)); } forEach ([_allUserInfos] call EFUNC(capture,player_performance));
["DEBUG", format[ ["DEBUG", format[
"Processed primary data loop in %1 ms", "Processed primary data loop in %1 ms",

View File

@@ -1,7 +1,7 @@
#define MAJOR 2 #define MAJOR 2
#define MINOR 0 #define MINOR 0
#define PATCH 0 #define PATCH 1
#define BUILD 20231009 #define BUILD 20231012
#define VERSION 2.0 #define VERSION 2.0
#define VERSION_STR MAJOR##.##MINOR##.##PATCH##.##BUILD #define VERSION_STR MAJOR##.##MINOR##.##PATCH##.##BUILD

View File

@@ -319,4 +319,7 @@ func main() {
// s := settings.Active.Get("cbaEventHandlers") // s := settings.Active.Get("cbaEventHandlers")
// // return the custom cba event handlers as an arma hashmap // // return the custom cba event handlers as an arma hashmap
// fmt.Println(a3interface.ToArmaHashMap(s)) // fmt.Println(a3interface.ToArmaHashMap(s))
fmt.Println("IFXMetrics extension started. Version: " + EXTENSION_VERSION)
fmt.Scanln()
} }

View File

@@ -0,0 +1,20 @@
version: '3.8'
services:
influxdb:
image: influxdb:latest
container_name: influxdb
restart: always
ports:
- 8086:8086
volumes:
- ./data:/var/lib/influxdb2
- ./config:/etc/influxdb2
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=exampleuser
- DOCKER_INFLUXDB_INIT_PASSWORD=dfaow3ho9i7funa0w3nv
- DOCKER_INFLUXDB_INIT_ORG=ifx-metrics
- DOCKER_INFLUXDB_INIT_BUCKET=test-bucket
- DOCKER_INFLUXDB_INIT_RETENTION=1w
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=f0982q3ahfu8yawbo27w8fb986ba90b0wb2f