buildlet: include details in GCEError.Error

Some of our logging in the coordinator includes pointers and repetition,
like so:

2022/09/27 19:16:27 failed with errors: [0xc02b50e120]
2022/09/27 19:16:27 Failed to create VM: "failed with errors: [0xc02b50e120]". Retrying after 1 second (attempt: 2).

The GCE error types only have MarshalJSON methods, so use that to show
more information. (This builds on the previous attempt in CL 428114.)
Remove the duplicate log, since the caller can log or otherwise handle
the error.

For golang/go#48857.

Change-Id: I0d31cac833ea617b4d722751e3ffe9a6689aeb87
Reviewed-on: https://go-review.googlesource.com/c/build/+/435379
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Run-TryBot: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Jenny Rakoczy <jenny@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/buildlet/gce.go b/buildlet/gce.go
index 84f0a56..a92bfd6 100644
--- a/buildlet/gce.go
+++ b/buildlet/gce.go
@@ -5,11 +5,12 @@
 package buildlet
 
 import (
+	"bytes"
 	"context"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
-	"log"
 	"net"
 	"os"
 	"os/exec"
@@ -45,7 +46,20 @@
 }
 
 func (q *GCEError) Error() string {
-	return fmt.Sprintf("failed with errors: %+v", q.OpErrors)
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "%d GCE operation errors: ", len(q.OpErrors))
+	for i, e := range q.OpErrors {
+		if i != 0 {
+			buf.WriteString("; ")
+		}
+		b, err := json.Marshal(e)
+		if err != nil {
+			fmt.Fprintf(&buf, "json.Marshal(OpErrors[%d]): %v", i, err)
+			continue
+		}
+		buf.Write(b)
+	}
+	return buf.String()
 }
 
 func (q *GCEError) Is(target error) bool {
@@ -239,7 +253,6 @@
 			if op.Error != nil {
 				err := &GCEError{OpErrors: make([]*compute.OperationErrorErrors, len(op.Error.Errors))}
 				copy(err.OpErrors, op.Error.Errors)
-				log.Println(err.Error())
 				return nil, err
 			}
 			break OpLoop
diff --git a/internal/coordinator/pool/gce.go b/internal/coordinator/pool/gce.go
index 0d44187..8b4822a 100644
--- a/internal/coordinator/pool/gce.go
+++ b/internal/coordinator/pool/gce.go
@@ -490,7 +490,7 @@
 			Zone: zone,
 		})
 		if errors.Is(err, buildlet.ErrQuotaExceeded) && ctx.Err() == nil {
-			log.Printf("Failed to create VM: %q. Retrying after 1 second (attempt: %d).", err, attempts)
+			log.Printf("Failed to create VM because quota exceeded. Retrying after 1 second (attempt: %d).", attempts)
 			attempts++
 			time.Sleep(time.Second)
 			continue