Monitoramento e telemetria (criando aplicativos de nuvem Real-World com o Azure)

por Rick Anderson, Tom Dykstra

Baixar o Projeto de Correção ou Baixar E-book

O livro eletrônico Criando Aplicativos de Nuvem do Mundo Real com o Azure é baseado em uma apresentação desenvolvida por Scott Guthrie. Ele explica 13 padrões e práticas que podem ajudá-lo a desenvolver aplicativos Web para a nuvem com êxito. Para obter informações sobre o livro eletrônico, consulte o primeiro capítulo.

Muitas pessoas dependem dos clientes para informá-los quando o aplicativo está inativo. Essa não é realmente uma prática recomendada em qualquer lugar, e especialmente não na nuvem. Não há garantia de notificação rápida e, quando você é notificado, geralmente obtém dados mínimos ou enganosos sobre o que aconteceu. Com bons sistemas de telemetria e log, você pode estar ciente do que está acontecendo com seu aplicativo e, quando algo der errado, você descobre imediatamente e tem informações úteis de solução de problemas para trabalhar.

Comprar ou alugar uma solução de telemetria

Observação

Este artigo foi escrito antes do Application Insights ser lançado. O Application Insights é a abordagem preferencial para soluções de telemetria no Azure. Consulte Configurar o Application Insights para seu site ASP.NET para obter mais informações.

Uma das coisas que é ótimo sobre o ambiente de nuvem é que é realmente fácil comprar ou alugar seu caminho para a vitória. A telemetria é um exemplo. Sem muito esforço, você pode obter um sistema de telemetria muito bom em funcionamento, muito econômico. Há vários grandes parceiros que se integram ao Azure e alguns deles têm camadas gratuitas, para que você possa obter telemetria básica para nada. Aqui estão apenas alguns dos que estão disponíveis atualmente no Azure:

O Microsoft System Center também inclui recursos de monitoramento.

Vamos percorrer rapidamente a configuração do New Relic para mostrar como pode ser fácil usar um sistema de telemetria.

No portal de gerenciamento do Azure, inscreva-se no serviço. Clique em Novo e, em seguida, clique em Armazenar. A caixa de diálogo Escolher um Complemento é exibida. Role para baixo e clique em Nova Relíquia.

Escolher um complemento

Clique na seta para a direita e escolha a camada de serviço desejada. Para esta demonstração, usaremos a camada gratuita.

Personalizar complemento

Clique na seta para a direita, confirme a "compra" e New Relic agora aparece como um Complemento no portal.

Examinar a compra

Novo complemento relic no portal de gerenciamento

Clique em Informações de Conexão e copie a chave de licença.

Informações de conexão

Vá para a guia Configurar para seu aplicativo Web no portal, defina Monitoramento de Desempenho como Complemento e defina a lista suspensa Escolher Complemento como Nova Relíquia. Em seguida, clique em Salvar.

Nova Relíquia na guia Configurar

No Visual Studio, instale o pacote NuGet New Relic em seu aplicativo.

Análise do desenvolvedor na guia Configurar

Implante o aplicativo no Azure e comece a usá-lo. Crie algumas tarefas Corrigir para fornecer alguma atividade para a Nova Relíquia monitorar.

Em seguida, volte para a página Nova Relíquia na guia Complementos do portal e clique em Gerenciar. O portal envia você para o portal de gerenciamento do New Relic, usando o logon único para autenticação para que você não precise inserir suas credenciais novamente. A página Visão geral apresenta uma variedade de estatísticas de desempenho. (Clique na imagem para ver a página de visão geral de tamanho completo.)

Guia Novo Monitoramento de Relíquias

Aqui estão apenas algumas das estatísticas que você pode ver:

  • Tempo médio de resposta em diferentes horas do dia.

    Tempo de resposta

  • Taxas de taxa de transferência (em solicitações por minuto) em diferentes horas do dia.

    Transferência

  • Tempo de CPU do servidor gasto tratando solicitações HTTP diferentes.

    Tempos de transação da Web

  • Tempo de CPU gasto em diferentes partes do código do aplicativo:

    Detalhes do rastreamento

  • Estatísticas históricas de desempenho.

    Desempenho histórico

  • Chamadas para serviços externos, como o serviço Blob e estatísticas, sobre o quão confiável e responsivo o serviço tem sido.

    Serviços externos

    Serviços externos2

    Serviço externo

  • Informações sobre de onde no mundo ou de onde veio o tráfego de aplicativo Web dos EUA.

    Geografia

Você também pode configurar relatórios e eventos. Por exemplo, você pode dizer que sempre que começar a ver erros, envie um email para alertar a equipe de suporte para o problema.

Relatórios

New Relic é apenas um exemplo de um sistema de telemetria; você também pode obter tudo isso de outros serviços. A beleza da nuvem é que sem precisar escrever nenhum código e, para um mínimo ou nenhuma despesa, de repente você pode obter muito mais informações sobre como seu aplicativo está sendo usado e o que seus clientes estão realmente experimentando.

Log para insights

Um pacote de telemetria é uma boa primeira etapa, mas você ainda precisa instrumentar seu próprio código. O serviço de telemetria informa quando há um problema e informa o que os clientes estão enfrentando, mas pode não fornecer muitas informações sobre o que está acontecendo em seu código.

Você não quer ter que fazer remotamente em um servidor de produção para ver o que seu aplicativo está fazendo. Isso pode ser prático quando você tem um servidor, mas e quando você dimensionou para centenas de servidores e você não sabe em quais você precisa fazer o controle remoto? O registro em log deve fornecer informações suficientes que você nunca precisa fazer remotamente em servidores de produção para analisar e depurar problemas. Você deve estar registrando informações suficientes para que possa isolar os problemas somente por meio dos logs.

Fazer logon em produção

Muitas pessoas ativam o rastreamento em produção somente quando há um problema e querem depurar. Isso pode introduzir um atraso substancial entre o tempo que você está ciente de um problema e a hora em que você obtém informações úteis de solução de problemas sobre ele. E as informações que você obtém podem não ser úteis para erros intermitentes.

O que recomendamos no ambiente de nuvem em que o armazenamento é barato é que você sempre deixe o logon em produção. Dessa forma, quando ocorrem erros, você já os registra e tem dados históricos que podem ajudá-lo a analisar problemas que se desenvolvem ao longo do tempo ou acontecem regularmente em momentos diferentes. Você pode automatizar um processo de limpeza para excluir logs antigos, mas pode achar que é mais caro configurar esse processo do que manter os logs.

A despesa adicional do registro em log é trivial em comparação com a quantidade de tempo e dinheiro de solução de problemas que você pode economizar tendo todas as informações que você precisa já disponíveis quando algo der errado. Então, quando alguém lhe diz que teve um erro aleatório por volta das 8:00 da noite passada, mas eles não se lembram do erro, você pode facilmente descobrir qual era o problema.

Por menos de US$ 4 por mês, você pode manter 50 gigabytes de logs em mãos, e o impacto no desempenho do registro em log é trivial, desde que você tenha uma coisa em mente , a fim de evitar gargalos de desempenho, verifique se sua biblioteca de registro em log é assíncrona.

Diferenciar logs que informam de logs que exigem ação

Os logs destinam-se a INFORMAR (quero que você saiba alguma coisa) ou ACT (quero que você faça algo). Tenha cuidado para gravar apenas logs act para problemas que realmente exigem que uma pessoa ou um processo automatizado tome medidas. Muitos logs act criarão ruído, exigindo muito trabalho para peneirar tudo isso para encontrar problemas genuínos. E se os logs do ACT dispararem automaticamente alguma ação, como enviar emails para a equipe de suporte, evite permitir que milhares dessas ações sejam disparadas por um único problema.

No rastreamento do .NET System.Diagnostics, os logs podem receber Erro, Aviso, Informações e Nível de Depuração/Detalhado. Você pode diferenciar o ACT dos logs de INFORM reservando o nível de erro para logs act e usando os níveis mais baixos para logs informá-los.

Níveis de registro em log

Configurar níveis de log em tempo de execução

Embora valha a pena fazer logon sempre em produção, outra prática recomendada é implementar uma estrutura de registro em log que permite ajustar em tempo de execução o nível de detalhes que você está registrando em log, sem reimplantar ou reiniciar seu aplicativo. Por exemplo, ao usar o recurso de rastreamento no System.Diagnostics , você pode criar logs de Erro, Aviso, Informações e Depuração/Detalhados. Recomendamos que você sempre registre logs de Erros, Avisos e Informações em produção e deseja ser capaz de adicionar dinamicamente o log de Depuração/Detalhado para solução de problemas caso a caso.

Aplicativos Web em Serviço de Aplicativo do Azure têm suporte interno para gravar System.Diagnostics logs no sistema de arquivos, no Armazenamento de Tabelas ou no Armazenamento de Blobs. Você pode selecionar diferentes níveis de log para cada destino de armazenamento e pode alterar o nível de registro em log em tempo real sem reiniciar o aplicativo. O suporte ao Armazenamento de Blobs facilita a execução de trabalhos de análise do HDInsight em seus logs de aplicativos, pois o HDInsight sabe como trabalhar diretamente com o Armazenamento de Blobs.

registrar exceções em log

Não basta colocar exceção. ToString() em seu código de registro em log. Isso deixa de fora informações contextuais. No caso de erros do SQL, ele deixa de fora o número de erro do SQL. Para todas as exceções, inclua informações de contexto, a própria exceção e exceções internas para garantir que você esteja fornecendo tudo o que será necessário para solução de problemas. Por exemplo, as informações de contexto podem incluir o nome do servidor, um identificador de transação e um nome de usuário (mas não a senha ou os segredos!).

Se você depender de cada desenvolvedor para fazer a coisa certa com o registro em log de exceções, alguns deles não. Para garantir que ele seja feito da maneira certa sempre, crie o tratamento de exceção diretamente na interface do agente: passe o próprio objeto de exceção para a classe de agente e registre os dados de exceção corretamente na classe de agente.

Registrar chamadas para serviços

É altamente recomendável que você escreva um log sempre que seu aplicativo chamar um serviço, seja para um banco de dados ou uma API REST ou qualquer serviço externo. Inclua em seus logs não apenas uma indicação de êxito ou falha, mas quanto tempo cada solicitação levou. No ambiente de nuvem, muitas vezes você verá problemas relacionados a lentidão em vez de interrupções completas. Algo que normalmente leva 10 milissegundos pode de repente começar a tomar um segundo. Quando alguém informa que seu aplicativo está lento, você deseja ser capaz de examinar o New Relic ou qualquer serviço de telemetria que você tenha e validar sua experiência e, em seguida, você deseja ser capaz de olhar são seus próprios logs para se aprofundar nos detalhes de por que ele é lento.

Usar uma interface ILogger

O que recomendamos fazer ao criar um aplicativo de produção é criar uma interface ILogger simples e colocar alguns métodos nele. Isso facilita a alteração da implementação de log posteriormente e não precisa passar por todo o código para fazer isso. Poderíamos estar usando a System.Diagnostics.Trace classe em todo o aplicativo Fix It, mas, em vez disso, estamos usando-a sob as capas em uma classe de registro em log que implementa o ILogger e fazemos chamadas de método ILogger em todo o aplicativo.

Dessa forma, se você quiser tornar o registro em log mais rico, poderá substituir System.Diagnostics.Trace por qualquer mecanismo de registro em log desejado. Por exemplo, à medida que seu aplicativo cresce, você pode decidir que deseja usar um pacote de registro em log mais abrangente, como NLog ou Enterprise Library Logging Application Block. (Log4Net é outra estrutura de registro em log popular, mas não faz log assíncrono.)

Um possível motivo para usar uma estrutura como o NLog é facilitar a divisão da saída de log em armazenamentos de dados separados de alto volume e de alto valor. Isso ajuda você a armazenar com eficiência grandes volumes de dados INFORM que você não precisa executar consultas rápidas, mantendo o acesso rápido aos dados act.

Registro em log semântico

Para obter uma maneira relativamente nova de fazer logs que podem produzir informações de diagnóstico mais úteis, consulte Enterprise Library Semmantic Logging Application Block (SLAB). O SLAB usa o ETW ( Rastreamento de Eventos para Windows ) e o suporte do EventSource no .NET 4.5 para permitir que você crie logs mais estruturados e consultáveis. Você define um método diferente para cada tipo de evento que você registra, o que permite personalizar as informações que você escreve. Por exemplo, para registrar um erro de Banco de Dados SQL, você pode chamar um LogSQLDatabaseError método. Para esse tipo de exceção, você sabe que uma informação importante é o número de erro, portanto, você pode incluir um parâmetro de número de erro na assinatura do método e registrar o número de erro como um campo separado no registro de log que você escreve. Como o número está em um campo separado, você pode obter relatórios mais facilmente e confiáveis com base nos números de erro do SQL do que você poderia se estivesse apenas concatenando o número de erro em uma cadeia de caracteres de mensagem.

Fazer logon no aplicativo Corrigir

A interface ILogger

Aqui está a interface ILogger no aplicativo Corrigir.

public interface ILogger
{
    void Information(string message);
    void Information(string fmt, params object[] vars);
    void Information(Exception exception, string fmt, params object[] vars);

    void Warning(string message);
    void Warning(string fmt, params object[] vars);
    void Warning(Exception exception, string fmt, params object[] vars);

    void Error(string message);
    void Error(string fmt, params object[] vars);
    void Error(Exception exception, string fmt, params object[] vars);

    void TraceApi(string componentName, string method, TimeSpan timespan);
    void TraceApi(string componentName, string method, TimeSpan timespan, string properties);
    void TraceApi(string componentName, string method, TimeSpan timespan, string fmt, params object[] vars);
}

Esses métodos permitem que você escreva logs nos mesmos quatro níveis com suporte do System.Diagnostics. Os métodos TraceApi são para registrar chamadas de serviço externo com informações sobre latência. Você também pode adicionar um conjunto de métodos para o nível de Depuração/Detalhado.

A implementação do Agente da interface ILogger

A implementação da interface é realmente simples. Basicamente, ele chama apenas os métodos padrão System.Diagnostics . O snippet a seguir mostra todos os três métodos De informações e um de cada um dos outros.

public class Logger : ILogger
{
    public void Information(string message)
    {
        Trace.TraceInformation(message);
    }

    public void Information(string fmt, params object[] vars)
    {
        Trace.TraceInformation(fmt, vars);
    }

    public void Information(Exception exception, string fmt, params object[] vars)
    {
        var msg = String.Format(fmt, vars);
        Trace.TraceInformation(string.Format(fmt, vars) + ";Exception Details={0}", exception.ToString());
    }

    public void Warning(string message)
    {
        Trace.TraceWarning(message);
    }

    public void Error(string message)
    {
        Trace.TraceError(message);
    }

    public void TraceApi(string componentName, string method, TimeSpan timespan, string properties)
    {
        string message = String.Concat("component:", componentName, ";method:", method, ";timespan:", timespan.ToString(), ";properties:", properties);
        Trace.TraceInformation(message);
    }
}

Chamando os métodos ILogger

Sempre que o código no aplicativo Fix It captura uma exceção, ele chama um método ILogger para registrar os detalhes da exceção. E sempre que faz uma chamada para o banco de dados, o serviço Blob ou uma API REST, ele inicia um cronômetro antes da chamada, interrompe o cronômetro quando o serviço retorna e registra o tempo decorrido junto com informações sobre êxito ou falha.

Observe que a mensagem de log inclui o nome da classe e o nome do método. É uma boa prática garantir que as mensagens de log identifiquem qual parte do código do aplicativo as escreveu.

public class FixItTaskRepository : IFixItTaskRepository
{
    private MyFixItContext db = new MyFixItContext();
    private ILogger log = null;

    public FixItTaskRepository(ILogger logger)
    {
        log = logger;
    }

    public async Task<FixItTask> FindTaskByIdAsync(int id)
    {
        FixItTask fixItTask = null;
        Stopwatch timespan = Stopwatch.StartNew();

        try
        {
            fixItTask = await db.FixItTasks.FindAsync(id);
            
            timespan.Stop();
            log.TraceApi("SQL Database", "FixItTaskRepository.FindTaskByIdAsync", timespan.Elapsed, "id={0}", id);
        }
        catch(Exception e)
        {
            log.Error(e, "Error in FixItTaskRepository.FindTaskByIdAsynx(id={0})", id);
        }

        return fixItTask;
    }

Portanto, agora, para cada vez que o aplicativo Fix It faz uma chamada para Banco de Dados SQL, você pode ver a chamada, o método que o chamou e exatamente quanto tempo levou.

Banco de Dados SQL consulta em logs

captura de tela mostrando as Propriedades de Edição de Entidade e como cada propriedade deve ser para uma atualização bem-sucedida com quanto tempo levou.

Se você navegar pelos logs, poderá ver que o tempo que as chamadas de banco de dados levam é variável. Essas informações podem ser úteis: porque o aplicativo registra tudo isso, você pode analisar tendências históricas em como o serviço de banco de dados está se saindo ao longo do tempo. Por exemplo, um serviço pode ser rápido na maior parte do tempo, mas as solicitações podem falhar ou as respostas podem diminuir em determinadas horas do dia.

Você pode fazer a mesma coisa para o serviço Blob – para cada vez que o aplicativo carrega um novo arquivo, há um log e você pode ver exatamente quanto tempo levou para carregar cada arquivo.

Log de upload de blob

São apenas algumas linhas extras de código para escrever toda vez que você chama um serviço, e agora sempre que alguém diz que teve um problema, você sabe exatamente qual era o problema, se foi um erro ou mesmo se estava apenas ficando lento. Você pode identificar a origem do problema sem precisar fazer o controle remoto em um servidor ou ativar o registro em log após o erro acontecer e esperar criá-lo novamente.

Injeção de dependência no aplicativo Corrigir

Você pode se perguntar como o construtor do repositório no exemplo mostrado acima obtém a implementação da interface do agente:

public class FixItTaskRepository : IFixItTaskRepository
{
    private MyFixItContext db = new MyFixItContext();
    private ILogger log = null;

    public FixItTaskRepository(ILogger logger)
    {
        log = logger;
    }

Para conectar a interface à implementação, o aplicativo usa di (injeção de dependência) com AutoFac. A DI permite que você use um objeto com base em uma interface em muitos locais em todo o código e só precisa especificar em um só lugar a implementação que é usada quando a interface é instanciada. Isso facilita a alteração da implementação: por exemplo, talvez você queira substituir o agente System.Diagnostics por um agente do NLog. Ou, para testes automatizados, talvez você queira substituir uma versão simulada do agente.

O aplicativo Fix It usa DI em todos os repositórios e todos os controladores. Os construtores das classes de controlador obtêm uma interface ITaskRepository da mesma forma que o repositório obtém uma interface do agente:

public class DashboardController : Controller
{
    private IFixItTaskRepository fixItRepository = null;

    public DashboardController(IFixItTaskRepository repository)
    {
        fixItRepository = repository;
    }

O aplicativo usa a biblioteca de DI do AutoFac para fornecer automaticamente instâncias taskRepository e Logger para esses construtores.

public class DependenciesConfig
{
    public static void RegisterDependencies()
    {
        var builder = new ContainerBuilder();

        builder.RegisterControllers(typeof(MvcApplication).Assembly);
        builder.RegisterType<Logger>().As<ILogger>().SingleInstance();

        builder.RegisterType<FixItTaskRepository>().As<IFixItTaskRepository>();
        builder.RegisterType<PhotoService>().As<IPhotoService>().SingleInstance();
        builder.RegisterType<FixItQueueManager>().As<IFixItQueueManager>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

Esse código basicamente diz que em qualquer lugar em que um construtor precise de uma interface ILogger , passe uma instância da classe Logger e sempre que precisar de uma interface IFixItTaskRepository , passe uma instância da classe FixItTaskRepository .

AutoFac é uma das muitas estruturas de injeção de dependência que você pode usar. Outro popular é o Unity, que é recomendado e suportado por Padrões e Práticas da Microsoft.

Suporte a log interno no Azure

O Azure dá suporte aos seguintes tipos de registro em log para Aplicativos Web no Serviço de Aplicativo do Azure:

  • Rastreamento system.Diagnostics (você pode ativar e desativar e definir níveis em tempo real sem reiniciar o site).
  • Eventos do Windows.
  • Logs do IIS (HTTP/FREB).

O Azure dá suporte aos seguintes tipos de logon em Serviços de Nuvem:

  • Rastreamento system.diagnostics.
  • Contadores de desempenho.
  • Eventos do Windows.
  • Logs do IIS (HTTP/FREB).
  • Monitoramento de diretório personalizado.

O aplicativo Fix It usa o rastreamento System.Diagnostics. Tudo o que você precisa fazer para habilitar o log do System.Diagnostics em um aplicativo Web é inverter um comutador no portal ou chamar a API REST. No portal, clique na guia Configuração do site e role para baixo para ver a seção Diagnóstico do Aplicativo . Você pode ativar ou desativar o log e selecionar o nível de registro em log desejado. Você pode fazer com que o Azure escreva os logs no sistema de arquivos ou em uma conta de armazenamento.

Diagnóstico de aplicativo e diagnóstico de site na guia Configurar

Depois de habilitar o registro em log no Azure, você poderá ver os logs na janela Saída do Visual Studio conforme eles são criados.

Menu Logs de streaming

Menu Logs de streaming2

Você também pode ter logs gravados em sua conta de armazenamento e exibi-los com qualquer ferramenta que possa acessar o serviço tabela de armazenamento do Azure, como Explorer de servidor no Visual Studio ou Gerenciador de Armazenamento do Azure.

Logs no Explorer do Servidor

Resumo

É muito simples implementar um sistema de telemetria pronto para uso, instrumentar o registro em log em seu próprio código e configurar o registro em log no Azure. E quando você tiver problemas de produção, a combinação de um sistema de telemetria e logs personalizados ajudará você a resolve problemas rapidamente antes que eles se tornem grandes problemas para seus clientes.

No próximo capítulo , veremos como lidar com erros transitórios para que eles não se tornem problemas de produção que você precisa investigar.

Recursos

Para obter mais informações, consulte os recursos a seguir.

Documentação principalmente sobre telemetria:

Documentação principalmente sobre registro em log:

Documentação principalmente sobre solução de problemas:

Vídeos:

  • FailSafe: criando Serviços de Nuvem escalonáveis e resilientes. Série de nove partes de Ulrich Homann, Marc Mercuri e Mark Simms. Apresenta conceitos de alto nível e princípios arquitetônicos de maneira muito acessível e interessante, com histórias extraídos da experiência da CAT (Equipe de Consultoria de Clientes) da Microsoft com clientes reais. Os episódios 4 e 9 são sobre monitoramento e telemetria. O episódio 9 inclui uma visão geral dos serviços de monitoramento MetricsHub, AppDynamics, New Relic e PagerDuty.
  • Criando grandes: lições aprendidas com os clientes do Azure – Parte II. Mark Simms fala sobre como projetar para falhas e instrumentar tudo. Semelhante à série Failsafe, mas entra em mais detalhes de instruções.

Exemplo de código: