Skip to content

Commit

Permalink
Add GetMetrics() (#1504)
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Cha <[email protected]>
  • Loading branch information
Alan-Cha authored Jun 23, 2023
1 parent a07b26c commit 6a9bde9
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
81 changes: 81 additions & 0 deletions controllers/storageclient/badgerdb/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,87 @@ func (cl Client) GetSummaryMetrics(applicationName string, version int, signatur
return &vms, nil
}

// GetMetrics returns a nested map of the metrics data
// Example:
//
// {
// "my-app": {
// "0": {
// "my-signature": {
// "my-metric": {
// "my-user": {
// "my-transaction-id": 5.0
// }
// }
// }
// }
// }
// }
func (cl Client) GetMetrics() (map[string]map[string]map[string]map[string]map[string]map[string]float64, error) {
metrics := map[string]map[string]map[string]map[string]map[string]map[string]float64{}

err := cl.db.View(func(txn *badger.Txn) error {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
prefix := []byte("kt-metric")
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
key := string(item.Key())

tokens := strings.Split(key, "::")
if len(tokens) != 7 {
return fmt.Errorf("incorrect number of tokens in metrics key: \"%s\": should be 7 (example: kt-metric::my-app::0::my-signature::my-metric::my-user::my-transaction-id)", key)
}
app := tokens[1]
version := tokens[2]
signature := tokens[3]
metric := tokens[4]
user := tokens[5]
transaction := tokens[6]

if _, ok := metrics[app]; !ok {
metrics[app] = map[string]map[string]map[string]map[string]map[string]float64{}
}

if _, ok := metrics[app][version]; !ok {
metrics[app][version] = map[string]map[string]map[string]map[string]float64{}
}

if _, ok := metrics[app][version][signature]; !ok {
metrics[app][version][signature] = map[string]map[string]map[string]float64{}
}

if _, ok := metrics[app][version][signature][metric]; !ok {
metrics[app][version][signature][metric] = map[string]map[string]float64{}
}

if _, ok := metrics[app][version][signature][metric][user]; !ok {
metrics[app][version][signature][metric][user] = map[string]float64{}
}

err := item.Value(func(v []byte) error {
floatValue, err := strconv.ParseFloat(string(v), 64)
if err != nil {
return err
}

// TODO: check if there is a preexisting transaction ID?
metrics[app][version][signature][metric][user][transaction] = floatValue
return nil
})
if err != nil {
return err
}
}
return nil
})
if err != nil {
return nil, err
}

return metrics, nil
}

// calculateSummarizedMetric calculates a metric summary for a particular collection of data
func calculateSummarizedMetric(data []float64) storageclient.SummarizedMetric {
if len(data) == 0 {
Expand Down
26 changes: 26 additions & 0 deletions controllers/storageclient/badgerdb/simple_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package badgerdb

import (
"encoding/json"
"strconv"
"testing"

Expand Down Expand Up @@ -205,3 +206,28 @@ func TestGetSummaryMetrics(t *testing.T) {
assert.Equal(t, 2.0, vms.MetricSummaries[metric].SummaryOverUsers.Min)
assert.Equal(t, 70.0, vms.MetricSummaries[metric].SummaryOverUsers.Max)
}

func TestGetMetrics(t *testing.T) {
tempDirPath := t.TempDir()

client, err := GetClient(badger.DefaultOptions(tempDirPath), AdditionalOptions{})
assert.NoError(t, err)

err = client.SetMetric("my-application", 0, "my-signature", "my-metric", "my-user", "my-transaction", 50.0)
assert.NoError(t, err)
err = client.SetMetric("my-application", 0, "my-signature", "my-metric", "my-user2", "my-transaction2", 10.0)
assert.NoError(t, err)
err = client.SetMetric("my-application", 1, "my-signature2", "my-metric2", "my-user", "my-transaction3", 20.0)
assert.NoError(t, err)
err = client.SetMetric("my-application", 2, "my-signature3", "my-metric3", "my-user2", "my-transaction4", 30.0)
assert.NoError(t, err)
err = client.SetMetric("my-application", 2, "my-signature3", "my-metric3", "my-user2", "my-transaction4", 40.0) // overwrites the previous set
assert.NoError(t, err)

metrics, err := client.GetMetrics()
assert.NoError(t, err)

jsonMetrics, err := json.Marshal(metrics)
assert.NoError(t, err)
assert.Equal(t, "{\"my-application\":{\"0\":{\"my-signature\":{\"my-metric\":{\"my-user\":{\"my-transaction\":50},\"my-user2\":{\"my-transaction2\":10}}}},\"1\":{\"my-signature2\":{\"my-metric2\":{\"my-user\":{\"my-transaction3\":20}}}},\"2\":{\"my-signature3\":{\"my-metric3\":{\"my-user2\":{\"my-transaction4\":40}}}}}}", string(jsonMetrics))
}
17 changes: 17 additions & 0 deletions controllers/storageclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ type VersionMetricSummary struct {
type Interface interface {
GetSummaryMetrics(applicationName string, version int, signature string) (*VersionMetricSummary, error)

// Returns a nested map of the metrics data
// Example:
// {
// "my-app": {
// "0": {
// "my-signature": {
// "my-metric": {
// "my-user": {
// "my-transaction-id": 5.0
// }
// }
// }
// }
// }
// }
GetMetrics() (map[string]map[string]map[string]map[string]map[string]map[string]float64, error)

// called by the A/B/n SDK gRPC API implementation (SDK for application clients)
// Example key: kt-metric::my-app::0::my-signature::my-metric::my-user::my-transaction-id -> my-metric-value (get the metric value with all the provided information)
SetMetric(applicationName string, version int, signature, metric, user, transaction string, metricValue float64) error
Expand Down

0 comments on commit 6a9bde9

Please sign in to comment.