internal/lsp: convert logging calls

Change-Id: I09ee44d0121b7ced001b8195f9fa81b5225cb0c7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/186197
Run-TryBot: Ian Cottrell <iancottrell@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index 8cafc03..67e29a9 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -16,8 +16,9 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/packages"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/trace"
-	"golang.org/x/tools/internal/lsp/xlog"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -130,7 +131,7 @@
 		uri := span.FileURI(filename)
 		f, err := imp.view.getFile(ctx, uri)
 		if err != nil {
-			xlog.Errorf(ctx, "unable to get file for %s: %v", f.URI(), err)
+			log.Error(ctx, "unable to get file", err, telemetry.File.Of(f.URI()))
 			continue
 		}
 		pkg.files = append(pkg.files, imp.view.session.cache.ParseGoHandle(f.Handle(ctx), mode))
diff --git a/internal/lsp/cache/gofile.go b/internal/lsp/cache/gofile.go
index e77c1e4..a347a67 100644
--- a/internal/lsp/cache/gofile.go
+++ b/internal/lsp/cache/gofile.go
@@ -12,7 +12,8 @@
 	"sync"
 
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -58,6 +59,7 @@
 func (f *goFile) GetAST(ctx context.Context, mode source.ParseMode) (*ast.File, error) {
 	f.view.mu.Lock()
 	defer f.view.mu.Unlock()
+	ctx = telemetry.File.With(ctx, f.URI())
 
 	if f.isDirty(ctx) || f.wrongParseMode(ctx, mode) {
 		if _, err := f.view.loadParseTypecheck(ctx, f); err != nil {
@@ -88,10 +90,11 @@
 func (f *goFile) GetPackages(ctx context.Context) []source.Package {
 	f.view.mu.Lock()
 	defer f.view.mu.Unlock()
+	ctx = telemetry.File.With(ctx, f.URI())
 
 	if f.isDirty(ctx) || f.wrongParseMode(ctx, source.ParseFull) {
 		if errs, err := f.view.loadParseTypecheck(ctx, f); err != nil {
-			xlog.Errorf(ctx, "unable to check package for %s: %v", f.URI(), err)
+			log.Error(ctx, "unable to check package", err, telemetry.File)
 
 			// Create diagnostics for errors if we are able to.
 			if len(errs) > 0 {
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index 30d2b69..614c9d6 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -10,7 +10,9 @@
 
 	"golang.org/x/tools/go/packages"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -101,9 +103,9 @@
 	// Track missing imports as we look at the package's errors.
 	missingImports := make(map[packagePath]struct{})
 
-	xlog.Debugf(ctx, "packages.Load: found %v packages", len(pkgs))
+	log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
 	for _, pkg := range pkgs {
-		xlog.Debugf(ctx, "packages.Load: package %s with files %v", pkg.PkgPath, pkg.CompiledGoFiles)
+		log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
 		// If the package comes back with errors from `go list`,
 		// don't bother type-checking it.
 		if len(pkg.Errors) > 0 {
@@ -228,12 +230,12 @@
 	for _, filename := range m.files {
 		f, err := v.getFile(ctx, span.FileURI(filename))
 		if err != nil {
-			xlog.Errorf(ctx, "no file %s: %v", filename, err)
+			log.Error(ctx, "no file", err, telemetry.File.Of(filename))
 			continue
 		}
 		gof, ok := f.(*goFile)
 		if !ok {
-			xlog.Errorf(ctx, "not a Go file: %s", f.URI())
+			log.Error(ctx, "not a Go file", nil, telemetry.File.Of(filename))
 			continue
 		}
 		if gof.meta == nil {
@@ -258,7 +260,7 @@
 		}
 		if _, ok := m.children[packageID(importPkg.ID)]; !ok {
 			if err := v.link(ctx, importPkgPath, importPkg, m, missingImports); err != nil {
-				xlog.Errorf(ctx, "error in dependency %s: %v", importPkgPath, err)
+				log.Error(ctx, "error in dependency", err, telemetry.Package.Of(importPkgPath))
 			}
 		}
 	}
diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go
index 3940a28..2eacabb 100644
--- a/internal/lsp/cache/session.go
+++ b/internal/lsp/cache/session.go
@@ -16,8 +16,9 @@
 
 	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/trace"
-	"golang.org/x/tools/internal/lsp/xlog"
 	"golang.org/x/tools/internal/span"
 	"golang.org/x/tools/internal/xcontext"
 )
@@ -182,6 +183,7 @@
 
 // TODO: Propagate the language ID through to the view.
 func (s *session) DidOpen(ctx context.Context, uri span.URI, _ source.FileKind, text []byte) {
+	ctx = telemetry.File.With(ctx, uri)
 	// Mark the file as open.
 	s.openFiles.Store(uri, true)
 
@@ -196,12 +198,12 @@
 		if strings.HasPrefix(string(uri), string(view.Folder())) {
 			f, err := view.GetFile(ctx, uri)
 			if err != nil {
-				xlog.Errorf(ctx, "error getting file for %s", uri)
+				log.Error(ctx, "error getting file", nil, telemetry.File)
 				return
 			}
 			gof, ok := f.(*goFile)
 			if !ok {
-				xlog.Errorf(ctx, "%s is not a Go file", uri)
+				log.Error(ctx, "not a Go file", nil, telemetry.File)
 				return
 			}
 			// Mark file as open.
@@ -273,7 +275,7 @@
 	}
 	_, hash, err := s.cache.GetFile(uri).Read(ctx)
 	if err != nil {
-		xlog.Errorf(ctx, "failed to read %s: %v", uri, err)
+		log.Error(ctx, "failed to read", err, telemetry.File)
 		return
 	}
 	if hash == s.overlays[uri].hash {
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 8f59aed..14687d2 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -6,6 +6,7 @@
 
 import (
 	"context"
+	"fmt"
 	"go/ast"
 	"go/parser"
 	"go/token"
@@ -19,7 +20,8 @@
 	"golang.org/x/tools/internal/imports"
 	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -136,7 +138,7 @@
 			panic("go/packages must not be used to parse files")
 		},
 		Logf: func(format string, args ...interface{}) {
-			xlog.Infof(ctx, format, args...)
+			log.Print(ctx, fmt.Sprintf(format, args...))
 		},
 		Tests: true,
 	}
@@ -156,8 +158,8 @@
 	cfg := v.Config(ctx)
 	env := &imports.ProcessEnv{
 		WorkingDir: cfg.Dir,
-		Logf: func(format string, u ...interface{}) {
-			xlog.Infof(v.backgroundCtx, format, u...)
+		Logf: func(format string, args ...interface{}) {
+			log.Print(ctx, fmt.Sprintf(format, args...))
 		},
 	}
 	for _, kv := range cfg.Env {
@@ -242,7 +244,7 @@
 	cfg := *v.Config(ctx)
 	pkgs, err := packages.Load(&cfg, "builtin")
 	if err != nil {
-		xlog.Errorf(ctx, "error getting package metadata for \"builtin\" package: %v", err)
+		log.Error(ctx, "error getting package metadata for \"builtin\" package", err)
 	}
 	if len(pkgs) != 1 {
 		v.builtinPkg, _ = ast.NewPackage(cfg.Fset, nil, nil, nil)
@@ -330,12 +332,12 @@
 	for _, filename := range m.files {
 		f, err := v.findFile(span.FileURI(filename))
 		if err != nil {
-			xlog.Errorf(ctx, "cannot find file %s: %v", f.URI(), err)
+			log.Error(ctx, "cannot find file", err, telemetry.File.Of(f.URI()))
 			continue
 		}
 		gof, ok := f.(*goFile)
 		if !ok {
-			xlog.Errorf(ctx, "non-Go file %v", f.URI())
+			log.Error(ctx, "non-Go file", nil, telemetry.File.Of(f.URI()))
 			continue
 		}
 		gof.mu.Lock()
diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go
index ca0862e..9e2a2ec 100644
--- a/internal/lsp/code_action.go
+++ b/internal/lsp/code_action.go
@@ -11,7 +11,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -58,7 +59,7 @@
 		if s.wantSuggestedFixes {
 			qf, err := quickFixes(ctx, view, gof)
 			if err != nil {
-				xlog.Errorf(ctx, "quick fixes failed for %s: %v", uri, err)
+				log.Error(ctx, "quick fixes failed", err, telemetry.File.Of(uri))
 			}
 			codeActions = append(codeActions, qf...)
 		}
diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go
index ac7705d..2901ce0 100644
--- a/internal/lsp/completion.go
+++ b/internal/lsp/completion.go
@@ -12,7 +12,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -36,7 +37,7 @@
 		WantDocumentaton: s.wantCompletionDocumentation,
 	})
 	if err != nil {
-		xlog.Infof(ctx, "no completions found for %s:%v:%v: %v", uri, int(params.Position.Line), int(params.Position.Character), err)
+		log.Print(ctx, "no completions found", tag.Of("At", rng), tag.Of("Failure", err))
 	}
 	return &protocol.CompletionList{
 		IsIncomplete: false,
@@ -63,11 +64,11 @@
 		prefix = strings.ToLower(surrounding.Prefix())
 		spn, err := surrounding.Range.Span()
 		if err != nil {
-			xlog.Infof(ctx, "failed to get span for surrounding position: %s:%v:%v: %v", m.URI, int(pos.Line), int(pos.Character), err)
+			log.Print(ctx, "failed to get span for surrounding position: %s:%v:%v: %v", tag.Of("Position", pos), tag.Of("Failure", err))
 		} else {
 			rng, err := m.Range(spn)
 			if err != nil {
-				xlog.Infof(ctx, "failed to convert surrounding position: %s:%v:%v: %v", m.URI, int(pos.Line), int(pos.Character), err)
+				log.Print(ctx, "failed to convert surrounding position", tag.Of("Position", pos), tag.Of("Failure", err))
 			} else {
 				insertionRange = rng
 			}
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index 2427cdc..be64ab6 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -9,7 +9,6 @@
 	"context"
 	"go/token"
 	"html/template"
-	"log"
 	"net"
 	"net/http"
 	"net/http/pprof"
@@ -19,7 +18,9 @@
 	"strconv"
 	"sync"
 
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/metric"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/lsp/telemetry/worker"
 	"golang.org/x/tools/internal/span"
 )
@@ -213,7 +214,7 @@
 	if err != nil {
 		return err
 	}
-	log.Printf("Debug serving on port: %d", listener.Addr().(*net.TCPAddr).Port)
+	log.Print(ctx, "Debug serving", tag.Of("Port", listener.Addr().(*net.TCPAddr).Port))
 	prometheus := prometheus{}
 	metric.RegisterObservers(prometheus.observeMetric)
 	rpcs := rpcs{}
@@ -236,10 +237,10 @@
 		mux.HandleFunc("/info", Render(infoTmpl, getInfo))
 		mux.HandleFunc("/memory", Render(memoryTmpl, getMemory))
 		if err := http.Serve(listener, mux); err != nil {
-			log.Printf("Debug server failed with %v", err)
+			log.Error(ctx, "Debug server failed", err)
 			return
 		}
-		log.Printf("Debug server finished")
+		log.Print(ctx, "Debug server finished")
 	}()
 	return nil
 }
@@ -254,7 +255,7 @@
 				data = fun(r)
 			}
 			if err := tmpl.Execute(w, data); err != nil {
-				log.Print(err)
+				log.Error(context.Background(), "", err)
 			}
 		})
 		<-done
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index b7fd90d..e77e846 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -10,14 +10,16 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/span"
 )
 
 func (s *Server) Diagnostics(ctx context.Context, view source.View, uri span.URI) {
+	ctx = telemetry.File.With(ctx, uri)
 	f, err := view.GetFile(ctx, uri)
 	if err != nil {
-		xlog.Errorf(ctx, "no file for %s: %v", uri, err)
+		log.Error(ctx, "no file", err, telemetry.File)
 		return
 	}
 	// For non-Go files, don't return any diagnostics.
@@ -27,7 +29,7 @@
 	}
 	reports, err := source.Diagnostics(ctx, view, gof, s.disabledAnalyses)
 	if err != nil {
-		xlog.Errorf(ctx, "failed to compute diagnostics for %s: %v", gof.URI(), err)
+		log.Error(ctx, "failed to compute diagnostics", err, telemetry.File)
 		return
 	}
 
@@ -39,7 +41,7 @@
 			if s.undelivered == nil {
 				s.undelivered = make(map[span.URI][]source.Diagnostic)
 			}
-			xlog.Errorf(ctx, "failed to deliver diagnostic for %s (will retry): %v", uri, err)
+			log.Error(ctx, "failed to deliver diagnostic (will retry)", err, telemetry.File)
 			s.undelivered[uri] = diagnostics
 			continue
 		}
@@ -50,7 +52,7 @@
 	// undelivered ones (only for remaining URIs).
 	for uri, diagnostics := range s.undelivered {
 		if err := s.publishDiagnostics(ctx, view, uri, diagnostics); err != nil {
-			xlog.Errorf(ctx, "failed to deliver diagnostic for %s (will not retry): %v", uri, err)
+			log.Error(ctx, "failed to deliver diagnostic for (will not retry)", err, telemetry.File)
 		}
 		// If we fail to deliver the same diagnostics twice, just give up.
 		delete(s.undelivered, uri)
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index 12adb19..eea37a5 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -15,7 +15,8 @@
 	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -155,7 +156,7 @@
 	}
 	buf := &bytes.Buffer{}
 	debug.PrintVersionInfo(buf, true, debug.PlainText)
-	xlog.Infof(ctx, "%s", buf)
+	log.Print(ctx, buf.String())
 	return nil
 }
 
@@ -210,7 +211,7 @@
 		case "FullDocumentation":
 			s.hoverKind = source.FullDocumentation
 		default:
-			xlog.Errorf(ctx, "unsupported hover kind %s", hoverKind)
+			log.Error(ctx, "unsupported hover kind", nil, tag.Of("HoverKind", hoverKind))
 			// The default value is already be set to synopsis.
 		}
 	}
diff --git a/internal/lsp/highlight.go b/internal/lsp/highlight.go
index ade399a..28945dd 100644
--- a/internal/lsp/highlight.go
+++ b/internal/lsp/highlight.go
@@ -9,7 +9,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -30,7 +31,7 @@
 	}
 	spans, err := source.Highlight(ctx, f, rng.Start)
 	if err != nil {
-		xlog.Errorf(ctx, "no highlight for %s: %v", spn, err)
+		log.Error(ctx, "no highlight", err, tag.Of("Span", spn))
 	}
 	return toProtocolHighlight(m, spans), nil
 }
diff --git a/internal/lsp/link.go b/internal/lsp/link.go
index 6ca0d87..a251e52 100644
--- a/internal/lsp/link.go
+++ b/internal/lsp/link.go
@@ -15,7 +15,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -37,13 +38,13 @@
 		case *ast.ImportSpec:
 			target, err := strconv.Unquote(n.Path.Value)
 			if err != nil {
-				xlog.Errorf(ctx, "cannot unquote import path %s: %v", n.Path.Value, err)
+				log.Error(ctx, "cannot unquote import path", err, tag.Of("Path", n.Path.Value))
 				return false
 			}
 			target = "https://godoc.org/" + target
 			l, err := toProtocolLink(view, m, target, n.Pos(), n.End())
 			if err != nil {
-				xlog.Errorf(ctx, "cannot initialize DocumentLink %s: %v", n.Path.Value, err)
+				log.Error(ctx, "cannot initialize DocumentLink", err, tag.Of("Path", n.Path.Value))
 				return false
 			}
 			links = append(links, l)
@@ -54,7 +55,7 @@
 			}
 			l, err := findLinksInString(n.Value, n.Pos(), view, m)
 			if err != nil {
-				xlog.Errorf(ctx, "cannot find links in string: %v", err)
+				log.Error(ctx, "cannot find links in string", err)
 				return false
 			}
 			links = append(links, l...)
@@ -67,7 +68,7 @@
 		for _, comment := range commentGroup.List {
 			l, err := findLinksInString(comment.Text, comment.Pos(), view, m)
 			if err != nil {
-				xlog.Errorf(ctx, "cannot find links in comment: %v", err)
+				log.Error(ctx, "cannot find links in comment", err)
 				continue
 			}
 			links = append(links, l...)
diff --git a/internal/lsp/protocol/protocol.go b/internal/lsp/protocol/protocol.go
index 8c3ef95..585f3a8 100644
--- a/internal/lsp/protocol/protocol.go
+++ b/internal/lsp/protocol/protocol.go
@@ -8,8 +8,8 @@
 	"context"
 
 	"golang.org/x/tools/internal/jsonrpc2"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/trace"
-	"golang.org/x/tools/internal/lsp/xlog"
 	"golang.org/x/tools/internal/xcontext"
 )
 
@@ -58,6 +58,6 @@
 		err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
 	}
 	if err := req.Reply(ctx, nil, err); err != nil {
-		xlog.Errorf(ctx, "%v", err)
+		log.Error(ctx, "", err)
 	}
 }
diff --git a/internal/lsp/protocol/tsclient.go b/internal/lsp/protocol/tsclient.go
index d5b4b01..226f531 100644
--- a/internal/lsp/protocol/tsclient.go
+++ b/internal/lsp/protocol/tsclient.go
@@ -7,7 +7,7 @@
 	"encoding/json"
 
 	"golang.org/x/tools/internal/jsonrpc2"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 )
 
 type Client interface {
@@ -43,7 +43,7 @@
 			return true
 		}
 		if err := h.client.ShowMessage(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "window/logMessage": // notif
@@ -53,7 +53,7 @@
 			return true
 		}
 		if err := h.client.LogMessage(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "telemetry/event": // notif
@@ -63,7 +63,7 @@
 			return true
 		}
 		if err := h.client.Event(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/publishDiagnostics": // notif
@@ -73,7 +73,7 @@
 			return true
 		}
 		if err := h.client.PublishDiagnostics(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/workspaceFolders": // req
@@ -83,7 +83,7 @@
 		}
 		resp, err := h.client.WorkspaceFolders(ctx)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/configuration": // req
@@ -94,7 +94,7 @@
 		}
 		resp, err := h.client.Configuration(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "client/registerCapability": // req
@@ -105,7 +105,7 @@
 		}
 		err := h.client.RegisterCapability(ctx, &params)
 		if err := r.Reply(ctx, nil, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "client/unregisterCapability": // req
@@ -116,7 +116,7 @@
 		}
 		err := h.client.UnregisterCapability(ctx, &params)
 		if err := r.Reply(ctx, nil, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "window/showMessageRequest": // req
@@ -127,7 +127,7 @@
 		}
 		resp, err := h.client.ShowMessageRequest(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/applyEdit": // req
@@ -138,7 +138,7 @@
 		}
 		resp, err := h.client.ApplyEdit(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 
diff --git a/internal/lsp/protocol/tsserver.go b/internal/lsp/protocol/tsserver.go
index 0d254da..7e96214 100644
--- a/internal/lsp/protocol/tsserver.go
+++ b/internal/lsp/protocol/tsserver.go
@@ -7,7 +7,7 @@
 	"encoding/json"
 
 	"golang.org/x/tools/internal/jsonrpc2"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 )
 
 type Server interface {
@@ -75,7 +75,7 @@
 			return true
 		}
 		if err := h.server.DidChangeWorkspaceFolders(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "initialized": // notif
@@ -85,12 +85,12 @@
 			return true
 		}
 		if err := h.server.Initialized(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "exit": // notif
 		if err := h.server.Exit(ctx); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/didChangeConfiguration": // notif
@@ -100,7 +100,7 @@
 			return true
 		}
 		if err := h.server.DidChangeConfiguration(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/didOpen": // notif
@@ -110,7 +110,7 @@
 			return true
 		}
 		if err := h.server.DidOpen(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/didChange": // notif
@@ -120,7 +120,7 @@
 			return true
 		}
 		if err := h.server.DidChange(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/didClose": // notif
@@ -130,7 +130,7 @@
 			return true
 		}
 		if err := h.server.DidClose(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/didSave": // notif
@@ -140,7 +140,7 @@
 			return true
 		}
 		if err := h.server.DidSave(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/willSave": // notif
@@ -150,7 +150,7 @@
 			return true
 		}
 		if err := h.server.WillSave(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/didChangeWatchedFiles": // notif
@@ -160,7 +160,7 @@
 			return true
 		}
 		if err := h.server.DidChangeWatchedFiles(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "$/setTraceNotification": // notif
@@ -170,7 +170,7 @@
 			return true
 		}
 		if err := h.server.SetTraceNotification(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "$/logTraceNotification": // notif
@@ -180,7 +180,7 @@
 			return true
 		}
 		if err := h.server.LogTraceNotification(ctx, &params); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/implementation": // req
@@ -191,7 +191,7 @@
 		}
 		resp, err := h.server.Implementation(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/typeDefinition": // req
@@ -202,7 +202,7 @@
 		}
 		resp, err := h.server.TypeDefinition(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/documentColor": // req
@@ -213,7 +213,7 @@
 		}
 		resp, err := h.server.DocumentColor(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/colorPresentation": // req
@@ -224,7 +224,7 @@
 		}
 		resp, err := h.server.ColorPresentation(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/foldingRange": // req
@@ -235,7 +235,7 @@
 		}
 		resp, err := h.server.FoldingRange(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/declaration": // req
@@ -246,7 +246,7 @@
 		}
 		resp, err := h.server.Declaration(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/selectionRange": // req
@@ -257,7 +257,7 @@
 		}
 		resp, err := h.server.SelectionRange(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "initialize": // req
@@ -268,7 +268,7 @@
 		}
 		resp, err := h.server.Initialize(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "shutdown": // req
@@ -278,7 +278,7 @@
 		}
 		err := h.server.Shutdown(ctx)
 		if err := r.Reply(ctx, nil, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/willSaveWaitUntil": // req
@@ -289,7 +289,7 @@
 		}
 		resp, err := h.server.WillSaveWaitUntil(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/completion": // req
@@ -300,7 +300,7 @@
 		}
 		resp, err := h.server.Completion(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "completionItem/resolve": // req
@@ -311,7 +311,7 @@
 		}
 		resp, err := h.server.Resolve(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/hover": // req
@@ -322,7 +322,7 @@
 		}
 		resp, err := h.server.Hover(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/signatureHelp": // req
@@ -333,7 +333,7 @@
 		}
 		resp, err := h.server.SignatureHelp(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/definition": // req
@@ -344,7 +344,7 @@
 		}
 		resp, err := h.server.Definition(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/references": // req
@@ -355,7 +355,7 @@
 		}
 		resp, err := h.server.References(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/documentHighlight": // req
@@ -366,7 +366,7 @@
 		}
 		resp, err := h.server.DocumentHighlight(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/documentSymbol": // req
@@ -377,7 +377,7 @@
 		}
 		resp, err := h.server.DocumentSymbol(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/symbol": // req
@@ -388,7 +388,7 @@
 		}
 		resp, err := h.server.Symbol(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/codeAction": // req
@@ -399,7 +399,7 @@
 		}
 		resp, err := h.server.CodeAction(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/codeLens": // req
@@ -410,7 +410,7 @@
 		}
 		resp, err := h.server.CodeLens(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "codeLens/resolve": // req
@@ -421,7 +421,7 @@
 		}
 		resp, err := h.server.ResolveCodeLens(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/formatting": // req
@@ -432,7 +432,7 @@
 		}
 		resp, err := h.server.Formatting(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/rangeFormatting": // req
@@ -443,7 +443,7 @@
 		}
 		resp, err := h.server.RangeFormatting(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/onTypeFormatting": // req
@@ -454,7 +454,7 @@
 		}
 		resp, err := h.server.OnTypeFormatting(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/rename": // req
@@ -465,7 +465,7 @@
 		}
 		resp, err := h.server.Rename(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/prepareRename": // req
@@ -476,7 +476,7 @@
 		}
 		resp, err := h.server.PrepareRename(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "textDocument/documentLink": // req
@@ -487,7 +487,7 @@
 		}
 		resp, err := h.server.DocumentLink(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "documentLink/resolve": // req
@@ -498,7 +498,7 @@
 		}
 		resp, err := h.server.ResolveDocumentLink(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 	case "workspace/executeCommand": // req
@@ -509,7 +509,7 @@
 		}
 		resp, err := h.server.ExecuteCommand(ctx, &params)
 		if err := r.Reply(ctx, resp, err); err != nil {
-			xlog.Errorf(ctx, "%v", err)
+			log.Error(ctx, "", err)
 		}
 		return true
 
diff --git a/internal/lsp/protocol/typescript/requests.ts b/internal/lsp/protocol/typescript/requests.ts
index 409faa8..fcce098 100644
--- a/internal/lsp/protocol/typescript/requests.ts
+++ b/internal/lsp/protocol/typescript/requests.ts
@@ -117,12 +117,12 @@
       return true
     }
     if err := h.${side.name}.${nm}(ctx, &params); err != nil {
-      xlog.Errorf(ctx, "%v", err)
+      log.Error(ctx, "", err)
     }
     return true`;
   } else {
     case1 = `if err := h.${side.name}.${nm}(ctx); err != nil {
-      xlog.Errorf(ctx, "%v", err)
+      log.Error(ctx, "", err)
     }
     return true`;
   }
@@ -160,18 +160,18 @@
   }
   const arg2 = a == '' ? '' : ', &params';
   let case2 = `if err := h.${side.name}.${nm}(ctx${arg2}); err != nil {
-    xlog.Errorf(ctx, "%v", err)
+    log.Error(ctx, "", err)
   }`;
   if (b != '') {
     case2 = `resp, err := h.${side.name}.${nm}(ctx${arg2})
     if err := r.Reply(ctx, resp, err); err != nil {
-      xlog.Errorf(ctx, "%v", err)
+      log.Error(ctx, "", err)
     }
     return true`;
   } else {  // response is nil
     case2 = `err := h.${side.name}.${nm}(ctx${arg2})
     if err := r.Reply(ctx, nil, err); err != nil {
-      xlog.Errorf(ctx, "%v", err)
+      log.Error(ctx, "", err)
     }
     return true`
   }
@@ -226,7 +226,7 @@
     "encoding/json"
 
     "golang.org/x/tools/internal/jsonrpc2"
-    "golang.org/x/tools/internal/lsp/xlog"
+    "golang.org/x/tools/internal/lsp/telemetry/log"
   )
   `);
   const a = side.name[0].toUpperCase() + side.name.substring(1)
diff --git a/internal/lsp/references.go b/internal/lsp/references.go
index 430dc3c..6be6375 100644
--- a/internal/lsp/references.go
+++ b/internal/lsp/references.go
@@ -9,7 +9,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -35,7 +36,7 @@
 	}
 	references, err := ident.References(ctx)
 	if err != nil {
-		xlog.Errorf(ctx, "no references for %s: %v", ident.Name, err)
+		log.Error(ctx, "no references", err, tag.Of("Identifier", ident.Name))
 	}
 	if params.Context.IncludeDeclaration {
 		// The declaration of this identifier may not be in the
diff --git a/internal/lsp/signature_help.go b/internal/lsp/signature_help.go
index 1fa7b04..34ce8e7 100644
--- a/internal/lsp/signature_help.go
+++ b/internal/lsp/signature_help.go
@@ -9,7 +9,8 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -30,7 +31,7 @@
 	}
 	info, err := source.SignatureHelp(ctx, f, rng.Start)
 	if err != nil {
-		xlog.Infof(ctx, "no signature help for %s:%v:%v : %s", uri, int(params.Position.Line), int(params.Position.Character), err)
+		log.Print(ctx, "no signature help", tag.Of("At", rng), tag.Of("Failure", err))
 		return nil, nil
 	}
 	return toProtocolSignatureHelp(info), nil
diff --git a/internal/lsp/source/analysis.go b/internal/lsp/source/analysis.go
index 27dfb8e..8e7eeb7 100644
--- a/internal/lsp/source/analysis.go
+++ b/internal/lsp/source/analysis.go
@@ -11,7 +11,6 @@
 	"fmt"
 	"go/token"
 	"go/types"
-	"log"
 	"reflect"
 	"sort"
 	"strings"
@@ -245,12 +244,12 @@
 // exportObjectFact implements Pass.ExportObjectFact.
 func (act *Action) exportObjectFact(obj types.Object, fact analysis.Fact) {
 	if act.pass.ExportObjectFact == nil {
-		log.Panicf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact)
+		panic(fmt.Sprintf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact))
 	}
 
 	if obj.Pkg() != act.Pkg.GetTypes() {
-		log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package",
-			act.Analyzer, act.Pkg, obj, fact)
+		panic(fmt.Sprintf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package",
+			act.Analyzer, act.Pkg, obj, fact))
 	}
 
 	key := objectFactKey{obj, factType(fact)}
@@ -284,7 +283,7 @@
 // exportPackageFact implements Pass.ExportPackageFact.
 func (act *Action) exportPackageFact(fact analysis.Fact) {
 	if act.pass.ExportPackageFact == nil {
-		log.Panicf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact)
+		panic(fmt.Sprintf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact))
 	}
 
 	key := packageFactKey{act.pass.Pkg, factType(fact)}
@@ -294,7 +293,7 @@
 func factType(fact analysis.Fact) reflect.Type {
 	t := reflect.TypeOf(fact)
 	if t.Kind() != reflect.Ptr {
-		log.Fatalf("invalid Fact type: got %T, want pointer", t)
+		panic(fmt.Sprintf("invalid Fact type: got %T, want pointer", t))
 	}
 	return t
 }
diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion_format.go
index 3adc69f..a7550a8 100644
--- a/internal/lsp/source/completion_format.go
+++ b/internal/lsp/source/completion_format.go
@@ -14,7 +14,8 @@
 	"strings"
 
 	"golang.org/x/tools/internal/lsp/snippet"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
+	"golang.org/x/tools/internal/lsp/telemetry/tag"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -98,33 +99,33 @@
 	if c.opts.WantDocumentaton {
 		declRange, err := objToRange(c.ctx, c.view.Session().Cache().FileSet(), obj)
 		if err != nil {
-			xlog.Errorf(c.ctx, "failed to get declaration range for object %s: %v", obj.Name(), err)
+			log.Error(c.ctx, "failed to get declaration range for object", err, tag.Of("Name", obj.Name()))
 			goto Return
 		}
 		pos := declRange.FileSet.Position(declRange.Start)
 		if !pos.IsValid() {
-			xlog.Errorf(c.ctx, "invalid declaration position for %v: %v", item.Label, err)
+			log.Error(c.ctx, "invalid declaration position", err, tag.Of("Label", item.Label))
 			goto Return
 		}
 		uri := span.FileURI(pos.Filename)
 		f, err := c.view.GetFile(c.ctx, uri)
 		if err != nil {
-			xlog.Errorf(c.ctx, "unable to get file for %s: %v", uri, err)
+			log.Error(c.ctx, "unable to get file", err, tag.Of("URI", uri))
 			goto Return
 		}
 		gof, ok := f.(GoFile)
 		if !ok {
-			xlog.Errorf(c.ctx, "declaration for %s not in a Go file: %s", item.Label, uri)
+			log.Error(c.ctx, "declaration in a Go file", err, tag.Of("Label", item.Label))
 			goto Return
 		}
 		ident, err := Identifier(c.ctx, c.view, gof, declRange.Start)
 		if err != nil {
-			xlog.Errorf(c.ctx, "no identifier for %s: %v", obj.Name(), err)
+			log.Error(c.ctx, "no identifier", err, tag.Of("Name", obj.Name()))
 			goto Return
 		}
 		documentation, err := ident.Documentation(c.ctx, SynopsisDocumentation)
 		if err != nil {
-			xlog.Errorf(c.ctx, "no documentation for %s: %v", obj.Name(), err)
+			log.Error(c.ctx, "no documentation", err, tag.Of("Name", obj.Name()))
 			goto Return
 		}
 		item.Documentation = documentation
@@ -200,7 +201,7 @@
 		cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
 		b := &bytes.Buffer{}
 		if err := cfg.Fprint(b, v.Session().Cache().FileSet(), p.Type); err != nil {
-			xlog.Errorf(ctx, "unable to print type %v", p.Type)
+			log.Error(ctx, "unable to print type", nil, tag.Of("Type", p.Type))
 			continue
 		}
 		typ := replacer.Replace(b.String())
diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go
index 03751df..befbf85 100644
--- a/internal/lsp/source/diagnostics.go
+++ b/internal/lsp/source/diagnostics.go
@@ -34,7 +34,8 @@
 	"golang.org/x/tools/go/analysis/passes/unsafeptr"
 	"golang.org/x/tools/go/analysis/passes/unusedresult"
 	"golang.org/x/tools/go/packages"
-	"golang.org/x/tools/internal/lsp/xlog"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -60,6 +61,7 @@
 )
 
 func Diagnostics(ctx context.Context, view View, f GoFile, disabledAnalyses map[string]struct{}) (map[span.URI][]Diagnostic, error) {
+	ctx = telemetry.File.With(ctx, f.URI())
 	pkg := f.GetPackage(ctx)
 	if pkg == nil {
 		return singleDiagnostic(f.URI(), "%s is not part of a package", f.URI()), nil
@@ -82,7 +84,7 @@
 	if !diagnostics(ctx, view, pkg, reports) {
 		// If we don't have any list, parse, or type errors, run analyses.
 		if err := analyses(ctx, view, pkg, disabledAnalyses, reports); err != nil {
-			xlog.Errorf(ctx, "failed to run analyses for %s: %v", f.URI(), err)
+			log.Error(ctx, "failed to run analyses", err, telemetry.File)
 		}
 	}
 	// Updates to the diagnostics for this package may need to be propagated.
@@ -230,30 +232,31 @@
 
 func pointToSpan(ctx context.Context, view View, spn span.Span) span.Span {
 	f, err := view.GetFile(ctx, spn.URI())
+	ctx = telemetry.File.With(ctx, spn.URI())
 	if err != nil {
-		xlog.Errorf(ctx, "could not find file for diagnostic: %v", spn.URI())
+		log.Error(ctx, "could not find file for diagnostic", nil, telemetry.File)
 		return spn
 	}
 	diagFile, ok := f.(GoFile)
 	if !ok {
-		xlog.Errorf(ctx, "%s is not a Go file", spn.URI())
+		log.Error(ctx, "not a Go file", nil, telemetry.File)
 		return spn
 	}
 	tok, err := diagFile.GetToken(ctx)
 	if err != nil {
-		xlog.Errorf(ctx, "could not find token.File for %s: %v", spn.URI(), err)
+		log.Error(ctx, "could not find token.File for diagnostic", err, telemetry.File)
 		return spn
 	}
 	data, _, err := diagFile.Handle(ctx).Read(ctx)
 	if err != nil {
-		xlog.Errorf(ctx, "could not find content for diagnostic: %v", spn.URI())
+		log.Error(ctx, "could not find content for diagnostic", err, telemetry.File)
 		return spn
 	}
 	c := span.NewTokenConverter(diagFile.FileSet(), tok)
 	s, err := spn.WithOffset(c)
 	//we just don't bother producing an error if this failed
 	if err != nil {
-		xlog.Errorf(ctx, "invalid span for diagnostic: %v: %v", spn.URI(), err)
+		log.Error(ctx, "invalid span for diagnostic", err, telemetry.File)
 		return spn
 	}
 	start := s.Start()
diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go
index dbbb467..f7a5530 100644
--- a/internal/lsp/source/format.go
+++ b/internal/lsp/source/format.go
@@ -15,8 +15,8 @@
 	"golang.org/x/tools/go/packages"
 	"golang.org/x/tools/internal/imports"
 	"golang.org/x/tools/internal/lsp/diff"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/trace"
-	"golang.org/x/tools/internal/lsp/xlog"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -116,7 +116,7 @@
 	defer done()
 	data, _, err := file.Handle(ctx).Read(ctx)
 	if err != nil {
-		xlog.Errorf(ctx, "Cannot compute text edits: %v", err)
+		log.Error(ctx, "Cannot compute text edits", err)
 		return nil
 	}
 	u := diff.SplitLines(string(data))
diff --git a/internal/lsp/text_synchronization.go b/internal/lsp/text_synchronization.go
index 6544010..e870154 100644
--- a/internal/lsp/text_synchronization.go
+++ b/internal/lsp/text_synchronization.go
@@ -12,8 +12,9 @@
 	"golang.org/x/tools/internal/jsonrpc2"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry"
+	"golang.org/x/tools/internal/lsp/telemetry/log"
 	"golang.org/x/tools/internal/lsp/telemetry/trace"
-	"golang.org/x/tools/internal/lsp/xlog"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -126,6 +127,7 @@
 
 func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
 	uri := span.NewURI(params.TextDocument.URI)
+	ctx = telemetry.File.With(ctx, uri)
 	s.session.DidClose(uri)
 	view := s.session.ViewOf(uri)
 	if err := view.SetContent(ctx, uri, nil); err != nil {
@@ -135,7 +137,7 @@
 	defer func() {
 		for _, uri := range clear {
 			if err := s.publishDiagnostics(ctx, view, uri, []source.Diagnostic{}); err != nil {
-				xlog.Errorf(ctx, "failed to clear diagnostics for %s: %v", uri, err)
+				log.Error(ctx, "failed to clear diagnostics", err, telemetry.File)
 			}
 		}
 	}()
@@ -143,18 +145,18 @@
 	// clear out all diagnostics for the package.
 	f, err := view.GetFile(ctx, uri)
 	if err != nil {
-		xlog.Errorf(ctx, "no file for %s: %v", uri, err)
+		log.Error(ctx, "no file for %s: %v", err, telemetry.File)
 		return nil
 	}
 	// For non-Go files, don't return any diagnostics.
 	gof, ok := f.(source.GoFile)
 	if !ok {
-		xlog.Errorf(ctx, "closing a non-Go file, no diagnostics to clear")
+		log.Error(ctx, "closing a non-Go file, no diagnostics to clear", nil, telemetry.File)
 		return nil
 	}
 	pkg := gof.GetPackage(ctx)
 	if pkg == nil {
-		xlog.Errorf(ctx, "no package available for %s", uri)
+		log.Error(ctx, "no package available", nil, telemetry.File)
 		return nil
 	}
 	for _, filename := range pkg.GetFilenames() {