You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
8.9 KiB
C#
271 lines
8.9 KiB
C#
1 month ago
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Net;
|
||
|
using System.Text;
|
||
|
using System.Threading;
|
||
|
using PlayFab.Internal;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace PlayFab.Public
|
||
|
{
|
||
|
#if !UNITY_WSA && !UNITY_WP8 && !NETFX_CORE
|
||
|
public interface IPlayFabLogger
|
||
|
{
|
||
|
IPAddress ip { get; set; }
|
||
|
int port { get; set; }
|
||
|
string url { get; set; }
|
||
|
|
||
|
// Unity MonoBehaviour callbacks
|
||
|
void OnEnable();
|
||
|
void OnDisable();
|
||
|
void OnDestroy();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This is some unity-log capturing logic, and threading tools that allow logging to be caught and processed on another thread
|
||
|
/// </summary>
|
||
|
public abstract class PlayFabLoggerBase : IPlayFabLogger
|
||
|
{
|
||
|
private static readonly StringBuilder Sb = new StringBuilder();
|
||
|
private readonly Queue<string> LogMessageQueue = new Queue<string>();
|
||
|
private const int LOG_CACHE_INTERVAL_MS = 10000;
|
||
|
|
||
|
private Thread _writeLogThread;
|
||
|
private readonly object _threadLock = new object();
|
||
|
private static readonly TimeSpan _threadKillTimeout = TimeSpan.FromSeconds(60);
|
||
|
private DateTime _threadKillTime = DateTime.UtcNow + _threadKillTimeout; // Kill the thread after 1 minute of inactivity
|
||
|
private bool _isApplicationPlaying = true;
|
||
|
private int _pendingLogsCount;
|
||
|
|
||
|
public IPAddress ip { get; set; }
|
||
|
public int port { get; set; }
|
||
|
public string url { get; set; }
|
||
|
|
||
|
protected PlayFabLoggerBase()
|
||
|
{
|
||
|
var gatherer = new PlayFabDataGatherer();
|
||
|
var message = gatherer.GenerateReport();
|
||
|
lock (LogMessageQueue)
|
||
|
{
|
||
|
LogMessageQueue.Enqueue(message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual void OnEnable()
|
||
|
{
|
||
|
PlayFabHttp.instance.StartCoroutine(RegisterLogger()); // Coroutine helper to set up log-callbacks
|
||
|
}
|
||
|
|
||
|
private IEnumerator RegisterLogger()
|
||
|
{
|
||
|
yield return new WaitForEndOfFrame(); // Effectively just a short wait before activating this registration
|
||
|
if (!string.IsNullOrEmpty(PlayFabSettings.LoggerHost))
|
||
|
{
|
||
|
#if UNITY_5 || UNITY_5_3_OR_NEWER
|
||
|
Application.logMessageReceivedThreaded += HandleUnityLog;
|
||
|
#else
|
||
|
Application.RegisterLogCallback(HandleUnityLog);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual void OnDisable()
|
||
|
{
|
||
|
if (!string.IsNullOrEmpty(PlayFabSettings.LoggerHost))
|
||
|
{
|
||
|
#if UNITY_5 || UNITY_5_3_OR_NEWER
|
||
|
Application.logMessageReceivedThreaded -= HandleUnityLog;
|
||
|
#else
|
||
|
Application.RegisterLogCallback(null);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual void OnDestroy()
|
||
|
{
|
||
|
_isApplicationPlaying = false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// BeginUploadLog is called at the begining of each burst
|
||
|
/// </summary>
|
||
|
protected abstract void BeginUploadLog();
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// UploadLog is called for each cached log, between BeginUploadLog and EndUploadLog
|
||
|
/// </summary>
|
||
|
protected abstract void UploadLog(string message);
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// EndUploadLog is called at the end of each burst
|
||
|
/// </summary>
|
||
|
protected abstract void EndUploadLog();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Handler to process Unity logs into our logging system
|
||
|
/// </summary>
|
||
|
/// <param name="message"></param>
|
||
|
/// <param name="stacktrace"></param>
|
||
|
/// <param name="type"></param>
|
||
|
private void HandleUnityLog(string message, string stacktrace, LogType type)
|
||
|
{
|
||
|
if (!PlayFabSettings.EnableRealTimeLogging)
|
||
|
return;
|
||
|
|
||
|
Sb.Length = 0;
|
||
|
if (type == LogType.Log || type == LogType.Warning)
|
||
|
{
|
||
|
Sb.Append(type).Append(": ").Append(message);
|
||
|
message = Sb.ToString();
|
||
|
lock (LogMessageQueue)
|
||
|
{
|
||
|
LogMessageQueue.Enqueue(message);
|
||
|
}
|
||
|
}
|
||
|
else if (type == LogType.Error || type == LogType.Exception)
|
||
|
{
|
||
|
Sb.Append(type).Append(": ").Append(message).Append("\n").Append(stacktrace).Append(StackTraceUtility.ExtractStackTrace());
|
||
|
message = Sb.ToString();
|
||
|
lock (LogMessageQueue)
|
||
|
{
|
||
|
LogMessageQueue.Enqueue(message);
|
||
|
}
|
||
|
}
|
||
|
ActivateThreadWorker();
|
||
|
}
|
||
|
|
||
|
private void ActivateThreadWorker()
|
||
|
{
|
||
|
lock (_threadLock)
|
||
|
{
|
||
|
if (_writeLogThread != null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
_writeLogThread = new Thread(WriteLogThreadWorker);
|
||
|
_writeLogThread.Start();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void WriteLogThreadWorker()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
bool active;
|
||
|
lock (_threadLock)
|
||
|
{
|
||
|
// Kill the thread after 1 minute of inactivity
|
||
|
_threadKillTime = DateTime.UtcNow + _threadKillTimeout;
|
||
|
}
|
||
|
|
||
|
var localLogQueue = new Queue<string>();
|
||
|
do
|
||
|
{
|
||
|
lock (LogMessageQueue)
|
||
|
{
|
||
|
_pendingLogsCount = LogMessageQueue.Count;
|
||
|
while (LogMessageQueue.Count > 0) // Transfer the messages to the local queue
|
||
|
localLogQueue.Enqueue(LogMessageQueue.Dequeue());
|
||
|
}
|
||
|
|
||
|
BeginUploadLog();
|
||
|
while (localLogQueue.Count > 0) // Transfer the messages to the local queue
|
||
|
UploadLog(localLogQueue.Dequeue());
|
||
|
EndUploadLog();
|
||
|
|
||
|
#region Expire Thread.
|
||
|
// Check if we've been inactive
|
||
|
lock (_threadLock)
|
||
|
{
|
||
|
var now = DateTime.UtcNow;
|
||
|
if (_pendingLogsCount > 0 && _isApplicationPlaying)
|
||
|
{
|
||
|
// Still active, reset the _threadKillTime
|
||
|
_threadKillTime = now + _threadKillTimeout;
|
||
|
}
|
||
|
// Kill the thread after 1 minute of inactivity
|
||
|
active = now <= _threadKillTime;
|
||
|
if (!active)
|
||
|
{
|
||
|
_writeLogThread = null;
|
||
|
}
|
||
|
// This thread will be stopped, so null this now, inside lock (_threadLock)
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
Thread.Sleep(LOG_CACHE_INTERVAL_MS);
|
||
|
} while (active);
|
||
|
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
Debug.LogException(e);
|
||
|
_writeLogThread = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
public interface IPlayFabLogger
|
||
|
{
|
||
|
string ip { get; set; }
|
||
|
int port { get; set; }
|
||
|
string url { get; set; }
|
||
|
|
||
|
// Unity MonoBehaviour callbacks
|
||
|
void OnEnable();
|
||
|
void OnDisable();
|
||
|
void OnDestroy();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This is just a placeholder. WP8 doesn't support direct threading, but instead makes you use the await command.
|
||
|
/// </summary>
|
||
|
public abstract class PlayFabLoggerBase : IPlayFabLogger
|
||
|
{
|
||
|
public string ip { get; set; }
|
||
|
public int port { get; set; }
|
||
|
public string url { get; set; }
|
||
|
|
||
|
// Unity MonoBehaviour callbacks
|
||
|
public void OnEnable() { }
|
||
|
public void OnDisable() { }
|
||
|
public void OnDestroy() { }
|
||
|
|
||
|
protected abstract void BeginUploadLog();
|
||
|
protected abstract void UploadLog(string message);
|
||
|
protected abstract void EndUploadLog();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// This translates the logs up to the PlayFab service via a PlayFab restful API
|
||
|
/// TODO: PLAYFAB - attach these to the PlayFab API
|
||
|
/// </summary>
|
||
|
public class PlayFabLogger : PlayFabLoggerBase
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// BeginUploadLog is called at the begining of each burst
|
||
|
/// </summary>
|
||
|
protected override void BeginUploadLog()
|
||
|
{
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// UploadLog is called for each cached log, between BeginUploadLog and EndUploadLog
|
||
|
/// </summary>
|
||
|
protected override void UploadLog(string message)
|
||
|
{
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Logs are cached and written in bursts
|
||
|
/// EndUploadLog is called at the end of each burst
|
||
|
/// </summary>
|
||
|
protected override void EndUploadLog()
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
}
|