← Back to list

SQL Server Error Log’larını Düzenleyip Tabloya Yazma: Tüm Log Tek Satırda

For the English version of this article, click here.

Ufuk Gökdemir · 2026-07-12 17:55 · 0 claps · 4.5 min read
#sql-server #error-log #log-management
Open on Medium ↗
Wiki topics: BIZ · Business Strategy 🧘 · Spirituality

SQL Server Error Log’larını Düzenleyip Tabloya Yazma: Tüm Log Tek Satırda

For the English version of this article, click here.

SQL Server, instance üzerinde gerçekleşen hata ve uyarıları error log dosyalarına yazar. Ancak bu log’ları okumak her zaman pratik değildir: SSMS üzerinden açmak yavaş olabilir ve filtreleme imkânı sınırlıdır. Bu makalede, kendi çalıştığım ortamlarda aktif bir şekilde kullandığım, kritik error log kayıtlarını düzenli bir şekilde tabloya aktaran ve bunu otomatize eden bir yapıdan bahsedeceğim. Sistem hazır olduğunda aşağıdaki gibi bir tablomuz hazır olacak.

Bu arada “Error log’larını yakalamak için Extended Events gibi daha güçlü seçeneklerimiz de mevcut elbette; fakat xp_readerrorlog ile bu yapıyı kurmak çok daha hızlı ve pratik — ekstra bir session tanımlamak, event file yönetmek ya da storage planlamak gerekmez. Error log'larındaki kritik hataları yakalamak için ayrı bir XE session açmak ve yönetmek, bu işin karmaşıklığını gereksiz yere artırır. Extended Events'i, log'da yakalanamayan daha ayrıntılı olayları izlemek istediğinizde devreye almak daha mantıklı."

Neden Bir Tabloya Taşıyalım?

SQL Server’ın error log mekanizması güçlüdür; ancak ham haliyle kullanımı biraz verimsizdir. Log dosyaları instance yeniden başlatıldığında ya da sp_cycle_errorlog çalıştırıldığında rotate edilir ve belirli bir tarihten sonraki log'lara erişilemez. Ayrıca log içindeki her hata kaydı, birden fazla satırdan oluşabilir — bu da parse etmeyi zorlaştırır.

Kritik hataları (severity bilgisi içeren satırları) bir tabloya taşıdığımızda şu avantajları elde ederiz:

  • Zaman aralığına göre hızlı sorgulama
  • ErrorNumber, Severity, State gibi alanlar üzerinde filtreleme
  • Uzun vadeli geçmiş saklama (rotation’dan bağımsız)
  • Alerting ve raporlama için temel oluşturma

Asıl Problem: İki Satır, Tek Hata

Aşağıdaki ekran görüntüsü SQL Server Management Studio’nun Log File Viewer’ından alınmıştır:

Görüntüde dikkat çeken şey şu: 7/11/2026 5:43:26 PM tarihli iki satıra bakın.

  • 1. satırThe query processor ran out of internal resources and could not produce a query plan.
  • 2. satırError: 8623, Severity: 16, State: 1.

Bu iki satır aynı hataya ait. Biri hatanın açıklamasını, diğeri yapısal bilgilerini (ErrorNumber, Severity, State) taşıyor. Aynı timestamp, aynı spid — ama Log File Viewer'da birbirinden bağımsız iki kayıt olarak görünüyor.

Şimdi bunu olduğu gibi bir tabloya yazdığınızı düşünün. Binlerce satır arasında hangi açıklama hangi error number ile ilişkili? Timestamp’ler aynı olduğunda bile spid çakışmaları ve sıralama farklılıkları bu eşleştirmeyi güvenilmez hale getirir.

sp_ErrorLog'un temel çözdüğü problem tam olarak bu: her iki satırı okuyup tek bir kayıt olarak tabloya yazmak.

Genel Mimari

Yapı üç bileşenden oluşuyor:

  1. Hedef database — Log kayıtlarının tutulacağı yer (_DBAPERF ya da mevcut bir monitoring database'i)
  2. Stored procedure — Log’ları okuyup parse eden ve tabloya yazan sp_ErrorLog
  3. SQL Server Agent Job — Procedure’ü periyodik olarak tetikleyen otomasyon katmanı

Adım 1: Hedef Tabloyu Oluşturma

Önce log kayıtlarının yazılacağı tabloyu oluşturuyoruz. Bu tabloyu, daha önce oluşturulmuş ya da ayrıca açılacak bir monitoring database’i içinde konumlandırabilirsiniz.

USE [_DBAPERF]
GO
CREATE TABLE [dbo].[ErrorLog](
 [LogTime] [datetime2](3) NOT NULL,
 [ErrorMessage] [nvarchar] (max) NOT NULL,
 [ErrorNumber] [int] NOT NULL,
 [Severity] [int] NOT NULL,
 [State] [int] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO  
ALTER AUTHORIZATION ON [dbo].[ErrorLog] TO  SCHEMA OWNER 

Kolon yapısına bakıldığında:

  • LogTime — Hatanın log'a düştüğü zaman damgası (milisaniye hassasiyetiyle)
  • ErrorMessage — Ham log satırının parse edilmiş tam metni
  • ErrorNumber, Severity, State — Error log satırı içinden ayrıştırılan yapısal bilgiler

Adım 2: Stored Procedure Oluşturma

sp_ErrorLog procedure'ü dört temel işi yapar: log'ları okur, severity içeren satırları tespit eder, iki satırı birleştirir ve tabloya yazar.

USE [_DBAPERF]
GO
CREATE PROCEDURE [dbo].[sp_ErrorLog]
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @logno       INT      = 0;  -- 0: Current Log File
    DECLARE @logFileType SMALLINT = 1;  -- 1: Server Log, 2: Agent Log
    DECLARE @start       DATETIME;
    DECLARE @end         DATETIME;
    DECLARE @ErrorLog TABLE (
        RowNum       INT IDENTITY(1,1),
        LogDateTime  NVARCHAR(50),
        ProcessInfo  NVARCHAR(100),
        ErrorMessage NVARCHAR(MAX)
    );
    -- Son 10 dakikayı tara
    SET @start = DATEADD(MINUTE, -10, GETDATE());
    SET @end   = GETDATE();
    DECLARE @searchString1 NVARCHAR(256) = '';
    DECLARE @searchString2 NVARCHAR(256) = '';

    -- Log kayıtlarını table değişkene al
    INSERT INTO @ErrorLog (LogDateTime, ProcessInfo, ErrorMessage)
    EXEC xp_readerrorlog @logno, @logFileType,
                         @searchString1, @searchString2,
                         @start, @end;
    DROP TABLE IF EXISTS #err;

    -- Severity içeren satırları bul, bir sonraki satırla birleştir
    SELECT DISTINCT
        TRY_CAST(e1.LogDateTime AS DATETIME2(3)) AS LogDateTime,
        e1.ErrorMessage + ' ' + ISNULL(e2.ErrorMessage, '') AS ErrorMessage
    INTO #err
    FROM @ErrorLog e1
    LEFT JOIN @ErrorLog e2 ON e2.RowNum = e1.RowNum + 1
    WHERE LOWER(e1.ErrorMessage) LIKE '%severity%';

    -- Parse edip hedef tabloya yaz
    INSERT INTO [_DBAPERF].[dbo].[ErrorLog]
    SELECT
        LogDateTime,
        ErrorMessage,
        -- Error number
        TRY_CAST(
            LTRIM(RTRIM(
                SUBSTRING(
                    ErrorMessage,
                    CHARINDEX('Error:', ErrorMessage) + 6,
                    CHARINDEX(',', ErrorMessage)
                        - CHARINDEX('Error:', ErrorMessage) - 6
                )
            )) AS INT
        ) AS ErrorNumber,
        -- Severity
        TRY_CAST(
            LTRIM(RTRIM(
                SUBSTRING(
                    ErrorMessage,
                    CHARINDEX('Severity:', ErrorMessage) + 9,
                    CHARINDEX(',', ErrorMessage, CHARINDEX('Severity:', ErrorMessage))
                        - CHARINDEX('Severity:', ErrorMessage) - 9
                )
            )) AS INT
        ) AS Severity,
        -- State
        TRY_CAST(
            LTRIM(RTRIM(
                SUBSTRING(
                    ErrorMessage,
                    CHARINDEX('State:', ErrorMessage) + 6,
                    CHARINDEX('.', ErrorMessage + '.', CHARINDEX('State:', ErrorMessage))
                        - CHARINDEX('State:', ErrorMessage) - 6
                )
            )) AS INT
        ) AS State
    FROM #err
    ORDER BY LogDateTime DESC;

    -- 180 günden eski kayıtları temizle
    DELETE FROM [_DBAPERF].[dbo].[ErrorLog]
    WHERE LogTime < DATEADD(DAY, -180, GETDATE());
END
GO

İki Satırın Birleştirilmesi — Temel Mantık

SQL Server’ın error log yapısında dikkat çeken bir nokta var: severity bilgisi içeren bir hata her zaman iki ardışık satır olarak gelir. İlk satır error numarası, severity ve state bilgilerini taşır; ikinci satır ise hatanın açıklama metnini içerir.

Bu yapıdan faydalanmak için @ErrorLog table variable'ına IDENTITY ile sıra numarası ekliyoruz. Ardından RowNum + 1 ile self join yaparak iki satırı tek bir kayıtta birleştiriyoruz:

FROM @ErrorLog e1
LEFT JOIN @ErrorLog e2 ON e2.RowNum = e1.RowNum + 1
WHERE LOWER(e1.ErrorMessage) LIKE '%severity%'

String Parsing ile Yapısal Alan Çıkarma

Ham error log satırı şu formatta gelir:

Error: 18456, Severity: 14, State: 8. Login failed for user 'sa'.

CHARINDEX ve SUBSTRING kombinasyonuyla ErrorNumber, Severity ve State değerlerini bu metinden ayrıştırıyoruz. TRY_CAST kullanmak önemli — beklenmedik bir format geldiğinde procedure hata fırlatmak yerine NULL döndürür ve çalışmaya devam eder.

Retention Yönetimi

Procedure’ün sonundaki DELETE bloğu, 180 günden eski kayıtları otomatik olarak temizler. Bu sayede tablo süresiz büyümez ve ayrı bir temizlik job'ı yazmanıza gerek kalmaz.

Adım 3: SQL Server Agent Job ile Otomatizasyon

Procedure’ü manuel çalıştırmak yeterli değil. Bunu 10 dakikada bir tetikleyecek bir SQL Server Agent Job oluşturuyoruz.

SSMS üzerinden:

  1. SQL Server Agent → Jobs → New Job
  2. General sekmesinde job’a bir isim verin: örneğin DBA - Collect Error Logs
  3. Steps sekmesinde yeni bir step ekleyin:
  • Type: Transact-SQL script (T-SQL)
  • Database: _DBAPERF
  • Command:
EXEC [dbo].[sp_ErrorLog];
  1. Schedules sekmesinde yeni bir schedule oluşturun:
  • Frequency: Daily
  • Occurs every: 10 minutes
  • Start time: 00:00:00

Job kaydedildikten sonra bir kez Start Job at Step ile manuel test yapmanızı öneririm.

Sonuç

Bu yapı sayesinde SQL Server error log’ları artık ham metin dosyalarında kaybolmuyor; her 10 dakikada bir parse edilerek sorgulanabilir bir tabloya aktarılıyor. ErrorNumber, Severity ve State kolonları üzerinden kolayca filtreleme yapabilir, belirli hata kodlarına göre alert mekanizmaları kurabilir ya da Grafana, Power BI gibi araçlara bağlayarak dashboard oluşturabilirsiniz. Database Mail kullanarak burada dilediğiniz bir filtreleme ile ciddi durumlarda mail attırabilirsiniz.


메타데이터
post_id
b2d8da1271b8
slug
sql-server-error-loglarını-düzenleyip-tabloya-yazma-tüm-log-tek-satırda-b2d8da1271b8
url
https://medium.com/@ufuk-gokdemir/sql-server-error-loglar%C4%B1n%C4%B1-d%C3%BCzenleyip-tabloya-yazma-t%C3%BCm-log-tek-sat%C4%B1rda-b2d8da1271b8
canonical_url
https://medium.com/@ufuk-gokdemir/sql-server-error-loglar%C4%B1n%C4%B1-d%C3%BCzenleyip-tabloya-yazma-t%C3%BCm-log-tek-sat%C4%B1rda-b2d8da1271b8
author_url
https://medium.com/@ufuk-gokdemir
status
ok
fetched_at
2026-07-16 18:45:13