Anterior
Próximo
Criando um appender com zip para o log4netpublicado em 13/01/2010
Esta semana no trabalho, tive a necessidade de criar um expurgo para os logs de um determinado projeto.
Os logs deste projeto são escritos em arquivos txt e rotacionados diariamente, o expurgo teria que funcionar
zipando e movendo os arquivos para um outro servidor sempre que a semana mudasse.
Minha primeira idéia foi criar um executável que rodaria sempre que uma semana terminasse e ziparia e moveria
os arquivos antigos para o servidor de histórico, mas após uma conversa com meu amigo Marcelo Teixeira fui
convencido de criar um novo appender para o log4net que fizesse esse trabalho todo.
Para salvar os logs e mudar os arquivos sempre que o dia terminasse ou que o tamanho do arquivo atingisse
20MB, estavámos utilizando o log4net e seu appender RollingFileAppender.
A idéia inicial era simples, fazer uma classe que herdasse de RollingFileAppender e reescrever o método
responsável pelo rotacionamento para que ele também zipasse e movesse os arquivos antigos.
Ao iniciar o desenvolvimento seguindo essa linha percebi que o log4net possuía um bug.
Para definirmos que o arquivo será rotacionado de (dia/dia, mes/mes, ano/ano, hora/hora etc) necessitamos
configurar a propriedade datePattern na configuração do appender, e ao tentar colocar <datePattern
value="w"/> ( padrão de semana do mês ) percebi que nada funcionava.
Não funcionava pois o método ComputeCheckPeriod do log4net tenta converter uma data para string utilizando o pattern passado e o
.net não tem nenhum pattern que represente as semanas do mês !!!
private RollPoint ComputeCheckPeriod(string datePattern)
{
// Get string representation of base line date
string r0 = s_date1970.ToString(datePattern, System.Globalization.DateTimeFormatInfo.InvariantInfo);
Fiquei meio decepcionado e parti para a correção do problema. Tinha diversas possibilidades como:
- Criar meu próprio padrão de datas que contemplasse também as semanas.
- Mudar a maneira de identificação de patterns da classe.
- Criar uma propriedade diferente para definir que teríamos um rotacionamento semanal.
Entre essas possibilidades, escolhi criar uma propriedade diferente para definir que teriamos um
rotacionamento semanal pois o desenvolvimento da mesma seria mais rápido e meu prazo estava curto.
Alterei então o método ComputeCheckPeriod para que se a propriedade Week ( criada por mim ) fosse true,
retornasse um RollPoint.TopOfWeek indicando assim um rotacionamento semanal.
// Check if the string representations are different
if (r0 != null && r1 != null && !r0.Equals(r1))
{
// Found highest precision roll point
// [UPDATE] - Force the weekly rotation since. NET does not support any weekly date pattern.
if (Week)
return RollPoint.TopOfWeek;
else
return (RollPoint)i;
}
Para zipar os arquivos antigos, alterei o método AdjustFileBeforeAppend para que zipasse os arquivos antigos
sempre que um rotacionamento por data fosse realizado.
virtual protected void AdjustFileBeforeAppend()
{
if (m_rollDate)
{
DateTime n = m_dateTime.Now;
if (n >= m_nextCheck)
{
m_now = n;
m_nextCheck = NextCheckDate(m_now, m_rollPoint);
RollOverTime(true);
// [UPDATE] - Zip All the old files when the log rolls up
this.ZipOldFiles();
}
}
if (m_rollSize)
{
if ((File != null) && ((CountingQuietTextWriter)QuietWriter).Count >= m_maxFileSize)
{
RollOverSize();
}
}
}
Método responsável por zipar os arquivos antigos:
///
/// [UPDATE]
/// Zip All the old files when the log rolls up
///
private void ZipOldFiles()
{
string zipDir = this.ZipPath.Substring(0, this.ZipPath.LastIndexOf("\\"));
if (Directory.Exists(zipDir) && IsZipFile(this.ZipPath))
{
string originalPath = File.Substring(0, File.LastIndexOf("\\"));
string[] logFiles = Directory.GetFiles(originalPath);
using (ZipFile zip = new ZipFile())
{
DateTime smallerDate = m_nextCheck;
// ziping files files...
foreach (string logFile in logFiles)
{
// Gets all the different files of the current file with the same prefix and are not zip
if (logFile != File && logFile.IndexOf(this.m_baseFileName).Equals(0) && !IsZipFile(logFile))
{
zip.AddFile(logFile);
// Getting the date of the older file to put in zip file name...
FileInfo fInfo = new FileInfo(logFile);
if (fInfo.CreationTime < smallerDate)
smallerDate = fInfo.CreationTime;
}
}
// saving the zip file...
if (zip.Entries.Count > 0)
zip.Save(this.ZipPath.Replace(".zip", smallerDate.ToString("-dd-MM-yyyy") + ".zip"));
// removing files...
foreach (string logFile in logFiles)
{
// Gets all the different files of the current file with the same prefix and are not zip
if (logFile != File && logFile.IndexOf(this.m_baseFileName).Equals(0) && !IsZipFile(logFile))
System.IO.File.Delete(logFile);
}
}
}
else
throw new ArgumentException("Invalid zip path. The property zipPath must be setted in the configuration file.");
}
A configuração deste apender para que rotacione e zipe os arquivos semanalmente deve ser feita da seguinte
forma:
<appender name="RollingLogFileAppender" type="Ajustes.Log.Appender.RollingFileAndZipAppender">
<file value="c:\\logs\\Arquivo.log"/>
<staticLogFileName value="false"/>
<appendToFile value="true"/>
<rollingStyle value="Composite"/>
<datePattern value="yyyyMMdd"/>
<week value="true"/>
<zipPath value="c:\\Historico.zip"/>
<maxSizeRollBackups value="150"/>
<maximumFileSize value="500KB"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t][%u] %-5p %c %m%n"/>
</layout>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
</appender>
Vale lembrar que se não definirmos a propriedade week, o appender funcionará normalmente, fazendo o
rotacionamento e zipando os arquivos de acordo com o date pattern passado.
O único ponto triste disso tudo é que como alguns métodos que alterei não estavam marcados como virtual, não
pude reescreve-los e por isso tive que copiar todo o conteúdo da classe RollingFileAppender para fazer as
alterações.
Poderia também ter baixado o código fonte do log4net, marcado os métodos como virtual e trabalhado em cima
deles com herança mas um dos meus requisitos era não alterar a dll original do log4net.
Abaixo você poderá fazer o download da classe, espero que seja útil. Todas as alterações feitas por mim estão
marcadas com a palavra UPDATE nos comentários.
Tags:
-
28/12/2011 15:02 - CArlos
Hi! Thank you for that excellent post, it was very useful.
As spaniard, I can understand most of what you explain, but i think that you will have lot of more visits writting in English.
Thanks aniway :)