SupportLogger.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // ----------------------------------------------------------------------------
  2. // <copyright file="SupportLogger.cs" company="Exit Games GmbH">
  3. // Loadbalancing Framework for Photon - Copyright (C) 2018 Exit Games GmbH
  4. // </copyright>
  5. // <summary>
  6. // Implements callbacks of the Realtime API to logs selected information
  7. // for support cases.
  8. // </summary>
  9. // <author>developer@photonengine.com</author>
  10. // ----------------------------------------------------------------------------
  11. #if UNITY_4_7 || UNITY_5 || UNITY_5_3_OR_NEWER
  12. #define SUPPORTED_UNITY
  13. #endif
  14. namespace Photon.Realtime
  15. {
  16. using System;
  17. using System.Text;
  18. using System.Collections;
  19. using System.Collections.Generic;
  20. using Stopwatch = System.Diagnostics.Stopwatch;
  21. using ExitGames.Client.Photon;
  22. #if SUPPORTED_UNITY
  23. using UnityEngine;
  24. #endif
  25. #if SUPPORTED_UNITY || NETFX_CORE
  26. using Hashtable = ExitGames.Client.Photon.Hashtable;
  27. using SupportClass = ExitGames.Client.Photon.SupportClass;
  28. #endif
  29. /// <summary>
  30. /// Helper class to debug log basic information about Photon client and vital traffic statistics.
  31. /// </summary>
  32. /// <remarks>
  33. /// Set SupportLogger.Client for this to work.
  34. /// </remarks>
  35. #if SUPPORTED_UNITY
  36. [DisallowMultipleComponent]
  37. #if PUN_2_OR_NEWER || FUSION_UNITY
  38. [AddComponentMenu("")] // hide from Unity Menus and searches
  39. #endif
  40. public class SupportLogger : MonoBehaviour, IConnectionCallbacks , IMatchmakingCallbacks , IInRoomCallbacks, ILobbyCallbacks, IErrorInfoCallback
  41. #else
  42. public class SupportLogger : IConnectionCallbacks, IInRoomCallbacks, IMatchmakingCallbacks , ILobbyCallbacks
  43. #endif
  44. {
  45. /// <summary>
  46. /// Toggle to enable or disable traffic statistics logging.
  47. /// </summary>
  48. public bool LogTrafficStats = true;
  49. //private bool loggedStillOfflineMessage;
  50. private LoadBalancingClient client;
  51. private Stopwatch startStopwatch;
  52. /// helps skip the initial OnApplicationPause call, which is not really of interest on start
  53. private bool initialOnApplicationPauseSkipped = false;
  54. private int pingMax;
  55. private int pingMin;
  56. /// <summary>
  57. /// Photon client to log information and statistics from.
  58. /// </summary>
  59. public LoadBalancingClient Client
  60. {
  61. get { return this.client; }
  62. set
  63. {
  64. if (this.client != value)
  65. {
  66. if (this.client != null)
  67. {
  68. this.client.RemoveCallbackTarget(this);
  69. }
  70. this.client = value;
  71. if (this.client != null)
  72. {
  73. this.client.AddCallbackTarget(this);
  74. }
  75. }
  76. }
  77. }
  78. #if SUPPORTED_UNITY
  79. protected void Start()
  80. {
  81. this.LogBasics();
  82. if (this.startStopwatch == null)
  83. {
  84. this.startStopwatch = new Stopwatch();
  85. this.startStopwatch.Start();
  86. }
  87. }
  88. protected void OnDestroy()
  89. {
  90. this.Client = null; // will remove this SupportLogger as callback target
  91. }
  92. protected void OnApplicationPause(bool pause)
  93. {
  94. if (!this.initialOnApplicationPauseSkipped)
  95. {
  96. this.initialOnApplicationPauseSkipped = true;
  97. return;
  98. }
  99. Debug.Log(string.Format("{0} SupportLogger OnApplicationPause({1}). Client: {2}.", this.GetFormattedTimestamp(), pause, this.client == null ? "null" : this.client.State.ToString()));
  100. }
  101. protected void OnApplicationQuit()
  102. {
  103. this.CancelInvoke();
  104. }
  105. #endif
  106. public void StartLogStats()
  107. {
  108. #if SUPPORTED_UNITY
  109. this.InvokeRepeating("LogStats", 10, 10);
  110. #else
  111. Debug.Log("Not implemented for non-Unity projects.");
  112. #endif
  113. }
  114. public void StopLogStats()
  115. {
  116. #if SUPPORTED_UNITY
  117. this.CancelInvoke("LogStats");
  118. #else
  119. Debug.Log("Not implemented for non-Unity projects.");
  120. #endif
  121. }
  122. private void StartTrackValues()
  123. {
  124. #if SUPPORTED_UNITY
  125. this.InvokeRepeating("TrackValues", 0.5f, 0.5f);
  126. #else
  127. Debug.Log("Not implemented for non-Unity projects.");
  128. #endif
  129. }
  130. private void StopTrackValues()
  131. {
  132. #if SUPPORTED_UNITY
  133. this.CancelInvoke("TrackValues");
  134. #else
  135. Debug.Log("Not implemented for non-Unity projects.");
  136. #endif
  137. }
  138. private string GetFormattedTimestamp()
  139. {
  140. if (this.startStopwatch == null)
  141. {
  142. this.startStopwatch = new Stopwatch();
  143. this.startStopwatch.Start();
  144. }
  145. TimeSpan span = this.startStopwatch.Elapsed;
  146. if (span.Minutes > 0)
  147. {
  148. return string.Format("[{0}:{1}.{1}]", span.Minutes, span.Seconds, span.Milliseconds);
  149. }
  150. return string.Format("[{0}.{1}]", span.Seconds, span.Milliseconds);
  151. }
  152. // called via InvokeRepeatedly
  153. private void TrackValues()
  154. {
  155. if (this.client != null)
  156. {
  157. int currentRtt = this.client.LoadBalancingPeer.RoundTripTime;
  158. if (currentRtt > this.pingMax)
  159. {
  160. this.pingMax = currentRtt;
  161. }
  162. if (currentRtt < this.pingMin)
  163. {
  164. this.pingMin = currentRtt;
  165. }
  166. }
  167. }
  168. /// <summary>
  169. /// Debug logs vital traffic statistics about the attached Photon Client.
  170. /// </summary>
  171. public void LogStats()
  172. {
  173. if (this.client == null || this.client.State == ClientState.PeerCreated)
  174. {
  175. return;
  176. }
  177. if (this.LogTrafficStats)
  178. {
  179. Debug.Log(string.Format("{0} SupportLogger {1} Ping min/max: {2}/{3}", this.GetFormattedTimestamp() , this.client.LoadBalancingPeer.VitalStatsToString(false) , this.pingMin , this.pingMax));
  180. }
  181. }
  182. /// <summary>
  183. /// Debug logs basic information (AppId, AppVersion, PeerID, Server address, Region) about the attached Photon Client.
  184. /// </summary>
  185. private void LogBasics()
  186. {
  187. if (this.client != null)
  188. {
  189. List<string> buildProperties = new List<string>(10);
  190. #if SUPPORTED_UNITY
  191. buildProperties.Add(Application.unityVersion);
  192. buildProperties.Add(Application.platform.ToString());
  193. #endif
  194. #if ENABLE_IL2CPP
  195. buildProperties.Add("ENABLE_IL2CPP");
  196. #endif
  197. #if ENABLE_MONO
  198. buildProperties.Add("ENABLE_MONO");
  199. #endif
  200. #if DEBUG
  201. buildProperties.Add("DEBUG");
  202. #endif
  203. #if MASTER
  204. buildProperties.Add("MASTER");
  205. #endif
  206. #if NET_4_6
  207. buildProperties.Add("NET_4_6");
  208. #endif
  209. #if NET_STANDARD_2_0
  210. buildProperties.Add("NET_STANDARD_2_0");
  211. #endif
  212. #if NETFX_CORE
  213. buildProperties.Add("NETFX_CORE");
  214. #endif
  215. #if NET_LEGACY
  216. buildProperties.Add("NET_LEGACY");
  217. #endif
  218. #if UNITY_64
  219. buildProperties.Add("UNITY_64");
  220. #endif
  221. #if UNITY_FUSION
  222. buildProperties.Add("UNITY_FUSION");
  223. #endif
  224. StringBuilder sb = new StringBuilder();
  225. string appIdShort = string.IsNullOrEmpty(this.client.AppId) || this.client.AppId.Length < 8 ? this.client.AppId : string.Concat(this.client.AppId.Substring(0, 8), "***");
  226. sb.AppendFormat("{0} SupportLogger Info: ", this.GetFormattedTimestamp());
  227. sb.AppendFormat("AppID: \"{0}\" AppVersion: \"{1}\" Client: v{2} ({4}) Build: {3} ", appIdShort, this.client.AppVersion, PhotonPeer.Version, string.Join(", ", buildProperties.ToArray()), this.client.LoadBalancingPeer.TargetFramework);
  228. if (this.client != null && this.client.LoadBalancingPeer != null && this.client.LoadBalancingPeer.SocketImplementation != null)
  229. {
  230. sb.AppendFormat("Socket: {0} ", this.client.LoadBalancingPeer.SocketImplementation.Name);
  231. }
  232. sb.AppendFormat("UserId: \"{0}\" AuthType: {1} AuthMode: {2} {3} ", this.client.UserId, (this.client.AuthValues != null) ? this.client.AuthValues.AuthType.ToString() : "N/A", this.client.AuthMode, this.client.EncryptionMode);
  233. sb.AppendFormat("State: {0} ", this.client.State);
  234. sb.AppendFormat("PeerID: {0} ", this.client.LoadBalancingPeer.PeerID);
  235. sb.AppendFormat("NameServer: {0} Current Server: {1} IP: {2} Region: {3} ", this.client.NameServerHost, this.client.CurrentServerAddress, this.client.LoadBalancingPeer.ServerIpAddress, this.client.CloudRegion);
  236. Debug.LogWarning(sb.ToString());
  237. }
  238. }
  239. public void OnConnected()
  240. {
  241. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnConnected().");
  242. this.pingMax = 0;
  243. this.pingMin = this.client.LoadBalancingPeer.RoundTripTime;
  244. this.LogBasics();
  245. if (this.LogTrafficStats)
  246. {
  247. this.client.LoadBalancingPeer.TrafficStatsEnabled = false;
  248. this.client.LoadBalancingPeer.TrafficStatsEnabled = true;
  249. this.StartLogStats();
  250. }
  251. this.StartTrackValues();
  252. }
  253. public void OnConnectedToMaster()
  254. {
  255. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnConnectedToMaster().");
  256. }
  257. public void OnFriendListUpdate(List<FriendInfo> friendList)
  258. {
  259. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnFriendListUpdate(friendList).");
  260. }
  261. public void OnJoinedLobby()
  262. {
  263. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnJoinedLobby(" + this.client.CurrentLobby + ").");
  264. }
  265. public void OnLeftLobby()
  266. {
  267. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnLeftLobby().");
  268. }
  269. public void OnCreateRoomFailed(short returnCode, string message)
  270. {
  271. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnCreateRoomFailed(" + returnCode+","+message+").");
  272. }
  273. public void OnJoinedRoom()
  274. {
  275. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnJoinedRoom(" + this.client.CurrentRoom + "). " + this.client.CurrentLobby + " GameServer:" + this.client.GameServerAddress);
  276. }
  277. public void OnJoinRoomFailed(short returnCode, string message)
  278. {
  279. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnJoinRoomFailed(" + returnCode+","+message+").");
  280. }
  281. public void OnJoinRandomFailed(short returnCode, string message)
  282. {
  283. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnJoinRandomFailed(" + returnCode+","+message+").");
  284. }
  285. public void OnCreatedRoom()
  286. {
  287. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnCreatedRoom(" + this.client.CurrentRoom + "). " + this.client.CurrentLobby + " GameServer:" + this.client.GameServerAddress);
  288. }
  289. public void OnLeftRoom()
  290. {
  291. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnLeftRoom().");
  292. }
  293. public void OnDisconnected(DisconnectCause cause)
  294. {
  295. this.StopLogStats();
  296. this.StopTrackValues();
  297. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnDisconnected(" + cause + ").");
  298. this.LogBasics();
  299. this.LogStats();
  300. }
  301. public void OnRegionListReceived(RegionHandler regionHandler)
  302. {
  303. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnRegionListReceived(regionHandler).");
  304. }
  305. public void OnRoomListUpdate(List<RoomInfo> roomList)
  306. {
  307. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnRoomListUpdate(roomList). roomList.Count: " + roomList.Count);
  308. }
  309. public void OnPlayerEnteredRoom(Player newPlayer)
  310. {
  311. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnPlayerEnteredRoom(" + newPlayer+").");
  312. }
  313. public void OnPlayerLeftRoom(Player otherPlayer)
  314. {
  315. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnPlayerLeftRoom(" + otherPlayer+").");
  316. }
  317. public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
  318. {
  319. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnRoomPropertiesUpdate(propertiesThatChanged).");
  320. }
  321. public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
  322. {
  323. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnPlayerPropertiesUpdate(targetPlayer,changedProps).");
  324. }
  325. public void OnMasterClientSwitched(Player newMasterClient)
  326. {
  327. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnMasterClientSwitched(" + newMasterClient+").");
  328. }
  329. public void OnCustomAuthenticationResponse(Dictionary<string, object> data)
  330. {
  331. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnCustomAuthenticationResponse(" + data.ToStringFull()+").");
  332. }
  333. public void OnCustomAuthenticationFailed (string debugMessage)
  334. {
  335. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnCustomAuthenticationFailed(" + debugMessage+").");
  336. }
  337. public void OnLobbyStatisticsUpdate(List<TypedLobbyInfo> lobbyStatistics)
  338. {
  339. Debug.Log(this.GetFormattedTimestamp() + " SupportLogger OnLobbyStatisticsUpdate(lobbyStatistics).");
  340. }
  341. #if !SUPPORTED_UNITY
  342. private static class Debug
  343. {
  344. public static void Log(string msg)
  345. {
  346. System.Diagnostics.Debug.WriteLine(msg);
  347. }
  348. public static void LogWarning(string msg)
  349. {
  350. System.Diagnostics.Debug.WriteLine(msg);
  351. }
  352. public static void LogError(string msg)
  353. {
  354. System.Diagnostics.Debug.WriteLine(msg);
  355. }
  356. }
  357. #endif
  358. public void OnErrorInfo(ErrorInfo errorInfo)
  359. {
  360. Debug.LogError(errorInfo.ToString());
  361. }
  362. }
  363. }