1 //------------------------------------------------------------------------------ 2 // <copyright file="DelimitedListTraceListener.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 8 using System; 9 using System.Text; 10 using System.Globalization; 11 using System.IO; 12 using System.Collections; 13 using System.Security.Permissions; 14 using System.Runtime.Versioning; 15 16 namespace System.Diagnostics { 17 [HostProtection(Synchronization=true)] 18 public class DelimitedListTraceListener : TextWriterTraceListener { 19 string delimiter = ";"; 20 string secondaryDelim = ","; 21 bool initializedDelim = false; 22 DelimitedListTraceListener(Stream stream)23 public DelimitedListTraceListener(Stream stream) : base(stream) { 24 } 25 DelimitedListTraceListener(Stream stream, string name)26 public DelimitedListTraceListener(Stream stream, string name) : base(stream, name) { 27 } 28 DelimitedListTraceListener(TextWriter writer)29 public DelimitedListTraceListener(TextWriter writer) : base(writer) { 30 } 31 DelimitedListTraceListener(TextWriter writer, string name)32 public DelimitedListTraceListener(TextWriter writer, string name) : base(writer, name) { 33 } 34 35 [ResourceExposure(ResourceScope.Machine)] 36 [ResourceConsumption(ResourceScope.Machine)] DelimitedListTraceListener(string fileName)37 public DelimitedListTraceListener(string fileName) : base (fileName) { 38 } 39 40 [ResourceExposure(ResourceScope.Machine)] 41 [ResourceConsumption(ResourceScope.Machine)] DelimitedListTraceListener(string fileName, string name)42 public DelimitedListTraceListener(string fileName, string name) : base(fileName, name) { 43 } 44 45 public string Delimiter { 46 get { 47 lock(this) { // Probably overkill 48 if (!initializedDelim) { 49 50 if (Attributes.ContainsKey("delimiter")) 51 delimiter = Attributes["delimiter"]; 52 53 initializedDelim = true; 54 } 55 } 56 return delimiter; 57 } 58 set { 59 if (value == null) 60 throw new ArgumentNullException("Delimiter"); 61 62 if (value.Length == 0) 63 throw new ArgumentException(SR.GetString("Generic_ArgCantBeEmptyString", "Delimiter")); 64 65 lock(this) { 66 delimiter = value; 67 initializedDelim = true; 68 } 69 70 if (delimiter == ",") 71 secondaryDelim = ";"; 72 else 73 secondaryDelim = ","; 74 } 75 } 76 GetSupportedAttributes()77 protected override internal string[] GetSupportedAttributes() { 78 return new String[]{"delimiter"}; 79 } 80 81 TraceEvent(TraceEventCache eventCache, String source, TraceEventType eventType, int id, string format, params object[] args)82 public override void TraceEvent(TraceEventCache eventCache, String source, TraceEventType eventType, int id, string format, params object[] args) { 83 if (Filter != null && !Filter.ShouldTrace(eventCache, source, eventType, id, format, args)) 84 return; 85 86 WriteHeader(source, eventType, id); 87 88 if (args != null) 89 WriteEscaped(String.Format(CultureInfo.InvariantCulture, format, args)); 90 else 91 WriteEscaped(format); 92 Write(Delimiter); // Use get_Delimiter 93 94 // one more delimiter for the data object 95 Write(Delimiter); // Use get_Delimiter 96 97 WriteFooter(eventCache); 98 } 99 TraceEvent(TraceEventCache eventCache, String source, TraceEventType eventType, int id, string message)100 public override void TraceEvent(TraceEventCache eventCache, String source, TraceEventType eventType, int id, string message) { 101 if (Filter != null && !Filter.ShouldTrace(eventCache, source, eventType, id, message)) 102 return; 103 104 WriteHeader(source, eventType, id); 105 106 WriteEscaped(message); 107 Write(Delimiter); // Use get_Delimiter 108 109 // one more delimiter for the data object 110 Write(Delimiter); // Use get_Delimiter 111 112 WriteFooter(eventCache); 113 } 114 TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, int id, object data)115 public override void TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, int id, object data) { 116 if (Filter != null && !Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data)) 117 return; 118 119 WriteHeader(source, eventType, id); 120 121 // first a delimiter for the message 122 Write(Delimiter); // Use get_Delimiter 123 124 WriteEscaped(data.ToString()); 125 Write(Delimiter); // Use get_Delimiter 126 127 WriteFooter(eventCache); 128 } 129 TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, int id, params object[] data)130 public override void TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, int id, params object[] data) { 131 if (Filter != null && !Filter.ShouldTrace(eventCache, source, eventType, id, null, null, null, data)) 132 return; 133 134 WriteHeader(source, eventType, id); 135 136 // first a delimiter for the message 137 Write(Delimiter); // Use get_Delimiter 138 139 if (data != null) { 140 for (int i=0; i<data.Length; i++) { 141 if (i != 0) 142 Write(secondaryDelim); 143 WriteEscaped(data[i].ToString()); 144 } 145 } 146 Write(Delimiter); // Use get_Delimiter 147 148 WriteFooter(eventCache); 149 } 150 WriteHeader(String source, TraceEventType eventType, int id)151 private void WriteHeader(String source, TraceEventType eventType, int id) { 152 WriteEscaped(source); 153 Write(Delimiter); // Use get_Delimiter 154 155 Write(eventType.ToString()); 156 Write(Delimiter); // Use get_Delimiter 157 158 Write(id.ToString(CultureInfo.InvariantCulture)); 159 Write(Delimiter); // Use get_Delimiter 160 } 161 162 [ResourceExposure(ResourceScope.None)] 163 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] WriteFooter(TraceEventCache eventCache)164 private void WriteFooter(TraceEventCache eventCache) { 165 if (eventCache != null) { 166 if (IsEnabled(TraceOptions.ProcessId)) 167 Write(eventCache.ProcessId.ToString(CultureInfo.InvariantCulture)); 168 Write(Delimiter); // Use get_Delimiter 169 170 if (IsEnabled(TraceOptions.LogicalOperationStack)) 171 WriteStackEscaped(eventCache.LogicalOperationStack); 172 Write(Delimiter); // Use get_Delimiter 173 174 if (IsEnabled(TraceOptions.ThreadId)) 175 WriteEscaped(eventCache.ThreadId.ToString(CultureInfo.InvariantCulture)); 176 Write(Delimiter); // Use get_Delimiter 177 178 if (IsEnabled(TraceOptions.DateTime)) 179 WriteEscaped(eventCache.DateTime.ToString("o", CultureInfo.InvariantCulture)); 180 Write(Delimiter); // Use get_Delimiter 181 182 if (IsEnabled(TraceOptions.Timestamp)) 183 Write(eventCache.Timestamp.ToString(CultureInfo.InvariantCulture)); 184 Write(Delimiter); // Use get_Delimiter 185 186 if (IsEnabled(TraceOptions.Callstack)) 187 WriteEscaped(eventCache.Callstack); 188 } 189 else { 190 for (int i=0; i<5; i++) 191 Write(Delimiter); // Use get_Delimiter 192 } 193 194 WriteLine(""); 195 } 196 WriteEscaped(string message)197 private void WriteEscaped(string message) { 198 if (!String.IsNullOrEmpty(message)) { 199 StringBuilder sb = new StringBuilder("\""); 200 int index; 201 int lastindex = 0; 202 while((index = message.IndexOf('"', lastindex)) != -1) { 203 sb.Append(message, lastindex, index - lastindex); 204 sb.Append("\"\""); 205 lastindex = index + 1; 206 } 207 208 sb.Append(message, lastindex, message.Length - lastindex); 209 sb.Append("\""); 210 Write(sb.ToString()); 211 } 212 } 213 WriteStackEscaped(Stack stack)214 private void WriteStackEscaped(Stack stack) { 215 StringBuilder sb = new StringBuilder("\""); 216 bool first = true; 217 foreach (Object obj in stack) { 218 if (!first) 219 sb.Append(", "); 220 else 221 first = false; 222 223 string operation = obj.ToString(); 224 225 int index; 226 int lastindex = 0; 227 while((index = operation.IndexOf('"', lastindex)) != -1) { 228 sb.Append(operation, lastindex, index - lastindex); 229 sb.Append("\"\""); 230 lastindex = index + 1; 231 } 232 233 sb.Append(operation, lastindex, operation.Length - lastindex); 234 } 235 sb.Append("\""); 236 Write(sb.ToString()); 237 } 238 239 } 240 } 241