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

Commit1a601c3

Browse files
authored
chore: move usage types to new package (#19103)
1 parent6eb02d1 commit1a601c3

File tree

12 files changed

+470
-225
lines changed

12 files changed

+470
-225
lines changed

‎coderd/provisionerdserver/provisionerdserver.go‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ import (
2828
protobuf"google.golang.org/protobuf/proto"
2929

3030
"cdr.dev/slog"
31-
32-
"github.com/coder/coder/v2/coderd/usage"
33-
"github.com/coder/coder/v2/coderd/util/slice"
34-
35-
"github.com/coder/coder/v2/codersdk/drpcsdk"
36-
37-
"github.com/coder/quartz"
38-
3931
"github.com/coder/coder/v2/coderd/apikey"
4032
"github.com/coder/coder/v2/coderd/audit"
4133
"github.com/coder/coder/v2/coderd/database"
@@ -49,13 +41,18 @@ import (
4941
"github.com/coder/coder/v2/coderd/schedule"
5042
"github.com/coder/coder/v2/coderd/telemetry"
5143
"github.com/coder/coder/v2/coderd/tracing"
44+
"github.com/coder/coder/v2/coderd/usage"
45+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
46+
"github.com/coder/coder/v2/coderd/util/slice"
5247
"github.com/coder/coder/v2/coderd/wspubsub"
5348
"github.com/coder/coder/v2/codersdk"
5449
"github.com/coder/coder/v2/codersdk/agentsdk"
50+
"github.com/coder/coder/v2/codersdk/drpcsdk"
5551
"github.com/coder/coder/v2/provisioner"
5652
"github.com/coder/coder/v2/provisionerd/proto"
5753
"github.com/coder/coder/v2/provisionersdk"
5854
sdkproto"github.com/coder/coder/v2/provisionersdk/proto"
55+
"github.com/coder/quartz"
5956
)
6057

6158
const (
@@ -2041,7 +2038,7 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
20412038
// Insert usage event for managed agents.
20422039
usageInserter:=s.UsageInserter.Load()
20432040
ifusageInserter!=nil {
2044-
event:=usage.DCManagedAgentsV1{
2041+
event:=usagetypes.DCManagedAgentsV1{
20452042
Count:1,
20462043
}
20472044
err= (*usageInserter).InsertDiscreteUsageEvent(ctx,db,event)

‎coderd/provisionerdserver/provisionerdserver_test.go‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"github.com/coder/coder/v2/coderd/schedule/cron"
4949
"github.com/coder/coder/v2/coderd/telemetry"
5050
"github.com/coder/coder/v2/coderd/usage"
51+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
5152
"github.com/coder/coder/v2/coderd/wspubsub"
5253
"github.com/coder/coder/v2/codersdk"
5354
"github.com/coder/coder/v2/codersdk/agentsdk"
@@ -3044,7 +3045,7 @@ func TestCompleteJob(t *testing.T) {
30443045
iftc.expectUsageEvent {
30453046
// Check that a usage event was collected.
30463047
require.Len(t,fakeUsageInserter.collectedEvents,1)
3047-
require.Equal(t,usage.DCManagedAgentsV1{
3048+
require.Equal(t,usagetypes.DCManagedAgentsV1{
30483049
Count:1,
30493050
},fakeUsageInserter.collectedEvents[0])
30503051
}else {
@@ -4226,7 +4227,7 @@ func (s *fakeStream) cancel() {
42264227
}
42274228

42284229
typefakeUsageInserterstruct {
4229-
collectedEvents []usage.Event
4230+
collectedEvents []usagetypes.Event
42304231
}
42314232

42324233
var_ usage.Inserter=&fakeUsageInserter{}
@@ -4239,7 +4240,7 @@ func newFakeUsageInserter() (*fakeUsageInserter, *atomic.Pointer[usage.Inserter]
42394240
returnfake,ptr
42404241
}
42414242

4242-
func (f*fakeUsageInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,eventusage.DiscreteEvent)error {
4243+
func (f*fakeUsageInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,eventusagetypes.DiscreteEvent)error {
42434244
f.collectedEvents=append(f.collectedEvents,event)
42444245
returnnil
42454246
}

‎coderd/usage/events.go‎

Lines changed: 0 additions & 82 deletions
This file was deleted.

‎coderd/usage/inserter.go‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55

66
"github.com/coder/coder/v2/coderd/database"
7+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
78
)
89

910
// Inserter accepts usage events generated by the product.
@@ -12,7 +13,7 @@ type Inserter interface {
1213
// within the given transaction.
1314
// The caller context must be authorized to create usage events in the
1415
// database.
15-
InsertDiscreteUsageEvent(ctx context.Context,tx database.Store,eventDiscreteEvent)error
16+
InsertDiscreteUsageEvent(ctx context.Context,tx database.Store,eventusagetypes.DiscreteEvent)error
1617
}
1718

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

2728
// InsertDiscreteUsageEvent is a no-op implementation of
2829
// InsertDiscreteUsageEvent.
29-
func (AGPLInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,_DiscreteEvent)error {
30+
func (AGPLInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,_usagetypes.DiscreteEvent)error {
3031
returnnil
3132
}

‎coderd/usage/usagetypes/events.go‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Package usagetypes contains the types for usage events. These are kept in
2+
// their own package to avoid importing any real code from coderd.
3+
//
4+
// Imports in this package should be limited to the standard library and the
5+
// following packages ONLY:
6+
// - github.com/google/uuid
7+
// - golang.org/x/xerrors
8+
//
9+
// This package is imported by the Tallyman codebase.
10+
package usagetypes
11+
12+
// Please read the package documentation before adding imports.
13+
import (
14+
"bytes"
15+
"encoding/json"
16+
"strings"
17+
18+
"golang.org/x/xerrors"
19+
)
20+
21+
// UsageEventType is an enum of all usage event types. It mirrors the database
22+
// type `usage_event_type`.
23+
typeUsageEventTypestring
24+
25+
const (
26+
UsageEventTypeDCManagedAgentsV1UsageEventType="dc_managed_agents_v1"
27+
)
28+
29+
func (eUsageEventType)Valid()bool {
30+
switche {
31+
caseUsageEventTypeDCManagedAgentsV1:
32+
returntrue
33+
default:
34+
returnfalse
35+
}
36+
}
37+
38+
func (eUsageEventType)IsDiscrete()bool {
39+
returne.Valid()&&strings.HasPrefix(string(e),"dc_")
40+
}
41+
42+
func (eUsageEventType)IsHeartbeat()bool {
43+
returne.Valid()&&strings.HasPrefix(string(e),"hb_")
44+
}
45+
46+
// ParseEvent parses the raw event data into the specified Go type. It fails if
47+
// there is any unknown fields or extra data after the event. The returned event
48+
// is validated.
49+
funcParseEvent[TEvent](data json.RawMessage) (T,error) {
50+
dec:=json.NewDecoder(bytes.NewReader(data))
51+
dec.DisallowUnknownFields()
52+
53+
vareventT
54+
err:=dec.Decode(&event)
55+
iferr!=nil {
56+
returnevent,xerrors.Errorf("unmarshal %T event: %w",event,err)
57+
}
58+
ifdec.More() {
59+
returnevent,xerrors.Errorf("extra data after %T event",event)
60+
}
61+
err=event.Valid()
62+
iferr!=nil {
63+
returnevent,xerrors.Errorf("invalid %T event: %w",event,err)
64+
}
65+
66+
returnevent,nil
67+
}
68+
69+
// ParseEventWithType parses the raw event data into the specified Go type. It
70+
// fails if there is any unknown fields or extra data after the event. The
71+
// returned event is validated.
72+
funcParseEventWithType(eventTypeUsageEventType,data json.RawMessage) (Event,error) {
73+
switcheventType {
74+
caseUsageEventTypeDCManagedAgentsV1:
75+
returnParseEvent[DCManagedAgentsV1](data)
76+
default:
77+
returnnil,xerrors.Errorf("unknown event type: %s",eventType)
78+
}
79+
}
80+
81+
// Event is a usage event that can be collected by the usage collector.
82+
//
83+
// Note that the following event types should not be updated once they are
84+
// merged into the product. Please consult Dean before making any changes.
85+
//
86+
// This type cannot be implemented outside of this package as it this package
87+
// is the source of truth for the coder/tallyman repo.
88+
typeEventinterface {
89+
usageEvent()// to prevent external types from implementing this interface
90+
EventType()UsageEventType
91+
Valid()error
92+
Fields()map[string]any// fields to be marshaled and sent to tallyman/Metronome
93+
}
94+
95+
// DiscreteEvent is a usage event that is collected as a discrete event.
96+
typeDiscreteEventinterface {
97+
Event
98+
discreteUsageEvent()// marker method, also prevents external types from implementing this interface
99+
}
100+
101+
// DCManagedAgentsV1 is a discrete usage event for the number of managed agents.
102+
// This event is sent in the following situations:
103+
// - Once on first startup after usage tracking is added to the product with
104+
// the count of all existing managed agents (count=N)
105+
// - A new managed agent is created (count=1)
106+
typeDCManagedAgentsV1struct {
107+
Countuint64`json:"count"`
108+
}
109+
110+
var_DiscreteEvent=DCManagedAgentsV1{}
111+
112+
func (DCManagedAgentsV1)usageEvent() {}
113+
func (DCManagedAgentsV1)discreteUsageEvent() {}
114+
func (DCManagedAgentsV1)EventType()UsageEventType {
115+
returnUsageEventTypeDCManagedAgentsV1
116+
}
117+
118+
func (eDCManagedAgentsV1)Valid()error {
119+
ife.Count==0 {
120+
returnxerrors.New("count must be greater than 0")
121+
}
122+
returnnil
123+
}
124+
125+
func (eDCManagedAgentsV1)Fields()map[string]any {
126+
returnmap[string]any{
127+
"count":e.Count,
128+
}
129+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package usagetypes_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
9+
)
10+
11+
funcTestParseEvent(t*testing.T) {
12+
t.Parallel()
13+
14+
t.Run("ExtraFields",func(t*testing.T) {
15+
t.Parallel()
16+
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1, "extra": "field"}`))
17+
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
18+
})
19+
20+
t.Run("ExtraData",func(t*testing.T) {
21+
t.Parallel()
22+
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}{"count": 2}`))
23+
require.ErrorContains(t,err,"extra data after usagetypes.DCManagedAgentsV1 event")
24+
})
25+
26+
t.Run("DCManagedAgentsV1",func(t*testing.T) {
27+
t.Parallel()
28+
29+
event,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}`))
30+
require.NoError(t,err)
31+
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
32+
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())
33+
34+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": "invalid"}`))
35+
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
36+
37+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{}`))
38+
require.ErrorContains(t,err,"invalid usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
39+
})
40+
}
41+
42+
funcTestParseEventWithType(t*testing.T) {
43+
t.Parallel()
44+
45+
t.Run("UnknownEvent",func(t*testing.T) {
46+
t.Parallel()
47+
_,err:=usagetypes.ParseEventWithType(usagetypes.UsageEventType("fake"), []byte(`{}`))
48+
require.ErrorContains(t,err,"unknown event type: fake")
49+
})
50+
51+
t.Run("DCManagedAgentsV1",func(t*testing.T) {
52+
t.Parallel()
53+
54+
eventType:=usagetypes.UsageEventTypeDCManagedAgentsV1
55+
event,err:=usagetypes.ParseEventWithType(eventType, []byte(`{"count": 1}`))
56+
require.NoError(t,err)
57+
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
58+
require.Equal(t,eventType,event.EventType())
59+
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())
60+
})
61+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp