mirror of
https://github.com/octoleo/syncthing.git
synced 2024-09-19 21:29:01 +00:00
cmd/stcrashreceiver: Add source code loader (#5779)
This commit is contained in:
parent
1cf352a722
commit
43b6ac9501
@ -19,6 +19,12 @@ import (
|
|||||||
|
|
||||||
const reportServer = "https://crash.syncthing.net/report/"
|
const reportServer = "https://crash.syncthing.net/report/"
|
||||||
|
|
||||||
|
var loader = newGithubSourceCodeLoader()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
raven.SetSourceCodeLoader(loader)
|
||||||
|
}
|
||||||
|
|
||||||
func sendReport(dsn, path string, report []byte) error {
|
func sendReport(dsn, path string, report []byte) error {
|
||||||
pkt, err := parseReport(path, report)
|
pkt, err := parseReport(path, report)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,17 +86,25 @@ func parseReport(path string, report []byte) (*raven.Packet, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock the source code loader to the version we are processing here.
|
||||||
|
if version.commit != "" {
|
||||||
|
// We have a commit hash, so we know exactly which source to use
|
||||||
|
loader.LockWithVersion(version.commit)
|
||||||
|
} else if strings.HasPrefix(version.tag, "v") {
|
||||||
|
// Lets hope the tag is close enough
|
||||||
|
loader.LockWithVersion(version.tag)
|
||||||
|
} else {
|
||||||
|
// Last resort
|
||||||
|
loader.LockWithVersion("master")
|
||||||
|
}
|
||||||
|
defer loader.Unlock()
|
||||||
|
|
||||||
var trace raven.Stacktrace
|
var trace raven.Stacktrace
|
||||||
for _, gr := range ctx.Goroutines {
|
for _, gr := range ctx.Goroutines {
|
||||||
if gr.First {
|
if gr.First {
|
||||||
trace.Frames = make([]*raven.StacktraceFrame, len(gr.Stack.Calls))
|
trace.Frames = make([]*raven.StacktraceFrame, len(gr.Stack.Calls))
|
||||||
for i, sc := range gr.Stack.Calls {
|
for i, sc := range gr.Stack.Calls {
|
||||||
trace.Frames[len(trace.Frames)-1-i] = &raven.StacktraceFrame{
|
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name(), sc.SrcPath, sc.Line, 3, nil)
|
||||||
Function: sc.Func.Name(),
|
|
||||||
Module: sc.Func.PkgName(),
|
|
||||||
Filename: sc.SrcPath,
|
|
||||||
Lineno: sc.Line,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -100,10 +114,10 @@ func parseReport(path string, report []byte) (*raven.Packet, error) {
|
|||||||
Message: string(subjectLine),
|
Message: string(subjectLine),
|
||||||
Platform: "go",
|
Platform: "go",
|
||||||
Release: version.tag,
|
Release: version.tag,
|
||||||
|
Environment: version.environment(),
|
||||||
Tags: raven.Tags{
|
Tags: raven.Tags{
|
||||||
raven.Tag{Key: "version", Value: version.version},
|
raven.Tag{Key: "version", Value: version.version},
|
||||||
raven.Tag{Key: "tag", Value: version.tag},
|
raven.Tag{Key: "tag", Value: version.tag},
|
||||||
raven.Tag{Key: "commit", Value: version.commit},
|
|
||||||
raven.Tag{Key: "codename", Value: version.codename},
|
raven.Tag{Key: "codename", Value: version.codename},
|
||||||
raven.Tag{Key: "runtime", Value: version.runtime},
|
raven.Tag{Key: "runtime", Value: version.runtime},
|
||||||
raven.Tag{Key: "goos", Value: version.goos},
|
raven.Tag{Key: "goos", Value: version.goos},
|
||||||
@ -115,6 +129,9 @@ func parseReport(path string, report []byte) (*raven.Packet, error) {
|
|||||||
},
|
},
|
||||||
Interfaces: []raven.Interface{&trace},
|
Interfaces: []raven.Interface{&trace},
|
||||||
}
|
}
|
||||||
|
if version.commit != "" {
|
||||||
|
pkt.Tags = append(pkt.Tags, raven.Tag{Key: "commit", Value: version.commit})
|
||||||
|
}
|
||||||
|
|
||||||
return pkt, nil
|
return pkt, nil
|
||||||
}
|
}
|
||||||
@ -133,6 +150,19 @@ type version struct {
|
|||||||
builder string // "jb@kvin.kastelo.net"
|
builder string // "jb@kvin.kastelo.net"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v version) environment() string {
|
||||||
|
if v.commit != "" {
|
||||||
|
return "Development"
|
||||||
|
}
|
||||||
|
if strings.Contains(v.tag, "-rc.") {
|
||||||
|
return "Candidate"
|
||||||
|
}
|
||||||
|
if strings.Contains(v.tag, "-") {
|
||||||
|
return "Beta"
|
||||||
|
}
|
||||||
|
return "Stable"
|
||||||
|
}
|
||||||
|
|
||||||
func parseVersion(line string) (version, error) {
|
func parseVersion(line string) (version, error) {
|
||||||
m := longVersionRE.FindStringSubmatch(line)
|
m := longVersionRE.FindStringSubmatch(line)
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
|
114
cmd/stcrashreceiver/sourcecodeloader.go
Normal file
114
cmd/stcrashreceiver/sourcecodeloader.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright (C) 2019 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
urlPrefix = "https://raw.githubusercontent.com/syncthing/syncthing/"
|
||||||
|
httpTimeout = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type githubSourceCodeLoader struct {
|
||||||
|
mut sync.Mutex
|
||||||
|
version string
|
||||||
|
cache map[string]map[string][][]byte // version -> file -> lines
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGithubSourceCodeLoader() *githubSourceCodeLoader {
|
||||||
|
return &githubSourceCodeLoader{
|
||||||
|
cache: make(map[string]map[string][][]byte),
|
||||||
|
client: &http.Client{Timeout: httpTimeout},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *githubSourceCodeLoader) LockWithVersion(version string) {
|
||||||
|
l.mut.Lock()
|
||||||
|
l.version = version
|
||||||
|
if _, ok := l.cache[version]; !ok {
|
||||||
|
l.cache[version] = make(map[string][][]byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *githubSourceCodeLoader) Unlock() {
|
||||||
|
l.mut.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]byte, int) {
|
||||||
|
filename = filepath.ToSlash(filename)
|
||||||
|
lines, ok := l.cache[l.version][filename]
|
||||||
|
if !ok {
|
||||||
|
// Cache whatever we managed to find (or nil if nothing, so we don't try again)
|
||||||
|
defer func() {
|
||||||
|
l.cache[l.version][filename] = lines
|
||||||
|
}()
|
||||||
|
|
||||||
|
knownPrefixes := []string{"/lib/", "/cmd/"}
|
||||||
|
var idx int
|
||||||
|
for _, pref := range knownPrefixes {
|
||||||
|
idx = strings.Index(filename, pref)
|
||||||
|
if idx >= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx == -1 {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
url := urlPrefix + l.version + filename[idx:]
|
||||||
|
resp, err := l.client.Get(url)
|
||||||
|
|
||||||
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
|
fmt.Println("Loading source:", err.Error())
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Loading source:", err.Error())
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
lines = bytes.Split(data, []byte{'\n'})
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLineFromLines(lines, line, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLineFromLines(lines [][]byte, line, context int) ([][]byte, int) {
|
||||||
|
if lines == nil {
|
||||||
|
// cached error from ReadFile: return no lines
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
line-- // stack trace lines are 1-indexed
|
||||||
|
start := line - context
|
||||||
|
var idx int
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
idx = line
|
||||||
|
} else {
|
||||||
|
idx = context
|
||||||
|
}
|
||||||
|
end := line + context + 1
|
||||||
|
if line >= len(lines) {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
if end > len(lines) {
|
||||||
|
end = len(lines)
|
||||||
|
}
|
||||||
|
return lines[start:end], idx
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user