Performance Counters: Creazione Custom Performance Counters

Introduzione

Nel mio ultimo progetto ho avuto necessita di utiliizzare alcuni performance counter per misuare la durata di alcuni processi del nostro sistema e di poter avere in tempo  reale anche la possibilita’ di visualizzare contatatori di processi paralleli (job e window service)

Abbiamo iniziato a creare un performance counter manager per alcune parti del nostro sistema che rimanevano in ascolto per tutta la durata dell’operazione.

Abbiamo creato un SamplePerformanceCounterManager come helper per poter creare i nostril performance counters e poi per poterli utilizzare in altre parti del sistema.

Prima di continuare con il codice,  consiglio di leggere i seguenti link che mi hanno aiutato nel capire e poi nell’utilizzare i performance counter (Questo e’ un semplice tutorial che spiega come ho utilizzato i custom performance counters, senza volte entrare in dettaglio sull’argomento performance counter. ) :

http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx

http://www.codeproject.com/Articles/8590/An-Introduction-To-Performance-Counters

SamplePerformanceCounterManager

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using log4net;
using Castle.Core; //Use for Singleton.

namespace SamplePeromrmanceCounter.Core.Diagnostics
{
[Singleton]
sealed class SamplePerformanceCounterManager : ISamplePerformanceCounterManager
{
//Logging
private static readonly ILog log = LogManager.GetLogger(typeof(SamplePerformanceCounterManager));

//Name of the Category of the PerfCounter group
private const string PERFCOUNTER_CATEGORY_KEY = "PerfCounter Group";

//Name of the PerfCounter
private const string PERCOUNTER_CUSTOM1 = "Performance Counter Custom 1";
private const string PERCOUNTER_CUSTOM2 = "Performance Counter Custom 2";

///
/// True if the performance counters are configured and ready to use.
/// If not, be sure to have ran the SetupPerformanceCounters method before access the performance counter values.
///
public bool IsPerformanceCountersReady { get; private set; }

public SamplePerformanceCounterManager()
{
this.IsPerformanceCountersReady = false;
}

#region Performance Counters

#region PERCOUNTER_CUSTOM1

private volatile PerformanceCounter _custom1PerfCounter;
private readonly object _perCounterCustom1SyncLock = new object();
private PerformanceCounter Custom1PerfCounter
{
get
{
if (_custom1PerfCounter == null)
{
lock (_perCounterCustom1SyncLock)
{
if (_custom1PerfCounter == null) // double-check
{
// Gestisco l'errore perchè il counter potrebbe non essere pronto
try
{
_custom1PerfCounter = new PerformanceCounter(PERFCOUNTER_CATEGORY_KEY, PERCOUNTER_CUSTOM1, false);
}
catch (Exception ex)
{
_custom1PerfCounter = null;
log.Error(string.Format("Errore durante la creazione del performance counter '{0}'.", PERCOUNTER_CUSTOM1), ex);
}
}
}
}
return _custom1PerfCounter;
}
}

///
/// GET/SET VALUE FOR PERF COUNTER.
///
public long PerfCounterCount1
{
get
{
try
{
if (CheckConfiguration())
{
return this.Custom1PerfCounter.RawValue;
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
return 0;
}
set
{
try
{
if (CheckConfiguration())
{
//DONE SET VALUE
this.Custom1PerfCounter.RawValue = value;
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
}
}

#endregion

#endregion

private const string MUTEX_NAME = @"Global\SamplePeromrmanceCounter.Core.Diagnostics.SamplePerformanceCounters";

///
/// Creates all the performance counters. If they already exists, they are destroyed and recreated.
///
public void SetupPerformanceCounters()
{
Mutex globalLock = null;

try
{
this.IsPerformanceCountersReady = false;

// Utilizzo un lock globale di sistema, per non eseguire il setup contemporaneo tra 2 processi diversi
globalLock = new Mutex(false, MUTEX_NAME);

// Aspetto fino a che il lock non viene rilasciato, assegno un timeout di 30 secondi per sicurezza.
if (!globalLock.WaitOne(TimeSpan.FromSeconds(30)))
{
log.WarnFormat("Cannot setup the performance counter: timeout acquiring the lock on '{0}' mutex lock. Setup aborted.", MUTEX_NAME);

// Imposto il manager come se avesse installato correttamente i counter, perchè se entro in questo timeout, vuol dire che un'altra applicazione li sta installando.
this.IsPerformanceCountersReady = true;

return;
}

// Se la categoria non esiste,
if (PerformanceCounterCategory.Exists(PERFCOUNTER_CATEGORY_KEY))
{
PerformanceCounterCategory.Delete(PERFCOUNTER_CATEGORY_KEY);

CounterCreationDataCollection counterCreationDataCollection = new CounterCreationDataCollection();

// Counter
CounterCreationData perfCouterCustom1Counter = new CounterCreationData();
perfCouterCustom1Counter.CounterType = PerformanceCounterType.NumberOfItems64;
perfCouterCustom1Counter.CounterName = PERCOUNTER_CUSTOM1;
perfCouterCustom1Counter.CounterHelp = "help about counter... bla bla bla";
counterCreationDataCollection.Add(perfCouterCustom1Counter);

PerformanceCounterCategory.Create(
PERFCOUNTER_CATEGORY_KEY,
"Contains the counters.",
PerformanceCounterCategoryType.SingleInstance,
counterCreationDataCollection);
}
this.IsPerformanceCountersReady = true;
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
finally
{
try
{
if (globalLock != null)
{
globalLock.ReleaseMutex();
globalLock.Dispose();
}
}
catch (Exception ex)
{
log.Error("Error while trying to ReleaseMutex on the global lock.", ex);
}
}
}

///
/// Reset all the counters, set them to the default value.
///
public void ResetAllCounters()
{
this.PerfCounterCount = 0;
}

private bool CheckConfiguration()
{
if (!this.IsPerformanceCountersReady)
{
log.Error("Cannot access the performance counters in this object state. You should run first the SetupPerformanceCounters method.");
}
return this.IsPerformanceCountersReady;
}
}
}

Il codice allegato e’ una semplice classe per la creazione e la gestione centralizzata ei performance counters. Tramite questa classe posso creare ed utilizzare i miei perfcounter in modo semplice in tutte le parte del mio codice.

Il codice si divide in 3 parti:

PERCOUNTER_CUSTOM1 : In questa region c’e’ tutta la gestione del performance counter. Con la proprieta’ PerfCounterCount1 “setto e getto” il valore del mio performance counter nelle parti del mio codice. Quando vado a impostare il valore della proprieta’, vado a controllare se il perfCounter e’ gia’ in lock o no. per non avere errori o problem legati al suo utilizzo.

SetupPerformanceCounters : e’ il setup per la creazione del gruppo e dei vari performance

CounterCreationData perfCouterCustom1Counter = new CounterCreationData();
perfCouterCustom1Counter.CounterType = PerformanceCounterType.NumberOfItems64;
perfCouterCustom1Counter.CounterName = PERCOUNTER_CUSTOM1;
perfCouterCustom1Counter.CounterHelp = "help about counter... bla bla bla";
counterCreationDataCollection.Add(perfCouterCustom1Counter);

Con questo codice, vado a creare e a tipizzare il counter. In questo caso il counter e’ di tipo NumberOfItems64 , per comprendere tutti i tipi possibili di performance counter, rimando al seguente link ufficiale della http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx

Il mio codice e’ fatto in modo che ogni volta, il mio gruppo di performance counter viene cancellato e ricreato da zero.

if (PerformanceCounterCategory.Exists(PERFCOUNTER_CATEGORY_KEY))
{
PerformanceCounterCategory.Delete(PERFCOUNTER_CATEGORY_KEY);
…..

Se ogni cosa e’ andata a buon fine, sul monitor dei performance counters  vedro’ una nuova categoria :
PerfCounter Group

PerfMon

Implementare i performance counter

Adesso che abbiamo creato i performance counters, come facciamo a valorizzarli automaticamente? Semplicemente implementando nel codice che vogliamo monitorare i nostri performance counters:

Prima di tutto chiameremo il nostro manager:

readonly ISamplePerformanceCounterManager _sampleCounterManager = null;

Poi imposteremo il nuovo valore nel perfCounter in questo modo:

_sampleCounterManager.PerfCounterCount1 = <i>value</i>;

Naturalmente questa chiamata dovra’ essere inserita in un timer o in un task per esempio . In questo modo ogni volta che il mio codice verra’ chiamato, il perfCouter verra’ valorizzato con un nuovo valore.

Allego il documento completo del post
Qui invece troverete il codice sorgente della classe

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...