sábado, 30 de janeiro de 2016

Utilizando o NLog

É um vídeo muito mais simples que o citado no post do log4net, mostrando muito menos detalhes, mas já dá para ver que é muito rápido começar a utilizar o NLog.

Há muita documentação no wiki do pacote oficial do GitHub.

1 - Instalar na aplicação o pacote nuget, que pode ser feito via comando no Package Manager Console:

Install-Package NLog

Para ser um acelerador, aconselho instalar a configuração na aplicação:
Install-Package NLog.Config

Há diversos instaladores específicos para facilitar ainda mais o uso, dependendo do projeto que for necessário:
  • NLog.Web - pacote contem targets e layout-renderes específicos para o ASP.Net and IIS.
  • NLog.Windows.Forms - pacote contem targets específicos Windows.Forms
  • NLog.Extended - MSMQ target, AppSetting layout renderer
  • NLog.Config - Configuração NLog exemplo/inicial
  • NLog.Schema - XSD Schema para o NLog config xml - para, entre outras coisas, ter o Intellisense no Visual Studio

2 - Configurar NLog.config

Aqui o NLog fica muito mais simples, já que o intellisense do Visual Studio ajuda em toda a configuração do arquivo.

O nível (level) do NLog possibilita as essas opções:
  • Trace - log muito detalhado, o que pode incluir alto volume de informação (como payload do protocolo). Este nível de log é tipicamente habilitado somente durante o desenvolvimento.
  • Debug - informação de depuração, menos detalhada que o trace, tipicamente não habilitado em produção.
  • Info - mensagens de informação, que normalmente são habilitado no ambiente de produção
  • Warn - mensagens de avisos, tipicamente para assuntos não críticos, que podem ser recuperadas ou falhas temporárias
  • Error - mensagens de erros - na maioria das vezes estas são exceções
  • Fatal - erros muito sérios
O que é o appender do log4net no NLog é o Targets (https://github.com/nlog/nlog/wiki/Targets)
Há também vários layouts disponívels (https://github.com/nlog/nlog/wiki/Layouts)
E é possível configurá-los com várias opções (https://github.com/NLog/NLog/wiki/Layout-renderers)

O resultado é uma configuração extremamente simples:

 Também é fácil fazer a configuração do log através de programação, como nesta resposta do Stack Overflow "Add, enable and disable NLog loggers programmatically".

3 Definir a instância da classe

Há um método para facilitar a configuração da instância na classe:

4 Efetuar log

logger.Trace("");
logger.Debug("");
logger.Info("");
logger.Warn("");
logger.Error("");
logger.Fatal("");

logger.Log(LogLevel.Info, "");

O código fonte do exemplo está disponível no GitHub.

Conhecendo o log4Net

Para conhecer o log4Net há algumas boas referências:

São necessários 5 passos para utilizar o log4net:

1 - Instalar na aplicação o pacote nuget, que pode ser feito via comando no Package Manager Console:

Install-Package log4net

2 - Configurar no app.config ou web.config o log, seguindo a documentação

A vantagem de definir as configurações do log nesses arquivos é poder alterá-las em ambiente de execução, sem necessidade de compilar as soluções
No elemento <confisections> configuramos que no arquivo haverá a seção para o log4net. No elemento <log4net>definimos a configuração do log.

<root>

O <root> é necessário para definir o nível(level) de log através do elemento (filtrando mensagens de relevância menor que a definida) e há 7 níveis:
  1. OFF - Nada é logado
  2. FATAL
  3. ERROR
  4. WARN
  5. INFO
  6. DEBUG
  7. ALL - Tudo é logado
Por exemplo, se o nível do log for definido para ERROR, somente mensagens de ERROR e FATAL serão armazenadas.
Além disso é necessário adicionar a tag <appender-ref> referenciando os appenders  (Que falaremos abaixo)

No exemplo acima no estou utilizando:
  • ConsoleAppender, ou seja, os logs sao enviados ao Console
  • FileAppender, para salvar em disco (No qual configuerei para salvar somente a última execução com a tag <appendtofile value="false">)




  • RollingFileAppender (Para salvar um histórico de arquivo limitando quantidade e tamanho)

  • Uma propriedade comum que utilizei nesses appenders foram os elementos <layout> e o <conversionpattern>. Há algumas opções interessantes como:
    • timestamp  = Número de milissegundos desde o início da aplicação)
    • %20timestamp = Para garantir que item a ser logado tenha no mínimo 20 caracteres, adicionando espaço. No exemplo acima, fará para o valor do timestamp
    • %property{user} = que podemos definir uma propriedade definida no código

    Para entender todas as demais configurações feitas, sugiro consultar a documentação que está no link de cada appender citado.

    Ainda há várias outras opções de Appenders como podemos ver na documentação.
    Também é possivel customizar appenders, como no exemplo deste link que faz um appender para CSV.

    No vídeo ainda é demonstrado o o AdoNetAppender salvando informações na base de dados.

    3 Aplicar as configurações do app.config

    Ao adicionar essa linha de código(para organizacao, no program.cs abaixo dos using), toda a configuração do log4net será feita lendo o arquivo de configuração (E recarregada em caso de alterações):

    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    

    Ou para a web:

    4 Configurar a instância

    Para configurar a instância, são indicadas 2 formas:
    1) Se você utilizar a Framework anterior a 4.5, deverá instanciar em toda classe conforme abaixo:
    Dessa forma o log é instanciado por classe e você saberá onde o log foi feito. O parâmetro string que esta sendo passado por reflector facilitar o copiar e colar, mas gera uma pequena perda de desempenho (Ja que a instância estática é criada uma vez por cada classe)


    2) A partir da framework 4.5 é possivel resolver o nome do log em momento de compilacao, utilizando o código abaixo:
    O código do LogHelper está disponível aqui:

    5 Efetuar log

    A parte mais fácil é utilizar o log. Basta utilizar a instância criada na classe e chamar os métodos:
    • Debug()
    • Info()
    • Warn()
    • Error()
    • Fatal()

    O código fonte do exemplo está disponível no GitHub.

    Log de aplicações (Avaliando as boas opções)

    O log pode ajudar, mas cuidado com o excesso

    O post “The problem with loggin” explica alguns cuidados para não se exceder ao usar log.

    O System.Diagnostics não é suficiente?

    No post “Logging best practices há uma crítica em relação ao excesso de frameworks alternativas de log, que ao invés de preencher os Gaps que faltam no Trace padrão, o reinventam completamente. Um examplo de proposta que preenche os Gaps é o Essential Diagnostics (http://essentialdiagnostics.codeplex.com/)

    Quais as outras frameworks?

    No post “When should I use Tracing vs Logger.NET, Enterprise Library, log4net or Ukadc.Diagnostics? estão listadas várias opções de pacotes de Log.

    No nuget, olhando a estatística de mais baixados
    de 6 semanas do dia 30/1/2016 estão:

    No github, o NLog está com mais popularidade:

    No post “log4net vs. Nlogainda é discutido a percepção de diversos outros desenvolvedores.
    Nos próximos posts, vou falar fazer exemplo dos dois pacotes. Tanto o System.Diagnostics, o log4net e o NLog são excelentes opções - mas pensando no que é mais simples de utilizar(e principalmente configurar) eu acabei preferindo o NLog.

    terça-feira, 26 de janeiro de 2016

    Teste unitário com Selenium WebDriver (Simples exemplo com o Chrome e Firefox)

    O vídeo(Selenium WebDriver - Install + Hello World with Visual Studio, C#)  é um ótimo passo a passo de como utilizar o Selenium Webdriver com uma aplicação c#.

    Para demonstrar, adicionei ao GitHub um simples exemplo de teste unitário fazendo uma busca no Bing utilizando Chrome e Firefox.

    As dependências dos projeto foram instaladas com o Nuget utilizando os seguintes comandos:
    Install-Package Selenium.WebDriver
    (Pacote básico para permitir o Selenium Webdriver e o firefox)

    Install-Package Selenium.WebDriver.ChromeDriver
    (Pacote para permitir os testes com o Chrome)

    O código acontece no método SearchAndNavigateTest, que basicamente abre a url do Bing, busca pela palavra chave "aplicacoesweb selenium" e clica no primeiro link que contiver "aplicacoesweb.blogspot" no atribute href.

    Este código é executado no FireFox e no Chrome no teste unitário TestMethod1()

    segunda-feira, 25 de janeiro de 2016

    Caching (OutputCacheAttribute e DonutCachingAttribute)

    O OutputCacheAttribute, atributo nativo no ASP.NET MVC, permite que façamos cache de resultados de actions para futuras respostas às requisições dos usuários. Há várias opções de configuração e é sugerido de se utilizar esse artifício quando você precisa otimizar o desempenho de sua aplicação.

    Otimizar desempenho é uma tarefa que deve ser feita de maneira muito criteriosa. Primeiro é importante você saber qual o problema atual a ser resolvido e as métricas da situação, por exemplo, está consumindo muito processamento determinada action (Atinge 100% de CPU, gasta muita memória e/ou demora muito tempo para retorno ao usuário). Deve-se tomar o cuidado para não aplicar uma solução de cache que poderá resolver os problemas anteriores, mas acabar gerando um outro problema de consumo de memória por manter as informações em cache. Por isso a importância das métricas antes e depois de aplicar a solução.

    Decidindo pela aplicação do OutputCacheAttribute é importante ainda saber que ele gera um cache respeitando configurações de variação por action do Controller, por tempo (Duration), por parâmetros de unicidade (VaryByContentEncoding, VaryByCustom, VaryByHeader, VaryByParam) e por local (Client, Downstream, Server). Se for decidido que o cache será no servidor é importante saber que futuras requisições nas condições de unicidade configuradas anteriormente receberá a informação do cache completa, ou seja, se o cache foi criado pela requisição de um usuário com perfil de administrador (que tem mais opções de menu que um usuário comum), todos os usuários ao requisitarem a página em cache irão ver a página como o administrador (com as opções de menu que não deveria ver).

    Se você tiver essa situação, para resolvê-la, há a teoria de cache chamada de Donut Hole Caching, que basicamente você pode escolher qual a parte do conteúdo deseja fazer cache e/ou qual deve ser atualizada automaticamente pelo contexto do usuário requisitante, este artigo em inglês explica a teoria de maneira detalhada e lúdica.

    Há uma implementação de pacote para utilizar o Donut Hole Caching no pacote Nuget MvcDonutCaching que também tem o fonte disponível no Github. Neste artigo há uma explicação de todas as dificuldades e escolhas feitas para viabilizar a implementação, mas basicamente a grande sacada é que utilizando o pacote, é possível definir ChildActions como dinâmicas para serem carregadas, mesmo quando o resto da página está em cache. Para viabilizar isso o pacote adiciona  comentário HTML para marcar pontos de atualização de parte de conteúdo nas próximas requisições, quando utilizado as extensões @HtmlAction(), @Html.RenderAction() e definindo o parâmetro excludeFromParentCache, conforme código abaixo:
    O ActionFilter (DonutOutputCacheAttribute) irá atualizar esses "buracos" no método OnResultExecuted.