A leitura diária dos arquivos de log do SQL Server é uma das tarefas primárias do DBA. Particularmente, tenho o hábito de visualizar o log corrente a cada dez minutos (no máximo), pois, a leitura do log faz parte da minha estratégia de monitoração. Nesse sentido, tenho preferido consultar os log usando T-SQL, ao invés da interface gráfica (Log File Viewer). Dentre os principais motivos para preferir o T-SQL destaco:
- A visualização fica mais fácil e o conteúdo do arquivo é carregado mais rapidamente (tente abrir um arquivo de log de erro muito grande usando o Log File Viewer e você sentirá uma certa demora);
 - Usando T-SQL é possível fazer pesquisas customizadas sobre o log do mesmo modo como fazemos na interface gráfica, contudo, a pesquisa com T-SQL é mais rápida;
 - E a principal vantagem, no meu ponto de vista, é que via T-SQL podemos ler o log de erro de vários servidores ao mesmo tempo, executando um único comando.
 
Para fazermos a leitura via T-SQL podemos utilizar as seguintes SP’s:
- Sp_readerrorlog
 - Xp_readerrorlog
 
Os arquivos de Log
Os logs de erro do SQL Server são salvo em arquivos, por padrão, na subpasta “Log” da unidade de disco onde a instância foi instalada. É possível abrir e visualizar o conteúdo desses arquivos utilizando um editor de texto como o Notepad.
Toda vez que a instância é reiniciada, o arquivo corrente é arquivado e renomeado sob o nome ERRORLOG.1, enquanto um novo arquivo de log é criado com o nome ERRORLOG. Por default, o SQL Server mantém até seis arquivos de log arquivados. Caso queira aumentar esse limite, estando no SQL Server Management Studio, faça conforme ilustrado nas figuras abaixo:
O arquivo de log corrente tem índice zero e essa informação é importante para a utilização das SP’s de leitura do log de erro que falaremos mais adiante.
É possível listar via T-SQL os arquivos de log de erro da instância. Veja como:
exec sp_enumerrorlogs
Veja que a stored procedure listou os arquivos de log de erro. Neste caso, os seis logs arquivados e o log corrente (de índice zero). Também mostrou a data e hora da última entrada no log (último registro) e o tamanho em disco do arquivo.
Usando SP_READERRORLOG / XP_READERRORLOG
Em termos de sintaxe e de benefícios, ambas SP’s são idênticas. Contudo, é válido destacar que a XP_READERRORLOG é uma procedure estendida, além de não documentada.
Para visualizar o log de erros atual do SQL Server simplesmente execute:
exec sp_readerrorlog

Essa stored procedure tem os seguintes parâmetros opcionais:
| Parâmetro | Valores | Descrição | 
| P1 | 0,1,2,4,5,6… | Indica o número do arquivo de log a ser lido. O default é 0. | 
| P2 | 1 ou 2 | Indica o tipo de log a ser lido, onde: 1 = sql server; 2 = sql agent. O default é 1, ou seja, o log do sql server | 
| P3 | Texto entre aspas simples ou aspas duplas a ser localizado dentro do log (coluna Text). ATENÇÃO: quando usar a XP_READERRORLOG o texto deve estar entre aspas duplas. A pesquisa é parcial, procurando em qualquer parte da palavra. Deixe NULL neste parâmetro para não utilizá-lo ou simplesmente basta omiti-lo. | |
| P4 | Trata-se de uma segunda string a ser pesquisada, objetivando refinar a consulta. Na verdade este parâmetro produz a combinação P3 + P4, ou seja, as duas palavras pesquisadas devem existir na mesma entrada (linha) do log. Deixe NULL neste parâmetro para não utilizá-lo ou simplesmente basta omiti-lo. | 
Vejamos alguns exemplos:
Localizar as entradas que contenham a palavra AdventureWorks no log corrente do SQL Server:
exec sp_readerrorlog 0, 1, 'adventureworks'
Localizar as entradas que contenham as palavras CHECKDB e AdventureWorks no log corrente do SQL Server:
exec sp_readerrorlog 0, 1, 'checkdb', 'adventureworks'
Esse tipo de consulta no log é muito útil quando queremos pesquisar por erros ou, por exemplo, filtrar as entradas referentes a backup, etc.
Criando um script para consultas mais refinadas
Como comentei no início do artigo, tenho o hábito de ficar lendo o log em intervalos de no máximo dez minutos. Desta forma, não tenho a necessidade de listar o log por completo, apenas as informações dos últimos dez minutos e, caso se faça necessário, ir ampliando esse range. Fazer esse tipo de pesquisa usando a SP_READERRORLOG ou XP_REAERRORLOG não é possível. Por conta disso, estou deixando o script de uma stored procedure “personalizada”, que possibilita a realização de consultas bem flexíveis. Recomendo criar essa SP na database Master ou em um banco de dados criado para fins administrativos. Caso prefira, você pode baixar o script com o código fonte da SP aqui.
USE Master
GO
IF OBJECT_ID('dbo.uspErrorLog') IS NOT NULL
DROP PROCEDURE dbo.uspErrorLog;
GO
CREATE PROCEDURE dbo.uspErrorLog
(
-- Quantidade de minutos a retroagir na pesquisa.
-- O Default são 30 minutos
-- Informe NULL para desconsiderar e não usar este parâmetro
@MinutosRetroagir INT = 30,
-- Data inicial para a pesquisa no log.
-- Registros com datas menores serão desconsiderados
-- O Default é NULL
-- Informe NULL para desconsiderar e não usar este parâmetro
@DataInicial DATETIME = NULL,
-- Data final para a pesquisa no log.
-- Registros com datas maiores serão desconsiderados
-- O Default é NULL
-- Informe NULL para desconsiderar e não usar este parâmetro
@DataFinal DATETIME = NULL,
-- Texto a ser pesquisado dentro da coluna ProcessInfo do log
-- Exemplo: Server, Backup, SPID, etc.
-- A pesquisa pelo texto é parcial (em qualquer parte)
-- O Default é NULL
-- Informe NULL para desconsiderar e não usar este parâmetro
@Processo VARCHAR(50) = NULL,
-- Texto a ser pesquisado dentro da coluna Text do log
-- Exemplo: error, starting, etc.
-- A pesquisa pelo texto é parcial (em qualquer parte)
-- O Default é NULL
-- Informe NULL para desconsiderar e não usar este parâmetro
@Texto VARCHAR(100) = NULL,
-- Filtra a pesquisa para exibir apenas o log do nome do servidor informado
-- Use este parâmetro quando estiver pesquisando o log de vários servidores ao mesmo tempo
-- O Default é NULL
-- Informe NULL para desconsiderar e não usar este parâmetro
@NomeServidor VARCHAR(128) = NULL
)
AS
DECLARE @Tmp TABLE
(    ID INT IDENTITY,
Data DATETIME,
Processo VARCHAR(50),
Texto VARCHAR(4000)
);
INSERT INTO @Tmp (Data, Processo, Texto) exec sp_readerrorlog;
SELECT * FROM @Tmp t
WHERE t.Data >=
CASE WHEN @MinutosRetroagir IS NOT NULL THEN DATEADD(MINUTE, -@MinutosRetroagir, GETDATE())
ELSE t.Data END
AND t.Data >= ISNULL(@DataInicial, t.Data)
AND t.Data <= ISNULL(@DataFinal, t.Data)
AND t.Processo LIKE
CASE WHEN @Processo IS NOT NULL THEN '%' + @Processo + '%'
ELSE t.Processo END
AND t.Texto LIKE
CASE WHEN @Texto IS NOT NULL THEN '%' + @Texto + '%'
ELSE t.Texto END
AND SERVERPROPERTY('ServerName') =
ISNULL(@NomeServidor, CONVERT(VARCHAR(128), SERVERPROPERTY('ServerName')))
ORDER BY t.ID DESC;
GO
Reciclando o log de erro
Como já foi mencionado, o log de erro é reciclado (reiniciado) automaticamente toda vez que a instância sofre um restart. Considerando que um servidor de banco não é resetado com frequência – normalmente permanece vários meses online, a tendência é o log ficar demasiado grande, dificultando a análise e leitura. Assim, quero deixar uma sugestão: recicle manualmente, de tempos em tempos, o log de erro do SQL Server. Particularmente, faço essa reciclagem a cada sete dias – normalmente crio um job que é executado aos domingos. Contudo, essa frequência de reciclagem varia de ambiente para ambiente, além de preferências e políticas.
O comando para reciclar manualmente o log de erros é o seguinte:
DBCC ERRORLOG
Conclusão
Inclua em sua estratégia diária de monitoramento a leitura dos log’s de erro do SQL Server. Em ambientes com várias instâncias essa tarefa pode ser facilitada, e muito, através do T-SQL, permitindo analisar o log de várias instâncias ao mesmo.
Até o próximo artigo!







