2 // XmlWriterTraceListener.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2007 Novell, Inc http://www.novell.com
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #if NET_2_0 && XML_DEP
35 using System.Diagnostics;
36 using System.Threading;
38 using System.Xml.XPath;
40 namespace System.Diagnostics
42 public class XmlWriterTraceListener : TextWriterTraceListener
44 static readonly string e2e_ns = "http://schemas.microsoft.com/2004/06/E2ETraceEvent";
45 static readonly string sys_ns = "http://schemas.microsoft.com/2004/06/windows/eventlog/system";
46 static readonly string default_name = "XmlWriter";
49 public XmlWriterTraceListener (string filename)
50 : this (filename, default_name)
54 public XmlWriterTraceListener (string filename, string name)
55 : this (new StreamWriter (new FileStream (filename, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)), name)
59 public XmlWriterTraceListener (Stream stream)
60 : this (stream, default_name)
64 public XmlWriterTraceListener (Stream writer, string name)
65 : this (new StreamWriter (writer), name)
69 public XmlWriterTraceListener (TextWriter writer)
70 : this (writer, default_name)
74 public XmlWriterTraceListener (TextWriter writer, string name)
77 XmlWriterSettings settings = new XmlWriterSettings ();
78 settings.OmitXmlDeclaration = true;
79 w = XmlWriter.Create (writer, settings);
82 public override void Close ()
87 public override void Fail (string message, string detailMessage)
89 TraceEvent (null, null, TraceEventType.Error,
90 0, String.Concat (message, " ", detailMessage));
93 public override void TraceData (TraceEventCache eventCache,
94 string source, TraceEventType eventType, int id,
97 TraceCore (eventCache, source, eventType, id, false,
98 Guid.Empty, 2, true, data);
101 [MonoLimitation ("level is not always correct")]
102 public override void TraceData (TraceEventCache eventCache,
103 string source, TraceEventType eventType, int id,
104 params object [] data)
106 TraceCore (eventCache, source, eventType, id, false,
107 Guid.Empty, 2, true, data);
110 [MonoLimitation ("level is not always correct")]
111 public override void TraceEvent (TraceEventCache eventCache,
112 string source, TraceEventType eventType, int id,
115 TraceCore (eventCache, source, eventType,
116 id, false, Guid.Empty, 2, true, message);
119 [MonoLimitation ("level is not always correct")]
120 public override void TraceEvent (TraceEventCache eventCache,
121 string source, TraceEventType eventType, int id,
122 string format, params object [] args)
124 TraceCore (eventCache, source, eventType,
125 id, false, Guid.Empty, 2, true, String.Format (format, args));
128 public override void TraceTransfer (TraceEventCache eventCache,
129 string source, int id, string message,
130 Guid relatedActivityId)
132 TraceCore (eventCache, source, TraceEventType.Transfer,
133 id, true, relatedActivityId, 255, true, message);
136 public override void Write (string message)
141 [MonoLimitation ("level is not always correct")]
142 public override void WriteLine (string message)
144 // FIXME: what is the correct level?
145 TraceCore (null, "Trace", TraceEventType.Information,
146 0, false, Guid.Empty, 8, false, message);
149 void TraceCore (TraceEventCache eventCache,
150 string source, TraceEventType eventType, int id,
151 bool hasRelatedActivity, Guid relatedActivity,
152 int level, bool wrapData, params object [] data)
154 Process p = eventCache != null ?
155 Process.GetProcessById (eventCache.ProcessId) :
156 Process.GetCurrentProcess ();
158 w.WriteStartElement ("E2ETraceEvent", e2e_ns);
161 w.WriteStartElement ("System", sys_ns);
162 w.WriteStartElement ("EventID", sys_ns);
163 w.WriteString (XmlConvert.ToString (id));
164 w.WriteEndElement ();
165 // FIXME: find out what should be written
166 w.WriteStartElement ("Type", sys_ns);
168 w.WriteEndElement ();
169 w.WriteStartElement ("SubType", sys_ns);
170 // FIXME: it does not seem always to match eventType value ...
171 w.WriteAttributeString ("Name", eventType.ToString ());
172 // FIXME: find out what should be written
174 w.WriteEndElement ();
175 // FIXME: find out what should be written
176 w.WriteStartElement ("Level", sys_ns);
177 w.WriteString (level.ToString ());
178 w.WriteEndElement ();
179 w.WriteStartElement ("TimeCreated", sys_ns);
180 w.WriteAttributeString ("SystemTime", XmlConvert.ToString (eventCache != null ? eventCache.DateTime : DateTime.Now));
181 w.WriteEndElement ();
182 w.WriteStartElement ("Source", sys_ns);
183 w.WriteAttributeString ("Name", source);
184 w.WriteEndElement ();
185 w.WriteStartElement ("Correlation", sys_ns);
186 w.WriteAttributeString ("ActivityID", String.Concat ("{", Guid.Empty, "}"));
187 w.WriteEndElement ();
188 w.WriteStartElement ("Execution", sys_ns);
189 // FIXME: which should I use here?
190 //w.WriteAttributeString ("ProcessName", p.ProcessName);
191 w.WriteAttributeString ("ProcessName", p.MainModule.ModuleName);
192 w.WriteAttributeString ("ProcessID", p.Id.ToString ());
193 w.WriteAttributeString ("ThreadID", eventCache != null ? eventCache.ThreadId : Thread.CurrentThread.ManagedThreadId.ToString ());
194 w.WriteEndElement ();
195 w.WriteStartElement ("Channel", sys_ns);
196 // FIXME: find out what should be written.
197 w.WriteEndElement ();
198 w.WriteStartElement ("Computer");
199 w.WriteString (p.MachineName);
200 w.WriteEndElement ();
202 w.WriteEndElement ();
205 w.WriteStartElement ("ApplicationData", e2e_ns);
206 w.WriteStartElement ("TraceData", e2e_ns);
207 foreach (object o in data) {
209 w.WriteStartElement ("DataItem", e2e_ns);
210 if (o is XPathNavigator)
211 // the output ignores xmlns difference between the parent (E2ETraceEvent and the content node).
212 // To clone such behavior, I took this approach.
213 w.WriteRaw (XPathNavigatorToString ((XPathNavigator) o));
215 w.WriteString (o.ToString ());
217 w.WriteEndElement ();
219 w.WriteEndElement ();
220 w.WriteEndElement ();
222 w.WriteEndElement ();
224 w.Flush (); // for XmlWriter
225 Flush (); // for TextWriter
228 static readonly XmlWriterSettings xml_writer_settings = new XmlWriterSettings () { OmitXmlDeclaration = true };
230 // I avoided OuterXml which includes indentation.
231 string XPathNavigatorToString (XPathNavigator nav)
233 var sw = new StringWriter ();
234 using (var xw = XmlWriter.Create (sw, xml_writer_settings))
235 nav.WriteSubtree (xw);
236 return sw.ToString ();