V ideálním světě by vývojář napsal aplikaci, předal ji lidem z Operations, a ti by ji nasadili a spravovali. Veškeré trable s chováním a výkonem aplikace by padaly na jejich hlavu a teprve až by bylo nejhůř, tak by se obrátili zpět na programátory. My však ale nežijeme v ideálním světě (spíše naštěstí než bohužel) a tak musíme mnohdy spravovat (nebo aspoň pomáhat spravovat) i vlastní aplikace (možná je to tak dobře, aspoň trestáme sami sebe, a ne nevinné správce :-).
I v tom ideálním světě bychom ale museli správcům naší aplikace nějak pomoct, minimálně by jim naše skvělá aplikace měla umožnit sledování svého stavu. ASP.NET aplikace jsou zrádné. Většinou jsou hostovány v rámci jiného procesu (aspnet_wp.exe pro IIS5 a w3wp.exe pro IIS6) a zjistit tak jejich stav je obtížné.
Ideálním místem monitorování stavu ASP.NET aplikací je Performance Monitor. Najdeme ho v Control Panels > Administrative Tools > Performance. Ten nám umožní sledovat performance countery, které můžeme přirovnat k průmyslovým čidlům. Narozdíl od sledování tlaku a teploty válcovací pece (pokud existuje :-), pokud ne, tak bych si ji měl rychle patentovat), performance countery sledují využívání paměti, přístup k disku, vytíženost procesoru a další hodnoty. Mnohé z nich nabízí operační systém a spoustu dalších přibude s každou další nainstalovanou a dobře napsanou službou či aplikací.
Ačkoliv .NET ( a ASP.NET) nabízí myriády performance counterů, všechny se týkají buď obecně .NET CLR nebo ASP.NET jako celku. Pokud na serveru běží více ASP.NET aplikací najednou, těžko můžeme identifikovat v rámci counteru vliv jedné z nich.
Naštěstí systém performance counterů je schopen přidat countery nové a organizovat je do vlastních kategorií. .NET dokonce v rámci System.Diagnostics namespace nabízí managed prostředí pro práci s performance countery. Můžeme si tak přidat vlastní countery a jejich hodnotu přímo nastavovat z naší aplikace. Správce pak může s našimi performance countery pracovat stejně jak je dosud zvyklý, vytvářet logy, definovat alerty a i pro nás vývojáře mohou být takové vlastní countery nedocenitelnými pomocníky při ladění výkonu a hledání úzkých hrdel (možná by se prostě některé terminus technicus neměli do češtiny překládat, z tohohle mi jde mráz po zádech :-).
System.Diagnostics
Dvě hlavní třídy slouží pro práci s performance countery. Je to PerformanceCounter, který zprostředkovává práci s konkrétním counterem a PerformanceCounterCategory, což je třídá, sloužící ke správě kategorií counterů.
Většinu metod třídy PerformanceCounterCategory v ASP.NET aplikacích bohužel použít nemůžeme. Při vytváření a správě kategorií je totiž na pozadí manipulováno s klíči v registrech (větev HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services), na což typicky účet, pod kterým ASP.NET běží nemá dostatečná práva a přidělovat je kvůli těmto operacím je zcela zbytečné bezpečnostní riziko.
Vytvoření vlastních kategorií a jejich counterů by tedy mělo proběhnout buď ručně, nebo v rámci jednoduché speciální aplikace, kterou spustí např. administrátor. Velmi jednoduché je to v rámci Server Exploreru ve Visual Studiu.
Implementace
Jak tedy pracovat s vlastním counterem z naší aplikace? Řekněme, že bychom rádi zpřístupnili počet aktivních sessions v naší aplikaci. Taková úloha je celkem univerzální a tak by bylo vhodné ji od vlastní aplikace nějak oddělit, aby byla snadno použitelná i jinde. Napíšeme si ji tedy například jako vlastní HttpModul.
V rámci něj budeme odchytávat události Start a End pro SessionStateModule. Uděláme si statickou proměnnou udávající počet sessions. Při startu nové session ji přičteme jedničku a při konci jedničku odebereme. Při každé změně počtu sessions zavoláme metodu, která aktualizuje hodnotu daného counteru.
Vlastní HttpModul implementuje rozhraní IHttpModule. V rámci něj musíme implementovat metodu Init a Dispose. Typicky v rámci Init() zaregistrujeme vlastní logiku pro události BeginRequest a EndRequest třídy HttpApplication (která je předána v Init jako parametr).
SessionStart a SessionEnd však nejsou události třídy HttpApplication, ale jsou ve vlastním modulu, již výše zmíněném SessionStateModule.
V rámci Init, tedy modul najdeme v kolekci Modules a zaregistrujeme jeho události:
public void Init(HttpApplication context)
{
// get session module
SessionStateModule sessionState = GetSessionStateModule(context);
sessionState.Start += new EventHandler(sessionState_Start);
sessionState.End += new EventHandler(sessionState_End);
}
private SessionStateModule GetSessionStateModule(HttpApplication application)
{
HttpModuleCollection modules = application.Modules;
foreach(object module in modules)
{
SessionStateModule sessionState = module as SessionStateModule;
if (sessionState != null)
{
return sessionState;
}
}
throw new Exception("SessionState module not found!");
}
SessionStateModule by se dal pravděpodobně nalézt rychleji použitím:
HttpModuleCollection modules = application.Modules;
SessionStateModule sessionState = modules["Session"] as SessionStateModule;
Je ale možné, že se jméno modulu změní; hledáním podle typu si tak spíše zajistíme jeho nalezení a daná operace se bude provádět jen jednou při startu aplikace, takže si můžeme náročnější hledání dovolit.
Předpokládejme, že již máme vytvořenou vlastní kategorii (pojmenovanou například podle aplikace – „NaseAplikace“) a v ní vytvořen counter „ActiveSessionCount“ typu NumberOfItems32 (countery mohou mít mnoho typů – zlomkové, průměrové, časové za vteřinu apod. – NumberOfItems32 je základní typ, ukazující prostý počet „jevů“).
Naše reakce na události Session.Start a Session.End pak bude vypadat nějak takto:
private void sessionState_Start(object sender, EventArgs e)
{
sessionCount ++;
UpdateSessionCounter();
}
private void sessionState_End(object sender, EventArgs e)
{
sessionCount --;
UpdateSessionCounter();
}
private static void UpdateSessionCounter()
{
PerformanceCounter counter = new PerformanceCounter("NaseAplikace", "ActiveSessionCount", false);
counter.RawValue = sessionCount;
counter.Close();
}
Pak už jen stačí ve web.configu přidat náš HttpModul:
<httpModules>
<!-- Provides performance counters for application monitoring -->
<add name="PerformanceCountersModule"
type="Shared.HttpModules.PerformanceCountersModule, Shared" />
</httpModules>
A nyní můžeme přidat náš nový counter do grafu a sledovat počty sessions. Můžeme si postupně přidat další a další countery, ať už formou našeho HttpModulu, nebo přímo do naší aplikace, pokud budeme chtít sledovat nějaké specifické údaje.
Velmi dobrým zdrojem dalšího studia je pěkná knihovna s článkem Using custom attributes to add performance counters to your application. Pozor ale, v rámci knihovny dochází k vytváření kategorií a counterů a na to ASP.NET nemá právo, jak jsem zmiňoval výše. Doporučuji také přehledný článek na MSDN: How To: Use Custom Performance Counters from ASP.NET.
Zdrojový kód PerformanceCountersModule