Tracing logged messages from end-to-end (using WCF Service and a Console Client)

by Jagadish Pulakhandam on 11/14/2012 9:15:41 AM
Rated 0 from 0 votes
Brief: Demonstrates on grouping/tracing messages based on logical operations belonging to the same activity across application domains.
Posted to: Windows Communication Foundation (WCF) Programming
Add to DiggAdd to del.icio.usAdd to FURLAdd to RedditAdd to YahooAdd to BlinklistAdd to GoogleAdd to ma.gnoliaAdd to ShadowsAdd to Technorati

An activity is usually comprised of one or more related "logical" operations (say, a group of operations to perform a task).  These operations might be performed either locally or remotely or even both (and may even through several tiers).  In simple, an activity can span through tiers.

In order to trace the activity (and all its related/logged messages) beyond application domains (say, client-to-service-client), we need to propagate activity across domains.  Once all the operations are part of the same activity (regardless of app domain), we will be able to trace all messages from all tiers of that activity, just by using ActivityID.

An understanding about the sample project atttached:
  • A Console Application which acts as a service client to WCF Service
  • Console Application logs its traces to "TraceOutput-Console.svclog"
  • Console Application creates Activity ID (GUID) using "CorrelationManager"
  • During service request, Console Application sends Activity ID as part of the request header
  • Service receives the request (along with Activity ID) sent by Console Application
  • Service logs its own traces to "TraceOutput-Service.svclog", but uses the same Activity ID sent by Console Application 
  • Returns response to Console Application (client)
  • Console Application (client) still uses the same Activity ID to write more trace information using the same Activity ID.
NOTE: Service should have "Write" access to the file path specified

Screen shots:

1. Console Application displays the output (response) received from WCF Service:

 

2. Trace Files generated by both Service (WCF Service) and Client (Console Application):



3. Trace information create by client (Console Application) - TraceOutput-Console.svclog:



4.  How does the client trace look like in SvcTraceViewer?



5. Trace information created by service (WCF Service) - TraceOutput-Service.svclog:



6.  How does the service trace look like in SvcTraceViewer?



7.  Combined trace of both client and service (just drag both log files into the tool) would look like the following:




Source Code:

1. Client (Console Application):

01.using System;
02.using System.Collections.Generic;
03.using System.Diagnostics;
04.using System.Linq;
05.using System.Text;
06.using ConsoleApplication1.ServiceReference1;
07. 
08.namespace ConsoleApplication1
09.{
10. 
11.    class Program
12.    {
13.        static void Main(string[] args)
14.        {
15.            // set the current Activity ID to a new GUID.
16.            Trace.CorrelationManager.ActivityId = Guid.NewGuid();
17. 
18.            TraceLog.WriteToLog("Sending request to Service");  //writes to trace (along with activity ID)
19.            Service1Client svcClient = new Service1Client();
20.            string result = svcClient.GetData(10); //call to service
21.            TraceLog.WriteToLog("Request Completed");  //writes to trace (along with activity ID)
22. 
23.            Console.WriteLine(result); //display results from service
24.            Console.ReadLine();
25.        }
26.    }
27. 
28.    //You can make this much more generic and make it as part of utils and reuse the same in multiple projects
29.    public class TraceLog
30.    {
31.        private static TraceSource _source;
32. 
33.        static TraceLog()
34.        {
35.            _source = new TraceSource("ConsoleTestSource"); //refactor this for better usage
36.            _source.Switch.Level = SourceLevels.All;
37.            Trace.AutoFlush = true;
38.        }
39. 
40.        protected static TraceSource Source
41.        {
42.            get { return _source; }
43.            set { _source = value; }
44.        }
45. 
46.        public static void SetSource(string name)
47.        {
48.            _source = new TraceSource(name);
49.        }
50. 
51.        public static void WriteToLog(string message)
52.        {
53.            //You can add more methods of this kind to log errors/warnings etc.
54. 
55.            //Source.TraceEvent(TraceEventType.Information, 0, message); //this would also work
56.            Source.TraceInformation(message);
57.        }
58. 
59.        public static string GetAllErrMessages(Exception ex)
60.        {
61.            StringBuilder sb = new StringBuilder();
62.            for (Exception eCurrent = ex; eCurrent != null; eCurrent = eCurrent.InnerException)
63.            {
64.                sb.AppendLine(eCurrent.Message + " at " + eCurrent.Source + ", trace: " + eCurrent.StackTrace);
65.            }
66.            return sb.ToString();
67.        }
68. 
69.        public static void WriteToLog(string message, Exception ex)
70.        {
71.            Source.TraceInformation(message + " - " + GetAllErrMessages(ex));
72.            Source.TraceEvent(TraceEventType.Error, 0, "{0}: {1}", message, ex);
73.        }
74. 
75.    }
76.}


App.Config

01.<?xml version="1.0"?>
02.<configuration>
03.  <system.diagnostics>
04.    <sources>
05. 
06.      <source name="System.ServiceModel" switchValue="Warning" propagateActivity="true" >
07.        <listeners>
08.          <add name="xmlListener"/>
09.        </listeners>
10.      </source>
11. 
12.      <source name="ConsoleTestSource">
13.        <listeners>
14.          <add name="xmlListener"/>
15.        </listeners>
16.      </source>
17. 
18.    </sources>
19. 
20.    <sharedListeners>
21.      <!--<add name="eventListener" type="System.Diagnostics.EventSchemaTraceListener,  System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
22.           initializeData="c:\temp\TraceOutput-Console.xml"
23.           traceOutputOptions="ProcessId, DateTime, Timestamp"
24.           bufferSize="65536"
25.           maximumFileSize="20480000"
26.           logRetentionOption="LimitedCircularFiles"
27.           maximumNumberOfFiles="2"/>-->
28. 
29.      <add name="xmlListener"
30.        type="System.Diagnostics.XmlWriterTraceListener"
31.        initializeData="c:\temp\TraceOutput-Console.svclog" />
32.       
33.    </sharedListeners>
34. 
35.  </system.diagnostics>
36.   
37.  <startup>
38.    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
39.  </startup>
40.  <system.serviceModel>
41.    <bindings>
42.      <basicHttpBinding>
43.        <binding name="SvcBasicHttpBinding" />
44.      </basicHttpBinding>
45.    </bindings>
46.    <client>
47.      <endpoint address="http://localhost/TestSvc/Service1.svc" binding="basicHttpBinding"
48.        bindingConfiguration="SvcBasicHttpBinding" contract="ServiceReference1.IService1"
49.        name="SvcBasicHttpBinding" />
50.    </client>
51.  </system.serviceModel>
52.</configuration>


2. Service (WCF application):

01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using System.Runtime.Serialization;
05.using System.ServiceModel;
06.using System.ServiceModel.Web;
07.using System.Text;
08. 
09.namespace TestSvc
10.{
11.    [ServiceContract]
12.    public interface IService1
13.    {
14. 
15.        [OperationContract]
16.        string GetData(int value);
17. 
18.    }
19. 
20.}

01.using System;
02.using System.Collections.Generic;
03.using System.Diagnostics;
04.using System.Linq;
05.using System.Runtime.Serialization;
06.using System.ServiceModel;
07.using System.ServiceModel.Web;
08.using System.Text;
09. 
10.namespace TestSvc
11.{
12.    public class Service1 : IService1
13.    {
14.        public string GetData(int value)
15.        {
16.            TraceLog.WriteToLog("Value provided was " + value.ToString()); //writes to trace (with propagated/received activity ID)
17.            return string.Format("The square of value provided is: {0}", value * value); //return the result
18.        }
19. 
20.    }
21. 
22.    //Same class used in client - You can make this much more generic and make it as part of utils and reuse the same in multiple projects
23.    public class TraceLog
24.    {
25.        private static TraceSource _source;
26. 
27.        static TraceLog()
28.        {
29.            _source = new TraceSource("ServiceTestSource");  //refactor this for better usage
30.            _source.Switch.Level = SourceLevels.All;
31.            Trace.AutoFlush = true;
32.        }
33. 
34.        protected static TraceSource Source
35.        {
36.            get { return _source; }
37.            set { _source = value; }
38.        }
39. 
40.        public static void SetSource(string name)
41.        {
42.            _source = new TraceSource(name);
43.        }
44. 
45.        public static void WriteToLog(string message)
46.        {
47.            //You can add more methods of this kind to log errors/warnings etc.
48. 
49.            //Source.TraceEvent(TraceEventType.Information, 0, message); //this would also work
50.            Source.TraceInformation(message);
51.        }
52. 
53.        public static string GetAllErrMessages(Exception ex)
54.        {
55.            StringBuilder sb = new StringBuilder();
56.            for (Exception eCurrent = ex; eCurrent != null; eCurrent = eCurrent.InnerException)
57.            {
58.                sb.AppendLine(eCurrent.Message + " at " + eCurrent.Source + ", trace: " + eCurrent.StackTrace);
59.            }
60.            return sb.ToString();
61.        }
62. 
63.        public static void WriteToLog(string message, Exception ex)
64.        {
65.            Source.TraceInformation(message + " - " + GetAllErrMessages(ex));
66.            Source.TraceEvent(TraceEventType.Error, 0, "{0}: {1}", message, ex);
67.        }
68. 
69.    }
70.}

web.config

01.<?xml version="1.0"?>
02.<configuration>
03. 
04.  <system.web>
05.    <compilation debug="true" targetFramework="4.0" />
06.  </system.web>
07. 
08.  <system.diagnostics>
09.    <sources>
10. 
11.      <source name="System.ServiceModel" switchValue="Warning" propagateActivity="true" >
12.        <listeners>
13.          <add name="xmlListener"/>
14.        </listeners>
15.      </source>
16. 
17.      <source name="ServiceTestSource">
18.        <listeners>
19.          <add name="xmlListener"/>
20.        </listeners>
21.      </source>
22. 
23.    </sources>
24. 
25.    <sharedListeners>
26.      <!--<add name="eventListener" type="System.Diagnostics.EventSchemaTraceListener,  System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
27.           initializeData="c:\temp\TraceOutput-Console.xml"
28.           traceOutputOptions="ProcessId, DateTime, Timestamp"
29.           bufferSize="65536"
30.           maximumFileSize="20480000"
31.           logRetentionOption="LimitedCircularFiles"
32.           maximumNumberOfFiles="2"/>-->
33. 
34.      <add name="xmlListener"
35.        type="System.Diagnostics.XmlWriterTraceListener"
36.        initializeData="c:\temp\TraceOutput-Service.svclog" />
37. 
38.    </sharedListeners>
39. 
40.  </system.diagnostics>
41. 
42. 
43. 
44.  <system.serviceModel>
45.    <services>
46.      <service behaviorConfiguration="SvcBehavior" name="TestSvc.Service1">
47.        <endpoint address="" binding="basicHttpBinding" bindingConfiguration=""
48.          name="SvcBasicHttpBinding" contract="TestSvc.IService1" />
49.        <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
50.          name="SvcMex" contract="IMetadataExchange" />
51.        <host>
52.          <baseAddresses>
53.            <add baseAddress="http://localhost/TestSvc" />
54.          </baseAddresses>
55.        </host>
56.      </service>
57.    </services>
58.    <behaviors>
59.      <serviceBehaviors>
60.        <behavior name="SvcBehavior">
61.          <serviceMetadata httpGetEnabled="true" />
62.          <serviceDebug includeExceptionDetailInFaults="true" />
63.        </behavior>
64.      </serviceBehaviors>
65.    </behaviors>
66.    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
67.  </system.serviceModel>
68. <system.webServer>
69.    <modules runAllManagedModulesForAllRequests="true"/>
70.  </system.webServer>
71.   
72.</configuration>



Rated 0 from 0 votes ( login  to rate)
DotnetKicks DotnetKicksDe DotNetShoutout


Discussion
No comments yet!