internal/lsp: add some trace spans to important functions

This uses the new opencensus compatability layer to add telementry to some of
the functions in the lsp, in order to allow us to understand their costs and
call patterns.

Change-Id: I7df820cd4eace7a4840ac6397d5df402369bf0a7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183419
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/external.go b/internal/lsp/cache/external.go
index ddb7367..5047a49 100644
--- a/internal/lsp/cache/external.go
+++ b/internal/lsp/cache/external.go
@@ -10,6 +10,7 @@
 	"os"
 
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -50,6 +51,8 @@
 }
 
 func (h *nativeFileHandle) Read(ctx context.Context) ([]byte, string, error) {
+	ctx, ts := trace.StartSpan(ctx, "cache.nativeFileHandle.Read")
+	defer ts.End()
 	//TODO: this should fail if the version is not the same as the handle
 	data, err := ioutil.ReadFile(h.identity.URI.Filename())
 	if err != nil {
diff --git a/internal/lsp/cache/parse.go b/internal/lsp/cache/parse.go
index ed3a2d8..0d48534 100644
--- a/internal/lsp/cache/parse.go
+++ b/internal/lsp/cache/parse.go
@@ -13,6 +13,7 @@
 	"go/token"
 
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/memoize"
 )
 
@@ -73,6 +74,8 @@
 }
 
 func parseGo(ctx context.Context, c *cache, fh source.FileHandle, mode source.ParseMode) (*ast.File, error) {
+	ctx, ts := trace.StartSpan(ctx, "cache.parseGo")
+	defer ts.End()
 	buf, _, err := fh.Read(ctx)
 	if err != nil {
 		return nil, err
diff --git a/internal/lsp/source/analysis.go b/internal/lsp/source/analysis.go
index c599e67..754cded 100644
--- a/internal/lsp/source/analysis.go
+++ b/internal/lsp/source/analysis.go
@@ -20,9 +20,12 @@
 
 	"golang.org/x/sync/errgroup"
 	"golang.org/x/tools/go/analysis"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 )
 
 func analyze(ctx context.Context, v View, pkgs []Package, analyzers []*analysis.Analyzer) ([]*Action, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.analyze")
+	defer ts.End()
 	if ctx.Err() != nil {
 		return nil, ctx.Err()
 	}
diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go
index 805c441..8bf7e21 100644
--- a/internal/lsp/source/completion.go
+++ b/internal/lsp/source/completion.go
@@ -13,6 +13,7 @@
 
 	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/internal/lsp/snippet"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -263,6 +264,8 @@
 // the client to score the quality of the completion. For instance, some clients
 // may tolerate imperfect matches as valid completion results, since users may make typos.
 func Completion(ctx context.Context, view View, f GoFile, pos token.Pos, opts CompletionOptions) ([]CompletionItem, *Selection, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Completion")
+	defer ts.End()
 	file := f.GetAST(ctx)
 	if file == nil {
 		return nil, nil, fmt.Errorf("no AST for %s", f.URI())
diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go
index 07200a3..398f366 100644
--- a/internal/lsp/source/format.go
+++ b/internal/lsp/source/format.go
@@ -16,11 +16,14 @@
 	"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/trace"
 	"golang.org/x/tools/internal/span"
 )
 
 // Format formats a file with a given range.
 func Format(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Format")
+	defer ts.End()
 	file := f.GetAST(ctx)
 	if file == nil {
 		return nil, fmt.Errorf("no AST for %s", f.URI())
@@ -50,6 +53,8 @@
 
 // Imports formats a file using the goimports tool.
 func Imports(ctx context.Context, view View, f GoFile, rng span.Range) ([]TextEdit, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Imports")
+	defer ts.End()
 	data, _, err := f.Handle(ctx).Read(ctx)
 	if err != nil {
 		return nil, err
@@ -128,6 +133,8 @@
 }
 
 func computeTextEdits(ctx context.Context, file File, formatted string) (edits []TextEdit) {
+	ctx, ts := trace.StartSpan(ctx, "source.computeTextEdits")
+	defer ts.End()
 	data, _, err := file.Handle(ctx).Read(ctx)
 	if err != nil {
 		file.View().Session().Logger().Errorf(ctx, "Cannot compute text edits: %v", err)
diff --git a/internal/lsp/source/highlight.go b/internal/lsp/source/highlight.go
index c67377f..eb3a25c 100644
--- a/internal/lsp/source/highlight.go
+++ b/internal/lsp/source/highlight.go
@@ -11,10 +11,13 @@
 	"go/token"
 
 	"golang.org/x/tools/go/ast/astutil"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
 func Highlight(ctx context.Context, f GoFile, pos token.Pos) ([]span.Span, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Highlight")
+	defer ts.End()
 	file := f.GetAST(ctx)
 	if file == nil {
 		return nil, fmt.Errorf("no AST for %s", f.URI())
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index b66299e..db412ef 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -12,6 +12,8 @@
 	"go/format"
 	"go/types"
 	"strings"
+
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 )
 
 type documentation struct {
@@ -31,6 +33,8 @@
 )
 
 func (i *IdentifierInfo) Hover(ctx context.Context, markdownSupported bool, hoverKind HoverKind) (string, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Hover")
+	defer ts.End()
 	h, err := i.decl.hover(ctx)
 	if err != nil {
 		return "", err
@@ -68,6 +72,8 @@
 }
 
 func (d declaration) hover(ctx context.Context) (*documentation, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.hover")
+	defer ts.End()
 	obj := d.obj
 	switch node := d.node.(type) {
 	case *ast.GenDecl:
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index 981019f..061c229 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -13,6 +13,7 @@
 	"strconv"
 
 	"golang.org/x/tools/go/ast/astutil"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -62,6 +63,8 @@
 
 // identifier checks a single position for a potential identifier.
 func identifier(ctx context.Context, view View, f GoFile, pos token.Pos) (*IdentifierInfo, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.identifier")
+	defer ts.End()
 	file := f.GetAST(ctx)
 	if file == nil {
 		return nil, fmt.Errorf("no AST for %s", f.URI())
diff --git a/internal/lsp/source/references.go b/internal/lsp/source/references.go
index cab6a21..0b199e6 100644
--- a/internal/lsp/source/references.go
+++ b/internal/lsp/source/references.go
@@ -10,6 +10,7 @@
 	"go/ast"
 	"go/types"
 
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -25,6 +26,8 @@
 // References returns a list of references for a given identifier within the packages
 // containing i.File. Declarations appear first in the result.
 func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.References")
+	defer ts.End()
 	var references []*ReferenceInfo
 
 	// If the object declaration is nil, assume it is an import spec and do not look for references.
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index 41668a8..885b990 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -15,6 +15,7 @@
 	"regexp"
 
 	"golang.org/x/tools/go/types/typeutil"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 	"golang.org/x/tools/refactor/satisfy"
 )
@@ -36,6 +37,8 @@
 
 // Rename returns a map of TextEdits for each file modified when renaming a given identifier within a package.
 func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.URI][]TextEdit, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.Rename")
+	defer ts.End()
 	if i.Name == newName {
 		return nil, fmt.Errorf("old and new names are the same: %s", newName)
 	}
diff --git a/internal/lsp/source/signature_help.go b/internal/lsp/source/signature_help.go
index ed23262..7a657b6 100644
--- a/internal/lsp/source/signature_help.go
+++ b/internal/lsp/source/signature_help.go
@@ -12,6 +12,7 @@
 	"go/types"
 
 	"golang.org/x/tools/go/ast/astutil"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 )
 
 type SignatureInformation struct {
@@ -25,6 +26,8 @@
 }
 
 func SignatureHelp(ctx context.Context, f GoFile, pos token.Pos) (*SignatureInformation, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.SignatureHelp")
+	defer ts.End()
 	file := f.GetAST(ctx)
 	if file == nil {
 		return nil, fmt.Errorf("no AST for %s", f.URI())
diff --git a/internal/lsp/source/symbols.go b/internal/lsp/source/symbols.go
index 879be50..28ff24e 100644
--- a/internal/lsp/source/symbols.go
+++ b/internal/lsp/source/symbols.go
@@ -12,6 +12,7 @@
 	"go/token"
 	"go/types"
 
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -41,6 +42,8 @@
 }
 
 func DocumentSymbols(ctx context.Context, f GoFile) ([]Symbol, error) {
+	ctx, ts := trace.StartSpan(ctx, "source.DocumentSymbols")
+	defer ts.End()
 	fset := f.FileSet()
 	file := f.GetAST(ctx)
 	if file == nil {
diff --git a/internal/lsp/symbols.go b/internal/lsp/symbols.go
index 0a908a8..c24fceb 100644
--- a/internal/lsp/symbols.go
+++ b/internal/lsp/symbols.go
@@ -9,10 +9,13 @@
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
+	"golang.org/x/tools/internal/lsp/telemetry/trace"
 	"golang.org/x/tools/internal/span"
 )
 
 func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
+	ctx, ts := trace.StartSpan(ctx, "lsp.Server.documentSymbol")
+	defer ts.End()
 	uri := span.NewURI(params.TextDocument.URI)
 	view := s.session.ViewOf(uri)
 	f, m, err := getGoFile(ctx, view, uri)
diff --git a/internal/lsp/text_synchronization.go b/internal/lsp/text_synchronization.go
index 7fe8d81..66f9a62 100644
--- a/internal/lsp/text_synchronization.go
+++ b/internal/lsp/text_synchronization.go
@@ -12,6 +12,7 @@
 	"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/trace"
 	"golang.org/x/tools/internal/span"
 )
 
@@ -64,6 +65,9 @@
 	// Run diagnostics on the newly-changed file.
 	go func() {
 		ctx := view.BackgroundContext()
+		//TODO: connect the remote span?
+		ctx, ts := trace.StartSpan(ctx, "lsp:background-worker")
+		defer ts.End()
 		s.Diagnostics(ctx, view, uri)
 	}()
 	return nil