using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; namespace P4Connect { class Logger { TextWriterTraceListener p4Listener; System.IO.FileStream p4LogFile; string prevPath; string name; private static StaticResourceManager myResourceManager = new StaticResourceManager(); static readonly Logger _instance = new Logger(); private Logger() { p4Listener = null; p4LogFile = null; prevPath = ""; name = "p4connect"; } public static Logger Instance { get { return _instance; } } public void Enable() { if (Config.LogPath != prevPath) { Disable(); if (Config.EnableLog) { try { prevPath = Config.LogPath; p4LogFile = new System.IO.FileStream(Config.LogPath, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.Read); StreamWriter writer = new StreamWriter(p4LogFile); p4Listener = new TextWriterTraceListener(writer, name); myResourceManager.AddStream(writer); // ensure flush and close at application exit // Write the initial trace message to the console trace listener. p4Listener.WriteLine(DateTime.Now.ToString() + " [" + p4Listener.Name + "] - 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.Enable" + e.Message); } } } } public void Disable() { try { if (p4Listener != null) { Trace.Flush(); Trace.Listeners.Remove(p4Listener); p4Listener.Close(); p4Listener = null; } if (p4LogFile != null) { p4LogFile.Close(); } p4LogFile = null; } catch (Exception e) { UnityEngine.Debug.Log("Exception in Logger.Disable " + e.Message); } } public void Log(int log_level, String source, String message) { if (Config.EnableLog) { string payload = DateTime.Now.ToString() + " " + ((LogLevel) log_level).ToString() + " [ " + source + " ] " + message; UnityEngine.Debug.Log(payload); if (p4Listener == null) System.Console.WriteLine("p4Listener is null! EnableLog: " + Config.EnableLog.ToString()); if (Config.EnableLog && p4Listener != null) { p4Listener.WriteLine(payload); Trace.Flush(); } } } /// Log_Level. 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 }; public static void P4ConnectLog(int log_level, String source, String message) { Logger.Instance.Log(log_level, source, message); } public static void p4log(string message) { if (!String.IsNullOrEmpty(message)) P4ConnectLog((int) LogLevel.Info, "p4log", message); } public static void p4logArray(string indent, string[] a) { if (a == null || a.Length == 0) return; foreach (string s in a) { p4log(indent + s); } } public static void p4logFileSpecs(string indent, IList<Perforce.P4.FileSpec> a) { if (a == null || a.Count == 0) return; foreach (Perforce.P4.FileSpec s in a) { //p4log(indent + " depot: " + s.DepotPath); //p4log(indent + "client: " + s.ClientPath); //p4log(indent + " local: " + s.LocalPath); //p4log(indent + " ver: " + s.Version); p4log(indent + s.ToString()); } } public static void p4logFilesAndOp(string indent, P4Connect.Engine.FilesAndOp obj) { p4log(indent + "FilesAndOp: " + obj.FileOp.ToString()); if (obj.File == null) p4log(indent + " file: NULL"); else p4log(indent + " file: " + obj.File.ToString()); if (obj.Meta == null) p4log(indent + " meta: NULL"); else p4log(indent + " meta: " + obj.Meta.ToString()); if (obj.MoveToFile == null) p4log(indent + " mov2: NULL"); else p4log(indent + " mov2: " + obj.MoveToFile.ToString()); } } /// <summary> /// Ensures deterministic StreamWriter Flush, and File close at application exit for /// static facades. The cleanup is done after all normal finalizers have been called. /// </summary> /// borrowed from: http://geekswithblogs.net/akraus1/articles/81629.aspx /// public class StaticResourceManager : System.Runtime.ConstrainedExecution.CriticalFinalizerObject { List<StreamWriter> writers = new List<StreamWriter>(); public void AddStream(StreamWriter writer) { writers.Add(writer); FileStream fStream = GetIfFileStream(writer.BaseStream); if (fStream != null) { GC.SuppressFinalize(fStream); // prevent GC on FileStream // prevent file close at application exit before want to let it happen GC.SuppressFinalize(fStream.SafeFileHandle); } } static FileStream GetIfFileStream(Stream stream) { if (stream is FileStream) return (FileStream)stream; else return null; } /// <summary> /// Deterministic cleanup of StreamWriters /// 1. StreamWriter Close -> FileStream -> Close -> possible Writes /// 2. FileHandle Close /// </summary> ~StaticResourceManager() { foreach (StreamWriter writer in writers) { FileStream fstream = GetIfFileStream(writer.BaseStream); Microsoft.Win32.SafeHandles.SafeFileHandle handle = null; if (fstream != null) { handle = fstream.SafeFileHandle; } writer.Close(); // Close StreamWriter first if (handle != null) // Close file handle now hurray handle.Close(); } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#11 | 16210 | Norman Morse | Remove files from old locations | ||
#10 | 15298 | Norman Morse | Fix Version Stamping to not use UpdateVersion.exe for personal (workshop) builds. | ||
#9 | 15266 | Norman Morse |
Integrated "UpdateVersion" tool to update the VersionInfo and the DLL properties with information from "Version" EC generates the Version file for us in builds. Workshop users need to generate their own Release number with two zeros (like 2015.2.0.0) which will have the last two numbers replaced with change ID. |
||
#8 | 15079 | 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. |
||
#7 | 14232 | Norman Morse | GA.8 release | ||
#6 | 14193 | Norman Morse |
GA.7 release Refactor Pending Changes Resolve Submit issues. Fixed Menu entries. Handle mismatched file and meta states. |
||
#5 | 13864 | Norman Morse | Final fixes for GA.5 release. | ||
#4 | 13824 | Norman Morse |
Changes to have fstat return true client paths. Remove versions, fixes problems with "local" paths sneaking into results. |
||
#3 | 12553 | Norman Morse |
integrate from internal main Build fixes for EC. Major changes to Configuration and re-initialization code. Bug fixes |
||
#2 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
#1 | 12362 | Norman Morse |
Added Debug Logging for p4log Fixed some path comparison issues. Created a CaseSensitivity test |