Skip to content

Commit 325314b

Browse files
committed
ReportDisabledIfNeeded
1 parent d2ca62d commit 325314b

File tree

3 files changed

+84
-6
lines changed

3 files changed

+84
-6
lines changed

cli/server.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,11 +814,31 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
814814
if err != nil {
815815
return xerrors.Errorf("create telemetry reporter: %w", err)
816816
}
817+
go options.Telemetry.RunSnapshotter()
817818
defer options.Telemetry.Close()
818819
} else {
819820
logger.Warn(ctx, fmt.Sprintf(`telemetry disabled, unable to notify of security issues. Read more: %s/admin/setup/telemetry`, vals.DocsURL.String()))
820821
}
821822

823+
if !vals.Telemetry.Enable.Value() {
824+
go func() {
825+
reporter, err := telemetry.New(telemetry.Options{
826+
DeploymentID: deploymentID,
827+
Database: options.Database,
828+
Logger: logger.Named("telemetry"),
829+
URL: vals.Telemetry.URL.Value(),
830+
})
831+
if err != nil {
832+
logger.Debug(ctx, "create telemetry reporter (disabled)", slog.Error(err))
833+
return
834+
}
835+
defer reporter.Close()
836+
if err := reporter.ReportDisabledIfNeeded(); err != nil {
837+
logger.Debug(ctx, "failed to report disabled telemetry", slog.Error(err))
838+
}
839+
}()
840+
}
841+
822842
// This prevents the pprof import from being accidentally deleted.
823843
_ = pprof.Handler
824844
if vals.Pprof.Enable {

coderd/telemetry/telemetry.go

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ type Options struct {
5959
// New constructs a reporter for telemetry data.
6060
// Duplicate data will be sent, it's on the server-side to index by UUID.
6161
// Data is anonymized prior to being sent!
62+
//
63+
// The returned Reporter should be started with RunSnapshotter() to begin
64+
// reporting.
6265
func New(options Options) (Reporter, error) {
6366
if options.SnapshotFrequency == 0 {
6467
// Report once every 30mins by default!
@@ -83,7 +86,6 @@ func New(options Options) (Reporter, error) {
8386
snapshotURL: snapshotURL,
8487
startedAt: dbtime.Now(),
8588
}
86-
go reporter.runSnapshotter()
8789
return reporter, nil
8890
}
8991

@@ -101,6 +103,12 @@ type Reporter interface {
101103
Report(snapshot *Snapshot)
102104
Enabled() bool
103105
Close()
106+
// RunSnapshotter runs reporting in a loop. It should be called in a
107+
// goroutine to avoid blocking the caller.
108+
RunSnapshotter()
109+
// ReportDisabledIfNeeded reports disabled telemetry if there was at least one report sent
110+
// before the telemetry was disabled, and we haven't sent a report since the telemetry was disabled.
111+
ReportDisabledIfNeeded() error
104112
}
105113

106114
type remoteReporter struct {
@@ -149,6 +157,12 @@ func (r *remoteReporter) reportSync(snapshot *Snapshot) {
149157
r.options.Logger.Debug(r.ctx, "bad response from telemetry server", slog.F("status", resp.StatusCode))
150158
return
151159
}
160+
if err := r.options.Database.UpsertTelemetryItem(r.ctx, database.UpsertTelemetryItemParams{
161+
Key: string(TelemetryItemKeyLastTelemetryUpdate),
162+
Value: dbtime.Now().Format(time.RFC3339),
163+
}); err != nil {
164+
r.options.Logger.Debug(r.ctx, "upsert last telemetry update", slog.Error(err))
165+
}
152166
r.options.Logger.Debug(r.ctx, "submitted snapshot")
153167
}
154168

@@ -177,7 +191,7 @@ func (r *remoteReporter) isClosed() bool {
177191
}
178192
}
179193

180-
func (r *remoteReporter) runSnapshotter() {
194+
func (r *remoteReporter) RunSnapshotter() {
181195
first := true
182196
ticker := time.NewTicker(r.options.SnapshotFrequency)
183197
defer ticker.Stop()
@@ -330,6 +344,45 @@ func checkIDPOrgSync(ctx context.Context, db database.Store, values *codersdk.De
330344
return syncConfig.Field != "", nil
331345
}
332346

347+
func (r *remoteReporter) ReportDisabledIfNeeded() error {
348+
db := r.options.Database
349+
lastTelemetryUpdate, telemetryUpdateErr := db.GetTelemetryItem(r.ctx, string(TelemetryItemKeyLastTelemetryUpdate))
350+
if telemetryUpdateErr != nil {
351+
r.options.Logger.Debug(r.ctx, "get last telemetry update at", slog.Error(telemetryUpdateErr))
352+
}
353+
telemetryDisabled, telemetryDisabledErr := db.GetTelemetryItem(r.ctx, string(TelemetryItemKeyTelemetryDisabled))
354+
if telemetryDisabledErr != nil {
355+
r.options.Logger.Debug(r.ctx, "get telemetry disabled", slog.Error(telemetryDisabledErr))
356+
}
357+
shouldReportDisabledTelemetry :=
358+
telemetryUpdateErr == nil &&
359+
((telemetryDisabledErr == nil && lastTelemetryUpdate.UpdatedAt.Before(telemetryDisabled.UpdatedAt)) ||
360+
errors.Is(telemetryDisabledErr, sql.ErrNoRows))
361+
if !shouldReportDisabledTelemetry {
362+
return nil
363+
}
364+
365+
if err := db.UpsertTelemetryItem(r.ctx, database.UpsertTelemetryItemParams{
366+
Key: string(TelemetryItemKeyTelemetryDisabled),
367+
Value: time.Now().Format(time.RFC3339),
368+
}); err != nil {
369+
return xerrors.Errorf("upsert telemetry disabled: %w", err)
370+
}
371+
item, err := db.GetTelemetryItem(r.ctx, string(TelemetryItemKeyTelemetryDisabled))
372+
if err != nil {
373+
return xerrors.Errorf("get telemetry disabled: %w", err)
374+
}
375+
376+
r.reportSync(
377+
&Snapshot{
378+
TelemetryItems: []TelemetryItem{
379+
ConvertTelemetryItem(item),
380+
},
381+
},
382+
)
383+
return nil
384+
}
385+
333386
// createSnapshot collects a full snapshot from the database.
334387
func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
335388
var (
@@ -1561,7 +1614,9 @@ type Organization struct {
15611614
type TelemetryItemKey string
15621615

15631616
const (
1564-
TelemetryItemKeyHTMLFirstServedAt TelemetryItemKey = "html_first_served_at"
1617+
TelemetryItemKeyHTMLFirstServedAt TelemetryItemKey = "html_first_served_at"
1618+
TelemetryItemKeyLastTelemetryUpdate TelemetryItemKey = "last_telemetry_update"
1619+
TelemetryItemKeyTelemetryDisabled TelemetryItemKey = "telemetry_disabled"
15651620
)
15661621

15671622
type TelemetryItem struct {
@@ -1573,6 +1628,8 @@ type TelemetryItem struct {
15731628

15741629
type noopReporter struct{}
15751630

1576-
func (*noopReporter) Report(_ *Snapshot) {}
1577-
func (*noopReporter) Enabled() bool { return false }
1578-
func (*noopReporter) Close() {}
1631+
func (*noopReporter) Report(_ *Snapshot) {}
1632+
func (*noopReporter) Enabled() bool { return false }
1633+
func (*noopReporter) Close() {}
1634+
func (*noopReporter) RunSnapshotter() {}
1635+
func (*noopReporter) ReportDisabledIfNeeded() error { return nil }

coderd/telemetry/telemetry_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ func collectSnapshot(t *testing.T, db database.Store, addOptionsFn func(opts tel
398398

399399
reporter, err := telemetry.New(options)
400400
require.NoError(t, err)
401+
go reporter.RunSnapshotter()
401402
t.Cleanup(reporter.Close)
402403
return <-deployment, <-snapshot
403404
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy