...
1
2
3
4
5
6
7
8
9
10
11
12
13 package metriton
14
15 import (
16 "context"
17 "errors"
18 "net/http"
19 "net/url"
20 "os"
21 "strconv"
22 "strings"
23 "sync"
24 )
25
26 var (
27
28 DefaultEndpoint = "https://metriton.datawire.io/scout"
29
30 BetaEndpoint = "https://metriton.datawire.io/beta/scout"
31
32
33
34
35 ScoutPyEndpoint = endpointFromEnv()
36 )
37
38 func getenvDefault(varname, def string) string {
39 ret := os.Getenv(varname)
40 if ret == "" {
41 ret = def
42 }
43 return ret
44 }
45
46 func endpointFromEnv() string {
47 host := getenvDefault("SCOUT_HOST", "metriton.datawire.io")
48 useHTTPS, _ := strconv.ParseBool(getenvDefault("SCOUT_HTTPS", "1"))
49 ret := &url.URL{
50 Scheme: "http",
51 Host: host,
52 Path: "/scout",
53 }
54 if useHTTPS {
55 ret.Scheme = "https"
56 }
57 return ret.String()
58 }
59
60
61 type Reporter struct {
62
63 Application string
64 Version string
65
66
67
68
69 GetInstallID func(*Reporter) (string, error)
70
71
72
73 BaseMetadata map[string]interface{}
74
75
76
77 Client *http.Client
78
79 Endpoint string
80
81 mu sync.Mutex
82 initialized bool
83 disabled bool
84 installID string
85 }
86
87 func (r *Reporter) ensureInitialized() error {
88 if r.Application == "" {
89 return errors.New("Reporter.Application may not be empty")
90 }
91 if r.Version == "" {
92 return errors.New("Reporter.Version may not be empty")
93 }
94 if r.GetInstallID == nil {
95 return errors.New("Reporter.GetInstallID may not be nil")
96 }
97
98 if r.initialized {
99 return nil
100 }
101
102 if r.BaseMetadata == nil {
103 r.BaseMetadata = make(map[string]interface{})
104 }
105
106 r.disabled = IsDisabledByUser()
107
108 installID, err := r.GetInstallID(r)
109 if err != nil {
110 return err
111 }
112 r.installID = installID
113
114 r.initialized = true
115
116 return nil
117 }
118
119
120 func IsDisabledByUser() bool {
121
122 if strings.HasPrefix(os.Getenv("TRAVIS_REPO_SLUG"), "datawire/") {
123 return true
124 }
125
126
127
128
129 return os.Getenv("SCOUT_DISABLE") != ""
130 }
131
132 func (r *Reporter) InstallID() string {
133 r.mu.Lock()
134 defer r.mu.Unlock()
135 _ = r.ensureInitialized()
136 return r.installID
137 }
138
139
140
141
142 func (r *Reporter) Report(ctx context.Context, metadata map[string]interface{}) (*Response, error) {
143 r.mu.Lock()
144
145 if err := r.ensureInitialized(); err != nil {
146 r.mu.Unlock()
147 return nil, err
148 }
149
150 var resp *Response
151 var err error
152
153 if r.disabled {
154 r.mu.Unlock()
155 } else {
156 client := r.Client
157 if client == nil {
158 client = http.DefaultClient
159 }
160
161 endpoint := r.Endpoint
162 if endpoint == "" {
163 endpoint = DefaultEndpoint
164 }
165
166 mergedMetadata := make(map[string]interface{}, len(r.BaseMetadata)+len(metadata))
167
168
169
170 for k, v := range r.BaseMetadata {
171 mergedMetadata[k] = v
172 }
173 for k, v := range metadata {
174 mergedMetadata[k] = v
175 }
176
177 report := Report{
178 Application: r.Application,
179 InstallID: r.installID,
180 Version: r.Version,
181 Metadata: mergedMetadata,
182 }
183
184 r.mu.Unlock()
185 resp, err = report.Send(ctx, client, endpoint)
186 if err != nil {
187 return nil, err
188 }
189 }
190
191 if resp == nil {
192
193 resp = &Response{
194 AppInfo: AppInfo{
195 LatestVersion: r.Version,
196 },
197 }
198 }
199
200 if resp != nil && resp.DisableScout {
201 r.mu.Lock()
202 r.disabled = true
203 r.mu.Unlock()
204 }
205
206 return resp, nil
207 }
208
View as plain text