forked from remind101/empire
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hb.go
124 lines (103 loc) · 2.69 KB
/
hb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// package hb is a Go package from sending errors to Honeybadger.
package hb
import (
"fmt"
"os"
"reflect"
"runtime"
"strings"
"github.com/remind101/pkg/reporter"
"golang.org/x/net/context"
)
// Ensure that Reporter implements the reporter.Reporter interface.
var _ reporter.Reporter = &Reporter{}
// Reporter is used to report errors to honeybadger.
type Reporter struct {
Environment string
// http client to use when sending reports to honeybadger.
client interface {
Send(*Report) error
}
cwd string
hostname string
}
// NewReporter returns a new Reporter instance.
func NewReporter(key string) *Reporter {
cwd, _ := os.Getwd()
hostname, _ := os.Hostname()
return &Reporter{
client: NewClientFromKey(key),
hostname: hostname,
cwd: cwd,
}
}
// Report reports the error to honeybadger.
func (r *Reporter) Report(ctx context.Context, err error) error {
report := r.NewReport(err)
return r.client.Send(report)
}
func (r *Reporter) NewReport(err error) *Report {
report := NewReport(err)
report.Server.ProjectRoot["path"] = r.cwd
report.Server.EnvironmentName = r.Environment
report.Server.Hostname = r.hostname
return report
}
// NewReport generates a new honeybadger report from an error.
func NewReport(err error) *Report {
r := &Report{
Notifier: &Notifier{
Name: "Honeybadger (Go)",
Url: "https://github.com/remind101/pkg/reporter/hb",
Version: "0.1",
Language: "Go",
},
Error: &Error{
Class: className(err),
Message: err.Error(),
Backtrace: make([]*BacktraceLine, 0),
Source: make(map[string]interface{}),
},
Request: &Request{
Params: make(map[string]interface{}),
Session: make(map[string]interface{}),
CgiData: make(map[string]interface{}),
Context: make(map[string]interface{}),
},
Server: &Server{
ProjectRoot: make(map[string]interface{}),
},
}
if e, ok := err.(*reporter.Error); ok {
r.Error.Class = className(e.Err)
for _, l := range e.Backtrace {
r.Error.Backtrace = append(r.Error.Backtrace, &BacktraceLine{
Method: functionName(l.PC),
File: l.File,
Number: fmt.Sprintf("%d", l.Line),
})
}
if e.Request != nil {
r.Request.Url = e.Request.URL.String()
for header, values := range e.Request.Header {
h := strings.Replace(strings.ToUpper(header), "-", "_", -1)
r.Request.CgiData["HTTP_"+h] = values
}
r.Request.CgiData["REQUEST_METHOD"] = e.Request.Method
}
for key, value := range e.Context {
r.Request.Context[key] = value
}
}
return r
}
func className(err error) string {
return reflect.TypeOf(err).String()
}
func functionName(pc uintptr) string {
fn := runtime.FuncForPC(pc)
if fn == nil {
return "???"
}
return fn.Name()
}