Stuff Every .NET App Should be Logging at Startup

In my opinion, a large part of being a good developer is ensuring the applications you build are maintainable and easy to debug both during development and after deployment. This becomes even more important if you work in the enterprise with plethora of complicated interdependent systems deployed regularly and the army of people constantly making changes to it; In such environments tasks such as maintaining, troubleshooting and monitoring the system is of tremendous value.

Unless all you build are HelloWorld applications which never get deployed anywhere you almost certainly have come across cases where either you or your support team have had to figure out:

  • What is causing that OutOfMemory exception?
  • Why is there such a performance degradation after the last release?
  • Why is the DLL I have referenced not doing what it is supposed to?
  • What system is my app running in?
  • What arguments the app has started with?
  • What version of JSON.NET is the app using?
  • ...

Over the years I have found myself and my colleagues spending precious time trying to deal with finding the answers to such questions over and over again particularly at times where there are production issues and downtime could cost the business a lot of money. So today I have decided to share with you a helper class I built a while back which can help answer such questions more proactively. The idea is to log the report generated by this class at the start of your application and if required on demand or at certain intervals.

The class is very simple to use and currently supports Windows, Linux and OSX:

DiagnosticReport report = DiagnosticReport.Generate();  
Console.WriteLine(report.ToString());  

Which then generates a report that looks like:

  

/
|Diagnostic Report generated at: 13-11-2017 18:14:41.174 (+00:00) in: 849.7042 milliseconds.
|
|System|..................................................................
|
|    . OS - Name         : Microsoft Windows 10.0.14393 
|    . OS - Type         : Windows (Server)
|    . OS - 64Bit        : True
|    . CLR Runtime       : .NET Framework 4.7.2110.0
|    . FQDN              : MyServer
|    . Machine Name      : MyServer.
|    . User              : MyServer\admin
|    . CPU               : Intel(R) Xeon(R) CPU E5-2673 v3 @ 2.40GHz
|    . CPU Core Count    : 2
|    . Installed RAM     : 16GB
|    . System Directory  : C:\Windows\system32
|    . Current Directory : C:\Users\admin\SampleApp
|    . Runtime Directory : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
|    . Uptime            : 20Day 12Hour 00Min 08Sec
|
|Process|......................................................................................................
|
|    . Id                  : 348
|    . Name                : LINQPad.UserQuery
|    . Started             : 13-11-2017 18:13:18.161 (+00:00)
|    . Loaded In           : 00:01:23.1225614
|    . Interactive         : True
|    . Optimized           : True
|    . 64Bit Process       : True
|    . Server GC           : True
|    . Large Address Aware : True
|    . WorkingSet          : 42MB
|    . Threads             : 88
|    . IO Threads          : 24 <-> 1,000
|    . Worker Threads      : 24 <-> 32,767
|    . File Version        : 1.0.0.0
|    . Product Version     : 1.0.0.0
|    . Language            : Language Neutral
|    . Copyright           : Copyright © Nima Ara 2017
|    . Original File Name  : LINQPad.UserQuery.exe
|    . File Name           : C:\Users\admin\AppData\Local\LINQPad\ProcessServer5AnyCPUB\LINQPad.UserQuery.exe
|    . Module Name         : LINQPad.UserQuery.exe
|    . Module File Name    : C:\Users\admin\AppData\Local\LINQPad\ProcessServer5AnyCPUB\LINQPad.UserQuery.exe
|    . Product Name        : A Sample Query
|    . CommandLine         : C:\Users\admin\AppData\Local\LINQPad\ProcessServer5AnyCPUB\LINQPad.UserQuery.exe
|                            C:/Program Files/LINQPad5/LINQPad.EXE
|                            C:/Program Files/LINQPad5/
|                            C:/Program Files/LINQPad5/LINQPad.config
|                            LINQPad.ivddgmnj.Server.2
|                            ivddgmnj
|                            4328
|                            True
|
|Drives|.......................................................................................
|
|     -----------------------------------------------------------------------------------------
|    | Name | Type      | Format | Label             | Capacity(GB) | Free(GB) | Available(GB) |
|    |------|-----------|--------|-------------------|--------------|----------|---------------|
|    | A:\  | Removable |        |                   | 0            | 0        | 0             |
|    | C:\  | Fixed     | NTFS   |                   | 127          | 108      | 108           |
|    | D:\  | Fixed     | NTFS   | Temporary Storage | 14           | 13       | 13            |
|    | E:\  | CDRom     |        |                   | 0            | 0        | 0             |
|     -----------------------------------------------------------------------------------------
|
|Assemblies|........................................................................................................................................
|
|    001| Name      : mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll
|    
|    002| Name      : System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
|    
|    003| Name      : System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
|    
|    004| Name      : System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
|    
|    005| Name      : System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
|    
|    006| Name      : System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
|    
|    007| Name      : System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
|    
|    008| Name      : System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml.Linq/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.Linq.dll
|    
|    009| Name      : System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Data.Linq.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Data.Linq/v4.0_4.0.0.0__b77a5c561934e089/System.Data.Linq.dll
|    
|    010| Name      : System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_64/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
|    
|    011| Name      : Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
|       . GAC       : True
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll
|       . CodeBase  : file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.CSharp/v4.0_4.0.0.0__b03f5f7f11d50a3a/Microsoft.CSharp.dll
|    
|    012| Name      : LINQPad, Version=1.0.0.0, Culture=neutral, PublicKeyToken=21353812cd2a2db5
|       . GAC       : False
|       . 64Bit     : True
|       . Optimized : False
|       . Framework : .NETFramework,Version=v4.5.2
|       . Location  : C:\Program Files\LINQPad5\LINQPad.exe
|       . CodeBase  : file:///C:/Program Files/LINQPad5/LINQPad.EXE
|    
|    013| Name      : LINQPad.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=21353812cd2a2db5
|       . GAC       : False
|       . 64Bit     : True
|       . Optimized : False
|       . Framework : .NETFramework,Version=v4.5.2
|       . Location  : 
|       . CodeBase  : file:///C:/Program Files/LINQPad5/LINQPad.exe
|    
|    014| Name      : query_viulpd, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|       . GAC       : False
|       . 64Bit     : True
|       . Optimized : False
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Users\admin\AppData\Local\Temp\2\LINQPad5\_tqnmweww\query_viulpd.dll
|       . CodeBase  : file:///C:/Users/admin/AppData/Local/Temp/2/LINQPad5/_tqnmweww/query_viulpd.dll
|    
|    015| Name      : Easy.Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|       . GAC       : False
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NETFramework,Version=v4.5
|       . Location  : C:\Users\admin\AppData\Local\Temp\2\LINQPad5\_tqnmweww\shadow_ebuhxn\easy.common.dll
|       . CodeBase  : file:///C:/Users/admin/AppData/Local/Temp/2/LINQPad5/_tqnmweww/shadow_ebuhxn/easy.common.dll
|    
|    016| Name      : System.Runtime.InteropServices.RuntimeInformation, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
|       . GAC       : False
|       . 64Bit     : True
|       . Optimized : True
|       . Framework : .NET 2, 3 or 3.5
|       . Location  : C:\Users\admin\AppData\Local\Temp\2\LINQPad5\netstandard2\System.Runtime.InteropServices.RuntimeInformation.dll
|       . CodeBase  : file:///C:/Users/admin/AppData/Local/Temp/2/LINQPad5/netstandard2/System.Runtime.InteropServices.RuntimeInformation.dll
|
|Environment-Variables|..................................................................................................................................................................................................
|
|    001. ALLUSERSPROFILE           : C:\ProgramData
|    002. APPDATA                   : C:\Users\admin\AppData\Roaming
|    003. CLIENTNAME                : SomeClient
|    004. CommonProgramFiles        : C:\Program Files\Common Files
|    005. CommonProgramFiles(x86)   : C:\Program Files (x86)\Common Files
|    006. CommonProgramW6432        : C:\Program Files\Common Files
|    007. COMPUTERNAME              : MyServer
|    008. ComSpec                   : C:\Windows\system32\cmd.exe
|    009. HOMEDRIVE                 : C:
|    010. HOMEPATH                  : \Users\admin
|    011. LOCALAPPDATA              : C:\Users\admin\AppData\Local
|    012. LOGONSERVER               : \\MyServer
|    013. NUMBER_OF_PROCESSORS      : 2
|    014. OS                        : Windows_NT
|    015. Path                      : C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\LINQPad5;C:\Users\admin\AppData\Local\Microsoft\WindowsApps;
|    016. PATHEXT                   : .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
|    017. PROCESSOR_ARCHITECTURE    : AMD64
|    018. PROCESSOR_IDENTIFIER      : Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
|    019. PROCESSOR_LEVEL           : 6
|    020. PROCESSOR_REVISION        : 3f02
|    021. ProgramData               : C:\ProgramData
|    022. ProgramFiles              : C:\Program Files
|    023. ProgramFiles(x86)         : C:\Program Files (x86)
|    024. ProgramW6432              : C:\Program Files
|    025. PSModulePath              : C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files\Microsoft Monitoring Agent\Agent\PowerShell\
|    026. PUBLIC                    : C:\Users\Public
|    027. SESSIONNAME               : RDP-Tcp#58
|    028. SystemDrive               : C:
|    029. SystemRoot                : C:\Windows
|    030. TEMP                      : C:\Users\admin\AppData\Local\Temp\2
|    031. TMP                       : C:\Users\admin\AppData\Local\Temp\2
|    032. USERDOMAIN                : MyServer
|    033. USERDOMAIN_ROAMINGPROFILE : MyServer
|    034. USERNAME                  : admin
|    035. USERPROFILE               : C:\Users\admin
|    036. windir                    : C:\Windows
|
|Networks|.....................................................................
|
|    . Windows IP Configuration
|      -------------------------
|      | Host               : MyServer
|      | Domain             : 
|      | DHCP Scope         : 
|      | Node Type          : Hybrid
|      | Is WINS Proxy      : False
|    
|    . Microsoft Hyper-V Network Adapter #2
|      -------------------------------------
|      | Name               : Ethernet 2
|      | MAC                : 00:0D:3B:A3:D6:AC
|      | Type               : Ethernet
|      | Status             : Up
|      | Supports Multicast : True
|      | Is Receive Only    : False
|      | Speed              : 10,000 Mbit/s
|      | IP Addresses       : [1.2.3.4]
|    
|    . Software Loopback Interface 1
|      ------------------------------
|      | Name               : Loopback Pseudo-Interface 1
|      | MAC                : 
|      | Type               : Loopback
|      | Status             : Up
|      | Supports Multicast : True
|      | Is Receive Only    : False
|      | Speed              : 1,073 Mbit/s
|    
|    . Microsoft ISATAP Adapter #2
|      ----------------------------
|      | Name               : isatap.MyServer.a8.internal.cloudapp.net
|      | MAC                : 00:00:00:00:00:00:00:E0
|      | Type               : Tunnel
|      | Status             : Down
|      | Supports Multicast : False
|      | Is Receive Only    : False
|      | Speed              : 0 Mbit/s
|    
|    . Teredo Tunneling Pseudo-Interface
|      ----------------------------------
|      | Name               : Teredo Tunneling Pseudo-Interface
|      | MAC                : 00:00:00:00:00:00:00:E0
|      | Type               : Tunnel
|      | Status             : Up
|      | Supports Multicast : False
|      | Is Receive Only    : False
|      | Speed              : 0 Mbit/s
|    
\

What does it produce?

The above report was generated in about 849 milliseconds on its first run and contains various information that are relevant to your application. This information has been categorised into six main sections which you can find in more detail at the bottom of this article but here's an overview:

  1. System
  2. Process
  3. Drives
  4. Assemblies
  5. Environment Variables
  6. Networking

If you are not interested in generating the full report, you have the option to only generate a specific section:

var drivesReport = DiagnosticReport.Generate(DiagnosticReportType.Drives);  

or combine multiple sections:

var drivesAndNetworkingReport = DiagnosticReport.Generate(  
       DiagnosticReportType.Drives | DiagnosticReportType.Networking);

or only exclude a specific section:

var partialReport = DiagnosticReport.Generate(  
       DiagnosticReportType.Full &~ DiagnosticReportType.EnvironmentVariables);

It is as simple as that!

Where do I find it?

You can see the source of the class in DiagnosticReport and can start generating your own reports by referencing the Easy.Common NuGet package from your .NET or .NET Core app.

What information is covered?

System

Contains information relating to the system under which the application is running:

  • The name of the operating system
  • The type of the operating system e.g Windows, Linux or OSX
  • The flag indicating whether the operating system is 64-bit capable
  • The version of the CLR
  • The Fully Qualified Domain Name (FQDN)
  • The machine name
  • The user under which the process is running
  • The processor name
  • The number of processor cores including Hyper Threading
  • The number of installed RAM
  • The location of the System directory
  • The location of the Current directory the application is running
  • The location where the CLR is installed
  • The duration the system has been up
Process

Contains information relating to the current process:

  • The process ID (PID)
  • The process name
  • The time at which the process was started
  • The time taken for the process to be loaded
  • The flag indicating whether the process is running in User Interactive mode (This will be false for a Windows Service or a service such as IIS that runs without a UI)
  • The flag indicating whether the application has been compiled in Release mode
  • The flag indicating whether the process is 64-bit
  • The flag indicating whether the GC mode is Server
  • The flag indicating whether the process is Large Address Aware
  • The current value of Working Set memory (RAM) in use by the process. This value includes both Shared and Private memory
  • The number of threads owned by the process
  • The minimum and maximum number of IO Completion Port threads
  • The minimum and maximum number of Thread Pool Worker threads
  • The file version of the process
  • The version of the product the process is distributed with
  • The default language for the process
  • The copyright notices that apply to the process
  • The name of the file the process was created as
  • The file name representing the process
  • The name of the process module
  • The file representing the process module
  • The name of the product the process is distributed with
  • The CommandLine including any arguments passed into the process
Drives

Contains information relating to the system drives including Fixed as well as Removable ones:

  • The name of the drive
  • The type of the drive e.g. Fixed, CDRom etc.
  • The format of the drive e.g. NTFS
  • The label of the drive
  • The capacity of the drive
  • The total amount of free space available on the drive (not just what is available to the current user)
  • The amount of free space available on the drive (this value takes into account disk quotas)
Assemblies

Contains information relating to the assemblies which have been loaded by the process:

  • The full name of the assembly
  • The flag indicating whether the assembly has been loaded from the GAC
  • The flag indicating whether the assembly is 64-bit
  • The flag indicating whether the assembly has been compiled in Release mode
  • The framework for which the assembly has been compiled
  • The location from which the assembly has been loaded from
  • The path to the location where the assembly was found. (If the assembly was downloaded from the web, this value may start with http)
Environment Variables

Contains the name and value of the environment variables available to the process.

Networking

Contains information relating to the networking infrastructure available to the process:

  • Windows IP Configuration including:
    • Host name
    • DNS details
  • Adapter information:
    • Name & descritption
    • Physical address (MAC)
    • IP addresses
    • DHCP details
    • Status
    • Speed

Nima Ara

@NimaAra