Reading PerfMon Counters in T-SQL with CLR

A collegue of mine asked me if it is possible to read out PerfMon counters that are not in the sys.dm_os_performance_counters DMV. I searched everywhere but the only possibility I could think of is by using a CLR user defined function.

So I wrote an assembly (I'm still a VB programmer, I never bothered to learn C#. And I'm never going to as long as VB.Net exists J ):

 

The code is fairly simple:

Imports System

Imports System.Data

Imports System.Data.SqlClient

Imports System.Data.SqlTypes

Imports Microsoft.SqlServer.Server

 

Partial
Public
Class UserDefinedFunctions

    <Microsoft.SqlServer.Server.SqlFunction()> _

    Public
Shared
Function ReadPerfMonCounter(ByVal Category As
String, ByVal Counter As
String, ByVal Instance As
String) As SqlString

        '******************************************************************************

        '* Disclaimer: I'm a lousy programmer!!!!                                     *

        '* ****************************************************************************

 

        Dim sTemp As
String

        Try

            Dim perfCounter As
New System.Diagnostics.PerformanceCounter(Category, Counter, Instance, "localhost")

 

            'Somehow it won't return a result on the first NextValue call.

            'Never mind: we just call it 2 times :).

            sTemp = perfCounter.NextValue().ToString

 

            'And wait a little while, but now she's ready to go.

            Threading.Thread.Sleep(1000)

 

            Return
New SqlString(perfCounter.NextValue.ToString)

        Catch ex As Exception

            Return
New SqlString(ex.Message)

        End
Try

 

    End
Function

End
Class

 

The only problem I had was the problem that the NextValue method of the perfCounter didn't return anything but 0 on its first call. That's why I call it 2 times now.

Once compiled you can deploy this assembly on your server. If you don't have .Net but want the assembly, just mail me.

I deployed it to the AdventureWorksTest database, which is a copy of the regular AdventureWorks database.

 

If you deploy it make sure your database has TRUSTWORTHY ON because I didn't sign the assembly. This assembly needs unrestricted access. That's unsafe on SQL 2005.

 

When you have done all that you can use a select statement like:

SELECT
AdventureWorksTest.dbo.ReadPerfMonCounter('PhysicalDisk','% Idle Time','0 C: D: E:');

 

That's all. Error handling could be better by the way. When you make a typo in your counter you'll wait forever instead of getting an error.

If you don't like the unsafe setting on the assembly you could transfer that part to a class library and reference it from your .NET stored procedure. Plenty opportunities left….

I didn't bother on execution context and all that. On my machine the service account is a local admin. You might need some impersonification code if not.

 

Regards,

Menzo