godev/cmd/telemetrygodev: log the upload failure reason

Help investigate uploads that do not validate, by logging their failure
reason.

Change-Id: Ie409c5923d26d7b65bfd84701a6a05dae82ee623
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/575515
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Auto-Submit: Robert Findley <rfindley@google.com>
diff --git a/godev/cmd/telemetrygodev/main.go b/godev/cmd/telemetrygodev/main.go
index 47411de..d09492e 100644
--- a/godev/cmd/telemetrygodev/main.go
+++ b/godev/cmd/telemetrygodev/main.go
@@ -63,13 +63,14 @@
 	fsys := fsys(cfg.DevMode)
 	mux := http.NewServeMux()
 
+	logger := slog.Default()
 	mux.Handle("/", handleRoot(fsys, buckets))
 	mux.Handle("/config", handleConfig(fsys, ucfg))
-	mux.Handle("/upload/", handleUpload(ucfg, buckets))
+	mux.Handle("/upload/", handleUpload(ucfg, buckets, logger))
 	mux.Handle("/charts/", handleChart(fsys, buckets))
 
 	mw := middleware.Chain(
-		middleware.Log(slog.Default()),
+		middleware.Log(logger),
 		middleware.Timeout(cfg.RequestTimeout),
 		middleware.RequestSize(cfg.MaxRequestBytes),
 		middleware.Recover(),
@@ -150,18 +151,30 @@
 	}
 }
 
-func handleUpload(ucfg *tconfig.Config, buckets *storage.API) content.HandlerFunc {
+func handleUpload(ucfg *tconfig.Config, buckets *storage.API, log *slog.Logger) content.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) error {
 		if r.Method == "POST" {
+			ctx := r.Context()
+			// Log the error, but only the first 80 characters.
+			// This prevents excessive logging related to broken payloads.
+			// The first line should give us a sense of the failure mode.
+			warn := func(msg string, err error) {
+				errs := []rune(err.Error())
+				if len(errs) > 80 {
+					errs = append(errs[:79], '…')
+				}
+				log.WarnContext(ctx, msg+": "+string(errs))
+			}
 			var report telemetry.Report
 			if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
+				warn("invalid JSON payload", err)
 				return content.Error(err, http.StatusBadRequest)
 			}
 			if err := validate(&report, ucfg); err != nil {
+				warn("invalid report", err)
 				return content.Error(err, http.StatusBadRequest)
 			}
 			// TODO: capture metrics for collisions.
-			ctx := r.Context()
 			name := fmt.Sprintf("%s/%g.json", report.Week, report.X)
 			f, err := buckets.Upload.Object(name).NewWriter(ctx)
 			if err != nil {