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
Comments
Anonymous
March 25, 2009
PingBack from http://blog.a-foton.ru/index.php/2009/03/25/reading-perfmon-counters-in-t-sql-with-clr/Anonymous
April 14, 2009
The comment has been removedAnonymous
April 14, 2009
The comment has been removedAnonymous
April 15, 2009
Dim perfCounter As New System.Diagnostics.PerformanceCounter(Category, Counter, Instance, ".") or System.Diagnostics.PerformanceCounter(Category, Counter, Instance, "localhost") shouldn't make much of a difference. On my system it runs (Win2008 Ent) but it could differ on other windows versions. Thanks for the tip!Anonymous
March 05, 2010
The comment has been removedAnonymous
March 09, 2010
The comment has been removed