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.
CrowdControl/Assets/PlayFabSDK/Shared/Public/PlayFabLogger.cs

271 lines
8.9 KiB
C#

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()
{
}
}
}