Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions gen/proto/go/prehog/v1alpha/teleport.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions gen/proto/ts/prehog/v1alpha/teleport_pb.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 13 additions & 8 deletions lib/usagereporter/teleport/usagereporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import (
"time"

"connectrpc.com/connect"
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/gravitational/teleport"
Expand Down Expand Up @@ -102,19 +102,28 @@ type StreamingUsageReporter struct {
// clusterName is the cluster's name, used for anonymization and as an event
// field.
clusterName types.ClusterName
clock clockwork.Clock
}

var _ UsageReporter = (*StreamingUsageReporter)(nil)

func (t *StreamingUsageReporter) AnonymizeAndSubmit(events ...Anonymizable) {
t.usageReporter.AddEventsToQueue(t.anonymize(events)...)
Comment thread
marcoandredinis marked this conversation as resolved.
}

// anonymize builds a submit request per event.
func (t *StreamingUsageReporter) anonymize(events []Anonymizable) []*prehogv1a.SubmitEventRequest {
reqs := make([]*prehogv1a.SubmitEventRequest, 0, len(events))
for _, e := range events {
req := e.Anonymize(t.anonymizer)
req.Timestamp = timestamppb.New(t.clock.Now())
req.Timestamp = timestamppb.Now()
req.ClusterName = t.anonymizer.AnonymizeString(t.clusterName.GetClusterName())
req.TeleportVersion = teleport.Version
t.usageReporter.AddEventsToQueue(req)
// Deduping resubmitted events requires a stable key per event.
req.EventKey = uuid.NewString()
reqs = append(reqs, req)
}

return reqs
}

func (t *StreamingUsageReporter) Run(ctx context.Context) {
Expand All @@ -133,8 +142,6 @@ func NewStreamingUsageReporter(logger *slog.Logger, clusterName types.ClusterNam
return nil, trace.Wrap(err)
}

clock := clockwork.NewRealClock()

reporter := usagereporter.NewUsageReporter(&usagereporter.Options[prehogv1a.SubmitEventRequest]{
Logger: logger,
Submit: submitter,
Expand All @@ -144,14 +151,12 @@ func NewStreamingUsageReporter(logger *slog.Logger, clusterName types.ClusterNam
MaxBufferSize: usageReporterMaxBufferSize,
SubmitDelay: usageReporterSubmitDelay,
RetryAttempts: usageReporterRetryAttempts,
Clock: clock,
})

return &StreamingUsageReporter{
usageReporter: reporter,
anonymizer: anonymizer,
clusterName: clusterName,
clock: clock,
}, nil
}

Expand Down
34 changes: 34 additions & 0 deletions lib/usagereporter/teleport/usagereporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/gravitational/teleport"
accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
usageeventsv1 "github.com/gravitational/teleport/api/gen/proto/go/usageevents/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/accesslist"
prehogv1a "github.com/gravitational/teleport/gen/proto/go/prehog/v1alpha"
"github.com/gravitational/teleport/lib/utils"
Expand Down Expand Up @@ -816,6 +817,39 @@ func TestConvertUsageEvent(t *testing.T) {
}
}

func TestAnonymize(t *testing.T) {
t.Parallel()

anonymizer, err := utils.NewHMACAnonymizer(utils.AnonymizationKeyString("anon-key-or-cluster-id"))
require.NoError(t, err)

clusterName, err := types.NewClusterName(types.ClusterNameSpecV2{
ClusterName: "test-cluster",
ClusterID: "test-cluster-id",
})
require.NoError(t, err)

reporter := &StreamingUsageReporter{
anonymizer: anonymizer,
clusterName: clusterName,
}

reqs := reporter.anonymize([]Anonymizable{
&UserLoginEvent{UserName: "alice", ConnectorType: "local"},
&UserLoginEvent{UserName: "alice", ConnectorType: "local"},
})

require.Len(t, reqs, 2)
require.NotEmpty(t, reqs[0].EventKey)
require.NotEqual(t, reqs[0].EventKey, reqs[1].EventKey,
"identical events must not share an event key")

for _, req := range reqs {
require.Equal(t, anonymizer.AnonymizeString("test-cluster"), req.ClusterName)
require.Equal(t, teleport.Version, req.TeleportVersion)
}
}

func TestEmitEditorChangeEvent(t *testing.T) {
tt := []struct {
name string
Expand Down
6 changes: 6 additions & 0 deletions proto/prehog/v1alpha/teleport.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2203,6 +2203,12 @@ message SubmitEventRequest {
// PostHog property: tp.teleport_version
string teleport_version = 95;

// event_key is a UUID distinguishing one underlying event occurrence,
// allowing consumers to deduplicate resubmissions.
//
// PostHog property: tp.event_key
string event_key = 128;
Comment on lines +2206 to +2210

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this in sync with cloud's version?
https://github.com/gravitational/cloud/blob/f2e2758344d2547ace065d5d699be0942f448e6b/build/prehog/proto/prehog/v1alpha/teleport.proto#L2202

Can you link the PR here to ensure we keep both protos in sync?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. To try to avoid iterations, my plan is to get teleport ready first, then PR cloud, then merge.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have both changes approved before merging any.
Let's say that we change teleport emitter but not the receiver part.
And now we try to change the receiver, but cloud's PR receives some back and forth comments and we end up with a different name.

We would need to get back here and change things again.

From
https://app.notion.com/p/goteleport/Implementing-Usage-Events-Prehog-2dcfdd3830be809f85a4c1e11a272d76

The process involves updating the Prehog service to handle the new event type, configuring the data warehouse to store the event data, and finally implementing the event emission in Teleport's codebase.


// the event being submitted
oneof event {
UserLoginEvent user_login = 3;
Expand Down
Loading