Registro em log e rastreamento em aplicativos .NET
À medida que você continua desenvolvendo o aplicativo e o processo se torna mais complexo, recomendamos aplicar diagnósticos de depuração adicionais ao aplicativo.
O rastreamento é uma maneira de monitorar a execução do seu aplicativo enquanto está em execução. Você pode adicionar instrumentação de rastreamento e depuração ao aplicativo .NET ao desenvolvê-lo. Você poderá usar essa instrumentação enquanto estiver desenvolvendo o aplicativo e depois de implantá-lo.
Essa técnica simples é surpreendentemente poderosa. Você pode usá-lo em situações que exigem mais do que um depurador:
- Problemas que ocorrem por longos períodos podem ser difíceis de depurar com um depurador tradicional. Os logs permitem uma análise detalhada post mortem, abrangendo longos períodos. Por outro lado, os depuradores são limitados a análises em tempo real.
- Aplicativos distribuídos e com multithread costumam ser difíceis de depurar. A anexação de um depurador tende a modificar comportamentos. Logs detalhados podem ser analisados, conforme necessário, para entender sistemas complexos.
- Problemas em aplicativos distribuídos podem surgir de uma interação complexa entre vários componentes. Talvez não seja razoável conectar um depurador a todas as partes do sistema.
- Muitos serviços não devem ser interrompidos. A anexação de um depurador geralmente causa falhas de tempo limite.
- Os problemas nem sempre são previstos. O registro em log e o rastreamento são projetados para baixa sobrecarga, de modo que os programas possam ser gravados caso ocorra um problema.
Gravar informações em janelas de saída
Até este ponto, usamos o console para exibir informações ao usuário do aplicativo. Existem outros tipos de aplicativos criados com o .NET que têm interfaces de usuário, como aplicativos móveis, web e de área de trabalho e não existe nenhum console visível. Nesses aplicativos, o System.Console
registra mensagens "nos bastidores". Essas mensagens podem aparecer em uma janela de saída no Visual Studio ou no Visual Studio Code. Elas também podem ter ser uma saída do log do sistema, como logcat
do Android. Como resultado, você deve ter muita atenção ao usar o System.Console.WriteLine
em um aplicativo que não seja de console.
Aqui, é possível usar System.Diagnostics.Debug
e System.Diagnostics.Trace
, além de System.Console
. Debug
e Trace
fazem parte de System.Diagnostics
e gravarão em logs apenas quando um ouvinte apropriado for anexado.
A escolha da API de estilo de impressão a ser usada cabe a você. As principais diferenças são:
- System.Console
- Está sempre habilitado e sempre grava no console.
- Útil para informações que seu cliente talvez precise ver na versão.
- Por ser a abordagem mais simples, costuma ser usado para a depuração temporária ad hoc. Geralmente, esse código de depuração nunca é submetido a check-in no controle do código-fonte.
- System.Diagnostics.Trace
- Habilitado somente quando
TRACE
é definido. - Grava em Ouvintes anexados, por padrão, o DefaultTraceListener.
- Use essa API ao criar logs que serão habilitados na maioria dos builds.
- Habilitado somente quando
- System.Diagnostics.Debug
- Habilitado somente quando
DEBUG
é definido (no modo de depuração). - Grava em um depurador anexado.
- Use essa API ao criar logs que serão habilitados apenas em builds de depuração.
- Habilitado somente quando
Console.WriteLine("This message is readable by the end user.");
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");
Ao projetar sua estratégia de rastreamento e depuração, pense em como você quer que seja a saída. Diversas instruções Escrever preenchidas com informações não relacionadas criam um log difícil de ler. Por outro lado, usar WriteLine para colocar instruções relacionadas em linhas separadas pode dificultar a distinção entre as informações. Em geral, use várias instruções Write quando quiser combinar informações de diversas fontes para criar uma única mensagem informativa. Use a instrução WriteLine ao criar uma única mensagem completa.
Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");
Esta saída é do registro em log anterior com Debug
:
Debug - This is a full line.
This is another full line.
Definir as constantes TRACE e DEBUG
Por padrão, quando um aplicativo é executado sob depuração, a constante DEBUG
é definida. Isso pode ser controlado com a adição de uma entrada DefineConstants
no arquivo de projeto em um grupo de propriedades. Confira um exemplo de como ativar TRACE
para configurações de Debug
e de Release
, além de DEBUG
para configurações de Debug
.
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
Ao usar Trace
quando não houver anexação ao depurador, será preciso configurar um ouvinte de rastreamento, como dotnet-trace.
Rastreamento condicional
Além dos métodos Write
e WriteLine
simples, também há a capacidade de adicionar condições com WriteIf
e WriteLineIf
. Por exemplo, a lógica a seguir verifica se o número é zero e, a seguir, grava uma mensagem de depuração:
if(count == 0)
{
Debug.WriteLine("The count is 0 and this may cause an exception.");
}
Você pode reescrevê-la em uma única linha de código:
Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");
Também é possível usar estas condições com Trace
e com os sinalizadores definidos no aplicativo:
bool errorFlag = false;
System.Diagnostics.Trace.WriteIf(errorFlag, "Error in AppendData procedure.");
System.Diagnostics.Debug.WriteIf(errorFlag, "Transaction abandoned.");
System.Diagnostics.Trace.Write("Invalid value for data request");
Verificar se existem determinadas condições
Uma declaração, ou instrução Assert
, testa uma condição que você especifica como um argumento para a instrução Assert
. Se a condição for avaliada como true
, nenhuma ação ocorrerá. Se a condição for avaliada como false
, a asserção falhará. Se você estiver executando um build de depuração, seu programa entrará no modo de interrupção.
É possível usar o método Assert
de Debug
ou Trace
, que estão no namespace System.Diagnostics
. Os métodos da classe Debug
não estão incluídos em uma versão de lançamento do programa, portanto, não aumentam o tamanho nem reduzem a velocidade do código da versão.
Use o método System.Diagnostics.Debug.Assert
livremente para testar condições que devem resultar em valores verdadeiros se seu código estiver correto. Por exemplo, suponha que você tenha escrito uma função de divisão de números inteiros. Pelas regras da matemática, o divisor nunca pode ser zero. Você pode testar essa condição usando uma instrução assert:
int IntegerDivide(int dividend, int divisor)
{
Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");
return dividend / divisor;
}
Quando você executa esse código no depurador, a instrução assert é avaliada. Porém, a comparação não é feita na versão de lançamento, de modo que não há nenhuma sobrecarga adicional.
Observação
Ao usar System.Diagnostics.Debug.Assert
, verifique se o código dentro de Assert
não alterará os resultados do programa se Assert for removido. Caso contrário, você pode introduzir acidentalmente um bug que aparece apenas na versão de lançamento do seu programa. Tenha um cuidado especial com as instruções assert que contêm chamadas de função ou de procedimento.
Usar Debug
e Trace
do namespace de System.Diagnostics
é uma maneira excelente de fornecer um contexto adicional quando você executa e depura seu aplicativo.