// // System.Diagnostics.TraceListener.cs // // Authors: // Jonathan Pryor (jonpryor@vt.edu) // Atsushi Enomoto (atsushi@ximian.com) // // Comments from John R. Hicks original implementation // can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics // // (C) 2002 Jonathan Pryor // (C) 2007 Novell, Inc. // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Collections.Specialized; using System.Runtime.InteropServices; using System.Diagnostics; namespace System.Diagnostics { public abstract class TraceListener : MarshalByRefObject, IDisposable { #if TARGET_JVM readonly LocalDataStoreSlot _indentLevelStore = System.Threading.Thread.AllocateDataSlot (); readonly LocalDataStoreSlot _indentSizeStore = System.Threading.Thread.AllocateDataSlot (); readonly LocalDataStoreSlot _attributesStore = System.Threading.Thread.AllocateDataSlot (); readonly LocalDataStoreSlot _filterStore = System.Threading.Thread.AllocateDataSlot (); readonly LocalDataStoreSlot _optionsStore = System.Threading.Thread.AllocateDataSlot (); private int indentLevel { get { object o = System.Threading.Thread.GetData (_indentLevelStore); if (o == null) return 0; return (int) o; } set { System.Threading.Thread.SetData (_indentLevelStore, value); } } private int indentSize { get { object o = System.Threading.Thread.GetData (_indentSizeStore); if (o == null) return 4; return (int) o; } set { System.Threading.Thread.SetData (_indentSizeStore, value); } } #if NET_2_0 private StringDictionary attributes { get { return (StringDictionary) System.Threading.Thread.GetData (_attributesStore); } set { System.Threading.Thread.SetData (_attributesStore, value); } } private TraceFilter filter { get { return (TraceFilter) System.Threading.Thread.GetData (_filterStore); } set { System.Threading.Thread.SetData (_filterStore, value); } } private TraceOptions options { get { object o = System.Threading.Thread.GetData (_optionsStore); if (o == null) return TraceOptions.None; return (TraceOptions) o; } set { System.Threading.Thread.SetData (_optionsStore, value); } } #endif #else [ThreadStatic] private int indentLevel = 0; [ThreadStatic] private int indentSize = 4; #if NET_2_0 [ThreadStatic] private StringDictionary attributes = new StringDictionary (); [ThreadStatic] private TraceFilter filter; [ThreadStatic] private TraceOptions options; #endif #endif private string name; private bool needIndent = true; protected TraceListener () : this ("") { } protected TraceListener (string name) { Name = name; } public int IndentLevel { get {return indentLevel;} set {indentLevel = value;} } public int IndentSize { get {return indentSize;} set {indentSize = value;} } public virtual string Name { get {return name;} set {name = value;} } protected bool NeedIndent { get {return needIndent;} set {needIndent = value;} } #if NET_2_0 [MonoLimitation ("This property exists but is never considered.")] public virtual bool IsThreadSafe { get { return false; } } #endif public virtual void Close () { Dispose (); } public void Dispose () { Dispose (true); GC.SuppressFinalize (this); } protected virtual void Dispose (bool disposing) { } public virtual void Fail (string message) { Fail (message, ""); } public virtual void Fail (string message, string detailMessage) { WriteLine ("---- DEBUG ASSERTION FAILED ----"); WriteLine ("---- Assert Short Message ----"); WriteLine (message); WriteLine ("---- Assert Long Message ----"); WriteLine (detailMessage); WriteLine (""); } public virtual void Flush () { } public virtual void Write (object o) { Write (o.ToString()); } public abstract void Write (string message); public virtual void Write (object o, string category) { Write (o.ToString(), category); } public virtual void Write (string message, string category) { Write (category + ": " + message); } protected virtual void WriteIndent () { // Must set NeedIndent to false before Write; otherwise, we get endless // recursion with Write->WriteIndent->Write->WriteIndent...*boom* NeedIndent = false; String indent = new String (' ', IndentLevel*IndentSize); Write (indent); } public virtual void WriteLine (object o) { WriteLine (o.ToString()); } public abstract void WriteLine (string message); public virtual void WriteLine (object o, string category) { WriteLine (o.ToString(), category); } public virtual void WriteLine (string message, string category) { WriteLine (category + ": " + message); } #if NET_2_0 internal static string FormatArray (ICollection list, string joiner) { string [] arr = new string [list.Count]; int i = 0; foreach (object o in list) arr [i++] = o != null ? o.ToString () : String.Empty; return String.Join (joiner, arr); } [ComVisible (false)] public virtual void TraceData (TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) { if (Filter != null && !Filter.ShouldTrace (eventCache, source, eventType, id, null, null, data, null)) return; WriteLine (String.Format ("{0} {1}: {2} : {3}", source, eventType, id, data)); if (eventCache == null) return; if ((TraceOutputOptions & TraceOptions.ProcessId) != 0) WriteLine (" ProcessId=" + eventCache.ProcessId); if ((TraceOutputOptions & TraceOptions.LogicalOperationStack) != 0) WriteLine (" LogicalOperationStack=" + FormatArray (eventCache.LogicalOperationStack, ", ")); if ((TraceOutputOptions & TraceOptions.ThreadId) != 0) WriteLine (" ThreadId=" + eventCache.ThreadId); if ((TraceOutputOptions & TraceOptions.DateTime) != 0) WriteLine (" DateTime=" + eventCache.DateTime.ToString ("o")); if ((TraceOutputOptions & TraceOptions.Timestamp) != 0) WriteLine (" Timestamp=" + eventCache.Timestamp); if ((TraceOutputOptions & TraceOptions.Callstack) != 0) WriteLine (" Callstack=" + eventCache.Callstack); } [ComVisible (false)] public virtual void TraceData (TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object [] data) { if (Filter != null && !Filter.ShouldTrace (eventCache, source, eventType, id, null, null, null, data)) return; TraceData (eventCache, source, eventType, id, FormatArray (data, " ")); } [ComVisible (false)] public virtual void TraceEvent (TraceEventCache eventCache, string source, TraceEventType eventType, int id) { TraceEvent (eventCache, source, eventType, id, null); } [ComVisible (false)] public virtual void TraceEvent (TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) { TraceData (eventCache, source, eventType, id, message); } [ComVisible (false)] public virtual void TraceEvent (TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object [] args) { TraceEvent (eventCache, source, eventType, id, String.Format (format, args)); } [ComVisible (false)] public virtual void TraceTransfer (TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId) { TraceEvent (eventCache, source, TraceEventType.Transfer, id, String.Format ("{0}, relatedActivityId={1}", message, relatedActivityId)); } protected internal virtual string [] GetSupportedAttributes () { return null; } public StringDictionary Attributes { get { return attributes; } } [ComVisibleAttribute (false)] public TraceFilter Filter { get { return filter; } set { filter = value; } } [ComVisibleAttribute (false)] public TraceOptions TraceOutputOptions { get { return options; } set { options = value; } } #endif } }