blob: edce7004288eb52c942d41d40e1cff5f336943de [file] [log] [blame]
// Copyright 2016 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.
package main
import (
"crypto/rand"
"encoding/hex"
"log"
"net/http"
"time"
"cloud.google.com/go/logging"
"github.com/golang/gddo/database"
)
// newGCELogger returns a handler that wraps h but logs each request
// using Google Cloud Logging service.
func newGCELogger(cli *logging.Logger) *GCELogger {
return &GCELogger{cli}
}
type GCELogger struct {
cli *logging.Logger
}
// Log creates an entry in Cloud Logging using the given log entry.
func (g *GCELogger) Log(l logging.Entry) {
g.cli.Log(l)
}
// LogEvent creates an entry in Cloud Logging to record user's behavior. We should only
// use this to log events we are interested in. General request logs are handled by GAE
// automatically in request_log and stderr.
func (g *GCELogger) LogEvent(w http.ResponseWriter, r *http.Request, content interface{}) {
const sessionCookieName = "GODOC_ORG_SESSION_ID"
cookie, err := r.Cookie(sessionCookieName)
if err != nil {
// Generates a random session id and sends it in response.
rs, err := randomString()
if err != nil {
log.Println("error generating a random session id: ", err)
return
}
// This cookie is intentionally short-lived and contains no information
// that might identify the user. Its sole purpose is to tie query
// terms and destination pages together to measure search quality.
cookie = &http.Cookie{
Name: sessionCookieName,
Value: rs,
Expires: time.Now().Add(time.Hour),
}
http.SetCookie(w, cookie)
}
// We must not record the client's IP address, or any other information
// that might compromise the user's privacy.
payload := map[string]interface{}{
sessionCookieName: cookie.Value,
"path": r.URL.RequestURI(),
"method": r.Method,
"referer": r.Referer(),
}
if pkgs, ok := content.([]database.Package); ok {
payload["packages"] = pkgs
}
// Log queues the entry to its internal buffer, or discarding the entry
// if the buffer was full.
g.cli.Log(logging.Entry{
Payload: payload,
})
}
func randomString() (string, error) {
b := make([]byte, 8)
_, err := rand.Read(b)
return hex.EncodeToString(b), err
}