Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: move usage types to new package#19103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall 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
15 changes: 6 additions & 9 deletionscoderd/provisionerdserver/provisionerdserver.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,14 +28,6 @@ import (
protobuf "google.golang.org/protobuf/proto"

"cdr.dev/slog"

"github.com/coder/coder/v2/coderd/usage"
"github.com/coder/coder/v2/coderd/util/slice"

"github.com/coder/coder/v2/codersdk/drpcsdk"

"github.com/coder/quartz"

"github.com/coder/coder/v2/coderd/apikey"
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
Expand All@@ -49,13 +41,18 @@ import (
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/coderd/usage"
"github.com/coder/coder/v2/coderd/usage/usagetypes"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/coderd/wspubsub"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/agentsdk"
"github.com/coder/coder/v2/codersdk/drpcsdk"
"github.com/coder/coder/v2/provisioner"
"github.com/coder/coder/v2/provisionerd/proto"
"github.com/coder/coder/v2/provisionersdk"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/quartz"
)

const (
Expand DownExpand Up@@ -2041,7 +2038,7 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
// Insert usage event for managed agents.
usageInserter := s.UsageInserter.Load()
if usageInserter != nil {
event :=usage.DCManagedAgentsV1{
event :=usagetypes.DCManagedAgentsV1{
Count: 1,
}
err = (*usageInserter).InsertDiscreteUsageEvent(ctx, db, event)
Expand Down
7 changes: 4 additions & 3 deletionscoderd/provisionerdserver/provisionerdserver_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ import (
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/usage"
"github.com/coder/coder/v2/coderd/usage/usagetypes"
"github.com/coder/coder/v2/coderd/wspubsub"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/agentsdk"
Expand DownExpand Up@@ -3044,7 +3045,7 @@ func TestCompleteJob(t *testing.T) {
if tc.expectUsageEvent {
// Check that a usage event was collected.
require.Len(t, fakeUsageInserter.collectedEvents, 1)
require.Equal(t,usage.DCManagedAgentsV1{
require.Equal(t,usagetypes.DCManagedAgentsV1{
Count: 1,
}, fakeUsageInserter.collectedEvents[0])
} else {
Expand DownExpand Up@@ -4226,7 +4227,7 @@ func (s *fakeStream) cancel() {
}

type fakeUsageInserter struct {
collectedEvents []usage.Event
collectedEvents []usagetypes.Event
}

var _ usage.Inserter = &fakeUsageInserter{}
Expand All@@ -4239,7 +4240,7 @@ func newFakeUsageInserter() (*fakeUsageInserter, *atomic.Pointer[usage.Inserter]
return fake, ptr
}

func (f *fakeUsageInserter) InsertDiscreteUsageEvent(_ context.Context, _ database.Store, eventusage.DiscreteEvent) error {
func (f *fakeUsageInserter) InsertDiscreteUsageEvent(_ context.Context, _ database.Store, eventusagetypes.DiscreteEvent) error {
f.collectedEvents = append(f.collectedEvents, event)
return nil
}
82 changes: 0 additions & 82 deletionscoderd/usage/events.go
View file
Open in desktop

This file was deleted.

5 changes: 3 additions & 2 deletionscoderd/usage/inserter.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import (
"context"

"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/usage/usagetypes"
)

// Inserter accepts usage events generated by the product.
Expand All@@ -12,7 +13,7 @@ type Inserter interface {
// within the given transaction.
// The caller context must be authorized to create usage events in the
// database.
InsertDiscreteUsageEvent(ctx context.Context, tx database.Store, event DiscreteEvent) error
InsertDiscreteUsageEvent(ctx context.Context, tx database.Store, eventusagetypes.DiscreteEvent) error
}

// AGPLInserter is a no-op implementation of Inserter.
Expand All@@ -26,6 +27,6 @@ func NewAGPLInserter() Inserter {

// InsertDiscreteUsageEvent is a no-op implementation of
// InsertDiscreteUsageEvent.
func (AGPLInserter) InsertDiscreteUsageEvent(_ context.Context, _ database.Store, _ DiscreteEvent) error {
func (AGPLInserter) InsertDiscreteUsageEvent(_ context.Context, _ database.Store, _usagetypes.DiscreteEvent) error {
return nil
}
129 changes: 129 additions & 0 deletionscoderd/usage/usagetypes/events.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
// Package usagetypes contains the types for usage events. These are kept in
// their own package to avoid importing any real code from coderd.
//
// Imports in this package should be limited to the standard library and the
// following packages ONLY:
// - github.com/google/uuid
// - golang.org/x/xerrors
//
// This package is imported by the Tallyman codebase.
package usagetypes

// Please read the package documentation before adding imports.
import (
"bytes"
"encoding/json"
"strings"

"golang.org/x/xerrors"
)

// UsageEventType is an enum of all usage event types. It mirrors the database
// type `usage_event_type`.
typeUsageEventTypestring

const (
UsageEventTypeDCManagedAgentsV1UsageEventType="dc_managed_agents_v1"
)

func (eUsageEventType)Valid()bool {
switche {
caseUsageEventTypeDCManagedAgentsV1:
returntrue
default:
returnfalse
}
}

func (eUsageEventType)IsDiscrete()bool {
returne.Valid()&&strings.HasPrefix(string(e),"dc_")
}

func (eUsageEventType)IsHeartbeat()bool {
returne.Valid()&&strings.HasPrefix(string(e),"hb_")
}

// ParseEvent parses the raw event data into the specified Go type. It fails if
// there is any unknown fields or extra data after the event. The returned event
// is validated.
funcParseEvent[TEvent](data json.RawMessage) (T,error) {
dec:=json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()
Copy link
Member

Choose a reason for hiding this comment

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

👍


vareventT
err:=dec.Decode(&event)
iferr!=nil {
returnevent,xerrors.Errorf("unmarshal %T event: %w",event,err)
}
ifdec.More() {
returnevent,xerrors.Errorf("extra data after %T event",event)
}
err=event.Valid()
iferr!=nil {
returnevent,xerrors.Errorf("invalid %T event: %w",event,err)
}

returnevent,nil
}

// ParseEventWithType parses the raw event data into the specified Go type. It
// fails if there is any unknown fields or extra data after the event. The
// returned event is validated.
funcParseEventWithType(eventTypeUsageEventType,data json.RawMessage) (Event,error) {
switcheventType {
caseUsageEventTypeDCManagedAgentsV1:
returnParseEvent[DCManagedAgentsV1](data)
default:
returnnil,xerrors.Errorf("unknown event type: %s",eventType)
}
}

// Event is a usage event that can be collected by the usage collector.
//
// Note that the following event types should not be updated once they are
// merged into the product. Please consult Dean before making any changes.
//
// This type cannot be implemented outside of this package as it this package
// is the source of truth for the coder/tallyman repo.
typeEventinterface {
usageEvent()// to prevent external types from implementing this interface
EventType()UsageEventType
Valid()error
Fields()map[string]any// fields to be marshaled and sent to tallyman/Metronome
}

// DiscreteEvent is a usage event that is collected as a discrete event.
typeDiscreteEventinterface {
Event
discreteUsageEvent()// marker method, also prevents external types from implementing this interface
}

// DCManagedAgentsV1 is a discrete usage event for the number of managed agents.
// This event is sent in the following situations:
// - Once on first startup after usage tracking is added to the product with
// the count of all existing managed agents (count=N)
// - A new managed agent is created (count=1)
typeDCManagedAgentsV1struct {
Countuint64`json:"count"`
}

var_DiscreteEvent=DCManagedAgentsV1{}

func (DCManagedAgentsV1)usageEvent() {}
func (DCManagedAgentsV1)discreteUsageEvent() {}
func (DCManagedAgentsV1)EventType()UsageEventType {
returnUsageEventTypeDCManagedAgentsV1
}

func (eDCManagedAgentsV1)Valid()error {
ife.Count==0 {
returnxerrors.New("count must be greater than 0")
}
returnnil
}

func (eDCManagedAgentsV1)Fields()map[string]any {
returnmap[string]any{
"count":e.Count,
}
}
61 changes: 61 additions & 0 deletionscoderd/usage/usagetypes/events_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
package usagetypes_test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/usage/usagetypes"
)

funcTestParseEvent(t*testing.T) {
t.Parallel()

t.Run("ExtraFields",func(t*testing.T) {
t.Parallel()
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1, "extra": "field"}`))
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
})

t.Run("ExtraData",func(t*testing.T) {
t.Parallel()
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}{"count": 2}`))
require.ErrorContains(t,err,"extra data after usagetypes.DCManagedAgentsV1 event")
})

t.Run("DCManagedAgentsV1",func(t*testing.T) {
t.Parallel()

event,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}`))
require.NoError(t,err)
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())

_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": "invalid"}`))
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")

_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{}`))
require.ErrorContains(t,err,"invalid usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
})
}

funcTestParseEventWithType(t*testing.T) {
t.Parallel()

t.Run("UnknownEvent",func(t*testing.T) {
t.Parallel()
_,err:=usagetypes.ParseEventWithType(usagetypes.UsageEventType("fake"), []byte(`{}`))
require.ErrorContains(t,err,"unknown event type: fake")
})

t.Run("DCManagedAgentsV1",func(t*testing.T) {
t.Parallel()

eventType:=usagetypes.UsageEventTypeDCManagedAgentsV1
event,err:=usagetypes.ParseEventWithType(eventType, []byte(`{"count": 1}`))
require.NoError(t,err)
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
require.Equal(t,eventType,event.EventType())
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())
})
}
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp