golang.org/x/tools/gopls@v0.15.3/internal/protocol/context.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package protocol 6 7 import ( 8 "bytes" 9 "context" 10 "sync" 11 12 "golang.org/x/tools/internal/event" 13 "golang.org/x/tools/internal/event/core" 14 "golang.org/x/tools/internal/event/export" 15 "golang.org/x/tools/internal/event/label" 16 "golang.org/x/tools/internal/xcontext" 17 ) 18 19 type contextKey int 20 21 const ( 22 clientKey = contextKey(iota) 23 ) 24 25 func WithClient(ctx context.Context, client Client) context.Context { 26 return context.WithValue(ctx, clientKey, client) 27 } 28 29 func LogEvent(ctx context.Context, ev core.Event, lm label.Map, mt MessageType) context.Context { 30 client, ok := ctx.Value(clientKey).(Client) 31 if !ok { 32 return ctx 33 } 34 buf := &bytes.Buffer{} 35 p := export.Printer{} 36 p.WriteEvent(buf, ev, lm) 37 msg := &LogMessageParams{Type: mt, Message: buf.String()} 38 // Handle messages generated via event.Error, which won't have a level Label. 39 if event.IsError(ev) { 40 msg.Type = Error 41 } 42 43 // The background goroutine lives forever once started, 44 // and ensures log messages are sent in order (#61216). 45 startLogSenderOnce.Do(func() { 46 go func() { 47 for f := range logQueue { 48 f() 49 } 50 }() 51 }) 52 53 // Add the log item to a queue, rather than sending a 54 // window/logMessage request to the client synchronously, 55 // which would slow down this thread. 56 ctx2 := xcontext.Detach(ctx) 57 logQueue <- func() { client.LogMessage(ctx2, msg) } 58 59 return ctx 60 } 61 62 var ( 63 startLogSenderOnce sync.Once 64 logQueue = make(chan func(), 100) // big enough for a large transient burst 65 )