Loggning och diagnostik med go-mssqldb

Drivrutinen go-mssqldb tillhandahåller konfigurerbar loggning för felsökning av anslutningsproblem, frågeproblem och prestandaanalys. Denna artikel beskriver tillgängliga loggflaggor och hur man använder anpassade loggare.

Loggflaggor

Använd anslutningsparametern log för att aktivera diagnostisk utgång. Log-flaggor är bitmaskvärden, vilket betyder att du kan kombinera dem genom att lägga till deras heltalsvärden:

Flaggvärde Category Beskrivning
1 Errors Logga felmeddelanden.
2 Messages Logga informationsmeddelanden från servern.
4 Rows Logga raddata.
8 SQL Logga SQL-satser som skickas till servern.
16 Parameters Logga parameternamn och värden.
32 Transactions Logga start-, bekräftelse- och återställningshändelser för transaktioner.
64 Debug Logga lågnivåprotokoll och TDS-detaljer.
128 Omförsökningar Logga återanslutningsförsök.

Flaggor 4 (rader) och 16 (parametrar) kan exponera applikationsdata, hemligheter eller personligt identifierbar information. Behandla dem som kortlivade diagnostiska flaggor, inte som rutinmässiga produktionsmiljöer.

Exempel

Endast fel i loggen:

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

Loggfel, SQL-satser och parametrar:

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

Note

Värdet 25 beräknas som 1 + 8 + 16 (fel + SQL + parametrar).

Logga allt:

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

Varning

Höga värden för loggningsflaggor (64, 128, 255) ger detaljerad utdata och kan påverka prestandan. Använd dem bara för felsökning.

Standardlogger

Som standard loggar drivrutinen till Gos standardpaket log , som skriver till os.Stderr. Utdata inkluderar tidsstämplar och loggkategorin:

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

Anpassad loggare med SetLogger

Använd mssql.SetLogger för att omdirigera drivrutinens loggutdata till en anpassad loggare. Loggaren måste implementera gränssnittet mssql.Logger :

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
}

Kontextmedveten loggare med SetContextLogger

Använd mssql.SetContextLogger för att tillhandahålla en kontextmedveten loggare. Loggaren måste implementera gränssnittet mssql.ContextLogger , som har en enda Log metod som tar emot kontexten, en loggkategori och en meddelandesträng. Detta tillvägagångssätt gör det möjligt att korrelera drivrutinsloggar med begäransspecifika spårningsdata (till exempel spårnings-ID:n):

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
}

Checklista för diagnostik

När du felsöker en anslutning eller en fråga:

  1. Börja med log=1 för fel, eller log=3 om du också behöver servermeddelanden.
  2. Återskapa problemet och granska feltexten innan du aktiverar fler kategorier.
  3. Lägg till 8 om du behöver bekräfta vilken SQL-sats eller proceduranrop som skickades.
  4. Lägg till 16 eller 4 endast i en säker miljö där parametervärden och returnerade rader kan loggas utan att känslig data exponeras.
  5. Om problemet verkar ligga på protokollnivå eller vara relaterat till omförsök, öka till log=64 eller lägg till 128 för diagnostik av omförsök.
  6. Ta bort eller minska loggningen efter att problemet är löst.

Strukturerad loggning med log/slog

Go 1.21 introducerade log/slog för strukturerad loggning. Använd SetContextLogger för att dirigera utdata från drivrutinen via slog:

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.
}

Integration med zerolog

Zerolog är en strukturerad logger med nollallokering. Ruta förarloggar genom zerolog:

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})
}

Integration med zap

Zap är en högpresterande strukturerad logger. Loggar för ruttförare via zap:

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})
}

Vidarebefordran av korrelations-ID

I distribuerade system, sprid en korrelations-ID genom kontexten så att drivrutinsloggar kan korreleras med den förfrågan som utlöste dem:

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)),
    )
}

Skicka sedan korrelations-ID:t genom din förfrågan:

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")
    // ...
}

Hur man använder korrelations-ID i praktiken

Använd korrelations-ID:n som en spårningsnyckel över loggar, återförsök och databasanrop:

  1. Generera eller acceptera ett korrelations-ID vid förfrågningsgränsen.
  2. Spara det i förfrågningskontexten och inkludera det i applikations- och drivrutinsloggar.
  3. För felsökning på SQL-sidan anger du det i sessionskontexten med sp_set_session_context och läser det med SESSION_CONTEXT.

Korrelations-ID:n lagras inte automatiskt i SQL Server-tabeller. SESSION_CONTEXT är sessions-scoped, så värden gäller endast för den aktuella anslutningen och finns inte kvar efter att sessionen avslutats.

Om du behöver varaktig historik, skriv korrelations-ID:t explicit till dina revisions- eller affärstabeller (till exempel en AuditLog tabell med correlation_id, tidsstämpel, operation och status).

Konfiguration för produktionsloggning

I produktion, aktivera minimal loggning för att undvika prestandaöverhead och förhindra att känslig data dyker upp i loggar:

Miljö Rekommenderat log värde Vad den fångar
Development 63 (fel + meddelanden + rader + SQL + parametrar + transaktioner) Full synlighet för felsökning.
Staging 3 (fel + meddelanden) Fel och servermeddelanden utan frågedetaljer.
Produktion 1 (fel) eller 0 (av) Endast fel, eller inaktivera drivrutinsloggning helt.

Försiktighet

Flaggan Parameters (16) loggar faktiska parametervärden, vilket kan inkludera personligt identifierbar information (PII), lösenord eller annan känslig data. Aktivera aldrig denna flagga i produktion. För en fullständig riskbedömning av varje flagga, se säkerhetsbästa praxis.

Inaktivera loggning i produktionsmiljö

Använd miljövariabler för att styra loggnivån per distributionssteg:

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