go-mssqldb ile logetme ve tanılama

Sürücü, go-mssqldb bağlantı sorunlarını, sorgu sorunlarını gidermek ve performans analizini yapmak için yapılandırılabilir kayıt işlemleri sağlar. Bu makale, mevcut log bayraklarını ve özel loggerların nasıl kullanılacağını açıklar.

Kayıt işaretleri

Tanı çıkışını etkinleştirmek için bağlantı log parametresini kullanın. Log bayrakları bitmask değerleridir, yani tam sayı değerlerini ekleyerek birleştirebilirsiniz:

Bayrak değeri Category Açıklama
1 Errors Hata mesajlarını kaydet.
2 Messages Sunucudan gelen bilgilendirici mesajları kaydedin.
4 Rows Satır verilerini kaydet.
8 SQL Sunucuya gönderilen SQL açıklamalarını kaydet.
16 Parametreler Parametre isimlerini ve değerlerini kaydet.
32 Transactions İşlem başlatma, commit ve geri alma olaylarını kaydedin.
64 Debug Düşük seviyeli protokol ve TDS detaylarını kaydedin.
128 Tekrar Denemeler Bağlantı tekrar deneme girişimlerini kaydet.

Bayraklar 4 (satırlar) ve 16 (parametreler) uygulama verilerini, sırları veya kişisel olarak tanımlanabilir bilgileri ortaya çıkarabilir. Bunları rutin üretim ayarları olarak değil, kısa ömürlü tanı bayrakları olarak ele alın.

Examples

Yalnızca hataları günlüğe kaydet:

sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=1

Log hataları, SQL ifadeleri ve parametreler:

sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=25

Note

Değer 25 (hatalar + SQL + parametreler) olarak hesaplanır.1 + 8 + 16

Her şeyi kaydet:

sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=255

Warning

Yüksek log bayrak değerleri (64, 128, 255) ayrıntılı çıktı üretir ve performansı etkileyebilir. Sadece hata ayıklama için kullanın.

Varsayılan günlük kaydedici

Varsayılan olarak, sürücü günlükleri Go'nun standart log paketine yazar; bu paket de os.Stderr hedefine yazar. Çıktı, zaman damgaları ve log kategorisini içerir:

2026/03/28 10:15:30 mssql: login successful
2026/03/28 10:15:30 mssql: SQL: SELECT 1

SetLogger ile özel günlükleyici

mssql.SetLogger öğesini, sürücü günlük çıktısını özel bir günlük kaydediciye yönlendirmek için kullanın. Günlükleyici, mssql.Logger arabirimini uygulamalıdır:

import "github.com/microsoft/go-mssqldb"

type myLogger struct{}

func (l *myLogger) Printf(format string, v ...interface{}) {
    // Write to your preferred logging system
    fmt.Printf("[MSSQL] "+format+"\n", v...)
}

func (l *myLogger) Println(v ...interface{}) {
    fmt.Println(append([]interface{}{"[MSSQL]"}, v...)...)
}

func main() {
    mssql.SetLogger(&myLogger{})
    // ... open connection
}

SetContextLogger ile bağlama duyarlı günlükleyici

Bağlama duyarlı bir günlük kaydedici sağlamak için mssql.SetContextLogger kullanın. Logger, bağlamı, bir günlük kategorisini ve bir mesaj dizesini alan tek bir Log yöntemine sahip olan mssql.ContextLogger arabirimini uygulamalıdır. Bu yaklaşım, sürücü loglarını istek kapsamlı takip verileriyle (örneğin iz kimlikleri) ilişkilendirmenize olanak tanır:

import (
    "context"
    "log/slog"
    "github.com/microsoft/go-mssqldb"
    "github.com/microsoft/go-mssqldb/msdsn"
)

type contextLogger struct{}

func (l *contextLogger) Log(ctx context.Context, category msdsn.Log, msg string) {
    slog.InfoContext(ctx, msg, "category", category)
}

func main() {
    mssql.SetContextLogger(&contextLogger{})
    // ... open connection
}

Tanılama denetim listesi

Bağlantı veya sorgu sorununu giderirken:

  1. Hatalar için log=1 ile başlayın veya sunucu iletilerine de ihtiyacınız varsa log=3 ile başlayın.
  2. Sorunu yeniden üretin ve hata metnini gözden geçirin, sonra daha fazla kategori etkinleştirin.
  3. Hangi SQL ifadesi veya prosedür çağrısının gönderildiğini doğrulamanız gerekirse ekleyin 8 .
  4. 16 veya 4 öğesini yalnızca, parametre değerlerinin ve döndürülen satırların hassas veriler açığa çıkarılmadan günlüğe kaydedilebildiği güvenli bir ortamda ekleyin.
  5. Sorun protokol düzeyinde veya tekrar deneme ile ilgili görünüyorsa, yeniden deneme teşhisi için artırın log=64 veya ekleyin 128 .
  6. Sorun çözüldükten sonra kayıtları kaldırın veya azaltın.

log/slog ile yapılandırılmış günlükleme

Go 1.21, yapılandırılmış günlükleme için log/slog öğesini kullanıma sundu. Sürücü çıkışını slog üzerinden yönlendirmek için SetContextLogger kullanın:

import (
    "context"
    "log/slog"
    "os"

    "github.com/microsoft/go-mssqldb"
    "github.com/microsoft/go-mssqldb/msdsn"
)

type slogLogger struct {
    logger *slog.Logger
}

func (l *slogLogger) Log(ctx context.Context, category msdsn.Log, msg string) {
    level := slog.LevelInfo
    if category == msdsn.LogErrors {
        level = slog.LevelError
    }
    if category == msdsn.LogDebug {
        level = slog.LevelDebug
    }

    l.logger.LogAttrs(ctx, level, msg,
        slog.Int("category", int(category)),
    )
}

func main() {
    logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    }))

    mssql.SetContextLogger(&slogLogger{logger: logger})

    // Connection logging now produces structured JSON.
}

Zerolog ile entegrasyon

zerolog, bellek tahsisi gerektirmeyen yapılandırılmış bir günlük kaydedicisidir. Zerolog üzerinden rota sürücü kayıtları:

import (
    "context"
    "os"

    "github.com/microsoft/go-mssqldb"
    "github.com/microsoft/go-mssqldb/msdsn"
    "github.com/rs/zerolog"
)

type zerologAdapter struct {
    logger zerolog.Logger
}

func (l *zerologAdapter) Log(ctx context.Context, category msdsn.Log, msg string) {
    event := l.logger.Info()
    if category == msdsn.LogErrors {
        event = l.logger.Error()
    }
    event.Int("category", int(category)).Msg(msg)
}

func main() {
    logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
    mssql.SetContextLogger(&zerologAdapter{logger: logger})
}

Zap ile entegrasyon

zap, yüksek performanslı, yapılandırılmış bir günlük kaydedicidir. Rota sürücüsü günlükleri zap üzerinden:

import (
    "context"

    "github.com/microsoft/go-mssqldb"
    "github.com/microsoft/go-mssqldb/msdsn"
    "go.uber.org/zap"
)

type zapAdapter struct {
    logger *zap.Logger
}

func (l *zapAdapter) Log(ctx context.Context, category msdsn.Log, msg string) {
    if category == msdsn.LogErrors {
        l.logger.Error(msg, zap.Int("category", int(category)))
    } else {
        l.logger.Info(msg, zap.Int("category", int(category)))
    }
}

func main() {
    logger, _ := zap.NewProduction()
    defer logger.Sync()

    mssql.SetContextLogger(&zapAdapter{logger: logger})
}

Korelasyon ID yayımı

Dağıtık sistemlerde, sürücü günlüklerinin onları tetikleyen istekle ilişkilendirilebilmesi için bir korelasyon kimliği bağlam üzerinden yayılır:

type correlationKey struct{}

func WithCorrelationID(ctx context.Context, id string) context.Context {
    return context.WithValue(ctx, correlationKey{}, id)
}

func CorrelationID(ctx context.Context) string {
    if id, ok := ctx.Value(correlationKey{}).(string); ok {
        return id
    }
    return "unknown"
}

type correlatedLogger struct {
    logger *slog.Logger
}

func (l *correlatedLogger) Log(ctx context.Context, category msdsn.Log, msg string) {
    l.logger.LogAttrs(ctx, slog.LevelInfo, msg,
        slog.String("correlation_id", CorrelationID(ctx)),
        slog.Int("category", int(category)),
    )
}

Sonra korelasyon kimliğini istek bağlamınıza aktarın:

func handleRequest(w http.ResponseWriter, r *http.Request) {
    correlationID := r.Header.Get("X-Correlation-ID")
    if correlationID == "" {
        correlationID = uuid.NewString()
    }

    ctx := WithCorrelationID(r.Context(), correlationID)

    // All database operations using this context will include the correlation ID.
    rows, err := db.QueryContext(ctx, "SELECT TOP (10) ProductID, Name FROM Production.Product")
    // ...
}

Korelasyon Kimlikleri pratikte nasıl kullanılır

Korelasyon kimliklerini loglar, tekrar denemeler ve veritabanı çağrıları arasında takip anahtarı olarak kullanın:

  1. İstek sınırında bir korelasyon ID'si oluşturun veya kabul edin.
  2. Bunu istek bağlamında saklayıp uygulama ve sürücü kayıtlarına dahil edin.
  3. SQL tarafında sorun giderme için bunu sp_set_session_context ile oturum bağlamında ayarlayın ve SESSION_CONTEXT ile okuyun.

Korelasyon kimlikleri otomatik olarak SQL Server tablolarında saklanmaz. SESSION_CONTEXT oturum kapsamlıdır, bu yüzden değerler yalnızca mevcut bağlantıya uygulanır ve oturum bittikten sonra da devam etmez.

Kalıcı geçmişe ihtiyacınız varsa, korelasyon kimliğini denetim veya iş tablolarınıza açıkça yazın (örneğin AuditLog , zaman damgası, operasyon ve durum içeren bir tablo correlation_id).

Üretim kayıt yapılandırması

Üretimde, performans yükünü önlemek ve hassas verilerin loglarda görünmemesini önlemek için minimum kayıt etkinleştirin:

Çevre Önerilen değer log Yakaladıkları
Development 63 (hatalar + mesajlar + satır + SQL + parametreler + işlemler) Hata ayıklama için tam görünürlük.
Staging 3 (hatalar + mesajlar) Sorgu detayları olmayan hatalar ve sunucu mesajları.
Üretim 1 (hatalar) veya 0 (kapalı) Sadece hatalar olur ya da sürücü kaydını tamamen devre dışı bırakır.

Dikkat

Bayrak Parameters (16) gerçek parametre değerlerini kaydeder; bunlar kişisel tanımlanabilir bilgiler (PII), şifreler veya diğer hassas verileri içerebilir. Bu bayrağı üretim ortamında asla etkinleştirme. Her bayrağın tam risk değerlendirmesi için bkz. Güvenlik en iyi uygulamaları.

Üretimde günlüklemeyi devre dışı bırak

Dağıtma aşaması başına log seviyesini kontrol etmek için ortam değişkenleri kullanın:

if os.Getenv("APP_ENV") == "production" {
    // Use only error-level logging in production.
    connString += "&log=1"
} else {
    // Full logging in development.
    connString += "&log=63"
}