A few months ago (back at the beginning of March) at the annual offsite meeting my virtual team had in Lisbon, my colleague Doug held an hour session about LogParser and some of the cool features it has. Doug promised to blog about it with more details, so I don’t want to steal him an argument (and he for sure knows more than me on the subject), but I started play with it to analyze some logs I had, and among the others I wrote a couple of scripts to automate some tasks I previously had to do manually, and just wanted to share with you (and post on my blog as a future reference).
So, here’s the deal: you may know from Tess, strong named assemblies should not be deployed in the /bin folder; and if you ever had to troubleshoot a managed memory leak, you probably know that if you have an assembly which is loaded multiple times in memory because you deployed it in the /bin folder of every application you have, it’s a good idea to install it in the GAC to avoid wasting server resources. So far so good, but how to find those assemblies? Well, as you can guess, the first thing is to use WinDBG.
Strong named assemblies in /bin
First, let’s see which assemblies are loaded in the Shared Domain:
1: 0:000> !dumpdomain -stat
2: Loaded Son of Strike data table version 5 from "C:\Windows\Microsoft.NET\Framework\v1.1.4322\mscorsvr.dll"
3: Domain Num Assemblies Size Assemblies Name
4: 0x793f05b8 1 2,138,112 System Domain
5: 0x793f1a88 20 11,731,968 Shared Domain
6: 0x0014af28 2 2,482,176 DefaultDomain
7: 0x00184e88 87 14,065,152 /LM/W3SVC/3/Root/MyTestApp-1-128273920700311250
8:
9: 0:000> !dumpdomain 0x793f1a88
10: Shared Domain: 0x793f1a88
11: LowFrequencyHeap: 0x793f1aec
12: HighFrequencyHeap: 0x793f1b44
13: StubHeap: 0x793f1b9c
14: Assembly: 0x15d44e48 [AjaxPro]
15: ClassLoader: 0x15d6b568
16: Module Name
17: 0x15d792b8 c:\Windows\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyTestApp\b803c58e\4108c9e9\assembly\dl2\eb13c2c4\00ffc7aa_14a1c701\ajax.dll
18:
19: Assembly: 0x15db5ca0 [System.EnterpriseServices]
20: ClassLoader: 0x15d9a6a0
21: Module Name
22: 0x15da1990 c:\Windows\assembly\gac\system.enterpriseservices\1.0.5000.0__b03f5f7f11d50a3a\system.enterpriseservices.dll
23: 0x15e149f0 c:\Windows\assembly\gac\system.enterpriseservices\1.0.5000.0__b03f5f7f11d50a3a\system.enterpriseservices.thunk.dll
24:
25: Assembly: 0x13b7d0 [mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
26: ClassLoader: 0x0013d158
27: Module Name
28: 0x79b7a000 c:\Windows\microsoft.net\framework\v1.1.4322\mscorlib.dll
29:
30: Assembly: 0x15d84470 [INGLibrary]
31: ClassLoader: 0x15d782c8
32: Module Name
33: 0x15d91eb0 c:\Windows\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyTestApp\b803c58e\4108c9e9\assembly\dl2\d6d79113\00ffc7aa_14a1c701\library.dll
Save the !dumpdomain output in a text file, and to the same with the !peb (process environment block) command:
1: 0:000> !peb
2: PEB at 7FFDF000
3: InheritedAddressSpace: No
4: ReadImageFileExecOptions: No
5: BeingDebugged: No
6: ImageBaseAddress: 00420000
7: Ldr.Initialized: Yes
8: Ldr.InInitializationOrderModuleList: 131f48 . 22b790
9: Ldr.InLoadOrderModuleList: 131ec0 . 22b780
10: Ldr.InMemoryOrderModuleList: 131ec8 . 22b788
11: Base TimeStamp Module
12: [...]
13: C:\WINNT\system32\MSASN1.DLL
14: C:\WINNT\Microsoft.NET\Framework\v1.1.4322\diasymreader.dll
15: C:\WINNT\Microsoft.NET\Framework\v1.1.4322\mscorsn.dll
16: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\root\804ee9b4\26f0df32\ruckcqbk.dll
17: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\t7eygstg.dll
18: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\86a3270b\005ce223_3a04c701\MyApp.dll
19: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\786b5a22\00028021_3a04c701\extractadgroups.dll
20: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\1271e8de\00a9138a_1dbac601\interop.activeds.dll
21: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\18ce4216\004ebb1c_3a04c701\mscexceptionhandler.dll
22: c:\winnt\assembly\gac\system.web.services\1.1.5000.0__b03f5f7f11d50a3a\system.web.services.dll
23: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\e318c820\00028021_3a04c701\storeclass.dll
24: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\MyApp\5f12d534\212de01\assembly\dl2\6a0627f3\00ba61a8_fb03c701\eventlogger.dll
25: [...]
26: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\datamenufunctions\2a40e000\d731a401\assembly\dl2\361c9551\00ba61a8_fb03c701\eventlogger.dll
27: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\datamenufunctions\2a40e000\d731a401\assembly\dl2\22d24657\00a81d1f_3a04c701\msesconnect.dll
28: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\datamenufunctions\2a40e000\d731a401\assembly\dl2\e44bca6d\004ebb1c_3a04c701\mscexceptionhandler.dll
29: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\datamenufunctions\2a40e000\d731a401\assembly\dl2\e525577d\002fb122_3a04c701\menuclass.dll
30: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductcounts\ba0b3f7a\19117a01\vvyh8t5h.dll
31: [...]
32: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductprofile\6abb3f96\ce8180e1\assembly\dl2\7515c31f\00d54e20_3a04c701\msesregistry.dll
33: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductprofile\6abb3f96\ce8180e1\assembly\dl2\79d2b595\00d54e20_3a04c701\utils.dll
34: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductprofile\6abb3f96\ce8180e1\assembly\dl2\20aefb4c\004ebb1c_3a04c701\mscexceptionhandler.dll
35: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductprofile\6abb3f96\ce8180e1\assembly\dl2\5eaca388\00a81d1f_3a04c701\msesconnect.dll
36: c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\dataproductprofile\6abb3f96\ce8180e1\assembly\dl2\337945df\00028021_3a04c701\cr.dll
37: [...]
Now that I have those files, I usually have opened them in Excel and with some tweaking I would have filtered the records to only show the files coming from the “temporary asp.net files” folder in the former case, and used the “Highlight duplicates” command in the latter.
Enter LogParser
To automate this process a while ago I wrote a quite simple console application, with a few command line switches to extract those values and it worked well, but then I wanted to get my hands dirty with LogParser to experiment some commands other that the useful ones Doug shared with the team.
So after some attempts to get exactly what I wanted, here are is the batch file for !dumpdomain (Note: I split the command line on multiple rows for reading convenience, but you must place it on a single row to work properly):
1: REM "USAGE: logparser logparser_!dd.bat <input file name> <output file name>"
2:
3: logparser "SELECT EXTRACT_FILENAME(text) as Strong_Named_Assemblies_In_/bin
4: INTO '%1' FROM '%2'
5: WHERE INDEX_OF(text, 'temporary asp.net files') > 0" -i:TEXTLINE -o:NAT -RTP:-1 -fileMode:0
Which outputs something like:
1: Strong_Named_Assemblies_In_/bin
2: -------------------------------
3: ajax.dll
4: library.dll
And here’s the batch for !peb:
1: REM "USAGE: logparser logparser_!peb.bat <input file name> <output file name>"
2:
3: logparser "SELECT EXTRACT_FILENAME(text) as Duplicated_Assemblies, COUNT(Duplicated_Assemblies) as Count
4: INTO '%1' FROM '%2'
5: WHERE INDEX_OF(text, 'temporary asp.net files') > 0
6: GROUP BY Duplicated_Assemblies HAVING COUNT(Duplicated_Assemblies) > 1" -i:TEXTLINE -o:NAT -RTP:-1 -fileMode:0
Which outputs something like:
: Duplicated_Assemblies Count
2: ----------------------- -----
3: mscexceptionhandler.dll 3
4: eventlogger.dll 2
5: msesconnect.dll 2
Conclusions
I realize that maybe there are better ways to do the same, probably Roberto could do the same directly within WinDBG with one of his scripts, but… just take this for what really is: a useful exercise with LogParser and a nice way make dump analysis a bit easier ?
Carlo
Quote of the Day:
It takes a steady hand to carry a full cup.
–Anonymous