cmd/stcrashreceiver: Enable (rough) affected users count (#6511)

Seeing thousands of reports is no use when we don't know if they
represent one poor user or thousands.
This commit is contained in:
Jakob Borg 2020-04-07 13:19:49 +02:00 committed by GitHub
parent df318ed370
commit 4b17c511f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 2 deletions

View File

@ -31,12 +31,14 @@ var (
clientsMut sync.Mutex clientsMut sync.Mutex
) )
func sendReport(dsn, path string, report []byte) error { func sendReport(dsn, path string, report []byte, userID string) error {
pkt, err := parseReport(path, report) pkt, err := parseReport(path, report)
if err != nil { if err != nil {
return err return err
} }
pkt.Interfaces = append(pkt.Interfaces, &raven.User{ID: userID})
clientsMut.Lock() clientsMut.Lock()
defer clientsMut.Unlock() defer clientsMut.Unlock()

View File

@ -16,14 +16,19 @@ import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"flag" "flag"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"net/http" "net/http"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/syncthing/syncthing/lib/sha256"
) )
const maxRequestSize = 1 << 20 // 1 MiB const maxRequestSize = 1 << 20 // 1 MiB
@ -145,9 +150,12 @@ func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWrite
// Send the report to Sentry // Send the report to Sentry
if r.dsn != "" { if r.dsn != "" {
// Remote ID
user := userIDFor(req)
go func() { go func() {
// There's no need for the client to have to wait for this part. // There's no need for the client to have to wait for this part.
if err := sendReport(r.dsn, reportID, bs); err != nil { if err := sendReport(r.dsn, reportID, bs, user); err != nil {
log.Println("Failed to send report:", err) log.Println("Failed to send report:", err)
} }
}() }()
@ -158,3 +166,20 @@ func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWrite
func (r *crashReceiver) dirFor(base string) string { func (r *crashReceiver) dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4]) return filepath.Join(base[0:2], base[2:4])
} }
// userIDFor returns a string we can use as the user ID for the purpose of
// counting affected users. It's the truncated hash of a salt, the user
// remote IP, and the current month.
func userIDFor(req *http.Request) string {
addr := req.RemoteAddr
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
addr = fwd
}
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
now := time.Now().Format("200601")
salt := "stcrashreporter"
hash := sha256.Sum256([]byte(salt + addr + now))
return fmt.Sprintf("%x", hash[:8])
}