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; namespace P4Connect { public static class Logger { static Log4netTraceListener p4Listener = null; public static void Initialize() { 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 Initialized."); // Add the new console trace listener to the collection of trace listeners. Trace.Listeners.Add(p4Listener); // Hook the Bridge logging calls up using the P4ConnectLog delegate Perforce.P4.LogFile.SetLoggingFunction(P4ConnectLog); //Trace.WriteLine("Trace.WriteLine"); //Debug.WriteLine("Debug.WriteLine"); 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; } } /// <summary> /// Configure logging to write to default log and the Unity console output. /// </summary> 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 = Main.DataPath + "P4Connect\\Editor\\logging.xml"; UnityEngine.Debug.Log("Looking for logging config at " + ConfigPath); if (System.IO.File.Exists(ConfigPath)) { UnityEngine.Debug.Log("Reading 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(); // Add custom renderers repo.RendererMap.Put(typeof(FileSpec), new FileSpecRenderer()); repo.RendererMap.Put(typeof(Engine.FilesAndOp), new FileAndOpRenderer()); repo.RendererMap.Put(typeof(System.Collections.IList), new FileSpecListRenderer()); repo.RendererMap.Put(typeof(System.Collections.IList), new FilesAndOpListRenderer()); repo.RendererMap.Put(typeof(System.Collections.IList), new FileAndMetaListRenderer()); } } /// <summary> An appender which logs to the unity console. </summary> private class UnityAppender : AppenderSkeleton { /// <inheritdoc /> 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 level, /// 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; //if (l >= Level.Fatal) return LogLevel.Fatal; } public static void P4ConnectLog(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 StringArrayToString(string[] a) { if (a == null) return NULL_STRING; return string.Format(ARRAY_BRACES, string.Join(ARRAY_DELIMITER, a)); } public static string FandOArrayToString(List<Engine.FilesAndOp> 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.AppendFormat("op: {0} file: {1} meta: {2} move: {3}", fao.FileOp, fao.File, fao.Meta, fao.MoveToFile); first = false; } sb.Append(RIGHT_BRACE); return sb.ToString(); } public class FileSpecListRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { var myList = obj as IList<FileSpec>; if (myList != null) { try { FileSpecRenderer rend = new FileSpecRenderer(); foreach (FileSpec spec in myList) { rend.RenderObject(map, spec, writer); } } catch (NullReferenceException ex) { writer.Write(SystemInfo.NullText); } } else { new DefaultRenderer().RenderObject(map, obj, writer); } } } public class FileSpecRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { FileSpec spec = obj as FileSpec; writer.WriteLine(string.Format("Depot: {0} Client: {1} Local: {2} Version: {3}", spec.DepotPath, spec.ClientPath, spec.LocalPath, spec.Version)); } } public class FilesAndOpListRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { var myList = obj as IList<Engine.FilesAndOp>; if (myList != null) { try { FileAndOpRenderer rend = new FileAndOpRenderer(); foreach (Engine.FilesAndOp spec in myList) { rend.RenderObject(map, spec, writer); } } catch (NullReferenceException ex) { writer.Write(SystemInfo.NullText); } } else { new DefaultRenderer().RenderObject(map, obj, writer); } } } public class FileAndOpRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { Engine.FilesAndOp fao = (Engine.FilesAndOp) obj; writer.WriteLine(string.Format("op: {0} file: {1} meta: {2} move: {3}", fao.FileOp.ToString(), fao.File, fao.Meta, fao.MoveToFile)); } } public class FileAndMetaListRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { var myList = obj as IList<FileAndMeta>; if (myList != null) { try { FileAndMetaRenderer rend = new FileAndMetaRenderer(); foreach (FileAndMeta fam in myList) { rend.RenderObject(map, fam, writer); } } catch (NullReferenceException ex) { writer.Write(SystemInfo.NullText); } } else { new DefaultRenderer().RenderObject(map, obj, writer); } } } public class FileAndMetaRenderer : IObjectRenderer { public void RenderObject(RendererMap map, object obj, TextWriter writer) { FileAndMeta fam = (FileAndMeta) obj; writer.WriteLine(string.Format("file: {0} meta: {1}", fam.File, fam.Meta)); } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#11 | 16251 | Norman Morse | Update Dev branch to match reorganization in workshop | ||
#10 | 15075 | Norman Morse |
Rewrote AssetStatusCache to Cache AssetStatuses and FileMetaData Fixed Edge conditions on Engine Operations Change Debug output defaults. Will now Checkout files which request to be "added" but which already exist in perforce. Output P4Connect version to log on initialization. |
||
#9 | 14236 | Norman Morse | update dev branch with GA.8 release files | ||
#8 | 13872 | Norman Morse | Update dev branch from GA.5 release | ||
#7 | 12558 | Norman Morse | Integrate from main to dev | ||
#6 | 12491 | Norman Morse | More minor fixes | ||
#5 | 12480 | Norman Morse |
Fixed crash in logging. Worked on UI issues. Cleaned up some connection usage. Still looking for the problem with pending changes. |
||
#4 | 12473 | Norman Morse | More minor fixes to logging and config | ||
#3 | 12467 | Norman Morse |
Many minor changes to improve logging Added a filter for Console log display where you can select a level Hooked the log file location to the Configuration Log Entry. |
||
#2 | 12445 | Norman Morse |
Integrated log4net and nunit into P4Connect. Still need cleanup and debugging, good enough for dev tree Also added ChangeManager and ChangeLists Classes for future use with multiple changes. |
||
#1 | 12363 | Norman Morse |
Merging //guest/perforce_software/p4connect/src/... to //guest/norman_morse/dev/p4connect/src/... |
||
//guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.Logger.cs | |||||
#1 | 12362 | Norman Morse |
Added Debug Logging for p4log Fixed some path comparison issues. Created a CaseSensitivity test |