Estendendo o System.Diagnostics – Parte II

Publicado originalmente na MSDN Magazine USA nr 21.

Estendendo o SourceSwitch

Como podemos ver, estender a classe Switch é relativamente simples. Estender o SourceSwitch é mais interessante e desafiante. Como mencionamos antes, a chave é usada com o ponto de entrada principal de rastreamento chamado TraceSource.

O TraceSource se baseia em duas enumerações: uma é usada para especificar o tipo do evento que está sendo rastreado e a segunda especifica os tipos de eventos que a fonte dada deve rastrear. O desafio de executar chaves de fonte personalizadas vem do fato de que as enumerações necessitam ser especialmente projetados para interoperar corretamente quando usadas dentro de um TraceSource.

Por exemplo, no .NET Framework, o TraceSource usa uma enumeração dos flags SourceLevels para representar as configurações de Switch e uma enumeração simples TraceEventType (não flag) para representar os tipos de evento, como mostrado a seguir:

 

TraceSource diagnostics = new TraceSource(

  "MyApplication");

// diagnostics.Switch.Level = SourceLevels.Error;

diagnostics.TraceEvent(TraceEventType.Error, 0,

  "File not found");

 

Para a chave de fonte de fluxo personalizada, reusamos a enumeração FlowSwitchSettings da seção anterior, para representar as configurações da chave e para adicionar uma enumeração nova. FlowEventType; para representar o tipo de um evento. Essa chave de fluxo pode controlar dois tipos de eventos: Entering e Exiting.

Conseqüentemente, a enumeração terá dois valores. Note que essa enumeração não é uma enumeração dos flags. Cada evento pode ser um evento de entrada ou de saída, mas não ambos:

 

public enum FlowEventType

{

    Entering = 32,

    Exiting = 64

}

 

Podemos observar, que esse nome de enumeração (FlowEventType), é uma frase de um substantivo singular de acordo com orientação básica de nomeação para a enumeração: usar um nome de tipo singular para a enumeração a menos que seus valores sejam campos bit.

Ao contrário do FlowSwitch, o FlowSourceSwitch (e todos os SourceSwitches), não necessitam das propriedades de ajuda (Entering e Exiting). Ao invés disso, contém um método ShouldTrace que compara o tipo do evento com a configuração da chave, para determinar se o evento deve ser rastreado ou não (Listagem ).

 

Listagem 10. Para rastrear ou não o evento

public class FlowSourceSwitch1 : SourceSwitch {

public FlowSourceSwitch1(string name) : base(name)

{

 

}

 

public new FlowSwitchSettings Level {

  get { return (FlowSwitchSettings)base.Level; }

  set { base.Level = (SourceLevels)value;  }

}

 

public bool ShouldTrace(FlowEventType eventType) {

  return ((int)eventType & (int)Level) != 0;

}

 

protected sealed override void OnValueChanged() {

  SwitchSetting =

    (int)Enum.Parse(typeof(FlowSwitchSettings),

    Value);

}

}

 

O método ShouldTrace é provavelmente o membro mais interessante de uma chave de fonte. Lembremo-nos que foi mencionado que os valores inteiros das duas enumerações usadas pelos fontes de rastreamento, tem que ser escolhidos com cuidado. Isso é devido à implementação do método ShouldTrace que executa uma comparação bit a bit dos valores inteiros, para determinar se um evento deve ser rastreado. Sendo o método SourceSwitch.ShouldTrace não virtual, não podemos mudar à forma como os valores são comparados.

 

Podemos apenas mudar, ou melhor, selecionar os valores com cuidado para personalizar o funcionamento do método. Note que o método é não virtual para maximizar o desempenho (permite o inlining).

O desempenho desse método é crítico para garantir que o processamento extra do rastreamento se aproxime de zero quando uma chave for desligada e a verificação da chave for levantada. Por exemplo, se a verificação puder ser inlined, e se a expressão booleana for falsa, o custo da declaração inteira será desprezível:

 

If (source.Switch.ShouldTrace(TraceEvent.Information))

source.TraceEvent(TraceEvent.Information,…);

 

De fato, não há nenhuma necessidade de adicionar o método ShouldTrace a uma chave personalizada, afinal, o método ShouldTrace é apenas uma sobrecarga e não é chamado por fontes de rastreamento. O TraceSource é que chama o método do tipo base ShouldTrace(TraceEventType) de qualquer maneira.

A sobrecarga é útil para os cenários em que o chamador quer retirar a verificação da chave para fora da chamada ao TraceEvent, visando melhorar o desempenho. Mais adiante, mostraremos como engatar um SourceSwitch personalizado a um TraceSource. Mas antes vamos ver se podemos fazer melhor do que o tão cuidadosamente elaborado FlowSourceSwitch.

SourceSwitch Genérico

A personalização ou extensibilidade, podem ser fornecidos via diversos mecanismos incluindo abstrações, eventos e callbacks. O .NET Framework 2.0 adicionou uma característica chamada Generics, que é um mecanismo muito poderoso de estensibilidade. A Listagem 11 mostra como o generics pode ser usado para fornecer uma chave que pode ser ajustada para suportar configurações personalizadas.

 

Listagem 11.  Switch com suporte a configurações

public class SourceSwitch