Showing the changes to interface/src/Application.cpp (1 of 37 files). Show all
Unified · Split
| @@ -68,6 +68,7 @@ · 67 unmodified lines | |||
| 68 | #include <input-plugins/InputPlugin.h> | 68 | #include <input-plugins/InputPlugin.h> |
| 69 | #include <controllers/UserInputMapper.h> | 69 | #include <controllers/UserInputMapper.h> |
| 70 | #include <controllers/StateController.h> | 70 | #include <controllers/StateController.h> |
| 71 | #include <UserActivityLoggerScriptingInterface.h> | ||
| 71 | #include <LogHandler.h> | 72 | #include <LogHandler.h> |
| 72 | #include <MainWindow.h> | 73 | #include <MainWindow.h> |
| 73 | #include <MessagesClient.h> | 74 | #include <MessagesClient.h> |
| @@ -150,6 +151,8 @@ · 76 unmodified lines | |||
| 150 | #include "InterfaceParentFinder.h" | 151 | #include "InterfaceParentFinder.h" |
| 151 | 152 | ||
| 152 | #include "FrameTimingsScriptingInterface.h" | 153 | #include "FrameTimingsScriptingInterface.h" |
| 154 | #include <GPUIdent.h> | ||
| 155 | #include <gl/GLHelpers.h> | ||
| 153 | 156 | ||
| 154 | // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU | 157 | // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU |
| 155 | // FIXME seems to be broken. | 158 | // FIXME seems to be broken. |
| @@ -437,7 +440,7 @@ bool setupEssentials(int& argc, char** argv) { · 281 unmodified lines | |||
| 437 | DependencyManager::set<HMDScriptingInterface>(); | 440 | DependencyManager::set<HMDScriptingInterface>(); |
| 438 | DependencyManager::set<ResourceScriptingInterface>(); | 441 | DependencyManager::set<ResourceScriptingInterface>(); |
| 439 | DependencyManager::set<ToolbarScriptingInterface>(); | 442 | DependencyManager::set<ToolbarScriptingInterface>(); |
| 440 | 443 | DependencyManager::set<UserActivityLoggerScriptingInterface>(); | |
| 441 | 444 | ||
| 442 | #if defined(Q_OS_MAC) || defined(Q_OS_WIN) | 445 | #if defined(Q_OS_MAC) || defined(Q_OS_WIN) |
| 443 | DependencyManager::set<SpeechRecognizer>(); | 446 | DependencyManager::set<SpeechRecognizer>(); |
| @@ -675,10 +678,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 231 unmodified lines | |||
| 675 | accountManager->setIsAgent(true); | 678 | accountManager->setIsAgent(true); |
| 676 | accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); | 679 | accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); |
| 677 | 680 | ||
| 678 | // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. | ||
| 679 | // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. | ||
| 680 | UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get()); | ||
| 681 | |||
| 682 | auto addressManager = DependencyManager::get<AddressManager>(); | 681 | auto addressManager = DependencyManager::get<AddressManager>(); |
| 683 | 682 | ||
| 684 | // use our MyAvatar position and quat for address manager path | 683 | // use our MyAvatar position and quat for address manager path |
| @@ -768,6 +767,39 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 83 unmodified lines | |||
| 768 | // Make sure we don't time out during slow operations at startup | 767 | // Make sure we don't time out during slow operations at startup |
| 769 | updateHeartbeat(); | 768 | updateHeartbeat(); |
| 770 | 769 | ||
| 770 | |||
| 771 | // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. | ||
| 772 | // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. | ||
| 773 | auto gpuIdent = GPUIdent::getInstance(); | ||
| 774 | auto glContextData = getGLContextData(); | ||
| 775 | QJsonObject properties = { | ||
| 776 | { "previousSessionCrashed", _previousSessionCrashed }, | ||
| 777 | { "previousSessionRuntime", sessionRunTime.get() }, | ||
| 778 | { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, | ||
| 779 | { "kernel_type", QSysInfo::kernelType() }, | ||
| 780 | { "kernel_version", QSysInfo::kernelVersion() }, | ||
| 781 | { "os_type", QSysInfo::productType() }, | ||
| 782 | { "os_version", QSysInfo::productVersion() }, | ||
| 783 | { "gpu_name", gpuIdent->getName() }, | ||
| 784 | { "gpu_driver", gpuIdent->getDriver() }, | ||
| 785 | { "gpu_memory", static_cast<qint64>(gpuIdent->getMemory()) }, | ||
| 786 | { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, | ||
| 787 | { "gl_version", glContextData["version"] }, | ||
| 788 | { "gl_vender", glContextData["vendor"] }, | ||
| 789 | { "gl_sl_version", glContextData["slVersion"] }, | ||
| 790 | { "gl_renderer", glContextData["renderer"] } | ||
| 791 | }; | ||
| 792 | auto macVersion = QSysInfo::macVersion(); | ||
| 793 | if (macVersion != QSysInfo::MV_None) { | ||
| 794 | properties["os_osx_version"] = QSysInfo::macVersion(); | ||
| 795 | } | ||
| 796 | auto windowsVersion = QSysInfo::windowsVersion(); | ||
| 797 | if (windowsVersion != QSysInfo::WV_None) { | ||
| 798 | properties["os_win_version"] = QSysInfo::windowsVersion(); | ||
| 799 | } | ||
| 800 | UserActivityLogger::getInstance().logAction("launch", properties); | ||
| 801 | |||
| 802 | |||
| 771 | // Tell our entity edit sender about our known jurisdictions | 803 | // Tell our entity edit sender about our known jurisdictions |
| 772 | _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); | 804 | _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); |
| 773 | _entityEditSender.setMyAvatar(getMyAvatar()); | 805 | _entityEditSender.setMyAvatar(getMyAvatar()); |
| @@ -1063,6 +1095,89 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 289 unmodified lines | |||
| 1063 | } | 1095 | } |
| 1064 | }); | 1096 | }); |
| 1065 | 1097 | ||
| 1098 | // Add periodic checks to send user activity data | ||
| 1099 | static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; | ||
| 1100 | static int SEND_STATS_INTERVAL_MS = 10000; | ||
| 1101 | static int NEARBY_AVATAR_RADIUS_METERS = 10; | ||
| 1102 | |||
| 1103 | // Periodically send fps as a user activity event | ||
| 1104 | QTimer* sendStatsTimer = new QTimer(this); | ||
| 1105 | sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); | ||
| 1106 | connect(sendStatsTimer, &QTimer::timeout, this, [this]() { | ||
| 1107 | QJsonObject properties = {}; | ||
| 1108 | MemoryInfo memInfo; | ||
| 1109 | if (getMemoryInfo(memInfo)) { | ||
| 1110 | properties["system_memory_total"] = static_cast<qint64>(memInfo.totalMemoryBytes); | ||
| 1111 | properties["system_memory_used"] = static_cast<qint64>(memInfo.usedMemoryBytes); | ||
| 1112 | properties["process_memory_used"] = static_cast<qint64>(memInfo.processUsedMemoryBytes); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | auto displayPlugin = qApp->getActiveDisplayPlugin(); | ||
| 1116 | |||
| 1117 | properties["fps"] = _frameCounter.rate(); | ||
| 1118 | properties["present_rate"] = displayPlugin->presentRate(); | ||
| 1119 | properties["new_frame_present_rate"] = displayPlugin->newFramePresentRate(); | ||
| 1120 | properties["dropped_frame_rate"] = displayPlugin->droppedFrameRate(); | ||
| 1121 | properties["sim_rate"] = getAverageSimsPerSecond(); | ||
| 1122 | properties["avatar_sim_rate"] = getAvatarSimrate(); | ||
| 1123 | |||
| 1124 | auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | ||
| 1125 | properties["packet_rate_in"] = bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(); | ||
| 1126 | properties["packet_rate_out"] = bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(); | ||
| 1127 | properties["kbps_in"] = bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(); | ||
| 1128 | properties["kbps_out"] = bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(); | ||
| 1129 | |||
| 1130 | auto nodeList = DependencyManager::get<NodeList>(); | ||
| 1131 | SharedNodePointer entityServerNode = nodeList->soloNodeOfType(NodeType::EntityServer); | ||
| 1132 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); | ||
| 1133 | SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); | ||
| 1134 | SharedNodePointer assetServerNode = nodeList->soloNodeOfType(NodeType::AssetServer); | ||
| 1135 | SharedNodePointer messagesMixerNode = nodeList->soloNodeOfType(NodeType::MessagesMixer); | ||
| 1136 | properties["entity_ping"] = entityServerNode ? entityServerNode->getPingMs() : -1; | ||
| 1137 | properties["audio_ping"] = audioMixerNode ? audioMixerNode->getPingMs() : -1; | ||
| 1138 | properties["avatar_ping"] = avatarMixerNode ? avatarMixerNode->getPingMs() : -1; | ||
| 1139 | properties["asset_ping"] = assetServerNode ? assetServerNode->getPingMs() : -1; | ||
| 1140 | properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1; | ||
| 1141 | |||
| 1142 | auto loadingRequests = ResourceCache::getLoadingRequests(); | ||
| 1143 | properties["active_downloads"] = loadingRequests.size(); | ||
| 1144 | properties["pending_downloads"] = ResourceCache::getPendingRequestCount(); | ||
| 1145 | |||
| 1146 | properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false; | ||
| 1147 | |||
| 1148 | UserActivityLogger::getInstance().logAction("stats", properties); | ||
| 1149 | }); | ||
| 1150 | sendStatsTimer->start(); | ||
| 1151 | |||
| 1152 | |||
| 1153 | // Periodically check for count of nearby avatars | ||
| 1154 | static int lastCountOfNearbyAvatars = -1; | ||
| 1155 | QTimer* checkNearbyAvatarsTimer = new QTimer(this); | ||
| 1156 | checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); | ||
| 1157 | connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() { | ||
| 1158 | auto avatarManager = DependencyManager::get<AvatarManager>(); | ||
| 1159 | int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(), | ||
| 1160 | NEARBY_AVATAR_RADIUS_METERS) - 1; | ||
| 1161 | if (nearbyAvatars != lastCountOfNearbyAvatars) { | ||
| 1162 | lastCountOfNearbyAvatars = nearbyAvatars; | ||
| 1163 | UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } }); | ||
| 1164 | } | ||
| 1165 | }); | ||
| 1166 | checkNearbyAvatarsTimer->start(); | ||
| 1167 | |||
| 1168 | // Track user activity event when we receive a mute packet | ||
| 1169 | auto onMutedByMixer = []() { | ||
| 1170 | UserActivityLogger::getInstance().logAction("received_mute_packet"); | ||
| 1171 | }; | ||
| 1172 | connect(DependencyManager::get<AudioClient>().data(), &AudioClient::mutedByMixer, this, onMutedByMixer); | ||
| 1173 | |||
| 1174 | // Track when the address bar is opened | ||
| 1175 | auto onAddressBarToggled = [this]() { | ||
| 1176 | // Record time | ||
| 1177 | UserActivityLogger::getInstance().logAction("opened_address_bar", { { "uptime_ms", _sessionRunTimer.elapsed() } }); | ||
| 1178 | }; | ||
| 1179 | connect(DependencyManager::get<DialogsManager>().data(), &DialogsManager::addressBarToggled, this, onAddressBarToggled); | ||
| 1180 | |||
| 1066 | // Make sure we don't time out during slow operations at startup | 1181 | // Make sure we don't time out during slow operations at startup |
| 1067 | updateHeartbeat(); | 1182 | updateHeartbeat(); |
| 1068 | 1183 | ||
| @@ -4578,6 +4693,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri · 3509 unmodified lines | |||
| 4578 | 4693 | ||
| 4579 | scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data()); | 4694 | scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data()); |
| 4580 | scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); | 4695 | scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); |
| 4696 | |||
| 4697 | scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data()); | ||
| 4581 | } | 4698 | } |
| 4582 | 4699 | ||
| 4583 | bool Application::canAcceptURL(const QString& urlString) const { | 4700 | bool Application::canAcceptURL(const QString& urlString) const { |
| @@ -5180,6 +5297,11 @@ void Application::updateDisplayMode() { · 596 unmodified lines | |||
| 5180 | return; | 5297 | return; |
| 5181 | } | 5298 | } |
| 5182 | 5299 | ||
| 5300 | UserActivityLogger::getInstance().logAction("changed_display_mode", { | ||
| 5301 | { "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" }, | ||
| 5302 | { "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" } | ||
| 5303 | }); | ||
| 5304 | |||
| 5183 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 5305 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 5184 | 5306 | ||
| 5185 | // Make the switch atomic from the perspective of other threads | 5307 | // Make the switch atomic from the perspective of other threads |