storage: log issued SQL query

Change-Id: I89a2ad20d0378077fb90cae45fcc8cab33c147ec
Reviewed-on: https://go-review.googlesource.com/36952
Run-TryBot: Quentin Smith <quentin@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/storage/app/query.go b/storage/app/query.go
index 61b2add..971238f 100644
--- a/storage/app/query.go
+++ b/storage/app/query.go
@@ -13,6 +13,8 @@
 )
 
 func (a *App) search(w http.ResponseWriter, r *http.Request) {
+	ctx := requestContext(r)
+
 	if err := r.ParseForm(); err != nil {
 		http.Error(w, err.Error(), 500)
 		return
@@ -27,6 +29,8 @@
 	query := a.DB.Query(q)
 	defer query.Close()
 
+	infof(ctx, "query: %s", query.Debug())
+
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	bw := benchfmt.NewPrinter(w)
 	for query.Next() {
@@ -36,6 +40,7 @@
 		}
 	}
 	if err := query.Err(); err != nil {
+		errorf(ctx, "query returned error: %v", err)
 		http.Error(w, err.Error(), 500)
 		return
 	}
diff --git a/storage/db/db.go b/storage/db/db.go
index 38d5011..89e7cd9 100644
--- a/storage/db/db.go
+++ b/storage/db/db.go
@@ -396,6 +396,8 @@
 func (db *DB) Query(q string) *Query {
 	qparts := query.SplitWords(q)
 
+	ret := &Query{q: q}
+
 	var args []interface{}
 	query := "SELECT r.Content FROM "
 	for i, part := range qparts {
@@ -403,8 +405,9 @@
 			query += " INNER JOIN "
 		}
 		partSql, partArgs, err := parseQueryPart(part)
+		ret.err = err
 		if err != nil {
-			return &Query{err: err}
+			return ret
 		}
 		query += fmt.Sprintf("(%s) t%d", partSql, i)
 		args = append(args, partArgs...)
@@ -421,11 +424,9 @@
 		query += " USING (UploadID, RecordID)"
 	}
 
-	rows, err := db.sql.Query(query, args...)
-	if err != nil {
-		return &Query{err: err}
-	}
-	return &Query{rows: rows}
+	ret.sqlQuery, ret.sqlArgs = query, args
+	ret.rows, ret.err = db.sql.Query(query, args...)
+	return ret
 }
 
 // Query is the result of a query.
@@ -441,11 +442,27 @@
 //   ...
 type Query struct {
 	rows *sql.Rows
+	// for Debug
+	q        string
+	sqlQuery string
+	sqlArgs  []interface{}
 	// from last call to Next
 	br  *benchfmt.Reader
 	err error
 }
 
+// Debug returns the human-readable state of the query.
+func (q *Query) Debug() string {
+	ret := fmt.Sprintf("q=%q", q.q)
+	if q.sqlQuery != "" || len(q.sqlArgs) > 0 {
+		ret += fmt.Sprintf(" sql={%q %#v}", q.sqlQuery, q.sqlArgs)
+	}
+	if q.err != nil {
+		ret += fmt.Sprintf(" err=%v", q.err)
+	}
+	return ret
+}
+
 // Next prepares the next result for reading with the Result
 // method. It returns false when there are no more results, either by
 // reaching the end of the input or an error.
diff --git a/storage/db/db_test.go b/storage/db/db_test.go
index dc8b7e4..14f5cc6 100644
--- a/storage/db/db_test.go
+++ b/storage/db/db_test.go
@@ -6,7 +6,6 @@
 
 import (
 	"bytes"
-	"context"
 	"fmt"
 	"reflect"
 	"sort"
@@ -15,6 +14,7 @@
 	"testing"
 	"time"
 
+	"golang.org/x/net/context"
 	"golang.org/x/perf/internal/diff"
 	"golang.org/x/perf/storage/benchfmt"
 	. "golang.org/x/perf/storage/db"