이 드라이버는 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
비고
값 25은(는) 1 + 8 + 16(errors + SQL + 매개변수)로 계산됩니다.
모든 기록:
sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&log=255
Warning
로그 플래그 값(64, 128, 255)이 높으면 과장된 출력이 발생하여 성능에 영향을 줄 수 있습니다. 디버깅에만 사용하세요.
기본 로거
기본적으로 드라이버는 Go의 표준 log 패키지에 로그를 기록하고, 이는 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 해야 합니다. 이 접근법은 운전자 로그를 요청 범위 추적 데이터(예: 추적 ID)와 연관시킬 수 있게 해줍니다:
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로 시작하세요. - 문제를 재현하고 오류 텍스트를 검토한 후 추가 카테고리를 활성화하세요.
- 어떤 SQL 문장이나 프로시저 호출이 전송되었는지 확인해야 한다면 추가
8하세요. - 추가
16하거나4민감한 데이터를 노출하지 않고 매개변수 값과 반환된 행을 기록할 수 있는 안전한 환경에서만 사용하세요. - 문제가 프로토콜 수준이나 재시도 관련으로 보인다면, 재시도 진단을 위해 용량을
log=64늘리거나 추가128하세요. - 문제가 해결되면 로그를 제거하거나 줄이세요.
로그/슬로그를 이용한 구조적 로깅
Go 1.21에서는 구조화된 로깅을 위한 log/slog가 도입되었습니다. 드라이버 출력을 slog을(를) 통해 라우팅하려면 SetContextLogger을(를) 사용하세요:
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를 통해 운전자 로그를 라우팅하기:
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})
}
Correlation ID 전파
분산 시스템에서는 상관관계 ID를 컨텍스트를 통해 전파하여 드라이버 로그를 트리거한 요청과 상관관계를 유지할 수 있습니다:
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)),
)
}
그 다음 요청 컨텍스트를 통해 상관 ID를 전달합니다:
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")
// ...
}
실제로 상관 ID 사용법
로그, 재시도, 데이터베이스 호출 간 추적 키로 상관 ID를 사용하세요:
- 요청 경계에서 상관 ID를 생성하거나 수락하세요.
- 요청 컨텍스트에 저장하고 애플리케이션 및 드라이버 로그에 포함하세요.
- SQL 측 문제 해결을 위해서는
sp_set_session_context를 사용해 세션 컨텍스트에 설정하고SESSION_CONTEXT로 읽으세요.
상관관계 ID는 SQL Server 테이블에 자동으로 저장되지 않습니다.
SESSION_CONTEXT 세션 범위가 설정되어 있어, 값은 현재 연결에만 적용되고 세션이 끝난 후에는 유지되지 않습니다.
영구적으로 보존되는 이력이 필요하다면 상관 ID를 감사용 또는 비즈니스 테이블에 명시적으로 기록하세요(예: 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"
}