using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using log4net;
using log4net.Config;
using log4net.Layout;
using log4net.Appender;
using log4net.Core;
using log4net.ObjectRenderer;
using log4net.Util;
using Perforce.P4;
using UnityEditor;
using UnityEngine;
namespace P4Connect
{
public static class Logger
{
static Log4netTraceListener p4Listener = null;
public static void Initialize()
{
if (!Config.EnableLog)
{
Disable();
return;
}
if (p4Listener != null)
return;
try
{
// UnityEngine.Debug.Log("Initialize Logger");
ConfigureAllLogging();
p4Listener = new Log4netTraceListener();
// Write the initial trace message to the console trace listener.
p4Listener.WriteLine(DateTime.Now.ToString() + " - Logger Init: P4Connect " + Version.PerforceReleaseString + "-" + Version.Build);
// Add the new console trace listener to the collection of trace listeners.
Trace.Listeners.Add(p4Listener);
// Hook the Bridge logging calls up using the .NetLog delegate
Perforce.P4.LogFile.SetLoggingFunction(NetLog);
// pass along exceptions with level greater than MinThrowLevel
Perforce.P4.P4Exception.MinThrowLevel = Perforce.P4.ErrorSeverity.E_EMPTY; // how much noise p4api.net makes
Trace.Flush();
}
catch (Exception e)
{
UnityEngine.Debug.Log("Exception in Logger.Initialize: " + e.Message);
UnityEngine.Debug.Log(" src: " + e.Source);
UnityEngine.Debug.Log(" stack: " + e.StackTrace);
Disable();
}
}
public static void Enable()
{
Initialize();
}
public static void Disable()
{
if (p4Listener != null)
{
p4Listener.Dispose();
p4Listener = null;
}
}
///
/// Configure logging to write to default log and the Unity console output.
///
public static void ConfigureAllLogging()
{
var patternLayout = new PatternLayout
{
ConversionPattern = "%date %-5level %logger.%method - %message%newline"
};
patternLayout.ActivateOptions();
// setup the appender that writes to the logfile
var fileAppender = new log4net.Appender.RollingFileAppender
{
AppendToFile = true,
File = Config.LogPath,
Layout = patternLayout,
MaxSizeRollBackups = 5,
MaximumFileSize = "1GB",
RollingStyle = RollingFileAppender.RollingMode.Size,
StaticLogFileName = true
};
fileAppender.ActivateOptions();
var unityLogger = new UnityAppender
{
Layout = patternLayout
};
unityLogger.ActivateOptions();
// See if logging.xml is available as an asset
string ConfigPath = Path.Combine(Application.dataPath, "P4Connect\\Editor\\logging.xml").Replace('/', System.IO.Path.DirectorySeparatorChar); ;
//UnityEngine.Debug.Log("Checking for logging config at " + ConfigPath);
if (System.IO.File.Exists(ConfigPath))
{
UnityEngine.Debug.Log("Found log4net configuration asset");
using (System.IO.Stream fs = System.IO.File.OpenRead(ConfigPath))
{
log4net.Config.XmlConfigurator.Configure(fs); // Customized configuration from asset
}
}
else
{
//UnityEngine.Debug.Log("Using log4net defaults");
BasicConfigurator.Configure(unityLogger, fileAppender); // "Wired-in" default configuration
ILog log = LogManager.GetLogger(typeof(Logger));
var repo = LogManager.GetRepository();
}
}
/// An appender which logs to the unity console.
private class UnityAppender : AppenderSkeleton
{
///
protected override void Append(log4net.Core.LoggingEvent loggingEvent)
{
string message = RenderLoggingEvent(loggingEvent);
LogLevel l = GetLogLevelFromLog4NetLevel(loggingEvent.Level);
if (l <= Config.ConsoleLogLevel) // Filter Log output to console
{
// Write to the console
if (Level.Compare(loggingEvent.Level, Level.Error) >= 0)
{
// everything above or equal to error is an error
UnityEngine.Debug.LogError(message);
}
else if (Level.Compare(loggingEvent.Level, Level.Warn) >= 0)
{
// everything that is a warning up to error is logged as warning
UnityEngine.Debug.LogWarning(message);
}
else
{
// everything else we'll just log normally
UnityEngine.Debug.Log(message);
}
}
}
}
public class Log4netTraceListener : System.Diagnostics.TraceListener
{
private readonly log4net.ILog _log;
public Log4netTraceListener()
{
_log = log4net.LogManager.GetLogger("trace");
}
public Log4netTraceListener(log4net.ILog log)
{
_log = log;
}
public override void Write(string message)
{
if (_log != null)
{
_log.Debug(message);
}
}
public override void WriteLine(string message)
{
if (_log != null)
{
_log.Debug(message);
}
}
}
/// Log_Level. From P4API The lower the level, the more severe the issue
/// 0 fatal
/// 1 error
/// 2 warning
/// 3 information
/// 4+ debugging messages
///
public enum LogLevel
{
Fatal,
Error,
Warn,
Info,
Debug
};
// Translate a Log4Net Level enum into a Logger.LogLevel enum
public static LogLevel GetLogLevelFromLog4NetLevel(Level l)
{
if (l >= Level.Debug)
return LogLevel.Debug;
if (l >= Level.Info)
return LogLevel.Info;
if (l >= Level.Warn)
return LogLevel.Warn;
if (l >= Level.Error)
return LogLevel.Error;
return LogLevel.Fatal;
}
public static void NetLog(int log_level, String source, String message)
{
log4net.ILog _log = log4net.LogManager.GetLogger(source);
LogLevel level = (LogLevel)log_level;
switch (level)
{
case LogLevel.Fatal:
_log.Fatal(message);
break;
case LogLevel.Error:
_log.Error(message);
break;
case LogLevel.Warn:
_log.Warn(message);
break;
case LogLevel.Info:
_log.Info(message);
break;
case LogLevel.Debug:
_log.Debug(message);
break;
}
}
private static string ARRAY_DELIMITER = ", ";
private static string ARRAY_BRACES = "[{0}]";
private static string LEFT_BRACE = "[";
private static string RIGHT_BRACE = "]";
private static string NULL_STRING = "null";
public static string ToStringNullSafe(this object value)
{
return(value ?? "null").ToString();
}
public static string StringArrayToString(string[] a)
{
if (a == null)
return NULL_STRING;
return string.Format(ARRAY_BRACES, string.Join(ARRAY_DELIMITER, a));
}
public static string AssetStatusListToString(List a)
{
if (a == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.Append(LEFT_BRACE);
bool first = true;
foreach (AssetStatusCache.AssetStatus stat in a)
{
if (!first)
sb.Append(ARRAY_DELIMITER);
sb.Append(stat.ToString());
first = false;
}
sb.Append(RIGHT_BRACE);
return sb.ToString();
}
public static string FileAndOpToString(Engine.FilesAndOp fao)
{
return string.Format("op: {0} file: {1} meta: {2} move: {3}",
fao.FileOp, fao.File, fao.Meta, fao.MoveToFile);
}
public static string FilesAndOpListToString(List a)
{
if (a == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.Append(LEFT_BRACE);
bool first = true;
foreach(Engine.FilesAndOp fao in a)
{
if (!first)
sb.Append(ARRAY_DELIMITER);
sb.Append(FileAndOpToString(fao));
first = false;
}
sb.Append(RIGHT_BRACE);
return sb.ToString();
}
public static string FileSpecListToString(IList a)
{
if (a == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.Append(LEFT_BRACE);
bool first = true;
foreach (Perforce.P4.FileSpec spec in a)
{
if (!first)
sb.Append(ARRAY_DELIMITER);
if (spec == null)
sb.AppendFormat(NULL_STRING);
else
sb.AppendFormat("Depot: {0} Client: {1} Local: {2} Version: {3}",
spec.DepotPath.ToStringNullSafe(), spec.ClientPath.ToStringNullSafe(), spec.LocalPath.ToStringNullSafe(), spec.Version.ToStringNullSafe());
first = false;
}
sb.Append(RIGHT_BRACE);
return sb.ToString();
}
public static string FileAndMetaListToString(List a)
{
if (a == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.Append(LEFT_BRACE);
bool first = true;
foreach (FileAndMeta fam in a)
{
if (!first)
sb.Append(ARRAY_DELIMITER);
sb.AppendFormat("file: {0} meta: {1}", fam.File, fam.Meta);
first = false;
}
sb.Append(RIGHT_BRACE);
return sb.ToString();
}
///
/// Debug function to create a compact string description of a FileMetaData element
///
///
///
public static string FileMetaDataToString(FileMetaData m)
{
if (m == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Action: {0} ", m.Action.ToStringNullSafe());
sb.AppendFormat("Mapped: {0} ", m.IsMapped);
sb.AppendFormat("Shelved: {0} ", m.Shelved);
sb.AppendFormat("HeadAction: {0} ", m.HeadAction.ToStringNullSafe());
sb.AppendFormat("HeadChange: {0} ", m.HeadChange.ToStringNullSafe());
sb.AppendFormat("Storage: {0} ", m.Type.ToStringNullSafe());
sb.AppendFormat("Depot: {0} Client: {1} Local: {2} ",
ToStringNullSafe(m.DepotPath), ToStringNullSafe(m.ClientPath), ToStringNullSafe(m.LocalPath));
return sb.ToString();
}
///
/// Debug function to create a compact string description of a FileMetaData List
///
///
///
public static string FileMetaDataListToString(IList a)
{
if (a == null)
return NULL_STRING;
StringBuilder sb = new StringBuilder();
sb.Append(LEFT_BRACE);
bool first = true;
foreach (Perforce.P4.FileMetaData m in a)
{
if (!first)
sb.Append(ARRAY_DELIMITER);
sb.Append(FileMetaDataToString(m));
first = false;
}
sb.Append(RIGHT_BRACE);
return sb.ToString();
}
}
}