Making an Argument for SNAP


One of the really cool things about working on and having the community use your tools is sometimes you get really great feedback and suggestions. Recently Heiko Hatzfeld from Microsoft PFE suggested we include method parameter or argument details into the output details produced by SNAP when it takes a snap of a process.

For each method argument I decided to capture several bits of data including the name, type, and value. I also included an isArray boolean which is set to true when the argument is an array and isComplex which is set to true when the argument is a complex type. If the value of the argument is null I write NULL to the output otherwise I try to capture the best string representation of the value available. When the target application and/or assemblies are compiled as Debug (optimizations off) you will get much more detail in almost every argument vs when the snap target is built in Release. For example, take a look at a very simple test application below which I used as the target for the SNAP logs I detail below.

class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                try
                {
                    Thread.Sleep(1000);
                    new Foo().CallingFoo(33);
                }
                catch
                {
                }
            }
        }

        private class Foo
        {
            public void CallingFoo(int value)
            {
                var f = value;
                new Bar().CallingBar(new[] {1,2,3});
            }
        }

        private class Bar
        {
            public void CallingBar(int[] args)
            {
                new FooBar().CallingFooBar("Some Message");
            }
        }

        private class FooBar
        {
            public void CallingFooBar(string msg)
            {
                Console.WriteLine("throwing Exception");
                Thread.Sleep(5000);
                throw new ArgumentException("Dummy Exception!");
            }
        }
    }

As you can see from the application code above I have several classes which have methods which each take one argument of different types and I set different values for each.

Here is an example of what SNAP captured while running the test application which was compiled in Debug. Note each argument’s name, type name, value and other information are available in almost every case. Keep in mind that it is only the test application that is compiled in Debug and calls into the .Net Framework will not have this level of detail as they are typically compiled for Release.

<?xml version="1.0" encoding="utf-8"?>
<snap version="1.9.4.1" whenTaken="2012-09-04 08:31:26" whenTakenUtc="2012-09-04 13:31:26" machine="TODDCA4" timeTakenInMs="222" user="Toddca">
  <process name="TestApp" id="11020" appPool="" uptime="00:00:02.0801190" privateBytesInMB="4" virtualBytesInMB="107" handleCount="134">
    <threads count="1">
      <thread id="9552" number="0">
        <stack hash="-1516059331">
          <frames count="5">
            <frame method="System.Threading.Thread.Sleep" module="C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll" hash="-2118368882">
              <arguments count="1">
                <argument name="millisecondsTimeout" value="NULL" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program+FooBar.CallingFooBar" module="C:devMySnapTestAppbinDebugTestApp.exe" hash="-1997173101">
              <arguments count="1">
                <argument name="msg" type="System.String" value="&quot;Some Message&quot;" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program+Bar.CallingBar" module="C:devMySnapTestAppbinDebugTestApp.exe" hash="1057856647">
              <arguments count="1">
                <argument name="args" type="System.Int32[]" value="array [3]" isArray="true" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program+Foo.CallingFoo" module="C:devMySnapTestAppbinDebugTestApp.exe" hash="624225995">
              <arguments count="1">
                <argument name="value" type="System.Int32" value="33" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program.Main" module="C:devMySnapTestAppbinDebugTestApp.exe" hash="917400010">
              <arguments count="1">
                <argument name="args" type="System.String[]" value="array [0]" isArray="true" isComplexType="false" />
              </arguments>
            </frame>
          </frames>
        </stack>
      </thread>
    </threads>
  </process>
</snap>

How here is an example of what SNAP captured while running the test application, compiled in Release. Note there is not any type information available and the values always seem to be NULL. In addition, you can see that you cannot always depend upon this isArray (or isComplex) to be always accurate as we know CallingFoo’s argument is an array of integers.

<?xml version="1.0" encoding="utf-8"?>
<snap version="1.9.4.1" whenTaken="2012-09-04 08:25:59" whenTakenUtc="2012-09-04 13:25:59" machine="TODDCA4" timeTakenInMs="230" user="Toddca">
  <process name="TestApp" id="10588" appPool="" uptime="00:00:02.0120070" privateBytesInMB="4" virtualBytesInMB="107" handleCount="133">
    <threads count="1">
      <thread id="9608" number="0">
        <stack hash="1222172973">
          <frames count="3">
            <frame method="TestApp.Program+FooBar.CallingFooBar" module="C:devMySnapTestAppbinReleaseTestApp.exe" hash="-1437933078">
              <arguments count="1">
                <argument name="msg" value="NULL" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program+Foo.CallingFoo" module="C:devMySnapTestAppbinReleaseTestApp.exe" hash="1183466018">
              <arguments count="1">
                <argument name="value" value="NULL" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
            <frame method="TestApp.Program.Main" module="C:devMySnapTestAppbinReleaseTestApp.exe" hash="1476640033">
              <arguments count="1">
                <argument name="args" value="NULL" isArray="false" isComplexType="false" />
              </arguments>
            </frame>
          </frames>
        </stack>
      </thread>
    </threads>
  </process>
</snap>

So I hope you guys enjoy the latest update to SNAP and keep your suggestions, ideas, and comments coming. I cannot promise that I can implement all ideas but I do read every bit of email I receive and consider each good idea.

As always you can download the latest version of snap from HERE

Thanks and Happy Debugging

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s