Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
go-mssqldb драйвер поддерживает настраиваемое журналирование для диагностики проблем с подключением, проблем с запросами и анализа производительности. В этой статье описаны доступные флаги лога и способы использования пользовательских логгеров.
Флаги журнала
Используйте log параметр подключения для включения диагностического вывода. Логарифмические флаги — это значения битовой маски, то есть их можно объединить, добавив их целочисленные значения:
| Значение флага | Category | Description |
|---|---|---|
1 |
Errors | Регистрировать сообщения об ошибках. |
2 |
Messages | Регистрировать информационные сообщения с сервера. |
4 |
Rows | Записать в журнал данные строки. |
8 |
SQL | Регистрируйте в журнале операторы SQL, отправляемые на сервер. |
16 |
Параметры | Записывайте в журнал имена и значения параметров. |
32 |
Transactions | Регистрировать в журнале события начала, подтверждения и отката транзакций. |
64 |
Debug | Регистрировать данные низкоуровневого протокола и сведения о TDS. |
128 |
Повторные попытки | Логировать попытки повторного подключения. |
Флаги 4 (строки) и 16 (параметры) могут раскрывать данные приложений, секреты или лично идентифицируемую информацию. Относитесь к ним как к кратковременным диагностическим сигналам, а не как к обычным производственным параметрам.
Примеры
Регистрировать только ошибки:
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=1
Регистрировать ошибки, SQL-запросы и параметры:
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=25
Note
Значение 25 вычисляется как 1 + 8 + 16 (ошибки + SQL + параметры).
Записывайте всё:
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=255
Предупреждение
Высокие значения логарифма (64, 128, 255) дают длинный результат и могут влиять на производительность. Используйте их только для отладки.
Стандартный логгер
По умолчанию драйвер входит в стандартный log пакет Go, который записывает в os.Stderr. Выходные данные включают временные метки и категорию журнала:
2026/03/28 10:15:30 mssql: login successful
2026/03/28 10:15:30 mssql: SQL: SELECT 1
Пользовательский логер с SetLogger
Используйте mssql.SetLogger для перенаправления вывода лога драйвера на пользовательский логгер. Логгер должен реализовать интерфейс: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
}
Логер, ориентированный на контекст, с SetContextLogger
Используйте mssql.SetContextLogger для предоставления контекстно-ориентированного логгера. Логгер должен реализовать mssql.ContextLogger интерфейс, который содержит один Log метод, принимающий контекст, категорию логарифма и строку сообщений. Этот подход позволяет сопоставлять журналы драйверов с данными трассировки, относящимися к конкретному запросу (например, с идентификаторами трассировки):
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
}
Контрольный список диагностики
При устранении неполадок соединения или запроса:
- Начните с
log=1, если нужны ошибки, или сlog=3, если вам также нужны сообщения сервера. - Воспроизведите проблему и просмотрите текст ошибки перед включением новых категорий.
- Добавьте
8, если нужно уточнить, какая инструкция SQL или какой вызов процедуры был отправлен. - Добавляйте
16или4только в безопасной среде, где значения параметров и возвращаемые строки можно логировать без раскрытия конфиденциальных данных. - Если проблема связана с уровнем протокола или с повторными попытками, увеличьте значение до
log=64или добавьте128для диагностики повторных попыток. - Удалите или сократите логирование после устранения проблемы.
Структурированное логирование с log/slog
В Go 1.21 появился log/slog для структурированного логирования. Используйте SetContextLogger для маршрутизации вывода драйвера через 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.
}
Интеграция с zerolog
zerolog — это структурированный логгер с нулевым распределением. Логи драйверов маршрутов через 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})
}
Интеграция с zap
ZAP — это высокопроизводительный структурированный логгер. Водитель маршрута ведёт журналы через 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})
}
Распространение корреляционных идентификаторов
В распределённых системах распространяйте идентификатор корреляции через контекст, чтобы логи драйверов можно было сопоставить с запросом, который их инициировал:
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)),
)
}
Затем передайте идентификатор корреляции через контекст вашего запроса:
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")
// ...
}
Как использовать корреляционные идентификаторы на практике
Используйте корреляционные идентификаторы в качестве ключа для отслеживания журналов, повторных попыток и вызовов базы данных:
- Генерируйте или принимайте идентификатор корреляции на границе запроса.
- Храните его в контексте запроса и включайте в журналы приложений и драйверов.
- Для устранения неполадок на стороне SQL задайте его в контексте сеанса с помощью
sp_set_session_contextи считайте с помощьюSESSION_CONTEXT.
Идентификаторы корреляции не хранятся автоматически в таблицах SQL Server.
SESSION_CONTEXT он ограничен сессионным диапазоном, поэтому значения применяются только к текущему соединению и не сохраняются после окончания сессии.
Если вам нужно долговременное хранение истории, явно записывайте идентификатор корреляции в таблицы аудита или бизнес-таблицы (например, в таблицу AuditLog с correlation_id временной меткой, операцией и статусом).
Конфигурация производственного логирования
В продакшене можно минимизировать логирование, чтобы избежать накладных расходов производительности и предотвратить появление конфиденциальных данных в журналах:
| Окружающая среда | Рекомендуемое log значение |
То, что он захватывает |
|---|---|---|
| Development |
63 (ошибки + сообщения + строки + SQL + параметры + транзакции) |
Полная видимость для отладки. |
| Staging |
3 (ошибки + сообщения) |
Ошибки и сообщения сервера без деталей запроса. |
| Производство |
1 (ошибки) или 0 (выключено) |
Только ошибки или полное отключение ведения журнала драйвера. |
Предостережение
Parameters Флаг (16) фиксирует фактические значения параметров, которые могут включать персональную информацию (PII), пароли или другие конфиденциальные данные. Никогда не включайте этот флаг в производстве. Для полной оценки рисков каждого флага см. лучшие практики безопасности.
Подавление лесозаготовки в производстве
Используйте переменные среды для управления уровнем журнала на каждом этапе развертывания:
if os.Getenv("APP_ENV") == "production" {
// Use only error-level logging in production.
connString += "&log=1"
} else {
// Full logging in development.
connString += "&log=63"
}