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