function doClick(index, numTabs, id) {
document.all("tab" + id, index).className = "tab";
for (var i=1; i
Nas versões anteriores do ASP.NET tínhamos algumas funcionalidades/serviços que nos permitiam monitorar a vida de uma aplicação ASP.NET. Podemos considerar como estes serviços os Traces e os contadores de performance. O ASP.NET 2.0 introduz um novo conceito, chamado de
Health Monitoring, que trata-se de uma infraestrutura completa para monitoramento da aplicação ASP.NET, permitindo-nos analisar posteriormente o comportamento de tal aplicação, analisando a performance, diagnosticar falhas da aplicação e também eventos significativos durante a vida da aplicação em questão.
Neste novo cenário, devemos nos atentar para dois principais conceitos que temos que ter em mente:
events e
providers. Um
event é responsável por armazenar informações de um determinado acontecimento dentro da aplicação. Já o
provider é o responsável por tratar e persistir (quando necessário) o evento. Este
provider pode, por exemplo, fazer entrada dentro do Event Log do Windows, salvar em uma base de dados qualquer, mandar o mesmo por e-mail, etc. A amarração entre o evento e o
provider é feita através de regras que definimos no arquivo de configuração - Web.Config - da aplicação.
O .NET Framework 2.0 já nos fornece uma porção de
providers capazes de tratar estes eventos, podendo inclusive, criar os nossos próprios
events e
providers (veremos isso mais tarde, ainda neste artigo). Essa infraestrutura pode ser exibida através da imagem abaixo:
|
Figura 1 - Estrutura dos events e providers em funcionamento. |
Partindo para o lado técnico e de design das classes, os eventos nada mais são do que classes que herdam a maioria das funcionalidades de uma classe base chamada de
WebBaseEvent, sendo esta necessária para criarmos os nossos eventos customizados. Todos estes eventos devem, depois de criados, ser registrados no arquivo de configuração para que a aplicação e o runtime do ASP.NET possa fazer o uso dos mesmos. O registro pode ser a nível de Web.Config, ficando estes eventos limitados a aplicação ou, se desejar compartilhar os eventos para que todas as aplicações o utilizem, pode optar por registrá-los no arquivo Machine.config. Quando você registra este evento em um arquivo de configuração (seja ele qual for), é necessário que você defina um nome que representará a categoria associada a este evento. Para ter uma idéia dos eventos já existentes dentro do .NET Framework, consulte a tabela abaixo:
Evento
|
Descrição
|
All Events
|
Captura qualquer evento criado.
|
HeartBeats
|
Permite efetuar a notificação de eventos.
|
Application Lifetime Events
|
Fornece informações sobre o início, término e recompilação da aplicação.
|
All Errors
|
Captura todos os erros gerados pela aplicação.
|
Infraestructure Errors
|
Captura os erros relacionados com o funcionamento do IIS e do ASP.NET.
|
Request Processing Errors
|
Excessões ocorridas durante o pedido de um determinado recurso.
|
All Audits
|
Utilizado para efetuar auditorias.
|
Failure Audits
|
Efetua a auditoria de tentativas falhas de Login.
|
Success Audits
|
Ao contrário do anterior, efetua a auditoria de tentativas com sucesso de Login.
|
|
Para comprovar que estes eventos já estão pré-definidos, podemos analisar o arquivo Web.Config (que corresponde as configurações padrões de todas as aplicações Web), sendo exibidos através da imagem abaixo:
|
Figura 2 - Eventos já definidos dentro do .NET Framework 2.0. |
Assim como os eventos, já existem também providers pré-definidos dentro do .NET Framework. São eles:
Provider
|
Descrição
|
SqlWebEventProvider
|
Utilizando este provider, o evento é armazenado dentro de uma base de dados SQL Server. É importante dizer que é necessário executar o utilitário aspnet_regsql.exe dentro do banco de dados para que seja criada a infraestrutura de tabelas necessárias. Este provider suporta buffer1.
|
SimpleMailWebEventProvider
|
Permite configurar o envio de e-mails com as informações contidas dentro de um evento. Este provider suporta buffer1.
|
TemplatedMailWebEventProvider
|
Semelhante ao anterior, mas neste caso podemos definir uma mensagem customizada a ser enviada.
|
EventLogProvider
|
Efetua as entradas dentro da categoria Application do Event Log do Windows.
|
WmiWebEventProvider
|
Através deste provider é possível vincular os eventos aos eventos WMI e, conseqüentemente, podem ser consumidos por listeners WMI.
|
|
1 - Quando falamos que um provider suporta buffering, isso quer dizer que ele espera este buffer completar para "descarregar" todo o conteúdo em memória em seu local de destino. Isso pode nos gerar um maior ganho de performance, pois evita de a cada evento ocorrido dentro da aplicação ter que perder tempo armazenando isso. Estes buffers são definidos dentro do elemento bufferModes.
Apesar de existirem todos estes providers dentro do .NET Framework, no arquivo de configuração só temos adicionados o SqlWebEventProvider, EventLogProvider e WmiWebEventProvider. Se desejarmos utilizar um dos outros providers devemos registrar o mesmo dentro do elemento providers do arquivo Web.Config local.
Dando seqüencia, vamos analisar as definições de regras, que é onde "amarramos" o provider com os events. É com estas regras que definimos por qual provider o nosso evento vai ser tratado. Isso permite a independência de providers, ou seja, podemos ter qualquer evento sendo tratado por qualquer provider. Felizmente, a infraestrutura não me obriga a tratar todos os eventos com apenas um único provider. Para exemplificar, vamos analisar como devemos fazer para habilitar o health monitoring e utilizar um evento e provider:
<system.web>
<healthMonitoring enabled="true">
<rules>
<clear />
<add
name="All Errors Default"
eventName="All Errors"
provider="EventLogProvider"
profile="Default"
minInterval="00:01:00"/>
</rules>
</healthMonitoring>
</system.web>
|
Web.Config
|
|
Como podemos analisar no código acima, apenas com algumas linhas de configurações dentro do arquivo Web.Config, o health monitoring já está habilitado. Antes de ver isso em funcionamento, vamos analisar os atributos: name identifica a regra; eventName refere-se ao evento que deverá ser tratado; provider é o nome do provider que iremos utilizar para persistir o evento; profile permite-nos associar um perfil a esta regra; e finalmente o atributo minInterval, qual tem um funcionamento interessante, ou seja, se uma excessão acontecer mais de uma vez dentro do período estipulado nele, apenas será logado/persistido uma vez o evento no EventLog (neste caso). Para poder testar, apenas vou criar um código .NET que gere uma excessão, como por exemplo uma divisão por 0 (zero):
|
Figura 3 - Health Monitoring em funcionamento. |
function doClick(index, numTabs, id) {
document.all("tab" + id, index).className = "tab";
for (var i=1; i
Criação de um Event e Provider customizado
Mesmo com todas as classes que o .NET Framework 2.0 traz para trabalhar com Health Monitoring, ainda temos a flexibilidade de criar os nossos próprios events e providers, se assim desejarmos. Para isso, basta trabalharmos com as classes base (tanto para event quanto para provider) que já trazem as funcionalidades principais para operar os dados e apenas customizamos o que e para onde direcionaremos estes eventos.
Como já vimos no começo do artigo, utilizamos a classe base WebBaseEvent para criarmos o nosso próprio evento. O cenário aqui será criar um event para utilizarmos no decorrer da aplicação e um provider para persistirmos os eventos em arquivos de texto (txt). O código abaixo mostra como devemos proceder para criarmos o nosso próprio event:
using System.Web.Management;
public class CodeEvent : WebBaseEvent
{
private static readonly int _eventCode = WebEventCodes.WebExtendedBase + 1;
public CodeEvent(string msg, object eventSource, int eventCode)
: base(msg, eventSource, CodeEvent._eventCode) {}
public CodeEvent(string msg, object eventSource, int eventCode, int eventDetails)
: base(msg, eventSource, CodeEvent._eventCode, eventDetails) {}
}
Imports System.Web.Management
Public Class CodeEvent
Inherits WebBaseEvent
Private Shared ReadOnly _eventCode As Integer = WebEventCodes.WebExtendedBase + 1
Public Sub New(ByVal msg As String, _
ByVal eventSource As Object, _
ByVal eventCode As Integer)
MyBase.New(msg, eventSource, CodeEvent._eventCode)
End Sub
Public Sub New(ByVal msg As String, _
ByVal eventSource As Object, _
ByVal eventCode As Integer, _
ByVal eventDetails As Integer)
MyBase.New(msg, eventSource, CodeEvent._eventCode, eventDetails)
End Sub
End Class
|
C#
|
VB.NET
|
|
A única coisa que devemos ter atenção é no código interno do event. Ele está definido como _eventCode e é responsável por gerar um código para distinguir os eventos desta classe. Depois do evento criado, antes de ver como fica a configuração no arquivo Web.Config, analisaremos como proceder para a criação do provider para o arquivo texto:
using System.IO;
using System.Web.Management;
public class TextEventProvider : WebEventProvider
{
private string _providerName = "TextEventProvider";
private string _path = string.Empty;
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config)
{
if (string.IsNullOrEmpty(config["path"]))
throw new ArgumentException("Caminho inválido/inexistente.");
this._path = config["path"];
base.Initialize(name, config);
}
public override void ProcessEvent(WebBaseEvent raisedEvent)
{
if (raisedEvent is CodeEvent)
{
StreamWriter sw = File.AppendText(this._path);
sw.WriteLine(
string.Format("{0}\t{1}\t{2}\t{3}\t",
raisedEvent.EventCode,
raisedEvent.EventID,
raisedEvent.EventTime,
raisedEvent.Message));
sw.Close();
}
}
public override void Shutdown(){}
public override void Flush(){}
}
Imports System.IO
Imports System.Web.Management
Public Class TextEventProvider
Inherits WebEventProvider
Private _providerName As String = "TextEventProvider"
Private _path As String = String.Empty
Public Overrides Sub Initialize(ByVal name As String, _
ByVal config As System.Collections.Specialized.NameValueCollection)
If String.IsNullOrEmpty(config("path")) Then
Throw New ArgumentException("Caminho inválido/inexistente.")
End If
Me._path = config("path")
MyBase.Initialize(name, config)
End Sub
Public Overrides Sub ProcessEvent(ByVal raisedEvent As _
System.Web.Management.WebBaseEvent)
If (TypeOf raisedEvent Is CodeEvent) Then
Dim sw As StreamWriter = File.AppendText(Me._path)
sw.WriteLine( _
String.Format("{0}\t{1}\t{2}\t{3}\t", _
raisedEvent.EventCode, _
raisedEvent.EventID, _
raisedEvent.EventTime, _
raisedEvent.Message))
sw.Close()
End If
End Sub
Public Overrides Sub Flush()
End Sub
Public Overrides Sub Shutdown()
End Sub
End Class
|
C#
|
VB.NET
|
|
Através do método Initialize recuperamos informações do arquivo de configuração que, neste nosso caso, devemos recuperar o caminho do arquivo através do atributo path. Temos também o método ProcessEvent que temos acesso ao evento gerado e assim podemos tratá-lo como quisermos. Como vamos armazenar isso em um arquivo TXT, utilizaremos o conjunto de caracteres "\t" para incluirmos o TAB entre os valores dos campos do evento. O método AppendText da classe File fará com que o conteúdo sempre será adicionado no TXT, sem perder o que já temos lá gravado.Com estas classes prontas, agora basta configurarmos o event e o provider dentro do Web.Config criando uma nova regra e "amarrando" o evento ao provider:
<system.web>
<healthMonitoring enabled="true">
<providers>
<add
name="TextEventProvider"
type="TextEventProvider"
path="C:\EventLog.txt"/>
</providers>
<eventMappings>
<add
name="Code Event"
type="CodeEvent"/>
</eventMappings>
<rules>
<add
name="Text Event Rule"
eventName="Code Event"
provider="TextEventProvider"
profile="Default"
minInterval="00:00:00"/>
</rules>
</healthMonitoring>
</system.web>
|
Web.Config
|
|
Aqui vale chamar a atenção para o atributo type. Como eu estou criando as classes internamente, ou seja, dentro do diretório App_Code do meu projeto ASP.NET, eu não precisei definir o nome do Assembly, informação que seria necessária se estivesse com esse código dentro de uma DLL a parte.
Da mesma forma que fizemos anteriormente, vamos criar uma situação e forçar a divisão por zero para que uma excessão seja atirada e, com isso, salvamos o evento que criamos com o uso do nosso provider, definido na regra Text Event Rule. O notificação é gerada quando invocamos o método Raise (que é herdado da classe base). O código abaixo exibe isso:
try
{
int i = 0;
int resultado = 10 / i;
}
catch (DivideByZeroException ex)
{
CodeEvent codeEvent = new CodeEvent("Divisão por zero.", sender, 0);
codeEvent.Raise();
}
Try
Dim i As Integer = 0
Dim resultado As Integer = 10 / i
Catch(ex As DivideByZeroException)
Dim codeEvent As New CodeEvent("Divisão por zero.", sender, 0)
codeEvent.Raise()
End Try
|
C#
|
VB.NET
|
|
|
Figura 4 - O arquivo TXT gerado com o Log. |
CONCLUSÃO: Como vimos no decorrer deste artigo, o Health Monitoring traz uma grande quantidade de features e classes que nos permitem trabalhar com o monitoramento da vida da aplicação sem precisarmos recorrer a componentes e/ou ferramentas de terceiros para isso. Finalmente, ratifico a simplicidade que temos quando precisamos criar algo mais customizado, onde os events e os providers que estão intrínsicos e fornecidos pelo .NET Framework não nos atende.