Skip to content

Commit c9da4cb

Browse files
authored
Add "dashboard" endpoints (#25)
1 parent a2e0a51 commit c9da4cb

18 files changed

+1124
-10
lines changed

client.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ type Client interface {
2020
Jobs() JobsClient
2121
// Models returns a client for access to all model related API functions
2222
Models() ModelsClient
23-
// Tags() TagsClient
23+
// Dashboard returns a client for access to dashboard API functions
24+
Dashboard() DashboardClient
2425
}
2526

2627
type standardClient struct {
2728
accountingClient *standardAccountingClient
2829
jobsClient *standardJobsClient
2930
modelsClient *standardModelsClient
31+
dashboardClient *standardDashboardClient
3032
requestor *requestor
3133
}
3234

@@ -62,6 +64,9 @@ func NewClient(baseURL string, opts ...ClientOption) Client {
6264
client.modelsClient = &standardModelsClient{
6365
baseClient: client,
6466
}
67+
client.dashboardClient = &standardDashboardClient{
68+
baseClient: client,
69+
}
6570

6671
return client
6772
}
@@ -101,3 +106,7 @@ func (c *standardClient) Jobs() JobsClient {
101106
func (c *standardClient) Models() ModelsClient {
102107
return c.modelsClient
103108
}
109+
110+
func (c *standardClient) Dashboard() DashboardClient {
111+
return c.dashboardClient
112+
}

client_fake.go

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type ClientFake struct {
88
AccountingFunc func() AccountingClient
99
JobsFunc func() JobsClient
1010
ModelsFunc func() ModelsClient
11+
DashboardFunc func() DashboardClient
1112
}
1213

1314
var _ Client = &ClientFake{}
@@ -35,3 +36,7 @@ func (c *ClientFake) Jobs() JobsClient {
3536
func (c *ClientFake) Models() ModelsClient {
3637
return c.ModelsFunc()
3738
}
39+
40+
func (c *ClientFake) Dashboard() DashboardClient {
41+
return c.DashboardFunc()
42+
}

client_fake_test.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,20 @@ func TestClientFake(t *testing.T) {
4444
calls++
4545
return nil
4646
},
47+
DashboardFunc: func() DashboardClient {
48+
calls++
49+
return nil
50+
},
4751
}
4852
fake.WithAPIKey("apiKey")
4953
fake.WithTeamKey("teamID", "token")
5054
fake.WithOptions(nil, nil)
5155
fake.Accounting()
5256
fake.Jobs()
5357
fake.Models()
58+
fake.Dashboard()
5459

55-
if calls != 6 {
60+
if calls != 7 {
5661
t.Errorf("Did not call all of the funcs: %d", calls)
5762
}
5863
}

client_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,13 @@ func TestClientModels(t *testing.T) {
8686
t.Errorf("modelsClient did not return")
8787
}
8888
}
89+
90+
func TestClientDashboard(t *testing.T) {
91+
dashboardClient := &standardDashboardClient{}
92+
c := (&standardClient{
93+
dashboardClient: dashboardClient,
94+
})
95+
if c.Dashboard() != dashboardClient {
96+
t.Errorf("dashboardClient did not return")
97+
}
98+
}

dashboard_client.go

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package modzy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"strconv"
8+
"strings"
9+
"time"
10+
11+
"github.com/modzy/sdk-go/internal/impossible"
12+
"github.com/modzy/sdk-go/model"
13+
)
14+
15+
type DashboardClient interface {
16+
GetAlerts(ctx context.Context, input *GetAlertsInput) (*GetAlertsOutput, error)
17+
GetAlertDetails(ctx context.Context, input *GetAlertDetailsInput) (*GetAlertDetailsOutput, error)
18+
GetDataProcessed(ctx context.Context, input *GetDataProcessedInput) (*GetDataProcessedOutput, error)
19+
GetPredictionsMade(ctx context.Context, input *GetPredictionsMadeInput) (*GetPredictionsMadeOutput, error)
20+
GetActiveUsers(ctx context.Context, input *GetActiveUsersInput) (*GetActiveUsersOutput, error)
21+
GetActiveModels(ctx context.Context, input *GetActiveModelsInput) (*GetActiveModelsOutput, error)
22+
GetPrometheusMetric(ctx context.Context, input *GetPrometheusMetricInput) (*GetPrometheusMetricOutput, error)
23+
}
24+
25+
type standardDashboardClient struct {
26+
baseClient *standardClient
27+
}
28+
29+
var _ DashboardClient = &standardDashboardClient{}
30+
31+
func (c *standardDashboardClient) GetAlerts(ctx context.Context, input *GetAlertsInput) (*GetAlertsOutput, error) {
32+
var out model.AlertsList
33+
path := "/api/notifications/alerts"
34+
_, err := c.baseClient.requestor.Get(ctx, path, &out)
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
summaries := []AlertSummary{}
40+
for _, s := range out {
41+
summaries = append(summaries, AlertSummary{
42+
Type: AlertType(s.Type),
43+
Count: s.Count,
44+
})
45+
}
46+
return &GetAlertsOutput{
47+
Alerts: summaries,
48+
}, nil
49+
}
50+
51+
func (c *standardDashboardClient) GetAlertDetails(ctx context.Context, input *GetAlertDetailsInput) (*GetAlertDetailsOutput, error) {
52+
var out []string
53+
path := fmt.Sprintf("/api/notifications/alerts/%s", input.Type)
54+
_, err := c.baseClient.requestor.Get(ctx, path, &out)
55+
if err != nil {
56+
return nil, err
57+
}
58+
return &GetAlertDetailsOutput{
59+
Type: input.Type,
60+
Entities: out,
61+
}, nil
62+
}
63+
64+
func (c *standardDashboardClient) GetDataProcessed(ctx context.Context, input *GetDataProcessedInput) (*GetDataProcessedOutput, error) {
65+
url := c.parseDashboardFilters("/api/metrics/data-processed", dashboardFilters{
66+
BeginDate: input.BeginDate,
67+
EndDate: input.EndDate,
68+
UserIdentifier: input.UserIdentifier,
69+
AccessKeyPrefix: input.AccessKeyPrefix,
70+
ModelIdentifier: input.ModelIdentifier,
71+
TeamIdentifier: input.TeamIdentifier,
72+
})
73+
74+
var out GetDataProcessedOutput
75+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
return &out, nil
81+
}
82+
83+
func (c *standardDashboardClient) GetPredictionsMade(ctx context.Context, input *GetPredictionsMadeInput) (*GetPredictionsMadeOutput, error) {
84+
url := c.parseDashboardFilters("/api/metrics/predictions-made", dashboardFilters{
85+
BeginDate: input.BeginDate,
86+
EndDate: input.EndDate,
87+
UserIdentifier: input.UserIdentifier,
88+
AccessKeyPrefix: input.AccessKeyPrefix,
89+
ModelIdentifier: input.ModelIdentifier,
90+
TeamIdentifier: input.TeamIdentifier,
91+
})
92+
93+
var out GetPredictionsMadeOutput
94+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
95+
if err != nil {
96+
return nil, err
97+
}
98+
99+
return &out, nil
100+
}
101+
102+
func (c *standardDashboardClient) GetActiveUsers(ctx context.Context, input *GetActiveUsersInput) (*GetActiveUsersOutput, error) {
103+
url := c.parseDashboardFilters("/api/metrics/active-users", dashboardFilters{
104+
BeginDate: input.BeginDate,
105+
EndDate: input.EndDate,
106+
UserIdentifier: input.UserIdentifier,
107+
AccessKeyPrefix: input.AccessKeyPrefix,
108+
ModelIdentifier: input.ModelIdentifier,
109+
TeamIdentifier: input.TeamIdentifier,
110+
})
111+
112+
var out []model.ActiveUserSummary
113+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
114+
if err != nil {
115+
return nil, err
116+
}
117+
118+
return &GetActiveUsersOutput{
119+
Users: out,
120+
}, nil
121+
}
122+
123+
func (c *standardDashboardClient) GetActiveModels(ctx context.Context, input *GetActiveModelsInput) (*GetActiveModelsOutput, error) {
124+
url := c.parseDashboardFilters("/api/metrics/active-models", dashboardFilters{
125+
BeginDate: input.BeginDate,
126+
EndDate: input.EndDate,
127+
UserIdentifier: input.UserIdentifier,
128+
AccessKeyPrefix: input.AccessKeyPrefix,
129+
ModelIdentifier: input.ModelIdentifier,
130+
TeamIdentifier: input.TeamIdentifier,
131+
})
132+
133+
var out []model.ActiveModelSummary
134+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
135+
if err != nil {
136+
return nil, err
137+
}
138+
139+
return &GetActiveModelsOutput{
140+
Models: out,
141+
}, nil
142+
}
143+
144+
func (c *standardDashboardClient) GetPrometheusMetric(ctx context.Context, input *GetPrometheusMetricInput) (*GetPrometheusMetricOutput, error) {
145+
url := c.parseDashboardFilters(
146+
fmt.Sprintf("/api/metrics/prometheus/%s", input.Metric),
147+
dashboardFilters{
148+
BeginDate: input.BeginDate,
149+
EndDate: input.EndDate,
150+
},
151+
)
152+
153+
var out model.PrometheusResponse
154+
_, err := c.baseClient.requestor.Get(ctx, url, &out)
155+
if err != nil {
156+
return nil, err
157+
}
158+
159+
var parsedValues []PrometheusValue
160+
161+
for _, result := range out.Data.Results {
162+
for _, value := range result.Values {
163+
msg := fmt.Sprintf("%s", value)
164+
msg = strings.TrimPrefix(msg, "[")
165+
msg = strings.TrimSuffix(msg, "]")
166+
msgParts := strings.Split(msg, ",")
167+
168+
if len(msgParts) < 2 {
169+
continue
170+
}
171+
172+
parsedIntTime, err := strconv.ParseInt(strings.TrimSpace(msgParts[0]), 10, 64)
173+
if err != nil {
174+
continue
175+
}
176+
177+
parsedValue := strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(msgParts[1]), `"`), `"`)
178+
parsedValues = append(parsedValues, PrometheusValue{
179+
Time: time.Unix(parsedIntTime, 0),
180+
Value: fmt.Sprintf("%v", parsedValue),
181+
})
182+
}
183+
}
184+
185+
return &GetPrometheusMetricOutput{
186+
Values: parsedValues,
187+
}, nil
188+
}
189+
190+
func (c *standardDashboardClient) parseDashboardFilters(path string, filters dashboardFilters) string {
191+
partialUrl, err := url.Parse(path)
192+
impossible.HandleError(err)
193+
194+
q := partialUrl.Query()
195+
if !filters.BeginDate.IsZero() {
196+
q.Add("begin-date", filters.BeginDate.String())
197+
}
198+
if !filters.EndDate.IsZero() {
199+
q.Add("end-date", filters.EndDate.String())
200+
}
201+
if filters.UserIdentifier != "" {
202+
q.Add("user-identifier", filters.UserIdentifier)
203+
}
204+
if filters.AccessKeyPrefix != "" {
205+
q.Add("access-key", filters.AccessKeyPrefix)
206+
}
207+
if filters.ModelIdentifier != "" {
208+
q.Add("model-identifier", filters.ModelIdentifier)
209+
}
210+
if filters.TeamIdentifier != "" {
211+
q.Add("team-identifier", filters.TeamIdentifier)
212+
}
213+
partialUrl.RawQuery = q.Encode()
214+
return partialUrl.String()
215+
}
216+
217+
type dashboardFilters struct {
218+
BeginDate model.ModzyDate
219+
EndDate model.ModzyDate
220+
UserIdentifier string
221+
AccessKeyPrefix string
222+
ModelIdentifier string
223+
TeamIdentifier string
224+
}

dashboard_client_fake.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package modzy
2+
3+
import (
4+
"context"
5+
)
6+
7+
// DashboardClientFake is meant to help in mocking the DashboardClient interface easily for unit testing.
8+
type DashboardClientFake struct {
9+
GetAlertsFunc func(ctx context.Context, input *GetAlertsInput) (*GetAlertsOutput, error)
10+
GetAlertDetailsFunc func(ctx context.Context, input *GetAlertDetailsInput) (*GetAlertDetailsOutput, error)
11+
GetDataProcessedFunc func(ctx context.Context, input *GetDataProcessedInput) (*GetDataProcessedOutput, error)
12+
GetPredictionsMadeFunc func(ctx context.Context, input *GetPredictionsMadeInput) (*GetPredictionsMadeOutput, error)
13+
GetActiveUsersFunc func(ctx context.Context, input *GetActiveUsersInput) (*GetActiveUsersOutput, error)
14+
GetActiveModelsFunc func(ctx context.Context, input *GetActiveModelsInput) (*GetActiveModelsOutput, error)
15+
GetPrometheusMetricFunc func(ctx context.Context, input *GetPrometheusMetricInput) (*GetPrometheusMetricOutput, error)
16+
}
17+
18+
var _ DashboardClient = &DashboardClientFake{}
19+
20+
func (c *DashboardClientFake) GetAlerts(ctx context.Context, input *GetAlertsInput) (*GetAlertsOutput, error) {
21+
return c.GetAlertsFunc(ctx, input)
22+
}
23+
24+
func (c *DashboardClientFake) GetAlertDetails(ctx context.Context, input *GetAlertDetailsInput) (*GetAlertDetailsOutput, error) {
25+
return c.GetAlertDetailsFunc(ctx, input)
26+
}
27+
28+
func (c *DashboardClientFake) GetDataProcessed(ctx context.Context, input *GetDataProcessedInput) (*GetDataProcessedOutput, error) {
29+
return c.GetDataProcessedFunc(ctx, input)
30+
}
31+
32+
func (c *DashboardClientFake) GetPredictionsMade(ctx context.Context, input *GetPredictionsMadeInput) (*GetPredictionsMadeOutput, error) {
33+
return c.GetPredictionsMadeFunc(ctx, input)
34+
}
35+
36+
func (c *DashboardClientFake) GetActiveUsers(ctx context.Context, input *GetActiveUsersInput) (*GetActiveUsersOutput, error) {
37+
return c.GetActiveUsersFunc(ctx, input)
38+
}
39+
40+
func (c *DashboardClientFake) GetActiveModels(ctx context.Context, input *GetActiveModelsInput) (*GetActiveModelsOutput, error) {
41+
return c.GetActiveModelsFunc(ctx, input)
42+
}
43+
44+
func (c *DashboardClientFake) GetPrometheusMetric(ctx context.Context, input *GetPrometheusMetricInput) (*GetPrometheusMetricOutput, error) {
45+
return c.GetPrometheusMetricFunc(ctx, input)
46+
}

0 commit comments

Comments
 (0)