Click here to Skip to main content
15,886,787 members
Articles / Programming Languages / Visual Basic

Using custom attributes to add performance counters to your application

Rate me:
Please Sign up or sign in to vote.
4.54/5 (13 votes)
8 Feb 2006CPOL2 min read 79.9K   489   32  
A brief overview of what performance counters are and a library that makes their use a bit easier.
Imports System.Diagnostics
Imports System.Reflection

' Target runtime : v1.1.4322 
' Class name: PerformanceCounterUtilities 
' Created: 2006-1-16 
'
#Region "PerformanceCounterUtilities"

Public Class PerformanceCounterUtilities

#Region "Tracing"
    Public Shared PerformanceCounterUtilitiesTracing As TraceSwitch = New TraceSwitch("PerformanceCounterUtilities", "Performance Counter Utility Library")
#End Region

#Region "UpdatePerformanceCounter"
    ' Takes the object oInput passed in and, given the PerformanceCounterCategory 
    ' and PerformanceCounter attributes passed in to it updates the 
    ' named performance counters with the given values
    Public Overloads Shared Sub UpdatePerformanceCounter(ByVal oInput As Object)

        Dim ObjectType As Type = oInput.GetType
        Dim CounterCategory As PerformanceCounterCategoryAttribute = Attribute.GetCustomAttribute(ObjectType, GetType(PerformanceCounterCategoryAttribute))

        If CounterCategory Is Nothing Then
            '\\ The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute
            If PerformanceCounterUtilitiesTracing.TraceWarning Then
                Trace.WriteLine("The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute", ObjectType.ToString)
            End If
            Debug.Fail(" The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute ")
            Exit Sub
        End If

        '\\ Get the property attributes
        Dim ObjectProperties() As PropertyInfo = ObjectType.GetProperties(BindingFlags.Instance Or BindingFlags.Public)
        Dim PerformanceCounterAttributes As New Collection

        For Each pi As PropertyInfo In ObjectProperties
            If pi.DeclaringType Is ObjectType Then
                Dim pc() As PerformanceCounterAttribute = pi.GetCustomAttributes(GetType(PerformanceCounterAttribute), False)
                If pc.Length > 0 Then
                    PerformanceCounterAttributes.Add(New PropertyToCounterAttributeLink(pc.GetValue(0), pi), pi.Name)
                End If
            End If
        Next

        If Not PerformanceCounterCategory.Exists(CounterCategory.Name) Then
            RebuildPerformanceCounterCategory(oInput)
        End If

        Dim Category As New PerformanceCounterCategory
        Category.CategoryName = CounterCategory.Name

        For Each Counter As PropertyToCounterAttributeLink In PerformanceCounterAttributes
            Try
                If Category.CounterExists(Counter.Attribute.Name) Then
                    Dim CounterInstance As New PerformanceCounter(CounterCategory.Name, Counter.Attribute.Name, "")
                    CounterInstance.ReadOnly = False
                    If Counter.Attribute.UpdateMethod = PerformanceCounterAttribute.PerformanceCounterUpdateMethod.Update_Increment Then
                        CounterInstance.Increment()
                    ElseIf Counter.Attribute.UpdateMethod = PerformanceCounterAttribute.PerformanceCounterUpdateMethod.Update_IncrementBy Then
                        CounterInstance.IncrementBy(RawValueFromProperty(Counter.PropInfo, oInput))
                    Else
                        CounterInstance.RawValue = RawValueFromProperty(Counter.PropInfo, oInput)
                    End If
                    CounterInstance.Close()
                Else
                    If PerformanceCounterUtilitiesTracing.TraceError Then
                        Trace.WriteLine("Counter instance does not exist", Counter.Attribute.Name)
                    End If
                    Debug.Fail("Counter instance does not exist")
                End If
            Catch ex As Exception
                If PerformanceCounterUtilitiesTracing.TraceError Then
                    Trace.WriteLine(ex.ToString, Counter.Attribute.Name)
                End If
                Debug.Fail("Counter instance correctly not created")
            End Try
        Next


    End Sub

    Public Overloads Shared Sub UpdatePerformanceCounter(ByVal oInput As Object, ByVal PropertyInfo As PropertyInfo)

        If PropertyInfo Is Nothing Then
            If PerformanceCounterUtilitiesTracing.TraceError Then
                Trace.WriteLine("Missing property info")
            End If
        End If

        Dim ObjectType As Type = oInput.GetType
        Dim CounterCategory As PerformanceCounterCategoryAttribute = Attribute.GetCustomAttribute(ObjectType, GetType(PerformanceCounterCategoryAttribute))

        If CounterCategory Is Nothing Then
            '\\ The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute
            If PerformanceCounterUtilitiesTracing.TraceWarning Then
                Trace.WriteLine("The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute", ObjectType.ToString)
            End If
            Debug.Fail(" The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute ")
            Exit Sub
        End If

        Dim pc() As PerformanceCounterAttribute = PropertyInfo.GetCustomAttributes(GetType(PerformanceCounterAttribute), False)
        If pc.Length > 0 Then
            With New PropertyToCounterAttributeLink(pc.GetValue(0), PropertyInfo)
                Dim CounterInstance As New PerformanceCounter(CounterCategory.Name, .Attribute.Name, "")
                CounterInstance.ReadOnly = False
                CounterInstance.RawValue = RawValueFromProperty(.PropInfo, oInput)
                CounterInstance.Close()
            End With
        End If

    End Sub

    Public Overloads Shared Sub UpdatePerformanceCounter(ByVal oInput As Object, ByVal PropertyName As String)

        Call UpdatePerformanceCounter(oInput, oInput.GetType.GetProperty(PropertyName))

    End Sub
#End Region

#Region "RebuildPerformanceCounterCategory"
    ' Deletes the performnce category if it exists then recreates it from this
    ' object
    Public Shared Sub RebuildPerformanceCounterCategory(ByVal oInput As Object)

        Dim ObjectType As Type = oInput.GetType
        Dim CounterCategory As PerformanceCounterCategoryAttribute = Attribute.GetCustomAttribute(ObjectType, GetType(PerformanceCounterCategoryAttribute))

        If CounterCategory Is Nothing Then
            '\\ The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute
            If PerformanceCounterUtilitiesTracing.TraceWarning Then
                Trace.WriteLine("The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute", ObjectType.ToString)
            End If
            Debug.Fail(" The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute ")
            Exit Sub
        End If

        RemoveperformanceCounterCategory(oInput)

        '\\ Get the property attributes
        Dim ObjectProperties() As PropertyInfo = ObjectType.GetProperties(BindingFlags.Instance Or BindingFlags.Public)
        Dim PerformanceCounterAttributes As New Collection
        Dim BasePeformanceCounterAttributes As New Collection

        For Each pi As PropertyInfo In ObjectProperties
            If pi.DeclaringType Is ObjectType Then
                Dim pc() As PerformanceCounterAttribute = pi.GetCustomAttributes(GetType(PerformanceCounterAttribute), False)
                If pc.Length > 0 Then
                    PerformanceCounterAttributes.Add(New PropertyToCounterAttributeLink(pc.GetValue(0), pi), pi.Name)
                End If
            End If
        Next

        If Not PerformanceCounterCategory.Exists(CounterCategory.Name) Then
            '\\ Create the performance counter category
            Dim CounterCollection As New CounterCreationDataCollection
            For Each counter As PropertyToCounterAttributeLink In PerformanceCounterAttributes
                CounterCollection.Add(New CounterCreationData(counter.Attribute.Name, counter.Attribute.Description, counter.Attribute.CounterType))
            Next
            Dim category As PerformanceCounterCategory = PerformanceCounterCategory.Create(CounterCategory.Name, CounterCategory.Description, SortCounterCollection(CounterCollection, oInput))
            PerformanceCounter.CloseSharedResources()
        End If

    End Sub
#End Region

#Region "RemovePerformanceCounterCategory"
    Public Shared Sub RemovePerformanceCounterCategory(ByVal oInput As Object)

        Dim ObjectType As Type = oInput.GetType
        Dim CounterCategory As PerformanceCounterCategoryAttribute = Attribute.GetCustomAttribute(ObjectType, GetType(PerformanceCounterCategoryAttribute))

        If CounterCategory Is Nothing Then
            '\\ The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute
            If PerformanceCounterUtilitiesTracing.TraceWarning Then
                Trace.WriteLine("The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute", ObjectType.ToString)
            End If
            Debug.Fail(" The object passed in does have a <PerformaceCounterCategoryAttribute()> attribute ")
            Exit Sub
        End If

        If PerformanceCounterCategory.Exists(CounterCategory.Name) Then
            Try
                PerformanceCounterCategory.Delete(CounterCategory.Name)
            Catch ex As Exception
                If PerformanceCounterUtilitiesTracing.TraceError Then
                    Trace.WriteLine(ex.ToString, CounterCategory.Name)
                End If
                Debug.Fail("Cannot delete this named counter category")
                Exit Sub
            End Try
        End If

    End Sub
#End Region

#Region "RawValueFromProperty"
    Private Shared Function RawValueFromProperty(ByVal pi As PropertyInfo, ByVal o As Object) As Long

        If pi.PropertyType Is GetType(Integer) OrElse pi.PropertyType Is GetType(Int32) OrElse pi.PropertyType Is GetType(Int64) Then
            Return Convert.ToInt64(pi.GetValue(o, Nothing))
        Else
            If Not pi.PropertyType.GetInterface("IList") Is Nothing Then
                Try
                    Return CType(pi.GetValue(o, Nothing), IList).Count
                Catch ex2 As Exception
                    Return 0
                End Try
            End If
        End If

    End Function
#End Region

#Region "PropertyToCounterAttributeLink"
    Private Class PropertyToCounterAttributeLink

        Public Attribute As PerformanceCounterAttribute
        Public PropInfo As PropertyInfo

        Public Sub New(ByVal AttributeIn As PerformanceCounterAttribute, ByVal pInfo As PropertyInfo)
            Attribute = AttributeIn
            PropInfo = pInfo
        End Sub
    End Class
#End Region

#Region "SortCounterCollection"
    Public Shared Function SortCounterCollection(ByVal colIn As CounterCreationDataCollection, ByVal o As Object) As CounterCreationDataCollection

        Dim ObjectType As Type = o.GetType
        Dim colOut As New CounterCreationDataCollection

        '\\ Get the property attributes
        Dim ObjectProperties() As PropertyInfo = ObjectType.GetProperties(BindingFlags.Instance Or BindingFlags.Public)
        Dim PerformanceCounterAttributes As New Collection
        Dim BasePeformanceCounterAttributes As New Collection

        For Each pi As PropertyInfo In ObjectProperties
            If pi.DeclaringType Is ObjectType Then
                Dim pc() As PerformanceCounterAttribute = pi.GetCustomAttributes(GetType(PerformanceCounterAttribute), False)
                    If pc.Length > 0 Then
                        If pc(0).CounterType = PerformanceCounterType.AverageBase OrElse _
                           pc(0).CounterType = PerformanceCounterType.CounterMultiBase OrElse _
                           pc(0).CounterType = PerformanceCounterType.RawBase OrElse _
                           pc(0).CounterType = PerformanceCounterType.SampleBase Then
                            BasePeformanceCounterAttributes.Add(New PropertyToCounterAttributeLink(pc.GetValue(0), pi), pi.Name)
                        Else
                            PerformanceCounterAttributes.Add(New PropertyToCounterAttributeLink(pc.GetValue(0), pi), pi.Name)
                        End If
                End If
            End If
        Next

        For Each pca As PropertyToCounterAttributeLink In PerformanceCounterAttributes
            colOut.Add(New CounterCreationData(pca.Attribute.Name, pca.Attribute.Description, pca.Attribute.CounterType))
            If pca.Attribute.AssociatedBasePropertyName <> "" Then
                Dim pca2 As PropertyToCounterAttributeLink
                pca2 = BasePeformanceCounterAttributes.Item(pca.Attribute.AssociatedBasePropertyName)
                colOut.Add(New CounterCreationData(pca2.Attribute.Name, pca2.Attribute.Description, pca2.Attribute.CounterType))
            End If
        Next

        '\\ Sort the performance counters 
        Return colOut

    End Function
#End Region

End Class

#End Region

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Ireland Ireland
C# / SQL Server developer
Microsoft MVP (Azure) 2017
Microsoft MVP (Visual Basic) 2006, 2007

Comments and Discussions