LogFile.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : implementation of the CLogFile class.
  9. #include "EditorDefs.h"
  10. #include "LogFile.h"
  11. // Qt
  12. #include <QTextEdit>
  13. #include <QScrollBar>
  14. #include <QListWidget>
  15. #include <QGuiApplication>
  16. #include <QScreen>
  17. // Editor
  18. #include "CryEdit.h" // for CCryEditApp
  19. #include "ProcessInfo.h" // for ProcessMemInfo
  20. #include "Controls/ConsoleSCB.h" // for CConsoleSCB
  21. #include <AzCore/std/ranges/ranges_algorithm.h>
  22. #include <stdarg.h>
  23. #if !defined(AZ_PLATFORM_WINDOWS)
  24. #include <time.h>
  25. #include <QTime>
  26. #else
  27. #include <Wbemidl.h>
  28. #pragma comment(lib, "wbemuuid.lib")
  29. #endif
  30. #if defined(AZ_PLATFORM_MAC)
  31. #include <mach/clock.h>
  32. #include <mach/mach.h>
  33. #include <Carbon/Carbon.h>
  34. #endif
  35. // Static member variables
  36. SANDBOX_API QListWidget* CLogFile::m_hWndListBox = nullptr;
  37. SANDBOX_API QTextEdit* CLogFile::m_hWndEditBox = nullptr;
  38. bool CLogFile::m_bShowMemUsage = false;
  39. bool CLogFile::m_bIsQuitting = false;
  40. //////////////////////////////////////////////////////////////////////////
  41. SANDBOX_API void Error(const char* format, ...)
  42. {
  43. va_list ArgList;
  44. va_start(ArgList, format);
  45. ErrorV(format, ArgList);
  46. va_end(ArgList);
  47. }
  48. //////////////////////////////////////////////////////////////////////////
  49. SANDBOX_API void ErrorV(const char* format, va_list argList)
  50. {
  51. char szBuffer[MAX_LOGBUFFER_SIZE];
  52. azvsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, format, argList);
  53. QString str = "####-ERROR-####: ";
  54. str += szBuffer;
  55. CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_ERROR, "%s", str.toUtf8().data());
  56. if (!CCryEditApp::instance()->IsInTestMode() && !CCryEditApp::instance()->IsInExportMode() && !CCryEditApp::instance()->IsInLevelLoadTestMode())
  57. {
  58. if (gEnv && gEnv->pSystem)
  59. {
  60. gEnv->pSystem->ShowMessage(szBuffer, "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
  61. }
  62. }
  63. }
  64. //////////////////////////////////////////////////////////////////////////
  65. SANDBOX_API void Warning(const char* format, ...)
  66. {
  67. va_list ArgList;
  68. va_start(ArgList, format);
  69. WarningV(format, ArgList);
  70. va_end(ArgList);
  71. }
  72. //////////////////////////////////////////////////////////////////////////
  73. SANDBOX_API void WarningV(const char* format, va_list argList)
  74. {
  75. char szBuffer[MAX_LOGBUFFER_SIZE];
  76. azvsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, format, argList);
  77. CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "%s", szBuffer);
  78. bool bNoUI = false;
  79. ICVar* pCVar = gEnv->pConsole->GetCVar("sys_no_crash_dialog");
  80. if (pCVar->GetIVal() != 0)
  81. {
  82. bNoUI = true;
  83. }
  84. if (!CCryEditApp::instance()->IsInTestMode() && !CCryEditApp::instance()->IsInExportMode() && !bNoUI)
  85. {
  86. if (gEnv && gEnv->pSystem)
  87. {
  88. gEnv->pSystem->ShowMessage(szBuffer, "Warning", MB_OK | MB_ICONWARNING | MB_APPLMODAL);
  89. }
  90. }
  91. }
  92. //////////////////////////////////////////////////////////////////////////
  93. SANDBOX_API void Log(const char* format, ...)
  94. {
  95. va_list ArgList;
  96. va_start(ArgList, format);
  97. LogV(format, ArgList);
  98. va_end(ArgList);
  99. }
  100. //////////////////////////////////////////////////////////////////////////
  101. SANDBOX_API void LogV(const char* format, va_list argList)
  102. {
  103. char szBuffer[MAX_LOGBUFFER_SIZE];
  104. azvsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, format, argList);
  105. CLogFile::WriteLine(szBuffer);
  106. }
  107. //////////////////////////////////////////////////////////////////////////
  108. const char* CLogFile::GetLogFileName()
  109. {
  110. if (gEnv && gEnv->pLog)
  111. {
  112. // Return the path
  113. return gEnv->pLog->GetFileName();
  114. }
  115. else
  116. {
  117. return "";
  118. }
  119. }
  120. void CLogFile::AttachListBox(QListWidget* hWndListBox)
  121. {
  122. m_hWndListBox = hWndListBox;
  123. }
  124. void CLogFile::AttachEditBox(QTextEdit* hWndEditBox)
  125. {
  126. m_hWndEditBox = hWndEditBox;
  127. }
  128. void CLogFile::FormatLine(const char * format, ...)
  129. {
  130. ////////////////////////////////////////////////////////////////////////
  131. // Write a line with printf style formatting
  132. ////////////////////////////////////////////////////////////////////////
  133. va_list ArgList;
  134. va_start(ArgList, format);
  135. FormatLineV(format, ArgList);
  136. va_end(ArgList);
  137. }
  138. void CLogFile::FormatLineV(const char * format, va_list argList)
  139. {
  140. char szBuffer[MAX_LOGBUFFER_SIZE];
  141. azvsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, format, argList);
  142. CryLog("%s", szBuffer);
  143. }
  144. namespace LogFileInternal
  145. {
  146. #if defined(AZ_PLATFORM_WINDOWS)
  147. // Stores information about the OS queried from WMI
  148. struct OSInfo
  149. {
  150. // Stores the Name property from Win32_OperatingSystem
  151. AZStd::string m_name;
  152. // Stores the Version property from Win32_OperatingSystem
  153. AZStd::string m_version;
  154. };
  155. // This uses the GetVersionEx API which was deprecated in Windows 10
  156. // as a fall back to query the version information for Windows
  157. // On Windows 10 and after, this always returns the version as 6.2
  158. OSInfo QueryOSInfoUsingGetVersionEx()
  159. {
  160. OSInfo osInfo;
  161. OSVERSIONINFO osVersionInfo;
  162. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  163. AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
  164. GetVersionEx(&osVersionInfo);
  165. AZ_POP_DISABLE_WARNING;
  166. // Default the name of the operating system to just Windows as the version information
  167. // is based on the manifest at the time application was built, which probably
  168. // does not match the current version of Windows that is running
  169. osInfo.m_name = "Windows";
  170. osInfo.m_version = AZStd::string::format("%ld.%ld", osVersionInfo.dwMajorVersion, osVersionInfo.dwMinorVersion);
  171. return osInfo;
  172. }
  173. // This specifically avoids using the GetVersion/GetVersionEx WinAPI
  174. // functions because those will only return the version of Windows
  175. // that was manifested at the time the application was built
  176. // and not the version of Windows that is currently running
  177. // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion
  178. AZ::Outcome<OSInfo, AZStd::string> QueryOSInfoUsingWMI()
  179. {
  180. // Get the thread Id as an numeric value
  181. static_assert(sizeof(AZStd::thread_id) <= sizeof(uintptr_t), "Thread Id should less than a size of a pointer");
  182. // Using curly braces to zero initalize all bytes the uintptr_t
  183. // If the thread Id is < sizeof(uintptr_t), the high bytes would be zeroed out
  184. uintptr_t numericThreadId{};
  185. *reinterpret_cast<AZStd::thread_id*>(&numericThreadId) = AZStd::this_thread::get_id();
  186. OSInfo osInfo;
  187. // Query the Windows version using WMI
  188. HRESULT hResult = CoInitialize(nullptr);
  189. if (FAILED(hResult))
  190. {
  191. return AZ::Failure(AZStd::string::format(
  192. "Failed to initialize the Com library on thread %#" PRIxPTR ": %lu", numericThreadId, static_cast<unsigned long>(hResult)));
  193. }
  194. // Obtain the initial locator to Windows Management on a particular host computer.
  195. IWbemLocator* locator = nullptr;
  196. hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&locator);
  197. if (FAILED(hResult))
  198. {
  199. return AZ::Failure(
  200. AZStd::string::format("Failed to create the Windows Management COM class: %lu", static_cast<unsigned long>(hResult)));
  201. }
  202. // Connect to the root\cimv2 namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
  203. IWbemServices* services = nullptr;
  204. auto serverPath = SysAllocString(TEXT(R"(ROOT\CIMV2)"));
  205. hResult = locator->ConnectServer(serverPath, nullptr, nullptr, 0, 0, nullptr, nullptr, &services);
  206. SysFreeString(serverPath);
  207. if (FAILED(hResult))
  208. {
  209. return AZ::Failure(
  210. AZStd::string::format("Could not connect the WMI on the local machine: %lu", static_cast<unsigned long>(hResult)));
  211. }
  212. // Set the IWbemServices proxy so that impersonation of the user (client) occurs.
  213. hResult = CoSetProxyBlanket(
  214. services,
  215. RPC_C_AUTHN_WINNT,
  216. RPC_C_AUTHZ_NONE,
  217. nullptr,
  218. RPC_C_AUTHN_LEVEL_CALL,
  219. RPC_C_IMP_LEVEL_IMPERSONATE,
  220. nullptr,
  221. EOAC_NONE);
  222. if (FAILED(hResult))
  223. {
  224. return AZ::Failure(
  225. AZStd::string::format("Cannot impersonate current user for proxy call: %lu", static_cast<unsigned long>(hResult)));
  226. }
  227. IEnumWbemClassObject* classObjectEnumerator = nullptr;
  228. // query the Name and Version property from the Win32_OperatingSystem class
  229. // https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-operatingsystem
  230. AZStd::wstring propertyQuery{ L"SELECT Name,Version FROM Win32_OperatingSystem" };
  231. // ExecQuery expects BSTR types
  232. auto query = SysAllocString(propertyQuery.c_str());
  233. auto language = SysAllocString(L"WQL");
  234. hResult =
  235. services->ExecQuery(language, query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &classObjectEnumerator);
  236. SysFreeString(language);
  237. SysFreeString(query);
  238. if (FAILED(hResult))
  239. {
  240. return AZ::Failure(AZStd::string::format(
  241. "WQL query from Win32_OperatingSystem WMI class has failed: %lu", static_cast<unsigned long>(hResult)));
  242. }
  243. // prepare to enumerate the object, blocking until the objects are ready
  244. IWbemClassObject* classObject = nullptr;
  245. ULONG numResults = 0;
  246. hResult = classObjectEnumerator->Next(WBEM_INFINITE, 1, &classObject, &numResults);
  247. if (FAILED(hResult))
  248. {
  249. return AZ::Failure(AZStd::string::format(
  250. "Enumerating the CIM objects has failed with result code: %lu", static_cast<unsigned long>(hResult)));
  251. }
  252. else if (classObject == nullptr || numResults == 0)
  253. {
  254. return AZ::Failure(AZStd::string(
  255. "There are no CIM objects found when querying the Win32_OperatingSystem class"));
  256. }
  257. constexpr const wchar_t* namePropertyName{ L"Name" };
  258. constexpr const wchar_t* versionPropertyName{ L"Version" };
  259. // get the class object's property value
  260. VARIANT propertyValue;
  261. // Query the Name field
  262. if (FAILED(classObject->Get(namePropertyName, 0, &propertyValue, nullptr, nullptr)))
  263. {
  264. return AZ::Failure(AZStd::string::format(
  265. R"(Could not retrieve the ")" AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING R"(" property from the CIM object: %lu)", namePropertyName, static_cast<unsigned long>(hResult)));
  266. }
  267. // If the name is a binary string copy it over
  268. if ((propertyValue.vt & VT_BSTR) == VT_BSTR)
  269. {
  270. AZStd::to_string(osInfo.m_name, V_BSTR(&propertyValue));
  271. }
  272. // VariantClear must be called on the variant retrieved from `IWbemClassObject::Get`
  273. // according to the documentation:
  274. // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
  275. VariantClear(&propertyValue);
  276. // Query the Version field
  277. if (FAILED(classObject->Get(versionPropertyName, 0, &propertyValue, nullptr, nullptr)))
  278. {
  279. {
  280. return AZ::Failure(AZStd::string::format(
  281. R"(Could not retrieve the ")" AZ_TRAIT_FORMAT_STRING_PRINTF_WSTRING R"(" property from the CIM object: %lu)", versionPropertyName, static_cast<unsigned long>(hResult)));
  282. }
  283. }
  284. // If the name is a binary string copy it over
  285. if ((propertyValue.vt & VT_BSTR) == VT_BSTR)
  286. {
  287. AZStd::to_string(osInfo.m_version, V_BSTR(&propertyValue));
  288. }
  289. // VariantClear must be called on the variant retrieved from `IWbemClassObject::Get`
  290. // according to the documentation:
  291. // https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemclassobject-get
  292. VariantClear(&propertyValue);
  293. if (classObject)
  294. {
  295. classObject->Release();
  296. }
  297. if (classObjectEnumerator)
  298. {
  299. classObjectEnumerator->Release();
  300. }
  301. if (services)
  302. {
  303. services->Release();
  304. }
  305. if (locator)
  306. {
  307. locator->Release();
  308. }
  309. CoUninitialize();
  310. return osInfo;
  311. }
  312. OSInfo QueryOSInfo()
  313. {
  314. auto queryOSInfoOutcome = QueryOSInfoUsingWMI();
  315. if (!queryOSInfoOutcome)
  316. {
  317. CryLog("Failed to query Windows version info using WMI with error: %s.\n"
  318. "Falling back to using GetVersionEx", queryOSInfoOutcome.GetError().c_str());
  319. return QueryOSInfoUsingGetVersionEx();
  320. }
  321. return queryOSInfoOutcome.GetValue();
  322. }
  323. #endif
  324. }
  325. void CLogFile::AboutSystem()
  326. {
  327. #if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
  328. //////////////////////////////////////////////////////////////////////
  329. // Write the system informations to the log
  330. //////////////////////////////////////////////////////////////////////
  331. char szBuffer[MAX_LOGBUFFER_SIZE];
  332. //wchar_t szCPUModel[64];
  333. MEMORYSTATUS MemoryStatus;
  334. #endif // defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
  335. #if defined(AZ_PLATFORM_WINDOWS)
  336. wchar_t szLanguageBufferW[64];
  337. DEVMODE DisplayConfig;
  338. //////////////////////////////////////////////////////////////////////
  339. // Display editor and Windows version
  340. //////////////////////////////////////////////////////////////////////
  341. // Get system language
  342. GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE,
  343. szLanguageBufferW, sizeof(szLanguageBufferW));
  344. AZStd::string szLanguageBuffer;
  345. AZStd::to_string(szLanguageBuffer, szLanguageBufferW);
  346. // Format and send OS information line
  347. azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, "Current Language: %s ", szLanguageBuffer.c_str());
  348. CryLog("%s", szBuffer);
  349. #else
  350. QLocale locale;
  351. CryLog("Current Language: %s (%s)", qPrintable(QLocale::languageToString(locale.language())), qPrintable(QLocale::countryToString(locale.country())));
  352. #endif
  353. #if defined(AZ_PLATFORM_WINDOWS)
  354. // Format and send OS version line
  355. auto osInfo = LogFileInternal::QueryOSInfo();
  356. QString str = QString("%1 %2").arg(osInfo.m_name.c_str()).arg(osInfo.m_version.c_str());
  357. //////////////////////////////////////////////////////////////////////
  358. // Show Windows directory
  359. //////////////////////////////////////////////////////////////////////
  360. CryLog("%s", str.toUtf8().data());
  361. #elif defined(AZ_PLATFORM_LINUX)
  362. // TODO: Add more detail about the current Linux Distro
  363. CryLog("Linux");
  364. #elif AZ_TRAIT_OS_PLATFORM_APPLE
  365. QString operatingSystemName;
  366. if (QSysInfo::MacintoshVersion >= Q_MV_OSX(10, 12))
  367. {
  368. operatingSystemName = "macOS ";
  369. }
  370. else
  371. {
  372. operatingSystemName = "OS X ";
  373. }
  374. int majorVersion = 0;
  375. int minorVersion = 0;
  376. AZ_PUSH_DISABLE_WARNING(, "-Wdeprecated-declarations")
  377. Gestalt(gestaltSystemVersionMajor, &majorVersion);
  378. Gestalt(gestaltSystemVersionMinor, &minorVersion);
  379. AZ_POP_DISABLE_WARNING
  380. CryLog("%s - %d.%d", qPrintable(operatingSystemName), majorVersion, minorVersion);
  381. #else
  382. CryLog("Unknown Operating System");
  383. #endif
  384. //////////////////////////////////////////////////////////////////////
  385. // Send system time & date
  386. //////////////////////////////////////////////////////////////////////
  387. #if defined(AZ_PLATFORM_WINDOWS)
  388. str = "Local time is ";
  389. azstrtime(szBuffer);
  390. str += szBuffer;
  391. str += " ";
  392. azstrdate(szBuffer);
  393. str += szBuffer;
  394. azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, ", system running for %ld minutes", GetTickCount() / 60000);
  395. str += szBuffer;
  396. CryLog("%s", str.toUtf8().data());
  397. #else
  398. struct timespec ts;
  399. #if AZ_TRAIT_OS_PLATFORM_APPLE
  400. clock_serv_t cclock;
  401. mach_timespec_t mts;
  402. host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
  403. clock_get_time(cclock, &mts);
  404. mach_port_deallocate(mach_task_self(), cclock);
  405. ts.tv_sec = mts.tv_sec;
  406. #else
  407. clock_gettime(CLOCK_MONOTONIC, &ts);
  408. #endif
  409. CryLog("Local time is %s, system running for %ld minutes", qPrintable(QTime::currentTime().toString("hh:mm:ss")), ts.tv_sec / 60);
  410. #endif
  411. //////////////////////////////////////////////////////////////////////
  412. // Send system memory status
  413. //////////////////////////////////////////////////////////////////////
  414. #if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
  415. GlobalMemoryStatus(&MemoryStatus);
  416. azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, "%zdMB phys. memory installed, %zdMB paging available",
  417. MemoryStatus.dwTotalPhys / 1048576 + 1,
  418. MemoryStatus.dwAvailPageFile / 1048576);
  419. CryLog("%s", szBuffer);
  420. #elif defined(AZ_PLATFORM_LINUX)
  421. //KDAB_TODO
  422. #else
  423. SInt32 mb = 0, lmb = 0;
  424. AZ_PUSH_DISABLE_WARNING(, "-Wdeprecated-declarations")
  425. Gestalt(gestaltPhysicalRAMSizeInMegabytes, &mb);
  426. Gestalt(gestaltLogicalRAMSize, &lmb);
  427. AZ_POP_DISABLE_WARNING
  428. CryLog("%dMB phys. memory installed, %dMB paging available", mb, lmb);
  429. #endif
  430. //////////////////////////////////////////////////////////////////////
  431. // Send display settings
  432. //////////////////////////////////////////////////////////////////////
  433. #if defined(AZ_PLATFORM_WINDOWS)
  434. EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &DisplayConfig);
  435. GetPrivateProfileStringW(L"boot.description", L"display.drv",
  436. L"(Unknown graphics card)", szLanguageBufferW, sizeof(szLanguageBufferW),
  437. L"system.ini");
  438. AZStd::to_string(szLanguageBuffer, szLanguageBufferW);
  439. azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, "Current display mode is %ldx%ldx%ld, %s",
  440. DisplayConfig.dmPelsWidth, DisplayConfig.dmPelsHeight,
  441. DisplayConfig.dmBitsPerPel, szLanguageBuffer.c_str());
  442. CryLog("%s", szBuffer);
  443. #else
  444. auto screen = QGuiApplication::primaryScreen();
  445. if (screen)
  446. {
  447. CryLog("Current display mode is %dx%dx%d, %s", screen->size().width(), screen->size().height(), screen->depth(), qPrintable(screen->name()));
  448. }
  449. #endif
  450. //////////////////////////////////////////////////////////////////////
  451. // Send input device configuration
  452. //////////////////////////////////////////////////////////////////////
  453. #if defined(AZ_PLATFORM_WINDOWS)
  454. str = "";
  455. // Detect the keyboard type
  456. switch (GetKeyboardType(0))
  457. {
  458. case 1:
  459. str = "IBM PC/XT (83-key)";
  460. break;
  461. case 2:
  462. str = "ICO (102-key)";
  463. break;
  464. case 3:
  465. str = "IBM PC/AT (84-key)";
  466. break;
  467. case 4:
  468. str = "IBM enhanced (101/102-key)";
  469. break;
  470. case 5:
  471. str = "Nokia 1050";
  472. break;
  473. case 6:
  474. str = "Nokia 9140";
  475. break;
  476. case 7:
  477. str = "Japanese";
  478. break;
  479. default:
  480. str = "Unknown";
  481. break;
  482. }
  483. // Any mouse attached ?
  484. if (!GetSystemMetrics(SM_MOUSEPRESENT))
  485. {
  486. CryLog("%s", (str + " keyboard and no mouse installed").toUtf8().data());
  487. }
  488. else
  489. {
  490. azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, " keyboard and %i+ button mouse installed",
  491. GetSystemMetrics(SM_CMOUSEBUTTONS));
  492. str += szBuffer;
  493. CryLog("%s", str.toUtf8().data());
  494. }
  495. CryLog("--------------------------------------------------------------------------------");
  496. #endif
  497. }
  498. //////////////////////////////////////////////////////////////////////////
  499. QString CLogFile::GetMemUsage()
  500. {
  501. AZ::ProcessMemInfo mi;
  502. AZ::QueryMemInfo(mi);
  503. constexpr int MB = 1024 * 1024;
  504. QString str;
  505. str = QStringLiteral("Memory=%1Mb, Pagefile=%2Mb").arg(mi.m_workingSet / MB).arg(mi.m_pagefileUsage / MB);
  506. //FormatLine( "PeakWorkingSet=%dMb, PeakPagefileUsage=%dMb",pc.PeakWorkingSetSize/MB,pc.PeakPagefileUsage/MB );
  507. //FormatLine( "PagedPoolUsage=%d",pc.QuotaPagedPoolUsage/MB );
  508. //FormatLine( "NonPagedPoolUsage=%d",pc.QuotaNonPagedPoolUsage/MB );
  509. return str;
  510. }
  511. //////////////////////////////////////////////////////////////////////////
  512. void CLogFile::WriteLine(const char* pszString)
  513. {
  514. CryLog("%s", pszString);
  515. }
  516. //////////////////////////////////////////////////////////////////////////
  517. void CLogFile::WriteString(const char* pszString)
  518. {
  519. if (gEnv && gEnv->pLog)
  520. {
  521. gEnv->pLog->LogAppendWithPrevLine("%s", pszString);
  522. }
  523. }
  524. static inline QString CopyAndRemoveColorCode(AZStd::string_view sText)
  525. {
  526. QByteArray ret(sText.data(), static_cast<int>(sText.size())); // alloc and copy
  527. char* s, * d;
  528. s = ret.data();
  529. d = s;
  530. // remove color code in place
  531. while (*s != 0)
  532. {
  533. if (*s == '$' && *(s + 1) >= '0' && *(s + 1) <= '9')
  534. {
  535. s += 2;
  536. continue;
  537. }
  538. *d++ = *s++;
  539. }
  540. ret.resize(static_cast<int>(d - ret.data()));
  541. return QString::fromLatin1(ret);
  542. }
  543. //////////////////////////////////////////////////////////////////////////
  544. void CLogFile::OnWriteToConsole(AZStd::string_view sText, bool bNewLine)
  545. {
  546. if (!gEnv)
  547. {
  548. return;
  549. }
  550. // if (GetIEditor()->IsInGameMode())
  551. // return;
  552. // Skip any non character.
  553. auto searchIt = AZStd::ranges::find_if(sText, [](char element) { return element >= 32; });
  554. sText = AZStd::string_view(searchIt, sText.end());
  555. // If we have a listbox attached, also output the string to this listbox
  556. if (m_hWndListBox)
  557. {
  558. QString str = CopyAndRemoveColorCode(sText); // editor prinout doesn't support color coded log messages
  559. if (m_bShowMemUsage)
  560. {
  561. str = QString("(") + GetMemUsage() + ")" + str;
  562. }
  563. // Add the string to the listbox
  564. m_hWndListBox->addItem(str);
  565. // Make sure the recently added string is visible
  566. m_hWndListBox->scrollToItem(m_hWndListBox->item(m_hWndListBox->count() - 1));
  567. if (m_hWndEditBox)
  568. {
  569. static int nCounter = 0;
  570. if (nCounter++ > 500)
  571. {
  572. // Clean Edit box every 500 lines.
  573. nCounter = 0;
  574. m_hWndEditBox->clear();
  575. }
  576. // remember selection and the top row
  577. int len = m_hWndEditBox->document()->toPlainText().length();
  578. int top = 0;
  579. int from = m_hWndEditBox->textCursor().selectionStart();
  580. int to = from + m_hWndEditBox->textCursor().selectionEnd();
  581. bool keepPos = false;
  582. if (from != len || to != len)
  583. {
  584. keepPos = m_hWndEditBox->hasFocus();
  585. if (keepPos)
  586. {
  587. top = m_hWndEditBox->verticalScrollBar()->value();
  588. }
  589. QTextCursor cur = m_hWndEditBox->textCursor();
  590. cur.setPosition(len);
  591. m_hWndEditBox->setTextCursor(cur);
  592. }
  593. if (bNewLine)
  594. {
  595. str = QString("\r\n") + str;
  596. str = str.trimmed();
  597. }
  598. m_hWndEditBox->textCursor().insertText(str);
  599. // restore selection and the top line
  600. if (keepPos)
  601. {
  602. QTextCursor cur = m_hWndEditBox->textCursor();
  603. cur.setPosition(from);
  604. cur.setPosition(to, QTextCursor::KeepAnchor);
  605. m_hWndEditBox->setTextCursor(cur);
  606. m_hWndEditBox->verticalScrollBar()->setValue(top);
  607. }
  608. }
  609. }
  610. if (CConsoleSCB::GetCreatedInstance())
  611. {
  612. const QString qtText = QString::fromUtf8(sText.data(), static_cast<int>(sText.size()));
  613. QString sOutLine(qtText);
  614. if (gSettings.bShowTimeInConsole)
  615. {
  616. char sTime[128];
  617. time_t ltime;
  618. time(&ltime);
  619. struct tm today;
  620. #if AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS
  621. localtime_s(&today, &ltime);
  622. #else
  623. today = *localtime(&ltime);
  624. #endif
  625. strftime(sTime, sizeof(sTime), "<%H:%M:%S> ", &today);
  626. sOutLine = sTime;
  627. sOutLine += qtText;
  628. }
  629. CConsoleSCB::GetCreatedInstance()->AddToConsole(sOutLine, bNewLine);
  630. }
  631. else
  632. {
  633. // add to intermediate messages until an instance of CConsoleSCB exists
  634. CConsoleSCB::AddToPendingLines(QString::fromUtf8(sText.data(), static_cast<int>(sText.size())), bNewLine);
  635. }
  636. //////////////////////////////////////////////////////////////////////////
  637. // Look for exit messages while writing to the console
  638. //////////////////////////////////////////////////////////////////////////
  639. if (gEnv && gEnv->pSystem && !gEnv->pSystem->IsQuitting() && !m_bIsQuitting)
  640. {
  641. if (QCoreApplication::closingDown())
  642. {
  643. m_bIsQuitting = true;
  644. CCryEditApp::instance()->ExitInstance();
  645. m_bIsQuitting = false;
  646. }
  647. }
  648. }
  649. //////////////////////////////////////////////////////////////////////////
  650. void CLogFile::OnWriteToFile([[maybe_unused]] AZStd::string_view sText, [[maybe_unused]] bool bNewLine)
  651. {
  652. }