Skip to content

Commit 9207458

Browse files
Allow caller to set log fields (#1094)
Co-authored-by: Piotr Fus <[email protected]>
1 parent 088150c commit 9207458

19 files changed

+208
-78
lines changed

README.md

+35
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,41 @@ Install [jq](https://stedolan.github.io/jq) so that the parameters can get parse
9595
make test
9696
```
9797

98+
## customizing Logging Tags
99+
100+
If you would like to ensure that certain tags are always present in the logs, `RegisterClientLogContextHook` can be used in your init function. See example below.
101+
```
102+
import "github.com/snowflakedb/gosnowflake"
103+
104+
func init() {
105+
// each time the logger is used, the logs will contain a REQUEST_ID field with requestID the value extracted
106+
// from the context
107+
gosnowflake.RegisterClientLogContextHook("REQUEST_ID", func(ctx context.Context) interface{} {
108+
return requestIdFromContext(ctx)
109+
})
110+
}
111+
```
112+
113+
## Setting Log Level
114+
If you want to change the log level, `SetLogLevel` can be used in your init function like this:
115+
```
116+
import "github.com/snowflakedb/gosnowflake"
117+
118+
func init() {
119+
// The following line changes the log level to debug
120+
_ = gosnowflake.GetLogger().SetLogLevel("debug")
121+
}
122+
```
123+
The following is a list of options you can pass in to set the level from least to most verbose:
124+
- `"OFF"`
125+
- `"error"`
126+
- `"warn"`
127+
- `"print"`
128+
- `"trace"`
129+
- `"debug"`
130+
- `"info"`
131+
132+
98133
## Capturing Code Coverage
99134

100135
Configure your testing environment as described above and run ``make cov``. The coverage percentage will be printed on the console when the testing completes.

auth.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func postAuth(
225225
params.Add(requestGUIDKey, NewUUID().String())
226226

227227
fullURL := sr.getFullURL(loginRequestPath, params)
228-
logger.Infof("full URL: %v", fullURL)
228+
logger.WithContext(ctx).Infof("full URL: %v", fullURL)
229229
resp, err := sr.FuncAuthPost(ctx, client, fullURL, headers, bodyCreator, timeout, sr.MaxRetryCount)
230230
if err != nil {
231231
return nil, err
@@ -235,7 +235,7 @@ func postAuth(
235235
var respd authResponse
236236
err = json.NewDecoder(resp.Body).Decode(&respd)
237237
if err != nil {
238-
logger.Errorf("failed to decode JSON. err: %v", err)
238+
logger.WithContext(ctx).Errorf("failed to decode JSON. err: %v", err)
239239
return nil, err
240240
}
241241
return &respd, nil
@@ -260,11 +260,11 @@ func postAuth(
260260
}
261261
b, err := io.ReadAll(resp.Body)
262262
if err != nil {
263-
logger.Errorf("failed to extract HTTP response body. err: %v", err)
263+
logger.WithContext(ctx).Errorf("failed to extract HTTP response body. err: %v", err)
264264
return nil, err
265265
}
266-
logger.Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, fullURL, b)
267-
logger.Infof("Header: %v", resp.Header)
266+
logger.WithContext(ctx).Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, fullURL, b)
267+
logger.WithContext(ctx).Infof("Header: %v", resp.Header)
268268
return nil, &SnowflakeError{
269269
Number: ErrFailedToAuth,
270270
SQLState: SQLStateConnectionRejected,
@@ -293,7 +293,7 @@ func authenticate(
293293
proofKey []byte,
294294
) (resp *authResponseMain, err error) {
295295
if sc.cfg.Authenticator == AuthTypeTokenAccessor {
296-
logger.Info("Bypass authentication using existing token from token accessor")
296+
logger.WithContext(ctx).Info("Bypass authentication using existing token from token accessor")
297297
sessionInfo := authResponseSessionInfo{
298298
DatabaseName: sc.cfg.Database,
299299
SchemaName: sc.cfg.Schema,
@@ -350,15 +350,15 @@ func authenticate(
350350
params.Add("roleName", sc.cfg.Role)
351351
}
352352

353-
logger.WithContext(sc.ctx).Infof("PARAMS for Auth: %v, %v, %v, %v, %v, %v",
353+
logger.WithContext(ctx).WithContext(sc.ctx).Infof("PARAMS for Auth: %v, %v, %v, %v, %v, %v",
354354
params, sc.rest.Protocol, sc.rest.Host, sc.rest.Port, sc.rest.LoginTimeout, sc.cfg.Authenticator.String())
355355

356356
respd, err := sc.rest.FuncPostAuth(ctx, sc.rest, sc.rest.getClientFor(sc.cfg.Authenticator), params, headers, bodyCreator, sc.rest.LoginTimeout)
357357
if err != nil {
358358
return nil, err
359359
}
360360
if !respd.Success {
361-
logger.Errorln("Authentication FAILED")
361+
logger.WithContext(ctx).Errorln("Authentication FAILED")
362362
sc.rest.TokenAccessor.SetTokens("", "", -1)
363363
if sessionParameters[clientRequestMfaToken] == true {
364364
deleteCredential(sc, mfaToken)
@@ -377,7 +377,7 @@ func authenticate(
377377
Message: respd.Message,
378378
}).exceptionTelemetry(sc)
379379
}
380-
logger.Info("Authentication SUCCESS")
380+
logger.WithContext(ctx).Info("Authentication SUCCESS")
381381
sc.rest.TokenAccessor.SetTokens(respd.Data.Token, respd.Data.MasterToken, respd.Data.SessionID)
382382
if sessionParameters[clientRequestMfaToken] == true {
383383
token := respd.Data.MfaToken
@@ -439,7 +439,7 @@ func createRequestBody(sc *snowflakeConn, sessionParameters map[string]interface
439439
}
440440
requestMain.Token = jwtTokenString
441441
case AuthTypeSnowflake:
442-
logger.Info("Username and password")
442+
logger.WithContext(sc.ctx).Info("Username and password")
443443
requestMain.LoginName = sc.cfg.User
444444
requestMain.Password = sc.cfg.Password
445445
switch {
@@ -450,7 +450,7 @@ func createRequestBody(sc *snowflakeConn, sessionParameters map[string]interface
450450
requestMain.ExtAuthnDuoMethod = "passcode"
451451
}
452452
case AuthTypeUsernamePasswordMFA:
453-
logger.Info("Username and password MFA")
453+
logger.WithContext(sc.ctx).Info("Username and password MFA")
454454
requestMain.LoginName = sc.cfg.User
455455
requestMain.Password = sc.cfg.Password
456456
if sc.cfg.MfaToken != "" {
@@ -527,7 +527,7 @@ func authenticateWithConfig(sc *snowflakeConn) error {
527527
}
528528
}
529529

530-
logger.Infof("Authenticating via %v", sc.cfg.Authenticator.String())
530+
logger.WithContext(sc.ctx).Infof("Authenticating via %v", sc.cfg.Authenticator.String())
531531
switch sc.cfg.Authenticator {
532532
case AuthTypeExternalBrowser:
533533
if sc.cfg.IDToken == "" {

authexternalbrowser.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func getIdpURLProofKey(
131131
return "", "", err
132132
}
133133
if !respd.Success {
134-
logger.Errorln("Authentication FAILED")
134+
logger.WithContext(ctx).Errorln("Authentication FAILED")
135135
sr.TokenAccessor.SetTokens("", "", -1)
136136
code, err := strconv.Atoi(respd.Code)
137137
if err != nil {
@@ -287,7 +287,7 @@ func doAuthenticateByExternalBrowser(
287287
n, err := c.Read(b)
288288
if err != nil {
289289
if err != io.EOF {
290-
logger.Infof("error reading from socket. err: %v", err)
290+
logger.WithContext(ctx).Infof("error reading from socket. err: %v", err)
291291
errAccept = &SnowflakeError{
292292
Number: ErrFailedToGetExternalBrowserResponse,
293293
SQLState: SQLStateConnectionRejected,

authokta.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func authenticateBySAML(
9292
return nil, err
9393
}
9494
if !respd.Success {
95-
logger.Errorln("Authentication FAILED")
95+
logger.WithContext(ctx).Errorln("Authentication FAILED")
9696
sr.TokenAccessor.SetTokens("", "", -1)
9797
code, err := strconv.Atoi(respd.Code)
9898
if err != nil {
@@ -215,7 +215,7 @@ func postAuthSAML(
215215
params.Add(requestIDKey, getOrGenerateRequestIDFromContext(ctx).String())
216216
fullURL := sr.getFullURL(authenticatorRequestPath, params)
217217

218-
logger.Infof("fullURL: %v", fullURL)
218+
logger.WithContext(ctx).Infof("fullURL: %v", fullURL)
219219
resp, err := sr.FuncPost(ctx, sr, fullURL, headers, body, timeout, defaultTimeProvider, nil)
220220
if err != nil {
221221
return nil, err
@@ -269,7 +269,7 @@ func postAuthOKTA(
269269
fullURL string,
270270
timeout time.Duration) (
271271
data *authOKTAResponse, err error) {
272-
logger.Infof("fullURL: %v", fullURL)
272+
logger.WithContext(ctx).Infof("fullURL: %v", fullURL)
273273
targetURL, err := url.Parse(fullURL)
274274
if err != nil {
275275
return nil, err
@@ -290,7 +290,7 @@ func postAuthOKTA(
290290
}
291291
_, err = io.ReadAll(resp.Body)
292292
if err != nil {
293-
logger.Errorf("failed to extract HTTP response body. err: %v", err)
293+
logger.WithContext(ctx).Errorf("failed to extract HTTP response body. err: %v", err)
294294
return nil, err
295295
}
296296
logger.WithContext(ctx).Infof("HTTP: %v, URL: %v", resp.StatusCode, fullURL)

bind_uploader.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (bu *bindUploader) createCSVRecord(data []interface{}) []byte {
175175
if ok {
176176
b.WriteString(escapeForCSV(value))
177177
} else if !reflect.ValueOf(data[i]).IsNil() {
178-
logger.Debugf("Cannot convert value to string in createCSVRecord. value: %v", data[i])
178+
logger.WithContext(bu.ctx).Debugf("Cannot convert value to string in createCSVRecord. value: %v", data[i])
179179
}
180180
}
181181
b.WriteString("\n")

chunk_downloader.go

+19-19
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,16 @@ func (scd *snowflakeChunkDownloader) start() error {
124124
// start downloading chunks if exists
125125
chunkMetaLen := len(scd.ChunkMetas)
126126
if chunkMetaLen > 0 {
127-
logger.Debugf("MaxChunkDownloadWorkers: %v", MaxChunkDownloadWorkers)
128-
logger.Debugf("chunks: %v, total bytes: %d", chunkMetaLen, scd.totalUncompressedSize())
127+
logger.WithContext(scd.ctx).Debugf("MaxChunkDownloadWorkers: %v", MaxChunkDownloadWorkers)
128+
logger.WithContext(scd.ctx).Debugf("chunks: %v, total bytes: %d", chunkMetaLen, scd.totalUncompressedSize())
129129
scd.ChunksMutex = &sync.Mutex{}
130130
scd.DoneDownloadCond = sync.NewCond(scd.ChunksMutex)
131131
scd.Chunks = make(map[int][]chunkRowType)
132132
scd.ChunksChan = make(chan int, chunkMetaLen)
133133
scd.ChunksError = make(chan *chunkError, MaxChunkDownloadWorkers)
134134
for i := 0; i < chunkMetaLen; i++ {
135135
chunk := scd.ChunkMetas[i]
136-
logger.Debugf("add chunk to channel ChunksChan: %v, URL: %v, RowCount: %v, UncompressedSize: %v, ChunkResultFormat: %v",
136+
logger.WithContext(scd.ctx).Debugf("add chunk to channel ChunksChan: %v, URL: %v, RowCount: %v, UncompressedSize: %v, ChunkResultFormat: %v",
137137
i+1, chunk.URL, chunk.RowCount, chunk.UncompressedSize, scd.QueryResultFormat)
138138
scd.ChunksChan <- i
139139
}
@@ -147,11 +147,11 @@ func (scd *snowflakeChunkDownloader) start() error {
147147
func (scd *snowflakeChunkDownloader) schedule() {
148148
select {
149149
case nextIdx := <-scd.ChunksChan:
150-
logger.Infof("schedule chunk: %v", nextIdx+1)
150+
logger.WithContext(scd.ctx).Infof("schedule chunk: %v", nextIdx+1)
151151
go scd.FuncDownload(scd.ctx, scd, nextIdx)
152152
default:
153153
// no more download
154-
logger.Info("no more download")
154+
logger.WithContext(scd.ctx).Info("no more download")
155155
}
156156
}
157157

@@ -164,15 +164,15 @@ func (scd *snowflakeChunkDownloader) checkErrorRetry() (err error) {
164164
// add the index to the chunks channel so that the download will be retried.
165165
go scd.FuncDownload(scd.ctx, scd, errc.Index)
166166
scd.ChunksErrorCounter++
167-
logger.Warningf("chunk idx: %v, err: %v. retrying (%v/%v)...",
167+
logger.WithContext(scd.ctx).Warningf("chunk idx: %v, err: %v. retrying (%v/%v)...",
168168
errc.Index, errc.Error, scd.ChunksErrorCounter, maxChunkDownloaderErrorCounter)
169169
} else {
170170
scd.ChunksFinalErrors = append(scd.ChunksFinalErrors, errc)
171-
logger.Warningf("chunk idx: %v, err: %v. no further retry", errc.Index, errc.Error)
171+
logger.WithContext(scd.ctx).Warningf("chunk idx: %v, err: %v. no further retry", errc.Index, errc.Error)
172172
return errc.Error
173173
}
174174
default:
175-
logger.Info("no error is detected.")
175+
logger.WithContext(scd.ctx).Info("no error is detected.")
176176
}
177177
return nil
178178
}
@@ -195,7 +195,7 @@ func (scd *snowflakeChunkDownloader) next() (chunkRowType, error) {
195195
}
196196

197197
for scd.Chunks[scd.CurrentChunkIndex] == nil {
198-
logger.Debugf("waiting for chunk idx: %v/%v",
198+
logger.WithContext(scd.ctx).Debugf("waiting for chunk idx: %v/%v",
199199
scd.CurrentChunkIndex+1, len(scd.ChunkMetas))
200200

201201
if err := scd.checkErrorRetry(); err != nil {
@@ -207,7 +207,7 @@ func (scd *snowflakeChunkDownloader) next() (chunkRowType, error) {
207207
// 1) one chunk download finishes or 2) an error occurs.
208208
scd.DoneDownloadCond.Wait()
209209
}
210-
logger.Debugf("ready: chunk %v", scd.CurrentChunkIndex+1)
210+
logger.WithContext(scd.ctx).Debugf("ready: chunk %v", scd.CurrentChunkIndex+1)
211211
scd.CurrentChunk = scd.Chunks[scd.CurrentChunkIndex]
212212
scd.ChunksMutex.Unlock()
213213
scd.CurrentChunkSize = len(scd.CurrentChunk)
@@ -216,7 +216,7 @@ func (scd *snowflakeChunkDownloader) next() (chunkRowType, error) {
216216
scd.schedule()
217217
}
218218

219-
logger.Debugf("no more data")
219+
logger.WithContext(scd.ctx).Debugf("no more data")
220220
if len(scd.ChunkMetas) > 0 {
221221
close(scd.ChunksError)
222222
close(scd.ChunksChan)
@@ -342,11 +342,11 @@ func (r *largeResultSetReader) Read(p []byte) (n int, err error) {
342342
}
343343

344344
func downloadChunk(ctx context.Context, scd *snowflakeChunkDownloader, idx int) {
345-
logger.Infof("download start chunk: %v", idx+1)
345+
logger.WithContext(ctx).Infof("download start chunk: %v", idx+1)
346346
defer scd.DoneDownloadCond.Broadcast()
347347

348348
if err := scd.FuncDownloadHelper(ctx, scd, idx); err != nil {
349-
logger.Errorf(
349+
logger.WithContext(ctx).Errorf(
350350
"failed to extract HTTP response body. URL: %v, err: %v", scd.ChunkMetas[idx].URL, err)
351351
scd.ChunksError <- &chunkError{Index: idx, Error: err}
352352
} else if scd.ctx.Err() == context.Canceled || scd.ctx.Err() == context.DeadlineExceeded {
@@ -357,9 +357,9 @@ func downloadChunk(ctx context.Context, scd *snowflakeChunkDownloader, idx int)
357357
func downloadChunkHelper(ctx context.Context, scd *snowflakeChunkDownloader, idx int) error {
358358
headers := make(map[string]string)
359359
if len(scd.ChunkHeader) > 0 {
360-
logger.Debug("chunk header is provided.")
360+
logger.WithContext(ctx).Debug("chunk header is provided.")
361361
for k, v := range scd.ChunkHeader {
362-
logger.Debugf("adding header: %v, value: %v", k, v)
362+
logger.WithContext(ctx).Debugf("adding header: %v, value: %v", k, v)
363363

364364
headers[k] = v
365365
}
@@ -374,14 +374,14 @@ func downloadChunkHelper(ctx context.Context, scd *snowflakeChunkDownloader, idx
374374
}
375375
bufStream := bufio.NewReader(resp.Body)
376376
defer resp.Body.Close()
377-
logger.Debugf("response returned chunk: %v for URL: %v", idx+1, scd.ChunkMetas[idx].URL)
377+
logger.WithContext(ctx).Debugf("response returned chunk: %v for URL: %v", idx+1, scd.ChunkMetas[idx].URL)
378378
if resp.StatusCode != http.StatusOK {
379379
b, err := io.ReadAll(bufStream)
380380
if err != nil {
381381
return err
382382
}
383-
logger.Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, scd.ChunkMetas[idx].URL, b)
384-
logger.Infof("Header: %v", resp.Header)
383+
logger.WithContext(ctx).Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, scd.ChunkMetas[idx].URL, b)
384+
logger.WithContext(ctx).Infof("Header: %v", resp.Header)
385385
return &SnowflakeError{
386386
Number: ErrFailedToGetChunk,
387387
SQLState: SQLStateConnectionFailure,
@@ -463,7 +463,7 @@ func decodeChunk(ctx context.Context, scd *snowflakeChunkDownloader, idx int, bu
463463
return err
464464
}
465465
}
466-
logger.Debugf(
466+
logger.WithContext(scd.ctx).Debugf(
467467
"decoded %d rows w/ %d bytes in %s (chunk %v)",
468468
scd.ChunkMetas[idx].RowCount,
469469
scd.ChunkMetas[idx].UncompressedSize,

connection.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (sc *snowflakeConn) exec(
9898

9999
queryContext, err := buildQueryContext(sc.queryContextCache)
100100
if err != nil {
101-
logger.Errorf("error while building query context: %v", err)
101+
logger.WithContext(ctx).Errorf("error while building query context: %v", err)
102102
}
103103
req := execRequest{
104104
SQLText: query,
@@ -163,7 +163,7 @@ func (sc *snowflakeConn) exec(
163163
if !sc.cfg.DisableQueryContextCache && data.Data.QueryContext != nil {
164164
queryContext, err := extractQueryContext(data)
165165
if err != nil {
166-
logger.Errorf("error while decoding query context: ", err)
166+
logger.WithContext(ctx).Errorf("error while decoding query context: %v", err)
167167
} else {
168168
sc.queryContextCache.add(sc, queryContext.Entries...)
169169
}
@@ -272,7 +272,7 @@ func (sc *snowflakeConn) Close() (err error) {
272272

273273
if sc.cfg != nil && !sc.cfg.KeepSessionAlive {
274274
if err = sc.rest.FuncCloseSession(sc.ctx, sc.rest, sc.rest.RequestTimeout); err != nil {
275-
logger.Error(err)
275+
logger.WithContext(sc.ctx).Error(err)
276276
}
277277
}
278278
return nil
@@ -350,7 +350,7 @@ func (sc *snowflakeConn) ExecContext(
350350
}
351351
return driver.ResultNoRows, nil
352352
}
353-
logger.Debug("DDL")
353+
logger.WithContext(ctx).Debug("DDL")
354354
if isStatementContext(ctx) {
355355
return &snowflakeResultNoRows{queryID: data.Data.QueryID}, nil
356356
}
@@ -571,7 +571,7 @@ func (w *wrapReader) Close() error {
571571
func (asb *ArrowStreamBatch) downloadChunkStreamHelper(ctx context.Context) error {
572572
headers := make(map[string]string)
573573
if len(asb.scd.ChunkHeader) > 0 {
574-
logger.Debug("chunk header is provided")
574+
logger.WithContext(ctx).Debug("chunk header is provided")
575575
for k, v := range asb.scd.ChunkHeader {
576576
logger.Debugf("adding header: %v, value: %v", k, v)
577577

@@ -586,16 +586,16 @@ func (asb *ArrowStreamBatch) downloadChunkStreamHelper(ctx context.Context) erro
586586
if err != nil {
587587
return err
588588
}
589-
logger.Debugf("response returned chunk: %v for URL: %v", asb.idx+1, asb.scd.ChunkMetas[asb.idx].URL)
589+
logger.WithContext(ctx).Debugf("response returned chunk: %v for URL: %v", asb.idx+1, asb.scd.ChunkMetas[asb.idx].URL)
590590
if resp.StatusCode != http.StatusOK {
591591
defer resp.Body.Close()
592592
b, err := io.ReadAll(resp.Body)
593593
if err != nil {
594594
return err
595595
}
596596

597-
logger.Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, asb.scd.ChunkMetas[asb.idx].URL, b)
598-
logger.Infof("Header: %v", resp.Header)
597+
logger.WithContext(ctx).Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, asb.scd.ChunkMetas[asb.idx].URL, b)
598+
logger.WithContext(ctx).Infof("Header: %v", resp.Header)
599599
return &SnowflakeError{
600600
Number: ErrFailedToGetChunk,
601601
SQLState: SQLStateConnectionFailure,

0 commit comments

Comments
 (0)