diff --git a/.gitignore b/.gitignore index 1dee516..df3975a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ ifxmetrics.config.json .hemttout -influxdb +influxdb/data +influxdb/config releases \ No newline at end of file diff --git a/.hemtt/project.toml b/.hemtt/project.toml index 1faf74b..3176f49 100644 --- a/.hemtt/project.toml +++ b/.hemtt/project.toml @@ -9,7 +9,8 @@ git_hash=6 # Default: 8 [files] include=[ - "ifxmetrics.config.json", + "ifxmetrics.config.example.json", + # "ifxmetrics.config.json", # used for copying during debugging "LICENSE", "README.md", "mod.cpp", diff --git a/README.md b/README.md index 85590b3..46c4540 100644 --- a/README.md +++ b/README.md @@ -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 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 # 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 -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 -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 @@ -144,10 +202,15 @@ Run this from the project root. docker build -t indifox926/build-a3go:linux-so -f ./build/Dockerfile.build . # 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 -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 diff --git a/addons/capture/fnc_entity_count.sqf b/addons/capture/fnc_entity_count.sqf index d1ce7fb..6163848 100644 --- a/addons/capture/fnc_entity_count.sqf +++ b/addons/capture/fnc_entity_count.sqf @@ -1,5 +1,9 @@ #include "script_component.hpp" +params [ + ["_allUserInfos", [], [[]]] +]; + private _hashesOut = []; private _allUnits = allUnits; @@ -10,18 +14,20 @@ private _allPlayers = call BIS_fnc_listPlayers; { private _thisSide = _x; private _thisSideStr = _thisSide call BIS_fnc_sideNameUnlocalized; + private _tags = +GVARMAIN(standardTags); + _tags pushBack ["side", _thisSideStr]; // Number of remote units _hashesOut pushBack ([ ["bucket", "server_performance"], ["measurement", "entities_remote"], - ["tags", GVARMAIN(standardTags)], + ["tags", _tags], ["fields", [ ["units_alive", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && not (local _x) } count _allUnits], ["units_dead", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && not (local _x) } count _allDeadMen], ["groups_total", { @@ -45,14 +51,14 @@ private _allPlayers = call BIS_fnc_listPlayers; _hashesOut pushBack ([ ["bucket", "server_performance"], ["measurement", "entities_local"], - ["tags", GVARMAIN(standardTags)], + ["tags", _tags], ["fields", [ ["units_alive", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && local _x } count _allUnits], ["units_dead", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && local _x } count _allDeadMen], ["groups_total", { @@ -78,13 +84,13 @@ private _allPlayers = call BIS_fnc_listPlayers; _hashesOut pushBack ([ ["bucket", "server_performance"], ["measurement", "entities_global"], - ["tags", GVARMAIN(standardTags)], + ["tags", _tags], ["fields", [ ["units_alive", { - side _x isEqualTo _thisSide + side group _x isEqualTo _thisSide } count _allUnits], ["units_dead", { - side _x isEqualTo _thisSide + side group _x isEqualTo _thisSide } count _allDeadMen], ["groups_total", { side _x isEqualTo _thisSide @@ -98,11 +104,11 @@ private _allPlayers = call BIS_fnc_listPlayers; (_x isKindOf "WeaponHolderSimulated") } count _vehicles], ["players_alive", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && alive _x } count _allPlayers], ["players_dead", { - side _x isEqualTo _thisSide && + side group _x isEqualTo _thisSide && !alive _x } count _allPlayers] ]] @@ -116,12 +122,8 @@ if (isServer) then { ["measurement", "player_count"], ["tags", GVARMAIN(standardTags)], ["fields", [ - ["players_connected", { - private _info = getUserInfo (getPlayerId _x); - if (!isNil "_info" && {count _info >= 6}) then { - _info select 7 - } else {false} - } count _allPlayers] + ["players_connected", count (_allUserInfos select {_x#7 isEqualTo false})], + ["headless_clients_connected", count (_allUserInfos select {_x#7 isEqualTo true})] ]] ]); }; diff --git a/addons/capture/fnc_player_performance.sqf b/addons/capture/fnc_player_performance.sqf index 4ac7df1..20f81f9 100644 --- a/addons/capture/fnc_player_performance.sqf +++ b/addons/capture/fnc_player_performance.sqf @@ -1,5 +1,9 @@ #include "script_component.hpp" +params [ + ["_allUserInfos", [], [[]]] +]; + private _hashesOut = []; { _x params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"]; @@ -23,6 +27,6 @@ private _hashesOut = []; ["desync", _desync] ]] ]); -} forEach (allUsers apply {getUserInfo _x}); +} forEach _allUserInfos; _hashesOut; \ No newline at end of file diff --git a/addons/main/config.cpp b/addons/main/config.cpp index 0e4501d..9e2196b 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -5,7 +5,11 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = 2.10; - requiredAddons[] = {}; + requiredAddons[] = { + "cba_main", + "cba_xeh", + "cba_settings" + }; author[] = {"IndigoFox"}; authorUrl = "https://github.com/indig0fox/IFXMetrics"; }; diff --git a/addons/main/fnc_captureLoop.sqf b/addons/main/fnc_captureLoop.sqf index 05b6ae1..927ae30 100644 --- a/addons/main/fnc_captureLoop.sqf +++ b/addons/main/fnc_captureLoop.sqf @@ -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 { GVARMAIN(extensionName) callExtension [ ":INFLUX:WRITE:", [_x] ]; - } forEach (call EFUNC(capture,entity_count)); + } forEach ([_allUserInfos] call EFUNC(capture,entity_count)); { GVARMAIN(extensionName) callExtension [ ":INFLUX:WRITE:", [_x] ]; - } forEach (call EFUNC(capture,player_performance)); + } forEach ([_allUserInfos] call EFUNC(capture,player_performance)); ["DEBUG", format[ "Processed primary data loop in %1 ms", diff --git a/extension/cmd/main.go b/extension/IFXMetrics/cmd/main.go similarity index 98% rename from extension/cmd/main.go rename to extension/IFXMetrics/cmd/main.go index aae9200..51e793b 100644 --- a/extension/cmd/main.go +++ b/extension/IFXMetrics/cmd/main.go @@ -319,4 +319,7 @@ func main() { // s := settings.Active.Get("cbaEventHandlers") // // return the custom cba event handlers as an arma hashmap // fmt.Println(a3interface.ToArmaHashMap(s)) + + fmt.Println("IFXMetrics extension started. Version: " + EXTENSION_VERSION) + fmt.Scanln() } diff --git a/extension/go.mod b/extension/IFXMetrics/go.mod similarity index 100% rename from extension/go.mod rename to extension/IFXMetrics/go.mod diff --git a/extension/go.sum b/extension/IFXMetrics/go.sum similarity index 100% rename from extension/go.sum rename to extension/IFXMetrics/go.sum diff --git a/extension/internal/influx/influx.go b/extension/IFXMetrics/internal/influx/influx.go similarity index 100% rename from extension/internal/influx/influx.go rename to extension/IFXMetrics/internal/influx/influx.go diff --git a/extension/internal/logger/logger.go b/extension/IFXMetrics/internal/logger/logger.go similarity index 100% rename from extension/internal/logger/logger.go rename to extension/IFXMetrics/internal/logger/logger.go diff --git a/extension/internal/settings/settings.go b/extension/IFXMetrics/internal/settings/settings.go similarity index 100% rename from extension/internal/settings/settings.go rename to extension/IFXMetrics/internal/settings/settings.go diff --git a/influxdb/docker-compose.yaml b/influxdb/docker-compose.yaml new file mode 100644 index 0000000..a97bb8b --- /dev/null +++ b/influxdb/docker-compose.yaml @@ -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 \ No newline at end of file