Visual Studio 2015

Uso do IntelliTrace para diagnosticar problemas com mais rapidez

Angelos Petropoulos

Pense sobre o fluxo de trabalho típico quando você estiver depurando. Até que a causa raiz de um problema tenha sido identificada com êxito, você fica preso em um loop de pontos de interrupção e repetindo as etapas de testes que reproduzem o problema. Agora você pode usar o IntelliTrace para gravar o histórico de informações de depuração enquanto o aplicativo está em execução. Isso ajuda a interromper esse loop. Você pode executar as etapas de testes uma vez para reproduzir o problema e usar o histórico de depuração para identificar a causa raiz.

O IntelliTrace é o conjunto de tecnologias histórico de depuração que estende o depurador do Visual Studio 2015 Enterprise. Também é um componente autônomo que você pode usar fora do Visual Studio. O IntelliTrace registra a execução do aplicativo procurando eventos interessantes. Quando ocorre um evento interessante, o IntelliTrace registra automaticamente a pilha de chamadas e variáveis locais enquanto o aplicativo continua em execução. Você pode controlar os eventos que o IntelliTrace considera “interessante” através de Ferramentas | Opções | IntelliTrace | Eventos do IntelliTrace.

O IntelliTrace apresenta um histórico de execução do seu aplicativo usando uma linha do tempo (uma visão detalhada dos eventos) e uma tabela que exibe os detalhes de cada evento. Ele também fornece acesso ao histórico de dados de depuração, ampliando e integrando com o depurador do Visual Studio. Isso permite voltar no tempo e ver a pilha de chamadas e variáveis locais dos eventos coletados.

O IntelliTrace encontrou uma nova casa na janela de Ferramentas de Diagnóstico no Visual Studio de 2015. A janela de Ferramentas de Diagnóstico contém a ferramenta de uso da CPU e a ferramenta de uso da memória, juntas com o IntelliTrace. Se houver suporte para o tipo de projeto e a configuração de depuração (para obter informações atualizadas, consulte aka.ms/diagtoolswindow), você verá uma janela de Ferramentas de Diagnóstico aparecer quando iniciar a depuração no Visual Studio 2015 (pressione F5 ou você sempre pode abri-lo manualmente usando Depuração | Mostrar Ferramentas de Diagnóstico). Ao ativar o histórico de depuração, você verá algo semelhante à Figura 1.

Históricos de depuração com o IntelliTrace
Figura 1 Históricos de depuração com o IntelliTrace

Explorar a interface do usuário

Esta é uma lista de cada componente da interface do usuário do IntelliTrace e sua finalidade e funcionalidade:

Eventos do depurador: A tabela de detalhes de Eventos do depurador (consulte Figura 2) é uma exibição em forma de tabela dos eventos coletados pelo IntelliTrace. As colunas da esquerda para a direita são:

  1. Um ponteiro para o evento para o qual o depurador está atualmente mostrando informações. Apenas uma linha terá a seta amarela indicando o local do ponteiro de instrução atual e uma linha pode ter uma seta rosa indicando quais históricos de eventos estão ativados.
  2. O ícone usado para representar esse evento na linha do tempo de Eventos do depurador.
  3. Uma breve descrição do evento.
  4. O número de segundos desde o início da sessão de depuração até a hora em que o evento foi coletado.
  5. A duração do evento. Observação: Nem todos os eventos têm uma duração).
  6. A ID e o nome do thread que gerou o evento. Observação: Nem todos os eventos são associados a um thread)

Tabela de eventos do depurador
Figura 2 Tabela de eventos do depurador

Caso clique em um evento na lista para expandi-la, você pode selecionar Ativar histórico de depuração e definir o depurador para o ponto em que o IntelliTrace registrou o evento selecionado.

Controle de filtro da categoria: Esse controle de filtragem permite ocultar ou mostrar as categorias de evento enquanto ainda estão sendo coletadas. Se você deseja se concentrar em uma determinada categoria ou estiver completamente sem interesse em outra, você pode usar isso para exibi-las rapidamente ou não. A lista atual de categorias inclui: ADO.NET, ASP.NET, Console, Associação de dados, Depurador, Variáveis de ambiente, Exceção, Arquivo, Gestos, Inicialização ociosa, Saída, Registro, Modelo de serviço, Threading, Rastreamento, Prompt do usuário e XAML.

Controle de filtro de thread: Esse controle de filtragem permite ocultar ou mostrar eventos pelo thread do qual eles foram gerados, caso você só esteja interessado no diagnóstico de um segmento específico ou estiver na realidade executando um thread específico que não tem nenhum problema.

Botão Mostrar os eventos de código externo: O IntelliTrace respeita a configuração Just My Code (Apenas meu código) do depurador. Isso significa que, por padrão, ele oculta eventos originados no código que não do usuário para reduzir o ruído. Ao clicar nele, isto vai ignorar a configuração do depurador e mostrar os eventos de código externo. Na maioria das vezes, isso levará a uma saída bastante detalhada.

Cronograma de eventos do depurador: Isso é uma exibição gráfica dos eventos que o IntelliTrace coletou ao longo do tempo. Isso é uma exibição diferente das mesmas informações mostradas na tabela de detalhes de eventos. Use a linha do tempo para obter uma visão detalhada e identificar e selecionar áreas que você deseja analisar com o modo de exibição de tabela de detalhes de eventos. Você pode filtrar o que você vê na exibição de tabela de detalhes de eventos, selecionando um intervalo de tempo específico.

A régua: Acima da linha do tempo, há uma régua que mostra o ponto no tempo em que cada evento ocorreu. Ela também permite selecionar um intervalo de tempo específico clicando e arrastando. Selecione um intervalo de tempo para filtrar a tabela de detalhes de eventos do depurador.

Acompanhamento de eventos de interrupção: Sempre que ocorre um evento de interrupção, ele aparece neste acompanhamento da linha do tempo. Eventos de interrupção são pontos de interrupção ocorridos, etapas concluídas, clicar em interromper tudo, invocação do Debugger.Break ou uma exceção sem tratamento que interrompe a execução. Pense nisso como a faixa mestre de linha do tempo para ajudar a orientá-lo onde os eventos em outras faixas ocorreram na execução do programa (porque usando pontos de interrupção e etapas é como você controla a execução do aplicativo). Ao clicar em um evento nesta faixa, é aplicado um filtro de tempo que filtrará os eventos na tabela de detalhes de eventos do depurador. Dessa forma, você pode facilmente filtrar somente os eventos que ocorreram quando uma linha de código foi pulada ou entre o pressionamento de F5 e a ocorrência de um ponto de interrupção.

Acompanhamento de eventos de saída: Este acompanhamento mostra eventos para mensagens que aparecem na janela de saída. As categorias de eventos que aparecem nesta faixa são: Exceções de lançamentos, Saída do programa (ou Console.WriteLine), Módulo carregado/descarregado, Saída de Thread e Saída do processo. Isso permite correlacionar mensagens de saída de depuração padrão com o restante das informações do histórico do depurador.

Acompanhamento de evento do IntelliTrace: Cada categoria de evento coletada pelo IntelliTrace aparece nesta faixa da linha do tempo: ADO.NET, ASP.NET, Console, Associação de dados, Variáveis de ambiente, Arquivo, Gestos, Inicialização ociosa, Registro, Modelo de serviço, Threading, Rastreamento, Prompt do usuário e XML.

Barra de ferramentas de diagnóstico: A barra de ferramentas fornece botões de aplicação de Zoom, bem como um botão Redefinir exibição para redefinir a linha do tempo para o nível de zoom padrão e limpar qualquer seleção de tempo existente. Isso filtra todos dados coletados na exibição. O menu suspenso Selecionar Ferramentas permite que você selecione as ferramentas que você gostaria de incluir na janela de Ferramentas de Diagnóstico, além do IntelliTrace.

Você pode executar várias ferramentas de diagnóstico ao mesmo tempo. A janela de Ferramentas de Diagnóstico pode hospedar o Uso de memória, ferramentas de Uso da CPU e o IntelliTrace, todos ao mesmo tempo. Isso proporciona uma visão holística para o comportamento do aplicativo. Por exemplo, a Figura 3 mostra como a série de eventos de carregamento do módulo aumenta o uso da memória e da CPU para um aplicativo ASP.NET conforme ele é iniciado.

A janela de Ferramentas de Diagnóstico mostra como seu aplicativo está se comportando e sendo executado
Figura 3 A janela de Ferramentas de Diagnóstico mostra como seu aplicativo está se comportando e sendo executado

Corrigir um Bug verdadeiro com o IntelliTrace

Agora, eu o acompanharei na correção de um bug real usando recursos de depuração ao vivo do IntelliTrace no Visual Studio 2015 Enterprise. O aplicativo que vou depurar é um aplicativo do Windows Forms do CodeProject chamado SocialClub.

O aplicativo mantém um banco de dados de membros de um clube social. O bug é que a pesquisa funciona incorretamente após o registro de um membro. Para reproduzir o bug, iniciarei o aplicativo e registrar um novo membro. Em seguida, executarei uma pesquisa Obter todos que deveria retornar todos os membros registrados. É esperado apenas um resultado, mas em vez disso são obtidos dois (consulte a Figura 4). O segundo resultado de pesquisa for inesperado, então isso é o que preciso corrigir.


Figura 4 Resultado da pesquisa Obter todos contém um registro inesperado

Para corrigir esse erro, o que devo fazer em seguida? Nesse ponto, minha hipótese é que há algo errado com a função de pesquisa Obter Todos ou há algo errado com o processo de registro do novo membro. O aplicativo tem outro modo de pesquisa que usa critérios de pesquisa específicos, de forma que vou usá-lo para pesquisar pelo registro inesperado retornado por Obter Todos (aquele com os dados ausentes e valores desconhecidos).

Aqui estão os cenários possíveis: Se eu não obtiver nenhum resultado, isso provavelmente significa que o registro inesperado não existe no banco de dados e o problema é com a função de pesquisa Obter Todos. Se eu receber um resultado correspondente a um registro com Desconhecido para ocupação e estado civil, o problema está provavelmente com a função de registro inserindo mais registros no banco de dados que deveria.

Agora executo uma pesquisa com Desconhecido para ocupação e estado civil, que retorna um resultado: o registro foi registrado com êxito como Engenheiro e Casado. É estranho e, infelizmente, ele não me deixa mais próximo da causa raiz do bug. Em vez de perder tempo configurando pontos de interrupção, registrando novos membros e pesquisando por eles repetidamente, verei como o IntelliTrace pode ajudar a agilizar a investigação.

Quero ver os eventos coletados pelo IntelliTrace, mas os eventos do IntelliTrace não são atualizados até que o depurador interrompa a execução do aplicativo (ou seja, que ele alcance um ponto de interrupção). Porque eu não tenho um ponto de interrupção específico em que estou interessado, basta clicar em Interromper tudo na barra de ferramentas do Visual Studio. O aplicativo está agora em um estado de interrupção com todos os threads suspensos. IntelliTrace está exibindo os dados coletados na linha do tempo e na exibição da tabela de detalhes da janela de Ferramentas de Diagnóstico.

Neste ponto, eu já interagi com o aplicativo um pouco desde que a depuração foi iniciada. O logon foi realizado, registrei um novo membro, pesquisei usando Obter Todos pesquisei com critérios de pesquisa específicos. No entanto, estou apenas interessado em eventos que ocorreram como resultado direto de clicar em Registrar. Para filtrar o modo de exibição para apenas esses eventos, passo o mouse sobre os eventos na linha do tempo até encontrar onde cliquei em Registrar. Em seguida, arrasto e seleciono um cluster de eventos. Quando eu examinar minha exibição de tabela detalhada, após a seleção de tempo, posso ver os dois eventos mais recentes listados (outro além de Interromper Tudo) existem duas instruções INSERT (consulte Figura 5).

A exibição da tabela de detalhes é filtrada para mostrar os eventos do intervalo de tempo selecionado
Figura 5 A exibição da tabela de detalhes é filtrada para mostrar os eventos do intervalo de tempo selecionado

Ao clicar em um evento na lista, ela é expandida em várias linhas para mostrar a instrução SQL executada inteira. Posso ver que tenho duas instruções INSERT acontecendo. A segunda está inserindo um registro incorreto com valores nulos. Aqui estão as duas instruções SQL:

Execute Reader "insert [dbo].[ClubMembers]([Name], [DateOfBirth],
  [Occupation], [Salary], [MaritalStatus], [HealthStatus], [NumberOfChildren],
  [ExpirationDate])values (@0, @1, @2, @3, @4, @5, @6, @7)
  select [Id] from [dbo].[ClubMembers] where @@ROWCOUNT > 0 and [Id] =
  scope_identity()"
Execute Reader "insert [dbo].[ClubMembers]([Name], [DateOfBirth],
  [Occupation], [Salary], [MaritalStatus], [HealthStatus], [NumberOfChildren],
  [ExpirationDate])values (null, @0, @1, null, @2, @3, null, @4) select [Id] from
  [dbo].[ClubMembers] where @@ROWCOUNT > 0 and [Id] = scope_identity()"

Você pode ignorar a instrução SELECT que segue a INSERT. Isso é o Entity Framework recuperando a ID do registro que ele acabou de inserir. A próxima pergunta é: Por que recebo duas instruções SQL executadas para um único clique do botão de registro? O IntelliTrace me ajuda a responder rapidamente a essa pergunta, permitindo que eu ative o histórico de depuração para cada um dos eventos (consulte a Figura 6) e verifique suas pilhas de histórico de chamadas respectivas na janela Pilha de Chamadas.

Ativar histórico de depuração para a primeira das duas instruções INSERT
Figura 6 Ativar histórico de depuração para a primeira das duas instruções INSERT

A primeira das instruções INSERT da pilha do histórico de chamadas é:

John.SocialClub.Data.dll!John.SocialClub.Data.Service.ClubMemberService.Create(...)
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Forms.Membership.Manage.RegisterMember()
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Forms.Membership.Manage.Register_Click(...)
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Program.Main()

A pilha do histórico de chamadas da segunda instrução INSERT com o registro incorreto é:

John.SocialClub.Data.dll!John.SocialClub.Data.Service.ClubMemberService.Create(...)
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Forms.Membership.Manage.RegisterMember()
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Forms.Membership.Manage.btnRegister_MouseClick(...)
John.SocialClub.Desktop.exe!John.SocialClub.Desktop.Program.Main()

Ao clicar em cada quadro, sou levado à linha de código correspondente. Depois de examinar as duas pilhas de histórico de chamadas, determinei que tenho dois manipuladores de eventos diferentes inscritos para o mesmo clique do botão: Register_Click(...) e btnRegister_MouseClick(...). Ao ler o código nessas duas funções, posso rapidamente deduzir que porque os campos do formulário são redefinidos após cada novo registro de membro, o primeiro manipulador de eventos insere os registros no banco de dados corretamente. No entanto, o segundo manipulador de eventos insere um registro com campos em branco e nulos. Rapidamente encontrei o bug usando Interromper Tudo e, em seguida, usei o IntelliTrace para identificar e navegar até a parte incorreta do código.

E se os eventos do IntelliTrace não forem suficientes para localizar o erro?

Neste ponto, tão entusiasmado quanto você sobre o IntelliTrace para aprimorar a forma como você depura, você deve estar se perguntando o que fazer se o IntelliTrace não registrar quaisquer eventos interessantes que possam levar à causa raiz do bug. Você está sem sorte? Não, não está. Não se esqueça de que você pode controlar quais eventos do IntelliTrace são ativados usando Ferramentas | Opções | IntelliTrace | Eventos do IntelliTrace. Nem todos são habilitados por padrão, mas mesmo habilitar todos eles nem sempre pode ser suficiente para alguns bugs irritantes.

Para essas questões complicadas, você pode configurar o IntelliTrace para registrar não apenas eventos, mas também todas as chamadas de método e seus parâmetros. Basta ir para Ferramentas | Opções | IntelliTrace e selecionar eventos do IntelliTrace e informações de chamada. Esse é um recurso poderoso de depuração, mas isso tem um custo do tempo de execução. Com essa configuração, o IntelliTrace interceptará e gravará todas as chamadas de método, o que afeta o desempenho do aplicativo. É por isso que ele não coleta chamadas de método por padrão. Você precisa escolher por meio das configurações do IntelliTrace.

Você pode exibir e navegar essas novas informações de duas maneiras diferentes. Você pode usar a subguia Chamadas na tabela de detalhes de Eventos do Depurador, que lista todas as chamadas gravadas (para obter mais informações sobre a exibição de chamadas, vá para aka.ms/itracecalls). Outra forma é ativar a Depuração do histórico para um evento e usar o controle do IntelliTrace no editor de texto para navegar para frente e para trás na execução do aplicativo. Os controles aparecem entre o código e o ponteiro de instrução. Então IntelliTrace faz isso para você para todos os seus cenários de depuração ao vivo.

E se você não conseguir reproduzir o Bug em um computador de desenvolvimento?

É onde entra a Depuração fora do tempo real com o IntelliTrace. Até agora, presumi que você sabe as etapas necessárias para reproduzir o problema que você está depurando. Isso não é sempre o caso. Alguns dos bugs mais difíceis e demorados são aqueles para os quais você talvez não tenha as etapas exatas para reproduzir. O IntelliTrace pode eliminar esse terrível cenário “sem reprodução”, permitindo que você registre a execução do aplicativo em um ambiente de produção ou de teste. Em seguida, você pode depurá-lo em sua máquina de desenvolvimento, explorando as informações coletadas usando a mesma janela de Ferramentas de Diagnóstico que estou usando aqui.

O IntelliTrace oferece um coletor autônomo que você pode implantar em outros ambientes aos quais o Visual Studio não pode se conectar. Você não deve encontrar qualquer resistência de seus administradores porque não há nenhuma instalação envolvida. É simplesmente uma questão de copiar o coletor para o ambiente de destino. O coletor registra a execução do aplicativo para um arquivo .itrace que você pode transferir para a máquina de desenvolvimento e abrir com o Visual Studio. Este cenário é conhecido como Depuração fora de tempo real porque você não pode controlar a execução do aplicativo durante a depuração. Para obter informações atualizadas sobre como usar o coletor do IntelliTrace autônomo, visite aka.ms/itracecollector.

Conclusão

A nova experiência e integração do IntelliTrace com a janela de Ferramentas de Diagnóstico têm algumas possibilidades interessantes. Você pode manter-se atualizado com as informações mais recentes sobre esses e outros recursos de diagnóstico indo para aka.ms/DiagnosticsBlog.


Angelos Petropoulos é gerente de programas sênior na equipe do Visual Studio. Depois de obter seu mestrado em engenharia de software orientado a objeto, ele trabalhou como um consultor de TI no Reino Unido. Depois de mudar para os Estados Unidos, ele ingressou na equipe de Ferramentas de Diagnóstico no Visual Studio e agora é o gerente de programa do IntelliTrace.

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: Andrew Hall, Daniel Moth, Dan Taylor, Charles Willis