.NET - Apresentando e usando Log4Net
Gravar informações de log de uma aplicação é um recurso básico e fundamental para uma aplicação robusta quer por razões de auditoria, segurança, rastreamento ou apenas informação. Você pode criar o seu próprio log ou usar os recursos que o Visual Basic oferece para isso. |
Nota: Eu já publiquei alguns artigos sobre como criar um log de erros, para saber mais veja em:
Então possuir uma ferramenta para logar informações sobre sua aplicação é de fundamental importância para todo o desenvolvedor pois ajuda a identificar problemas de forma mais rápida mostrando o estado da aplicação em um determinando ponto. Mas apenas gerar os arquivos de log não é suficiente é necessário estar equipado com um framework que seja fácil de configurar, usar e seja extensível. Seria ideal se ele fosse gratuito também.
Felizmente a descrição acima se encaixa na ferramenta Log4Net, um framework para gerar e gerenciar logs.
O log4net é um projeto open source sendo um porte
do famoso projeto log4j para Java que resultou em excelente trabalho, iniciado
por uma equipe da www.neoworks.com com as contribuições feitas pela comunidade.
O log4net oferece muitas vantagens em relação a outros sistemas de registro de
log, o que o torna uma escolha perfeita para o uso em qualquer tipo de
aplicação, a partir de um simples aplicativo de usuário único para a complexa
aplicação distribuída usando comunicação remota.
A lista detalha de recursos pode ser vista neste link : http://logging.apache.org/log4net/release/features.html
O manual pode ser consultado neste link: http://logging.apache.org/log4net/release/manual/introduction.html
Você pode baixar o Log4Net neste link: http://logging.apache.org/log4net/download_log4net.cgi
Ele pode ser baixado a partir do site sob a licença Apache. A versão mais recente é a 1.2.12, sobre a qual este artigo se baseia.
log4Net - Conceitos básicos
Vou dar um breve resumo sobre o Log4Net e sugiro que se consulte a documentação no site da Apache você realmente for utilizar a ferramenta pra valer em suas aplicações.
Estrutura do log4Net
O framework é construído sobre o conceito de camadas e possui 4 principais componentes: Logger, Repository, Appender, e Layout.
1- Logger
Este é o principal componente com o qual sua aplicação interage. É ele que gera as mensagens de log.
O logger fornece diferentes métodos para registrar
qualquer mensagem. Você pode criar vários loggers em aplicação. Cada logger que
você instancia em sua classe é mantida como uma "entidade nomeada" dentro do
framework log4net . Isso significa que você não precisa passar adiante a
instância do Logger entre as diferentes classes ou objetos para reutilizá-lo. Em
vez disso, você pode chamá-lo com esse nome de qualquer lugar no aplicativo. Os
loggers mantidos dentro do framework seguem uma determinada organização.
Atualmente, o framework log4net usa a organização hierárquica . Esta hierarquia
é semelhante à forma como definimos namespaces na plataforma . NET. Por exemplo,
suponha que existem dois loggers definidos como abc e ab. Neste caso, o logger
ab é considerado o ancestral do logger abc. Cada logger herda as propriedades de
seu logger pai. No topo da hierarquia esta o logger padrão, que também é chamado
de logger raiz, a partir do qual todos os loggers são herdados. Embora este
esquema de nomes de namespace seja preferido na maioria dos cenários, você pode
nomear seu logger a seu critério.
O log4Net define a interface ILog que deverá ser implementada por todos os loggers.
Níveis de log
Nesta a estrutura o log4Net oferece sete níveis de log e suas respectivas propriedades booleanas e cinco métodos diferentes para realizar um trace em um aplicativo conforme mostra a tabela abaixo:
Nível |
Método permitido | propriedade Boolean |
Valor |
OFF |
nada é logado | Não pode ser chamado | |
FATAL |
void
Fatal(...); |
bool
IsFatalEnabled; |
|
ERROR |
void Error(...); |
bool
IsErrorEnabled; |
|
WARN |
void Warn(...); |
bool
IsWarnEnabled; |
|
INFO |
void Info(...); |
bool
IsInfoEnabled; |
|
DEBUG |
void
Debug(...); |
bool
IsDebugEnabled; |
|
ALL |
Tudo é logado | Não pode ser chamado |
Cada logger é atribuído com um nível de prioridade (mostrados na tabela acima). Se não for atribuído um nível de prioridade a um logger ele tentará herdar o valor do nível do seu ancestral de acordo com a hierarquia.
Vamos supor que você criou um objeto logger e atribuiu a ele o nível INFO. Nesta caso o framework irá definir sua propriedade Boolean individual sendo que verificação do nível é realizada quando você chamar qualquer um dos métodos para realizar o log.
Esses conceitos ficarão mais claros nos exemplos que veremos adiante.
2- Repository
Essa segunda camada é responsável por manter a organização dos loggers.(para mais detalhes consulte o manual)
3- Appender
Qualquer framework decente para logo deve ser capaz de gerar a saída para vários destinos, como a saída das instruções de rastreamento para o console ou a serialização em um arquivo de log. O log4net é uma combinação perfeita para este requisito. Ele usa um componente chamado Appender para definir o meio de saída. Tal como o nome sugere, estes componentes acrescentam-se a si mesmos ao componente Loggerr e retransmitem a saída para um fluxo de saída. Você pode acrescentar vários appenders a um único logger. Existem vários appenders fornecidos pela estrutura log4net, a lista completa de appenders fornecidos pela estrutura log4net pode ser vista neste link, na seção Appender: http://logging.apache.org/log4net/release/manual/introduction.html
Cada tipo de appender tem seu próprio conjunto de sintaxe baseada para onde os dados estão indo. Os mais usuais são os que registram a bases de dados. Vou listar os 3 appenders mais importantes e comuns:
Este appender é geralmente usado para testes mas pode ser útil também em produção. Ele escreve a saída para janela OutPut ou para janela Command se você estiver usando uma aplicação do tipo Console.
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date{ABSOLUTE} [%thread] %level %logger - %message%newline"/> </layout> <filter type="log4net.Filter.StringMatchFilter"> <stringToMatch value="teste" /> </filter> <filter type="log4net.Filter.DenyAllFilter" /> </appender> |
Neste exemplo usa o layout que exibe a saída no formato: "2013-10-22 15:41:03,581 [10] WARN Log4NetTeste.frmMain - teste, nível WARN." e coloca uma nova linha no final.
Este appender irá escrever a saída em um arquivo texto. Para usar este appender temos que especificar o nome do arquivo texto.(Se não informar o caminho o arquivo será armazenado no mesmo local do executável.). Note que indicamos que os registros serão anexados (<appendToFile value="true" />) ao arquivo, ao invés de sobrescrever o que já existe. Definimos também que o nível de lock será mínimo o que permite que o arquivo seja usado por múltiplos appenders.
<appender name="FileAppender" type="log4net.Appender.FileAppender"> <file value="MeuArquivodeLog.txt" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="INFO" /> <levelMax value="FATAL" /> </filter> </appender> |
Este é uma appender que sempre que possível deve ser usado no lugar do
file appender. O seu objetivo é realizar as mesmas funções que o file
appender mas com uma opção adicional para armazenar apenas uma certa
quantidade de dados antes de iniciar um novo arquivo de log.
Mesmo um pequeno aplicativo pode sobrecarregar o sistema de arquivos se for dado
tempo suficiente para escrever em arquivo de texto, se a opção de restrição de
tamanho não for utilizada. Neste exemplo , estou logando da mesma forma que o
file appender acima , mas estou especificando que o arquivo de log deve ser
limitado a 1MB e que deve ser mantido até 5 arquivos compactados antes de eu
começar excluí-los (o mais antigo é excluído primeiro ).
Os arquivos serão nomeados com o mesmo nome que o arquivo, só com um ponto e o número depois dele (exemplo: MeuArqiuvoDeLog.txt.2 seria o segundo arquivo do arquivo de log ) . A entrada staticLogFileName garante que o arquivo de log atual sempre será nomeado conforme foi especificado na tag file (no meu caso , MeuArquivoDeLog.txt).
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="MeuArquivodeLog.txt" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="5" /> <maximumFileSize value="1MB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender> |
Este appender registra o log de eventos para um banco de dados. Ele usa uma sintaxe onde temos um ConnectionType que é basicamente uma seqüência de conexão, um commandText que especifica uma consulta simples onde você pode definir qualquer tipo de consulta INSERT (ou Stored Procedure), e as definições de parâmetros onde cada parâmetro é especificado e mapeado para uma variável log4net. O tamanho pode ser especificado para limitar a informação colocada na parâmetro. Não vou entrar em detalhes deste appender pois vou escrever uma artigo específico onde ele será usado.
4- Filters
Os Appenders podem filtrar os eventos que são
enviados a a eles. Os filtros podem ser especificados na configuração para
permitir o controle preciso dos eventos que são registrados através de
diferentes appenders.
A forma mais simples de controle é especificar um limite no appender. Isso
funcionando registrando apenas os eventos que têm um nível que é igual ou
superior ao limite definido. (Para detalhes veja, seção Filters, em :
http://logging.apache.org/log4net/release/manual/introduction.html
Vejamos um exemplo de de filtro com o filtro:
LevelRangeFilter
Um filtro de faixa de nível informa que o sistema registra apenas as entradas
que estão dentro do intervalo especificado. Este intervalo é inclusivo, assim,
no exemplo abaixo, os eventos com nível de INFO, WARN, ERROR, FATAL ou
serão registrados, mas eventos de DEBUG serão ignorados.
<filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="INFO" /> <levelMax value="FATAL" /> </filter> |
5- Layout
O componente layout é utilizado para mostrar a saída formatada final para o usuário. A saída pode ser mostrada em vários formatos, dependendo do esquema que estamos usando. Pode ser linear ou um arquivo XML. O componente de layout trabalha com um appender. Há uma lista de diferentes layouts na documentação da API. Você não pode usar vários layouts com um appender. Para criar seu próprio layout, você precisa herdar a classe log4net.Layout.LayoutSkeleton, que implementa a interface ILayout.
Exemplo de sintaxe usada:
<
layout type="log4net.Layout.PatternLayout"><
conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" /></
layout>A entrada do padrão de conversão (conversionPattern) é usada para o layout padrão para indicar ao appender como a informação vai ser armazenada. Existem muitas palavras-chaves diferentes que podem ser usados nestes padrões , bem como sequências literais .
A seguir temos uma relação das sequências mais úteis e importantes. (A lista completa pode ser encontrada na documentação log4net.)
sequência | descrição |
%date | Mostra a data usando as informações de fuso horário local. Esta data pode ser formatada usando as chaves e um padrão de layout como %date{MMMM dd, aaaa hh:mm:ss,fff} para exibir a saída como "01 de janeiro de 2011 14:15:43,767 " . E aconselhável que você use um dos formatadores de datas do log4net (ABSOLUTE , DATE , ou ISO8601 ), uma vez que oferecem um melhor desempenho. |
%utcdate | É igual ao modificador date% , mas gera em tempo universal. Os modificadores de data/hora todos funcionam da mesma maneira . |
%exception | Se uma exceção é passada, ela será inserida e uma nova linha será colocada após a exceção. Se nenhuma exceção for passada , essa entrada será ignorada e nenhuma nova linha irá ser colocada. A nova linha é geralmente colocado na extremidade do log de entrada, e, geralmente, uma nova linha também é colocada antes da exceção. |
%level | Este é o nível especificado para o evento ( DEBUG , INFO, WARN , etc.) |
%message | Esta é a mensagem que você passou para o log de eventos. |
%newline | Esta é uma nova entrada de linha . Com base na plataforma na qual você está usando o aplicativo, esta será traduzida para o caractere de nova linha apropriado. (Este é o método preferido para introduzir uma nova linha e não tem problemas de desempenho em comparação com os operadores específicos da plataforma.) |
%timestamp | Indica o número de milissegundos desde o início da aplicação. |
%therad | Informa o nome da thread onde a entrada foi feita (ou o número se o segmento não for nomeado). |
%identity | Indica o nome do usuário atual usando o método Principal.Identity.Name |
%location | É útil se você estiver rodando no modo Debug. Informa onde o método log foi chamado (número da linha, método). |
%line | Indica o número da linha de código de entrada |
%method | Indica o método que chamou o log de entrada |
%username | Exibe a saída da propriedade WindowsIdentity. |
Configurando o log4Net em sua aplicação
Antes de começar a usar o log4Net em sua aplicação você precisa configurar os seus componentes. Existem dois métodos diferentes que podemos usar para especificar a configuração do log4Net:
O primeiro método tem as seguintes vantagens:
Nota:Pense bem nisso antes de definir qual método vai usar.
No arquivo de configuração você precisa ter uma seção <root> para definir as suas referências de logger de nível superior. Estes são os loggers que herdam informações do seu logger base (root). Outra coisa a seção <root> define é o nível mínimo para registrar eventos de log. Uma vez que tudo herda a partir do root, nenhum appender irá registrar informações abaixo da que foi especificada aqui. Esta é uma maneira fácil de controlar rapidamente o nível de registro em sua aplicação. Aqui está um exemplo com um nível padrão INFO (o que significa que as mensagens de depuração serão ignoradas) e uma referência a dois appenders que devem ser habilitados na raiz:
<root>
<level value="INFO"/>
<appender-ref ref="FileAppender"/>
<appender-ref ref="ConsoleAppender" />
</root>
|
Algumas vezes você vai desejar conhecer mais sobre uma parte particular de sua aplicação. Você pode fazer isso especificando referências a um logger adicional além das definidas na seção root. A seguir temos um exemplo onde um logger adicional foi colocado no arquivo config da aplicação para logar as mensagens do console que ocorrem no interior da classe MacClass:
<logger name="Log4NetTest.MacClass">
<level value="DEBUG"/>
<appender-ref ref="ConsoleAppender"/>
</logger>
|
Em um arquivo de configuração onde haverá mais informações armazenadas além de apenas as informações de configuração log4net, você precisará especificar uma seção para identificar onde a configuração log4net está armazenada. No exemplo a seguir usamos a seção configSections para especificar que as informações de configurações do log4net serão armazenadas sobre a tag "log4net".
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
|
Modelo do arquivo de configuração
A seguir temos um modelo do arquivo de configuração que você pode usar para criar o seu arquivo. O arquivo esta vazio e tem cada uma das seções identificadas para ajudar a identificação:
<!--This is the root of your config file--> <configuration> <!-- Level 0 --> <!--This specifies what the section name is--> <configSections> <!-- Level 1 --> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> <!-- Level 2 --> </configSections> <log4net> <!-- Level 1 --> <appender> <!-- Level 2 --> <layout> <!-- Level 3 --> <conversionPattern /> <!-- Level 4 --> </layout> <filter> <!-- Level 3 --> </filter> </appender> <root> <!-- Level 2 --> <level /> <!-- Level 3 --> <appender-ref /> <!-- Level 3 --> </root> <logger> <!-- Level 2 --> <level /> <!-- Level 3 --> <appender-ref /> <!-- Level 3 --> </logger> </log4net> </configuration> |
Usando o log4Net com o Visual Studio Express 2012 for desktop
Abra o Visual Studio 2012 Express for desktop e clique em New Project;
Selecione a linguagem Visual Basic e o template Windows Forms application e informe o nome Log4Net_Teste1 e clique em OK;
Vamos adicionar uma referência a library log4Net em nosso projeto. Podemos fazer isso manualmente baixando o pacote do site da Apache ou usando o Nuget. Vou usar o Nuget pois é mais fácil e prático.
A seguir clique no menu TOOLS -> Library Package Manager -> Manage Nuget Package for Solution;
Clique na guia OnLine e a seguir digite na caixa de busca log4net;
Escolha o pacote log4Net 1.2.12 e clique no botão Install;
Confirme a instalação e ao final clique no botão Close;
Vamos incluir no formulário form1.vb 3 controles Button a partir da ToolBox conforme o leiaute da figura abaixo:
Agora vamos criar duas classes em nosso projeto chamadas Mac1 e Mac2 contendo o método Executar. Para isso clique em PROJECT->Add Class e informe o nome Mac1.vb repetindo a operação para criar a classe Mac2.vb.
Agora vamos definir o código da classe Mac1 no arquivo Mac1.vb conforme abaixo:
Imports
log4net Public Class Mac1Private Shared log As ILog = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType) Public
Sub
Executar() End Class |
Repita o procedimento e defina o código da classe Mac2 no arquivo Mac2.vb como mostrado a seguir:
Imports
log4net Public Class Mac2Private Shared log As ILog = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType) Public
Sub
Executar() End Class |
Observe que tivemos que importar o namespaces do log3Net e definir uma instância do logger usando a interface ILog.
Voltemos agora para o nosso formulário form1.vb
A seguir inclua os seguintes namespaces no formulário form1.vb (ou na classe onde desejar usar o log4net):
Imports
log4netA seguir vamos definir uma instância estática da interface ILog no formulário:
Private
Shared log As log4net.ILogNo evento Load do formulário vamos fazer uma chamada ao método Configure da classe BasicConfigurator do log4net;
Private
Sub
Form1_Load(sender As
Object,
e As
EventArgs)
Handles
MyBase.Load log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)BasicConfigurator.Configure() log.Debug( "Evento Load do formulário form1")End Sub |
Estamos usando o nível de prioridade DEBUG.
No evento Click do botão de comando Chamar Classe Mac1 inclua o código abaixo:
Private
Sub
btnChamarMac1_Click(sender
As
Object,
e As
EventArgs)
Handles
btnChamarMac1.Click log.Debug( "Chamando a classe Mac1")Dim oMac1 As New Mac1 oMac1.Executar() log.Debug( "Retornado ao formulário form1")End Sub |
No evento Click do botão de comando Chamar Classe Mac2 inclua o código abaixo:
Private
Sub
btnChamarMac2_Click(sender
As
Object,
e As
EventArgs)
Handles
btnChamarMac2.Click log.Debug( "Chamando a classe Mac2")Dim oMac2 As New Mac2 oMac2.Executar() log.Debug( "Retornado ao formulário form1")End Sub |
Em cada código do evento Click dos botões estamos logando usando o nível DEBUG.
Execute a aplicação pressionando F5.
Após a aplicação iniciar abra janela "Output" (Ctrl+Alt+O) e clique em cada um dos botões de comando do formulário.
O resultado pode ser visto na figura abaixo:
Creio que essa é uma das formas mais simples (e limitada) de ver o log4net funcionando.
Esta abordagem permite que você comece a logar rapidamente e ainda tem as seguintes vantagens:
A desvantagem é que essa abordagem serve apenas para fins de ilustração ou para uma aplicação de teste.
Usando o log4Net com um arquivo de configuração
Vamos agora incluir um novo formulário em nosso projeto via Menu PROJECT -> Add Windows Form;
Aceite o nome padrão form2.vb e clique em Add;
A seguir vamos incluir no formulário form2.vb 5 botões de comando para podermos usar os demais níveis de prioridade do log4net.
A partir da ToolBox inclua 5 Buttons no formulário form2.vb conforme mostra a figura abaixo:
A seguir inclua os seguintes namespaces no formulário form2.vb.
Imports
log4netA seguir vamos definir uma instância estática da interface ILog no formulário:
Private
Shared log As log4net.ILogNo evento Load do formulário vamos fazer uma chamada ao método Configure da classe BasicConfigurator do log4net;
Private
Sub
Form1_Load(sender As
Object,
e As
EventArgs)
Handles
MyBase.Load log = log4net. LogManager.GetLogger("AplicacaoMacoratti")log4net.Config.XmlConfigurator.Configure() End Sub |
Desta vez estamos definindo um logger com o nome AplicacaoMacoratti e usando um arquivo de configuração.
A seguir vamos definir em cada evento Click dos botões o log correspondente a cada nível definido:
Private
Sub
btnDebug_Click(sender As
Object,
e As
EventArgs)
Handles
btnDebug.Click
log.Debug( "Debug' -> nível de mensagem")
End
Sub log.Info( "Info' -> nível de mensagem")
End
Sub log.Warn( "Warning' -> nível de mensagem")
End
Sub log.Error( "'Error' -> nível de mensagem")
End
Sub log.Fatal( "'Fatal' -> nível de mensagem")End Sub
|
Bem, agora temos que incluir um arquivo de configuração ao nosso projeto. Podemos criar o nosso próprio arquivo ou usar o arquivo App.Config que foi criado com o projeto. Eu vou usar o arquivo App.Config.
Abra o arquivo App.Config e inclua as linhas de código destacadas em azul conforme mostrado abaixo:
<? xml version="1.0" encoding="utf-8" ?>< configuration>< startup>< supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></ startup>
< section name="log4net"type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </ configSections></ configuration>
|
Agora vamos criar uma nova tag chamada <log4net> sob a tag </configSections>. Abra a tag e coloque o código a seguir no interior da tag <log4net>:
.... < appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">< file value="c:\dados\logMac.txt" />< appendToFile value="true" />< rollingStyle value="Size" />< maxSizeRollBackups value="3" />< maximumFileSize value="150KB" />< staticLogFileName value="true" />< layout type="log4net.Layout.PatternLayout">< conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" /></ layout></ appender></ log4net>... |
Estamos usando o appender "RollingFileAppender" que loga eventos para um arquivo no sistema de arquivos.
Neste appender usamos os seguintes membros:
Finalmente, ainda no interior da tag <log4net> inclua as tags abaixo:
.... < level value="DEBUG" />< appender-ref ref="RollingFileAppender" /></ logger>... |
Agora salve o arquivo App.Config.
Execute o projeto e clique no botão DEBUG. Após isso altere o valor do nível de prioridade no arquivo App.Config para INFO, e repita a operação para todos os níveis.
Pronto ! você pode abrir o seu arquivo de log e visualizar as mensagens.
Usando log4Net em uma aplicação Console com Visual C#
Vamos agora mostrar outro exemplo bem simples de usar o log4net. Desta vez vamos criar uma aplicação Console usando a linguagem C# e mostrar como já podemos registrar os eventos usando o log4net sem muito esforço.
Abra o Visual Studio 2012 Express for desktop e clique em New Project;
Selecione a linguagem Visual C# e o template Console Application e informe o nome Log4Net_CSharp1 e clique em OK;
Da mesma forma vamos adicionar uma referência a library log4Net em nosso projeto. Podemos fazer isso manualmente baixando o pacote do site da Apache ou usando o Nuget. Vou usar o Nuget pois é mais fácil e prático.
A seguir clique no menu TOOLS -> Library Package Manager -> Manage Nuget Package for Solution;
Clique na guia OnLine e a seguir digite na caixa de busca log4net;
Escolha o pacote log4Net 1.2.12 e clique no botão Install;
Agora abra o arquivo Program.cs e digite o seguinte código :
using System; namespace Log4Net_CSharp1 { class Program { static void Main(string[] args) { log4net.ILog log; log4net.Config.BasicConfigurator.Configure(); log = log4net.LogManager.GetLogger("Program"); log.Debug("Registrando eventos com log4net ; Debug"); log.Info("Registro de log nivel Info..."); log.Warn("Registro de log nível Warn..."); log.Error("Registro de log nível Error"); log.Fatal("Registro de log nível Fatal"); Console.ReadLine(); } } } |
Execute o projeto e veja o resultado:
Na segunda parte deste artigo veremos como logar para um banco de dados usando o log4net.
Nota: Lembre-se que o log4net é executado sob os privilégios do usuário ativo. Esteja certo de que o usuário ativo tenha permissão para criar/modificar/deletar arquivos textos.
Mateus 15:19
Porque do coração procedem os maus pensamentos, homicídios, adultérios, prostituição, furtos, falsos testemunhos e blasfêmias.Mateus 15:20
São estas as coisas que contaminam o homem; mas o comer sem lavar as mãos, isso não o contamina.
Referências: