3 // Atsushi Enomoto <atsushi@ximian.com>
5 // Copyright (C) 2011 Novell, Inc. http://www.novell.com
6 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System.Collections.Generic;
29 using System.Configuration;
30 using System.Diagnostics;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Configuration;
35 using System.ServiceModel.Diagnostics;
36 using System.Threading;
39 using System.Xml.XPath;
42 namespace System.ServiceModel
44 internal enum MessageLogSourceKind
48 ServiceLevelReceiveDatagram,
49 ServiceLevelSendDatagram,
50 // more, maybe for clients?
53 internal static class Logger
56 enum TraceEventType // dummy
71 const string xmlns = "http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace";
72 static MessageLoggingSettings settings = new MessageLoggingSettings ();
74 static TextWriter log_writer;
75 static XmlWriter xml_writer;
77 static readonly TraceSource source = new TraceSource ("System.ServiceModel");
78 static readonly TraceSource message_source = new TraceSource ("System.ServiceModel.MessageLogging");
84 Environment.GetEnvironmentVariable ("MOON_WCF_TRACE") ??
85 Environment.GetEnvironmentVariable ("MONO_WCF_TRACE");
89 log_writer = Console.Out;
92 log_writer = Console.Error;
97 if (!String.IsNullOrEmpty (env))
98 log_writer = File.CreateText (env);
99 } catch (Exception ex) {
100 Console.Error.WriteLine ("WARNING: WCF trace environment variable points to non-creatable file name: " + env);
106 if (log_writer != null)
107 xml_writer = XmlWriter.Create (log_writer, new XmlWriterSettings () { OmitXmlDeclaration = true });
110 message_source.Switch.Level = SourceLevels.Information;
114 #region logger methods
116 public static void Critical (string message, params object [] args)
118 Log (TraceEventType.Critical, message, args);
121 public static void Error (string message, params object [] args)
123 Log (TraceEventType.Error, message, args);
126 public static void Warning (string message, params object [] args)
128 Log (TraceEventType.Warning, message, args);
131 public static void Info (string message, params object [] args)
133 Log (TraceEventType.Information, message, args);
136 public static void Verbose (string message, params object [] args)
138 Log (TraceEventType.Verbose, message, args);
141 // FIXME: do we need more?
143 static void Log (TraceEventType eventType, string message, params object [] args)
145 if (log_writer != null) {
149 log_writer.Write ("[{0}] ", event_id);
151 TraceCore (TraceEventType.Information, event_id,
152 false, Guid.Empty, // FIXME
154 log_writer.WriteLine (message, args);
157 source.TraceEvent (eventType, event_id, message, args);
165 #region message logging
167 static readonly XmlWriterSettings xws = new XmlWriterSettings () { OmitXmlDeclaration = true };
169 public static void LogMessage (MessageLogSourceKind sourceKind, ref Message msg, long maxMessageSize)
171 if (log_writer != null) {
172 if (maxMessageSize > int.MaxValue)
173 throw new ArgumentOutOfRangeException ("maxMessageSize");
174 var mb = msg.CreateBufferedCopy ((int) maxMessageSize);
175 msg = mb.CreateMessage ();
176 LogMessage (new MessageLogTraceRecord (sourceKind, msg.GetType (), mb));
180 public static void LogMessage (MessageLogTraceRecord log)
182 if (log_writer != null) {
183 var sw = new StringWriter ();
185 var xw = XmlWriter.Create (sw, xws);
187 var doc = new XmlDocument ();
188 var xw = doc.CreateNavigator ().AppendChild ();
190 xw.WriteStartElement ("MessageLogTraceRecord", xmlns);
191 xw.WriteStartAttribute ("Time");
192 xw.WriteValue (log.Time);
193 xw.WriteEndAttribute ();
194 xw.WriteAttributeString ("Source", log.Source.ToString ());
195 xw.WriteAttributeString ("Type", log.Type.FullName);
196 var msg = log.Message.CreateMessage ();
198 msg.WriteMessage (xw);
199 xw.WriteEndElement ();
205 log_writer.Write ("[{0}] ", event_id);
207 TraceCore (TraceEventType.Information, event_id, /*FIXME*/false, /*FIXME*/Guid.Empty, sw);
209 TraceCore (TraceEventType.Information, event_id, /*FIXME*/false, /*FIXME*/Guid.Empty, doc.CreateNavigator ());
211 message_source.TraceData (TraceEventType.Information, event_id, doc.CreateNavigator ());
220 #region XmlWriterTraceListener compatibility
221 static void TraceCore (//TraceEventCache eventCache,
222 /*string source,*/ TraceEventType eventType, int id,
223 bool hasRelatedActivity, Guid relatedActivity,
224 /*int level, bool wrapData, */params object [] data)
226 string source = "mono(dummy)";
228 bool wrapData = true;
231 w.WriteStartElement ("E2ETraceEvent", e2e_ns);
234 w.WriteStartElement ("System", sys_ns);
235 w.WriteStartElement ("EventID", sys_ns);
236 w.WriteString (XmlConvert.ToString (id));
237 w.WriteEndElement ();
238 w.WriteStartElement ("Type", sys_ns);
239 // ...what to write here?
241 w.WriteEndElement ();
242 w.WriteStartElement ("SubType", sys_ns);
243 // FIXME: it does not seem always to match eventType value ...
244 w.WriteAttributeString ("Name", eventType.ToString ());
245 // ...what to write here?
247 w.WriteEndElement ();
248 // ...what to write here?
249 w.WriteStartElement ("Level", sys_ns);
250 w.WriteString (level.ToString ());
251 w.WriteEndElement ();
252 w.WriteStartElement ("TimeCreated", sys_ns);
253 w.WriteAttributeString ("SystemTime", XmlConvert.ToString (DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind));
254 w.WriteEndElement ();
255 w.WriteStartElement ("Source", sys_ns);
256 w.WriteAttributeString ("Name", source);
257 w.WriteEndElement ();
258 w.WriteStartElement ("Correlation", sys_ns);
259 w.WriteAttributeString ("ActivityID", String.Concat ("{", Guid.Empty, "}"));
260 w.WriteEndElement ();
261 w.WriteStartElement ("Execution", sys_ns);
262 w.WriteAttributeString ("ProcessName", "mono (dummy)");
263 w.WriteAttributeString ("ProcessID", "0");
264 w.WriteAttributeString ("ThreadID", Thread.CurrentThread.ManagedThreadId.ToString ());
265 w.WriteEndElement ();
266 w.WriteStartElement ("Channel", sys_ns);
267 // ...what to write here?
268 w.WriteEndElement ();
269 w.WriteStartElement ("Computer");
270 w.WriteString ("localhost(dummy)");
271 w.WriteEndElement ();
273 w.WriteEndElement ();
276 w.WriteStartElement ("ApplicationData", e2e_ns);
277 w.WriteStartElement ("TraceData", e2e_ns);
278 foreach (object o in data) {
280 w.WriteStartElement ("DataItem", e2e_ns);
282 // in moonlight we don't have XPathNavigator, so just use raw string...
284 w.WriteString (o.ToString ());
286 if (o is XPathNavigator)
287 // the output ignores xmlns difference between the parent (E2ETraceEvent and the content node).
288 // To clone such behavior, I took this approach.
289 w.WriteRaw (XPathNavigatorToString ((XPathNavigator) o));
291 w.WriteString (o.ToString ());
294 w.WriteEndElement ();
296 w.WriteEndElement ();
297 w.WriteEndElement ();
299 w.WriteEndElement ();
301 w.Flush (); // for XmlWriter
302 log_writer.WriteLine ();
303 log_writer.Flush (); // for TextWriter
306 static readonly XmlWriterSettings xml_writer_settings = new XmlWriterSettings () { OmitXmlDeclaration = true };
309 // I avoided OuterXml which includes indentation.
310 static string XPathNavigatorToString (XPathNavigator nav)
312 var sw = new StringWriter ();
313 using (var xw = XmlWriter.Create (sw, xml_writer_settings))
314 nav.WriteSubtree (xw);
315 return sw.ToString ();
319 static readonly string e2e_ns = "http://schemas.microsoft.com/2004/06/E2ETraceEvent";
320 static readonly string sys_ns = "http://schemas.microsoft.com/2004/06/windows/eventlog/system";