From a650fd495c1bfd1a3c726505f69fcd626049c214 Mon Sep 17 00:00:00 2001 From: Kargatum Date: Thu, 28 Oct 2021 19:47:29 +0700 Subject: [PATCH] feat(Core/Metrics): implement real time statistic visualization (#8663) --- apps/grafana/1_General.json | 1319 +++++++++++++ apps/grafana/2_Maps.json | 691 +++++++ apps/grafana/3_Network.json | 280 +++ apps/grafana/4_Performance_profiling.json | 1677 +++++++++++++++++ conf/dist/config.cmake | 2 + src/cmake/showoptions.cmake | 12 + src/common/Collision/Maps/MapTree.cpp | 8 + src/common/Metric/Metric.cpp | 343 ++++ src/common/Metric/Metric.h | 227 +++ src/common/Threading/PCQueue.h | 5 + .../database/Database/DatabaseWorkerPool.cpp | 6 + .../database/Database/DatabaseWorkerPool.h | 2 + src/server/game/Handlers/CharacterHandler.cpp | 9 +- src/server/game/Maps/Map.cpp | 9 + src/server/game/Maps/MapUpdater.cpp | 3 + .../MovementGenerators/PathGenerator.cpp | 3 + src/server/game/Server/WorldSession.cpp | 7 + src/server/game/World/World.cpp | 149 +- src/server/scripts/Commands/cs_server.cpp | 4 + src/server/worldserver/Main.cpp | 17 + src/server/worldserver/worldserver.conf.dist | 56 + 21 files changed, 4798 insertions(+), 31 deletions(-) create mode 100644 apps/grafana/1_General.json create mode 100644 apps/grafana/2_Maps.json create mode 100644 apps/grafana/3_Network.json create mode 100644 apps/grafana/4_Performance_profiling.json create mode 100644 src/common/Metric/Metric.cpp create mode 100644 src/common/Metric/Metric.h diff --git a/apps/grafana/1_General.json b/apps/grafana/1_General.json new file mode 100644 index 0000000000..b84dcb3dfc --- /dev/null +++ b/apps/grafana/1_General.json @@ -0,0 +1,1319 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 5, + "iteration": 1595020261725, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 0 + }, + "hideTimeOverride": false, + "id": 5, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + } + ], + "measurement": "online_players", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Online players", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 0 + }, + "id": 6, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "timeFrom": "1m", + "title": "Update diff (avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 9, + "y": 0 + }, + "id": 7, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "timeFrom": "5m", + "title": "Update diff (avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 14, + "y": 0 + }, + "id": 8, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "timeFrom": "15m", + "timeShift": null, + "title": "Update diff (avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 19, + "y": 0 + }, + "id": 12, + "options": { + "showLabels": false, + "showTime": true, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "groupBy": [], + "measurement": "events", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"title\" FROM \"events\" WHERE (\"realm\" =~ /^$realm$/) order by \"time\" desc limit 2", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "title" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Recent events", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "title": false + }, + "indexByName": {}, + "renameByName": { + "Time": "", + "title": "" + } + } + } + ], + "type": "logs" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 3 + }, + "hiddenSeries": false, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Update diff", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"update_time_diff\" WHERE (\"realm\" =~ /$realm$/) AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Update diff", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "ms", + "short" + ], + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Map update", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 18 + }, + "hiddenSeries": false, + "id": 4, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Online players", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "online_players", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"online_players\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(null)", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Online players", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 25 + }, + "hiddenSeries": false, + "id": 3, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Logouts", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Logins", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "player_events", + "policy": "default", + "query": "SELECT count(\"text\") FROM \"player_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'Login' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "text" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=", + "value": "Acore" + } + ] + }, + { + "alias": "Logouts", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "policy": "default", + "query": "SELECT count(\"text\") FROM \"player_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'Logout' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Player login/logout", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 25, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allFormat": "regex values", + "allValue": null, + "current": { + "selected": false, + "text": "Acore", + "value": "Acore" + }, + "datasource": "Influx", + "definition": "", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [], + "query": "show tag values from events with key = realm", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "General info", + "uid": "BfuPZmZMz", + "version": 3 +} \ No newline at end of file diff --git a/apps/grafana/2_Maps.json b/apps/grafana/2_Maps.json new file mode 100644 index 0000000000..5da97972da --- /dev/null +++ b/apps/grafana/2_Maps.json @@ -0,0 +1,691 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 6, + "iteration": 1595939001794, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Unload tile", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Load tile", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"map_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'LoadMapTile' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Unload tile", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"map_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'UnloadMapTile' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Map", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Pathfinding queries", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"mmap_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'CalculatePath' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MMap", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 5, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id Instance $tag_map_instanceid", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "map_instanceid" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_creatures", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Creatures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 5, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id Instance $tag_map_instanceid", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "map_instanceid" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_gameobjects", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Gameobjects", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 25, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allFormat": "regex values", + "allValue": null, + "current": { + "text": "Acore", + "value": "Acore" + }, + "datasource": "Influx", + "definition": "", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [], + "query": "show tag values from events with key = realm", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Maps, vmaps and mmaps", + "uid": "6IhqWiWGz", + "version": 2 +} \ No newline at end of file diff --git a/apps/grafana/3_Network.json b/apps/grafana/3_Network.json new file mode 100644 index 0000000000..327b7b5e19 --- /dev/null +++ b/apps/grafana/3_Network.json @@ -0,0 +1,280 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 7, + "iteration": 1595939048589, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Processed packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "processed_packets", + "query": "SELECT sum(\"value\") FROM \"processed_packets\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(0)", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + }, + { + "alias": "Processed packets / mean per session", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "processed_packets", + "query": "SELECT mean(\"value\") FROM \"processed_packets\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(0)", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Processed packets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 25, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allFormat": "regex values", + "allValue": null, + "current": { + "text": "Acore", + "value": "Acore" + }, + "datasource": "Influx", + "definition": "", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [], + "query": "show tag values from events with key = realm", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Network", + "uid": "_QtkMmWMk", + "version": 2 +} \ No newline at end of file diff --git a/apps/grafana/4_Performance_profiling.json b/apps/grafana/4_Performance_profiling.json new file mode 100644 index 0000000000..04363a540e --- /dev/null +++ b/apps/grafana/4_Performance_profiling.json @@ -0,0 +1,1677 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "Influx", + "enable": true, + "hide": false, + "iconColor": "#c0c6be", + "limit": 100, + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showIn": 0, + "tags": [], + "textColumn": "text", + "type": "tags" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 15, + "iteration": 1626984445687, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Update diff", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"update_time_diff\" WHERE (\"realm\" =~ /$realm$/) AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Update diff", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "ms", + "short" + ], + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Total", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "world_update_time_total", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + }, + { + "alias": "$tag_type", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "type" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "world_update_time", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "World Update - Split", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_type", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "type" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "world_update_time", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + }, + { + "condition": "AND", + "key": "parent_type", + "operator": "!~", + "value": "/./" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "World Update - Stacked", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Map update - Split", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_update_time_diff", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Map update - Stacked", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Account ID $tag_account_id", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "account_id" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "world_update_sessions_time", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"map_update_time_diff\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"map_id\" fill(none)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Update sessions - Split", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Opcode $tag_opcode", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "opcode" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "worldsession_update_opcode_time", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT max(\"value\") FROM \"worldsession_update_opcode_time\" WHERE (\"realm\" =~ /^$realm$/) AND $timeFilter GROUP BY time($__interval), \"opcode\" fill(null)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Opcode handlers - Split", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 5, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id Instance $tag_map_instanceid", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "map_instanceid" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_creatures", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Creatures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 5, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 31 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Map $tag_map_id Instance $tag_map_instanceid", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "map_id" + ], + "type": "tag" + }, + { + "params": [ + "map_instanceid" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "map_gameobjects", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Gameobjects", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 39 + }, + "hiddenSeries": false, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Login DB", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "db_queue_login", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + }, + { + "alias": "Character DB", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "db_queue_character", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + }, + { + "alias": "World DB", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "db_queue_world", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "max" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Database queue", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:102", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:103", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": "Acore", + "value": "Acore" + }, + "datasource": "Influx", + "definition": "show tag values from events with key = realm", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "realm", + "options": [], + "query": "show tag values from events with key = realm", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Performance profiling", + "uid": "IRRL03nMk", + "version": 9 +} \ No newline at end of file diff --git a/conf/dist/config.cmake b/conf/dist/config.cmake index 728323112d..5b8779b061 100644 --- a/conf/dist/config.cmake +++ b/conf/dist/config.cmake @@ -67,6 +67,8 @@ option(WITHOUT_GIT "Disable the GIT testing routines" option(ENABLE_VMAP_CHECKS "Enable Checks relative to DisableMgr system on vmap" 1) option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0) option(WITH_STRICT_DATABASE_TYPE_CHECKS "Enable strict checking of database field value accessors" 0) +option(WITHOUT_METRICS "Disable metrics reporting (i.e. InfluxDB and Grafana)" 0) +option(WITH_DETAILED_METRICS "Enable detailed metrics reporting (i.e. time each session takes to update)" 0) IsDynamicLinkingRequired(WITH_DYNAMIC_LINKING_FORCED) IsDynamicLinkingModulesRequired(WITH_DYNAMIC_LINKING_FORCED) diff --git a/src/cmake/showoptions.cmake b/src/cmake/showoptions.cmake index 0a9a8362c7..8e81121409 100644 --- a/src/cmake/showoptions.cmake +++ b/src/cmake/showoptions.cmake @@ -156,6 +156,18 @@ if(WITH_STRICT_DATABASE_TYPE_CHECKS) add_definitions(-DACORE_STRICT_DATABASE_TYPE_CHECKS) endif() +if(WITHOUT_METRICS) + message("") + message(" *** WITHOUT_METRICS - WARNING!") + message(" *** Please note that this will disable all metrics output (i.e. InfluxDB and Grafana)") + add_definitions(-DWITHOUT_METRICS) +elseif (WITH_DETAILED_METRICS) + message("") + message(" *** WITH_DETAILED_METRICS - WARNING!") + message(" *** Please note that this will enable detailed metrics output (i.e. time each session takes to update)") + add_definitions(-DWITH_DETAILED_METRICS) +endif() + if(BUILD_SHARED_LIBS) message("") message(" *** WITH_DYNAMIC_LINKING - INFO!") diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index 5a4b3b81d1..7cf745090b 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -18,6 +18,7 @@ #include "MapTree.h" #include "Errors.h" #include "Log.h" +#include "Metric.h" #include "ModelInstance.h" #include "VMapDefinitions.h" #include "VMapMgr2.h" @@ -452,6 +453,10 @@ namespace VMAP { iLoadedTiles[packTileID(tileX, tileY)] = false; } + + METRIC_EVENT("map_events", "LoadMapTile", + "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY)); + return result; } @@ -518,6 +523,9 @@ namespace VMAP } } iLoadedTiles.erase(tile); + + METRIC_EVENT("map_events", "UnloadMapTile", + "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY)); } void StaticMapTree::GetModelInstances(ModelInstance*& models, uint32& count) diff --git a/src/common/Metric/Metric.cpp b/src/common/Metric/Metric.cpp new file mode 100644 index 0000000000..fb0e39a8c0 --- /dev/null +++ b/src/common/Metric/Metric.cpp @@ -0,0 +1,343 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Metric.h" +#include "Common.h" +#include "Config.h" +#include "DeadlineTimer.h" +#include "Log.h" +#include "Strand.h" +#include "Util.h" +#include "Tokenize.h" +#include +#include + +Metric::Metric() +{ +} + +Metric::~Metric() +{ +} + +Metric* Metric::instance() +{ + static Metric instance; + return &instance; +} + +void Metric::Initialize(std::string const& realmName, Acore::Asio::IoContext& ioContext, std::function overallStatusLogger) +{ + _dataStream = std::make_unique(); + _realmName = FormatInfluxDBTagValue(realmName); + _batchTimer = std::make_unique(ioContext); + _overallStatusTimer = std::make_unique(ioContext); + _overallStatusLogger = overallStatusLogger; + LoadFromConfigs(); +} + +bool Metric::Connect() +{ + auto& stream = static_cast(GetDataStream()); + stream.connect(_hostname, _port); + + auto error = stream.error(); + if (error) + { + FMT_LOG_ERROR("metric", "Error connecting to '{}:{}', disabling Metric. Error message: {}", + _hostname, _port, error.message()); + + _enabled = false; + return false; + } + + stream.clear(); + return true; +} + +void Metric::LoadFromConfigs() +{ + bool previousValue = _enabled; + _enabled = sConfigMgr->GetOption("Metric.Enable", false); + _updateInterval = sConfigMgr->GetOption("Metric.Interval", 10); + + if (_updateInterval < 1) + { + FMT_LOG_ERROR("metric", "'Metric.Interval' config set to {}, overriding to 1.", _updateInterval); + _updateInterval = 1; + } + + _overallStatusTimerInterval = sConfigMgr->GetOption("Metric.OverallStatusInterval", 1); + if (_overallStatusTimerInterval < 1) + { + FMT_LOG_ERROR("metric", "'Metric.OverallStatusInterval' config set to {}, overriding to 1.", _overallStatusTimerInterval); + _overallStatusTimerInterval = 1; + } + + _thresholds.clear(); + std::vector thresholdSettings = sConfigMgr->GetKeysByString("Metric.Threshold."); + for (std::string const& thresholdSetting : thresholdSettings) + { + int64 thresholdValue = sConfigMgr->GetOption(thresholdSetting, 0); + std::string thresholdName = thresholdSetting.substr(strlen("Metric.Threshold.")); + _thresholds[thresholdName] = thresholdValue; + } + + // Schedule a send at this point only if the config changed from Disabled to Enabled. + // Cancel any scheduled operation if the config changed from Enabled to Disabled. + if (_enabled && !previousValue) + { + std::string connectionInfo = sConfigMgr->GetOption("Metric.ConnectionInfo", ""); + if (connectionInfo.empty()) + { + FMT_LOG_ERROR("metric", "'Metric.ConnectionInfo' not specified in configuration file."); + return; + } + + std::vector tokens = Acore::Tokenize(connectionInfo, ';', true); + if (tokens.size() != 3) + { + FMT_LOG_ERROR("metric", "'Metric.ConnectionInfo' specified with wrong format in configuration file."); + return; + } + + _hostname.assign(tokens[0]); + _port.assign(tokens[1]); + _databaseName.assign(tokens[2]); + Connect(); + + ScheduleSend(); + ScheduleOverallStatusLog(); + } +} + +void Metric::Update() +{ + if (_overallStatusTimerTriggered) + { + _overallStatusTimerTriggered = false; + _overallStatusLogger(); + } +} + +bool Metric::ShouldLog(std::string const& category, int64 value) const +{ + auto threshold = _thresholds.find(category); + + if (threshold == _thresholds.end()) + { + return false; + } + + return value >= threshold->second; +} + +void Metric::LogEvent(std::string const& category, std::string const& title, std::string const& description) +{ + using namespace std::chrono; + + MetricData* data = new MetricData; + data->Category = category; + data->Timestamp = system_clock::now(); + data->Type = METRIC_DATA_EVENT; + data->Title = title; + data->Text = description; + + _queuedData.Enqueue(data); +} + +void Metric::SendBatch() +{ + using namespace std::chrono; + + std::stringstream batchedData; + MetricData* data; + bool firstLoop = true; + + while (_queuedData.Dequeue(data)) + { + if (!firstLoop) + batchedData << "\n"; + + batchedData << data->Category; + if (!_realmName.empty()) + batchedData << ",realm=" << _realmName; + + for (MetricTag const& tag : data->Tags) + batchedData << "," << tag.first << "=" << FormatInfluxDBTagValue(tag.second); + + batchedData << " "; + + switch (data->Type) + { + case METRIC_DATA_VALUE: + batchedData << "value=" << data->Value; + break; + case METRIC_DATA_EVENT: + batchedData << "title=\"" << data->Title << "\",text=\"" << data->Text << "\""; + break; + } + + batchedData << " " << std::to_string(duration_cast(data->Timestamp.time_since_epoch()).count()); + + firstLoop = false; + delete data; + } + + // Check if there's any data to send + if (batchedData.tellp() == std::streampos(0)) + { + ScheduleSend(); + return; + } + + if (!GetDataStream().good() && !Connect()) + return; + + GetDataStream() << "POST " << "/write?db=" << _databaseName << " HTTP/1.1\r\n"; + GetDataStream() << "Host: " << _hostname << ":" << _port << "\r\n"; + GetDataStream() << "Accept: */*\r\n"; + GetDataStream() << "Content-Type: application/octet-stream\r\n"; + GetDataStream() << "Content-Transfer-Encoding: binary\r\n"; + + GetDataStream() << "Content-Length: " << std::to_string(batchedData.tellp()) << "\r\n\r\n"; + GetDataStream() << batchedData.rdbuf(); + + std::string http_version; + GetDataStream() >> http_version; + unsigned int status_code = 0; + GetDataStream() >> status_code; + + if (status_code != 204) + { + FMT_LOG_ERROR("metric", "Error sending data, returned HTTP code: {}", status_code); + } + + // Read and ignore the status description + std::string status_description; + std::getline(GetDataStream(), status_description); + + // Read headers + std::string header; + + while (std::getline(GetDataStream(), header) && header != "\r") + { + if (header == "Connection: close\r") + { + static_cast(GetDataStream()).close(); + } + } + + ScheduleSend(); +} + +void Metric::ScheduleSend() +{ + if (_enabled) + { + _batchTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); + _batchTimer->async_wait(std::bind(&Metric::SendBatch, this)); + } + else + { + static_cast(GetDataStream()).close(); + MetricData* data; + + // Clear the queue + while (_queuedData.Dequeue(data)) + { + delete data; + } + } +} + +void Metric::Unload() +{ + // Send what's queued only if IoContext is stopped (so only on shutdown) + if (_enabled && Acore::Asio::get_io_context(*_batchTimer).stopped()) + { + _enabled = false; + SendBatch(); + } + + _batchTimer->cancel(); + _overallStatusTimer->cancel(); +} + +void Metric::ScheduleOverallStatusLog() +{ + if (_enabled) + { + _overallStatusTimer->expires_from_now(boost::posix_time::seconds(_overallStatusTimerInterval)); + _overallStatusTimer->async_wait([this](const boost::system::error_code&) + { + _overallStatusTimerTriggered = true; + ScheduleOverallStatusLog(); + }); + } +} + +std::string Metric::FormatInfluxDBValue(bool value) +{ + return value ? "t" : "f"; +} + +template +std::string Metric::FormatInfluxDBValue(T value) +{ + return std::to_string(value) + 'i'; +} + +std::string Metric::FormatInfluxDBValue(std::string const& value) +{ + return '"' + boost::replace_all_copy(value, "\"", "\\\"") + '"'; +} + +std::string Metric::FormatInfluxDBValue(char const* value) +{ + return FormatInfluxDBValue(std::string(value)); +} + +std::string Metric::FormatInfluxDBValue(double value) +{ + return std::to_string(value); +} + +std::string Metric::FormatInfluxDBValue(float value) +{ + return FormatInfluxDBValue(double(value)); +} + +std::string Metric::FormatInfluxDBTagValue(std::string const& value) +{ + // ToDo: should handle '=' and ',' characters too + return boost::replace_all_copy(value, " ", "\\ "); +} + +std::string Metric::FormatInfluxDBValue(std::chrono::nanoseconds value) +{ + return FormatInfluxDBValue(std::chrono::duration_cast(value).count()); +} + +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(int8); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(uint8); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(int16); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(uint16); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(int32); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(uint32); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(int64); +template AC_COMMON_API std::string Metric::FormatInfluxDBValue(uint64); diff --git a/src/common/Metric/Metric.h b/src/common/Metric/Metric.h new file mode 100644 index 0000000000..5506303286 --- /dev/null +++ b/src/common/Metric/Metric.h @@ -0,0 +1,227 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef METRIC_H__ +#define METRIC_H__ + +#include "Define.h" +#include "Duration.h" +#include "MPSCQueue.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Acore::Asio +{ + class IoContext; + class DeadlineTimer; +} + +enum MetricDataType +{ + METRIC_DATA_VALUE, + METRIC_DATA_EVENT +}; + +typedef std::pair MetricTag; + +struct MetricData +{ + std::string Category; + SystemTimePoint Timestamp; + MetricDataType Type; + std::vector Tags; + + // LogValue-specific fields + std::string Value; + + // LogEvent-specific fields + std::string Title; + std::string Text; +}; + +class AC_COMMON_API Metric +{ +private: + std::iostream& GetDataStream() { return *_dataStream; } + std::unique_ptr _dataStream; + MPSCQueue _queuedData; + std::unique_ptr _batchTimer; + std::unique_ptr _overallStatusTimer; + int32 _updateInterval = 0; + int32 _overallStatusTimerInterval = 0; + bool _enabled = false; + bool _overallStatusTimerTriggered = false; + std::string _hostname; + std::string _port; + std::string _databaseName; + std::function _overallStatusLogger; + std::string _realmName; + std::unordered_map _thresholds; + + bool Connect(); + void SendBatch(); + void ScheduleSend(); + void ScheduleOverallStatusLog(); + + static std::string FormatInfluxDBValue(bool value); + + template + static std::string FormatInfluxDBValue(T value); + + static std::string FormatInfluxDBValue(std::string const& value); + static std::string FormatInfluxDBValue(char const* value); + static std::string FormatInfluxDBValue(double value); + static std::string FormatInfluxDBValue(float value); + static std::string FormatInfluxDBValue(std::chrono::nanoseconds value); + + static std::string FormatInfluxDBTagValue(std::string const& value); + + // ToDo: should format TagKey and FieldKey too in the same way as TagValue + +public: + Metric(); + ~Metric(); + + static Metric* instance(); + + void Initialize(std::string const& realmName, Acore::Asio::IoContext& ioContext, std::function overallStatusLogger); + void LoadFromConfigs(); + void Update(); + bool ShouldLog(std::string const& category, int64 value) const; + + template + void LogValue(std::string const& category, T value, std::vector tags) + { + using namespace std::chrono; + + MetricData* data = new MetricData; + data->Category = category; + data->Timestamp = system_clock::now(); + data->Type = METRIC_DATA_VALUE; + data->Value = FormatInfluxDBValue(value); + data->Tags = std::move(tags); + + _queuedData.Enqueue(data); + } + + void LogEvent(std::string const& category, std::string const& title, std::string const& description); + + void Unload(); + bool IsEnabled() const { return _enabled; } +}; + +#define sMetric Metric::instance() + +template +class MetricStopWatch +{ +public: + MetricStopWatch(LoggerType&& loggerFunc) : + _logger(std::forward(loggerFunc)), + _startTime(sMetric->IsEnabled() ? std::chrono::steady_clock::now() : TimePoint()) + { + } + + ~MetricStopWatch() + { + if (sMetric->IsEnabled()) + _logger(_startTime); + } + +private: + LoggerType _logger; + TimePoint _startTime; +}; + +template +MetricStopWatch MakeMetricStopWatch(LoggerType&& loggerFunc) +{ + return { std::forward(loggerFunc) }; +} + +#define METRIC_TAG(name, value) { name, value } + +#define METRIC_DO_CONCAT(a, b) a##b +#define METRIC_CONCAT(a, b) METRIC_DO_CONCAT(a, b) +#define METRIC_UNIQUE_NAME(name) METRIC_CONCAT(name, __LINE__) + +#if defined PERFORMANCE_PROFILING || defined WITHOUT_METRICS +#define METRIC_EVENT(category, title, description) ((void)0) +#define METRIC_VALUE(category, value, ...) ((void)0) +#define METRIC_TIMER(category, ...) ((void)0) +#define METRIC_DETAILED_EVENT(category, title, description) ((void)0) +#define METRIC_DETAILED_TIMER(category, ...) ((void)0) +#define METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0) +#else +#if AC_PLATFORM != AC_PLATFORM_WINDOWS +#define METRIC_EVENT(category, title, description) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogEvent(category, title, description); \ + } while (0) +#define METRIC_VALUE(category, value, ...) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogValue(category, value, { __VA_ARGS__ }); \ + } while (0) +#else +#define METRIC_EVENT(category, title, description) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogEvent(category, title, description); \ + } while (0) \ + __pragma(warning(pop)) +#define METRIC_VALUE(category, value, ...) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogValue(category, value, { __VA_ARGS__ }); \ + } while (0) \ + __pragma(warning(pop)) +#endif +#define METRIC_TIMER(category, ...) \ + MetricStopWatch METRIC_UNIQUE_NAME(__ac_metric_stop_watch) = MakeMetricStopWatch([&](TimePoint start) \ + { \ + sMetric->LogValue(category, std::chrono::steady_clock::now() - start, { __VA_ARGS__ }); \ + }); +#if defined WITH_DETAILED_METRICS +#define METRIC_DETAILED_TIMER(category, ...) \ + MetricStopWatch METRIC_UNIQUE_NAME(__ac_metric_stop_watch) = MakeMetricStopWatch([&](TimePoint start) \ + { \ + int64 duration = int64(std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count()); \ + if (sMetric->ShouldLog(category, duration)) \ + sMetric->LogValue(category, duration, { __VA_ARGS__ }); \ + }); +#define METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) METRIC_TIMER(category, __VA_ARGS__) +#define METRIC_DETAILED_EVENT(category, title, description) METRIC_EVENT(category, title, description) +#else +#define METRIC_DETAILED_EVENT(category, title, description) ((void)0) +#define METRIC_DETAILED_TIMER(category, ...) ((void)0) +#define METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0) +#endif + +#endif + +#endif // METRIC_H__ diff --git a/src/common/Threading/PCQueue.h b/src/common/Threading/PCQueue.h index 390e3b3289..040eed1be0 100644 --- a/src/common/Threading/PCQueue.h +++ b/src/common/Threading/PCQueue.h @@ -51,6 +51,11 @@ public: return _queue.empty(); } + size_t Size() const + { + return _queue.size(); + } + bool Pop(T& value) { std::lock_guard lock(_queueLock); diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index b21d4ab2fb..836d824320 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -430,6 +430,12 @@ void DatabaseWorkerPool::Enqueue(SQLOperation* op) _queue->Push(op); } +template +size_t DatabaseWorkerPool::QueueSize() const +{ + return _queue->Size(); +} + template T* DatabaseWorkerPool::GetFreeConnection() { diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index 1b45a03947..86c2662fb6 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -213,6 +213,8 @@ public: #endif } + size_t QueueSize() const; + private: uint32 OpenConnections(InternalIndex type, uint8 numConnections); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 4af1ca5eab..1c9308d3e9 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -29,12 +29,14 @@ #include "GuildMgr.h" #include "Language.h" #include "Log.h" +#include "Metric.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" #include "Pet.h" #include "Player.h" #include "PlayerDump.h" +#include "QueryHolder.h" #include "Realm.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -43,15 +45,14 @@ #include "SocialMgr.h" #include "SpellAuraEffects.h" #include "SpellAuras.h" +#include "StringConvert.h" +#include "Tokenize.h" #include "Transport.h" #include "UpdateMask.h" #include "Util.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "QueryHolder.h" -#include "StringConvert.h" -#include "Tokenize.h" #ifdef ELUNA #include "LuaEngine.h" @@ -1087,6 +1088,8 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); sScriptMgr->OnFirstLogin(pCurrChar); } + + METRIC_EVENT("player_events", "Login", pCurrChar->GetName()); } void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 08d2652318..037ba3eb17 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -28,6 +28,7 @@ #include "LFGMgr.h" #include "Map.h" #include "MapInstanced.h" +#include "Metric.h" #include "Object.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -868,6 +869,14 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) HandleDelayedVisibility(); sScriptMgr->OnMapUpdate(this, t_diff); + + METRIC_VALUE("map_creatures", uint64(GetObjectsStore().Size()), + METRIC_TAG("map_id", std::to_string(GetId())), + METRIC_TAG("map_instanceid", std::to_string(GetInstanceId()))); + + METRIC_VALUE("map_gameobjects", uint64(GetObjectsStore().Size()), + METRIC_TAG("map_id", std::to_string(GetId())), + METRIC_TAG("map_instanceid", std::to_string(GetInstanceId()))); } void Map::HandleDelayedVisibility() diff --git a/src/server/game/Maps/MapUpdater.cpp b/src/server/game/Maps/MapUpdater.cpp index ea58d9d19c..75e6bc9964 100644 --- a/src/server/game/Maps/MapUpdater.cpp +++ b/src/server/game/Maps/MapUpdater.cpp @@ -19,6 +19,7 @@ #include "LFGMgr.h" #include "Map.h" #include "MapUpdater.h" +#include "Metric.h" class UpdateRequest { @@ -39,9 +40,11 @@ public: void call() override { + METRIC_TIMER("map_update_time_diff", METRIC_TAG("map_id", std::to_string(m_map.GetId()))); m_map.Update(m_diff, s_diff); m_updater.update_finished(); } + private: Map& m_map; MapUpdater& m_updater; diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp index 6f2dd59ee7..a465d96585 100644 --- a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp @@ -20,6 +20,7 @@ #include "Geometry.h" #include "Log.h" #include "Map.h" +#include "Metric.h" #include "MMapFactory.h" #include "MMapMgr.h" #include "PathGenerator.h" @@ -61,6 +62,8 @@ bool PathGenerator::CalculatePath(float x, float y, float z, float destX, float if (!Acore::IsValidMapCoord(destX, destY, destZ) || !Acore::IsValidMapCoord(x, y, z)) return false; + METRIC_DETAILED_EVENT("mmap_events", "CalculatePath", ""); + G3D::Vector3 dest(destX, destY, destZ); SetEndPosition(dest); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 0cc33d3308..b048bbbd36 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -30,6 +30,7 @@ #include "Hyperlinks.h" #include "Log.h" #include "MapMgr.h" +#include "Metric.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -319,6 +320,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) OpcodeClient opcode = static_cast(packet->GetOpcode()); ClientOpcodeHandler const* opHandle = opcodeTable[opcode]; + METRIC_DETAILED_TIMER("worldsession_update_opcode_time", METRIC_TAG("opcode", opHandle->Name)); + try { switch (opHandle->Status) @@ -441,6 +444,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) _recvQueue.readd(requeuePackets.begin(), requeuePackets.end()); + METRIC_VALUE("processed_packets", processedPackets); + if (!updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter { // Send time sync packet every 10s. @@ -671,6 +676,8 @@ void WorldSession::LogoutPlayer(bool save) //! Call script hook before deletion sScriptMgr->OnPlayerLogout(_player); + METRIC_EVENT("player_events", "Logout", _player->GetName()); + LOG_INFO("entities.player", "Account: %d (IP: %s) Logout Character:[%s] (%s) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), _player->getLevel()); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 2e9f23716d..d776ed3f14 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -60,6 +60,7 @@ #include "LootMgr.h" #include "MMapFactory.h" #include "MapMgr.h" +#include "Metric.h" #include "ObjectMgr.h" #include "Opcodes.h" #include "OutdoorPvPMgr.h" @@ -437,6 +438,7 @@ void World::LoadConfigSettings(bool reload) } sLog->LoadFromConfig(); + sMetric->LoadFromConfigs(); } // Set realm id and enable db logging @@ -2107,10 +2109,13 @@ void World::SetInitialWorldSettings() } uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); + LOG_INFO("server.loading", " "); LOG_INFO("server.loading", "WORLD: World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); // outError for red color in console LOG_INFO("server.loading", " "); + METRIC_EVENT("events", "World initialized", "World initialized in " + std::to_string(startupDuration / 60000) + " minutes " + std::to_string((startupDuration % 60000) / 1000) + " seconds"); + if (sConfigMgr->isDryRun()) { LOG_INFO("server.loading", "AzerothCore dry run completed, terminating."); @@ -2199,6 +2204,8 @@ void World::LoadAutobroadcasts() /// Update the World ! void World::Update(uint32 diff) { + METRIC_TIMER("world_update_time_total"); + m_updateTime = diff; if (m_int_configs[CONFIG_INTERVAL_LOG_UPDATE]) @@ -2238,26 +2245,45 @@ void World::Update(uint32 diff) ///- Update the game time and check for shutdown time _UpdateGameTime(); - /// Handle daily quests reset time - if (m_gameTime > m_NextDailyQuestReset) - ResetDailyQuests(); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Check quest reset times")); - /// Handle weekly quests reset time - if (m_gameTime > m_NextWeeklyQuestReset) - ResetWeeklyQuests(); + /// Handle daily quests reset time + if (m_gameTime > m_NextDailyQuestReset) + { + ResetDailyQuests(); + } - /// Handle monthly quests reset time - if (m_gameTime > m_NextMonthlyQuestReset) - ResetMonthlyQuests(); + /// Handle weekly quests reset time + if (m_gameTime > m_NextWeeklyQuestReset) + { + ResetWeeklyQuests(); + } + + /// Handle monthly quests reset time + if (m_gameTime > m_NextMonthlyQuestReset) + { + ResetMonthlyQuests(); + } + } if (m_gameTime > m_NextRandomBGReset) + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Reset random BG")); ResetRandomBG(); + } if (m_gameTime > m_NextCalendarOldEventsDeletionTime) + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Delete old calendar events")); CalendarDeleteOldEvents(); + } if (m_gameTime > m_NextGuildReset) + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Reset guild cap")); ResetGuildCap(); + } // pussywizard: // acquire mutex now, this is kind of waiting for listing thread to finish it's work (since it can't process next packet) @@ -2269,6 +2295,8 @@ void World::Update(uint32 diff) // pussywizard: handle auctions when the timer has passed if (m_timers[WUPDATE_AUCTIONS].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update expired auctions")); + m_timers[WUPDATE_AUCTIONS].Reset(); // pussywizard: handle expired auctions, auctions expired when realm was offline are also handled here (not during loading when many required things aren't loaded yet) @@ -2283,8 +2311,13 @@ void World::Update(uint32 diff) mail_expire_check_timer = m_gameTime + 6 * 3600; } - UpdateSessions(diff); + { + ///
  • Handle session updates when the timer has passed + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update sessions")); + UpdateSessions(diff); + } } + // end of section with mutex AsyncAuctionListingMgr::SetAuctionListingAllowed(true); @@ -2300,6 +2333,8 @@ void World::Update(uint32 diff) { if (m_timers[WUPDATE_CLEANDB].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Clean logs table")); + m_timers[WUPDATE_CLEANDB].Reset(); LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_OLD_LOGS); @@ -2311,33 +2346,58 @@ void World::Update(uint32 diff) } } - sLFGMgr->Update(diff, 0); // pussywizard: remove obsolete stuff before finding compatibility during map update + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update LFG 0")); + sLFGMgr->Update(diff, 0); // pussywizard: remove obsolete stuff before finding compatibility during map update + } - sMapMgr->Update(diff); + ///- Update objects when the timer has passed (maps, transport, creatures, ...) + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update maps")); + sMapMgr->Update(diff); + } if (sWorld->getBoolConfig(CONFIG_AUTOBROADCAST)) { if (m_timers[WUPDATE_AUTOBROADCAST].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Send autobroadcast")); m_timers[WUPDATE_AUTOBROADCAST].Reset(); SendAutoBroadcast(); } } - sBattlegroundMgr->Update(diff); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update battlegrounds")); + sBattlegroundMgr->Update(diff); + } - sOutdoorPvPMgr->Update(diff); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update outdoor pvp")); + sOutdoorPvPMgr->Update(diff); + } - sBattlefieldMgr->Update(diff); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update battlefields")); + sBattlefieldMgr->Update(diff); + } - sLFGMgr->Update(diff, 2); // pussywizard: handle created proposals + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update LFG 2")); + sLFGMgr->Update(diff, 2); // pussywizard: handle created proposals + } - // execute callbacks from sql queries that were queued recently - ProcessQueryCallbacks(); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Process query callbacks")); + // execute callbacks from sql queries that were queued recently + ProcessQueryCallbacks(); + } ///
  • Update uptime table if (m_timers[WUPDATE_UPTIME].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update uptime")); + uint32 tmpDiff = uint32(m_gameTime - m_startTime); uint32 maxOnlinePlayers = GetMaxPlayerCount(); @@ -2356,6 +2416,7 @@ void World::Update(uint32 diff) ///- Erase corpses once every 20 minutes if (m_timers[WUPDATE_CORPSES].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Remove old corpses")); m_timers[WUPDATE_CORPSES].Reset(); sMapMgr->DoForAllMaps([](Map* map) { @@ -2366,6 +2427,7 @@ void World::Update(uint32 diff) ///- Process Game events when necessary if (m_timers[WUPDATE_EVENTS].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update game events")); m_timers[WUPDATE_EVENTS].Reset(); // to give time for Update() to be processed uint32 nextGameEvent = sGameEventMgr->Update(); m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); @@ -2375,6 +2437,7 @@ void World::Update(uint32 diff) ///- Ping to keep MySQL connections alive if (m_timers[WUPDATE_PINGDB].Passed()) { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Ping MySQL")); m_timers[WUPDATE_PINGDB].Reset(); LOG_DEBUG("sql.driver", "Ping MySQL to keep connection alive"); CharacterDatabase.KeepAlive(); @@ -2382,15 +2445,34 @@ void World::Update(uint32 diff) WorldDatabase.KeepAlive(); } - // update the instance reset times - sInstanceSaveMgr->Update(); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update instance reset times")); + // update the instance reset times + sInstanceSaveMgr->Update(); + } - // And last, but not least handle the issued cli commands - ProcessCliCommands(); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Process cli commands")); + // And last, but not least handle the issued cli commands + ProcessCliCommands(); + } - sScriptMgr->OnWorldUpdate(diff); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update world scripts")); + sScriptMgr->OnWorldUpdate(diff); + } - SavingSystemMgr::Update(diff); + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update saving system")); + SavingSystemMgr::Update(diff); + } + + { + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update metrics")); + // Stats logger update + sMetric->Update(); + METRIC_VALUE("update_time_diff", diff); + } } void World::ForceGameEventUpdate() @@ -2710,10 +2792,18 @@ void World::SendServerMessage(ServerMessageType type, const char* text, Player* void World::UpdateSessions(uint32 diff) { - ///- Add new sessions - WorldSession* sess = nullptr; - while (addSessQueue.next(sess)) - AddSession_ (sess); + { + METRIC_DETAILED_NO_THRESHOLD_TIMER("world_update_time", + METRIC_TAG("type", "Add sessions"), + METRIC_TAG("parent_type", "Update sessions")); + + ///- Add new sessions + WorldSession* sess = nullptr; + while (addSessQueue.next(sess)) + { + AddSession_(sess); + } + } ///- Then send an update signal to remaining ones for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next) @@ -2745,6 +2835,9 @@ void World::UpdateSessions(uint32 diff) continue; } + [[maybe_unused]] uint32 currentSessionId = itr->first; + METRIC_DETAILED_TIMER("world_update_sessions_time", METRIC_TAG("account_id", std::to_string(currentSessionId))); + if (!pSession->Update(diff, updater)) { if (!RemoveQueuedPlayer(pSession) && getIntConfig(CONFIG_INTERVAL_DISCONNECT_TOLERANCE)) diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 9dae990b3a..00efa83fa1 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -219,6 +219,10 @@ public: handler->PSendSysMessage("Using World DB Revision: %s", sWorld->GetWorldDBRevision()); handler->PSendSysMessage("Using Character DB Revision: %s", sWorld->GetCharacterDBRevision()); handler->PSendSysMessage("Using Auth DB Revision: %s", sWorld->GetAuthDBRevision()); + + handler->PSendSysMessage("LoginDatabase queue size: %zu", LoginDatabase.QueueSize()); + handler->PSendSysMessage("CharacterDatabase queue size: %zu", CharacterDatabase.QueueSize()); + handler->PSendSysMessage("WorldDatabase queue size: %zu", WorldDatabase.QueueSize()); return true; } diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 1226336f62..37edfc1fdc 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -37,6 +37,7 @@ #include "GitRevision.h" #include "IoContext.h" #include "MapMgr.h" +#include "Metric.h" #include "MySQLThreading.h" #include "ObjectAccessor.h" #include "OpenSSLCrypto.h" @@ -288,6 +289,22 @@ int main(int argc, char** argv) LoadRealmInfo(*ioContext); + sMetric->Initialize(realm.Name, *ioContext, []() + { + METRIC_VALUE("online_players", sWorld->GetPlayerCount()); + METRIC_VALUE("db_queue_login", uint64(LoginDatabase.QueueSize())); + METRIC_VALUE("db_queue_character", uint64(CharacterDatabase.QueueSize())); + METRIC_VALUE("db_queue_world", uint64(WorldDatabase.QueueSize())); + }); + + METRIC_EVENT("events", "Worldserver started", ""); + + std::shared_ptr sMetricHandle(nullptr, [](void*) + { + METRIC_EVENT("events", "Worldserver shutdown", ""); + sMetric->Unload(); + }); + // Loading modules configs sConfigMgr->PrintLoadedModulesConfigs(); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 0919abb85c..7a524d4201 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -31,6 +31,7 @@ # LOGGING SYSTEM SETTINGS # PACKET SPOOF PROTECTION SETTINGS # DEBUG +# METRIC SETTINGS # ################################################################################################### @@ -3821,3 +3822,58 @@ Debug.Arena = 0 # ################################################################################################### + +################################################################################################### +# METRIC SETTINGS +# +# These settings control the statistics sent to the metric database (currently InfluxDB) +# +# Metric.Enable +# Description: Enables statistics sent to the metric database. +# Default: 0 - (Disabled) +# 1 - (Enabled) +# + +Metric.Enable = 0 + +# +# Metric.Interval +# Description: Interval between every batch of data sent in seconds +# Default: 10 seconds +# + +Metric.Interval = 10 + +# +# Metric.ConnectionInfo +# Description: Connection settings for metric database (currently InfluxDB). +# Example: "hostname;port;database" +# Default: "127.0.0.1;8086;worldserver" +# + +Metric.ConnectionInfo = "127.0.0.1;8086;worldserver" + +# +# Metric.OverallStatusInterval +# Description: Interval between every gathering of overall worldserver status data in seconds +# Default: 1 second +# + +Metric.OverallStatusInterval = 1 + +# +# Metric threshold values: Given a metric "name" +# Metric.Threshold.name +# Description: Skips sending statistics with a value lower than the config value. +# If the threshold is commented out, the metric will be ignored. +# Only metrics logged with METRIC_DETAILED_TIMER in the sources are affected. +# Disabled by default. Requires WITH_DETAILED_METRICS CMake flag. +# +# Format: Value as integer +# + +#Metric.Threshold.world_update_sessions_time = 100 +#Metric.Threshold.worldsession_update_opcode_time = 50 + +# +###################################################################################################