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  )