Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make formatters functions internal #126

Merged
merged 1 commit into from
Dec 16, 2022
Merged
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
109 changes: 109 additions & 0 deletions internal/event/formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package event

import (
"encoding/json"
"fmt"
"github.com/wavefronthq/wavefront-sdk-go/event"
"github.com/wavefronthq/wavefront-sdk-go/internal"
"strconv"
)

// Line encode the event to a wf proxy format
// set endMillis to 0 for a 'Instantaneous' event
func Line(name string, startMillis, endMillis int64, source string, tags map[string]string, setters ...event.Option) (string, error) {
sb := internal.GetBuffer()
defer internal.PutBuffer(sb)

annotations := map[string]string{}
l := map[string]interface{}{
"annotations": annotations,
}
for _, set := range setters {
set(l)
}

sb.WriteString("@Event")

startMillis, endMillis = adjustStartEndTime(startMillis, endMillis)

sb.WriteString(" ")
sb.WriteString(strconv.FormatInt(startMillis, 10))
sb.WriteString(" ")
sb.WriteString(strconv.FormatInt(endMillis, 10))

sb.WriteString(" ")
sb.WriteString(strconv.Quote(name))

for k, v := range annotations {
sb.WriteString(" ")
sb.WriteString(k)
sb.WriteString("=")
sb.WriteString(strconv.Quote(v))
}

if len(source) > 0 {
sb.WriteString(" host=")
sb.WriteString(strconv.Quote(source))
}

for k, v := range tags {
sb.WriteString(" tag=")
sb.WriteString(strconv.Quote(fmt.Sprintf("%v: %v", k, v)))
}

sb.WriteString("\n")
return sb.String(), nil
}

// LineJSON encodes the event to a wf API format
func LineJSON(name string, startMillis, endMillis int64, source string, tags map[string]string, setters ...event.Option) (string, error) {
annotations := map[string]string{}
l := map[string]interface{}{
"name": name,
"annotations": annotations,
}

for _, set := range setters {
set(l)
}

startMillis, endMillis = adjustStartEndTime(startMillis, endMillis)

l["startTime"] = startMillis
l["endTime"] = endMillis

if len(tags) > 0 {
var tagList []string
for k, v := range tags {
tagList = append(tagList, fmt.Sprintf("%v: %v", k, v))
}
l["tags"] = tagList
}

if len(source) > 0 {
l["hosts"] = []string{source}
}

jsonData, err := json.Marshal(l)
if err != nil {
return "", err
}

return string(jsonData), nil
}

func adjustStartEndTime(startMillis, endMillis int64) (int64, int64) {
// secs to millis
if startMillis < 999999999999 {
startMillis = startMillis * 1000
}

if endMillis <= 999999999999 {
endMillis = endMillis * 1000
}

if endMillis == 0 {
endMillis = startMillis + 1
}
return startMillis, endMillis
}
71 changes: 71 additions & 0 deletions internal/histogram/formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package histogram

import (
"bytes"
"errors"
"fmt"
"github.com/wavefronthq/wavefront-sdk-go/histogram"
"github.com/wavefronthq/wavefront-sdk-go/internal"
"strconv"
)

// Gets a histogram line in the Wavefront histogram data format:
// {!M | !H | !D} [<timestamp>] #<count> <mean> [centroids] <histogramName> source=<source> [pointTags]
// Example: "!M 1533531013 #20 30.0 #10 5.1 request.latency source=appServer1 region=us-west"
func HistogramLine(name string, centroids histogram.Centroids, hgs map[histogram.Granularity]bool, ts int64, source string, tags map[string]string, defaultSource string) (string, error) {
if name == "" {
return "", errors.New("empty distribution name")
}

if len(centroids) == 0 {
return "", fmt.Errorf("distribution should have at least one centroid: histogram=%s", name)
}

if len(hgs) == 0 {
return "", fmt.Errorf("histogram granularities cannot be empty: histogram=%s", name)
}

if source == "" {
source = defaultSource
}

sb := internal.GetBuffer()
defer internal.PutBuffer(sb)

if ts != 0 {
sb.WriteString(" ")
sb.WriteString(strconv.FormatInt(ts, 10))
}
// Preprocess line. We know len(hgs) > 0 here.
for _, centroid := range centroids.Compact() {
sb.WriteString(" #")
sb.WriteString(strconv.Itoa(centroid.Count))
sb.WriteString(" ")
sb.WriteString(strconv.FormatFloat(centroid.Value, 'f', -1, 64))
}
sb.WriteString(" ")
sb.WriteString(strconv.Quote(internal.Sanitize(name)))
sb.WriteString(" source=")
sb.WriteString(internal.SanitizeValue(source))

for k, v := range tags {
if v == "" {
return "", fmt.Errorf("tag values cannot be empty: histogram=%s tag=%s", name, k)
}
sb.WriteString(" ")
sb.WriteString(strconv.Quote(internal.Sanitize(k)))
sb.WriteString("=")
sb.WriteString(internal.SanitizeValue(v))
}
sbBytes := sb.Bytes()

sbg := bytes.Buffer{}
for hg, on := range hgs {
if on {
sbg.WriteString(hg.String())
sbg.Write(sbBytes)
sbg.WriteString("\n")
}
}
return sbg.String(), nil
}
99 changes: 99 additions & 0 deletions internal/histogram/formatter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package histogram

import (
"github.com/stretchr/testify/assert"
"github.com/wavefronthq/wavefront-sdk-go/histogram"
"testing"
)

var line string

func BenchmarkHistogramLine(b *testing.B) {
name := "request.latency"
centroids := makeCentroids()
hgs := map[histogram.Granularity]bool{histogram.MINUTE: true}
ts := int64(1533529977)
src := "test_source"
tags := map[string]string{"env": "test"}

var r string
for n := 0; n < b.N; n++ {
r, _ = HistogramLine(name, centroids, hgs, ts, src, tags, "")
}
line = r
}

func TestHistogramLineCentroidsFormat(t *testing.T) {
centroids := histogram.Centroids{
{Value: 30.0, Count: 20},
{Value: 5.1, Count: 10},
{Value: 30.0, Count: 20},
{Value: 5.1, Count: 10},
{Value: 30.0, Count: 20},
}

line, err := HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.MINUTE: true},
1533529977, "test_source", map[string]string{"env": "test"}, "")

assert.Nil(t, err)
expected := []string{
"!M 1533529977 #60 30 #20 5.1 \"request.latency\" source=\"test_source\" \"env\"=\"test\"\n",
"!M 1533529977 #20 5.1 #60 30 \"request.latency\" source=\"test_source\" \"env\"=\"test\"\n",
}
ok := false
for _, exp := range expected {
if assert.ObjectsAreEqual(exp, line) {
ok = true
}
}
if !ok {
assert.Equal(t, expected[0], line)
assert.Equal(t, expected[1], line)
}
}

func TestHistogramLine(t *testing.T) {
centroids := makeCentroids()

line, err := HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.MINUTE: true},
1533529977, "test_source", map[string]string{"env": "test"}, "")
expected := "!M 1533529977 #20 30 \"request.latency\" source=\"test_source\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.MINUTE: true, histogram.HOUR: false},
1533529977, "", map[string]string{"env": "test"}, "default")
expected = "!M 1533529977 #20 30 \"request.latency\" source=\"default\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.HOUR: true, histogram.MINUTE: false},
1533529977, "", map[string]string{"env": "test"}, "default")
expected = "!H 1533529977 #20 30 \"request.latency\" source=\"default\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.DAY: true},
1533529977, "", map[string]string{"env": "test"}, "default")
expected = "!D 1533529977 #20 30 \"request.latency\" source=\"default\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = HistogramLine("request.latency", centroids, map[histogram.Granularity]bool{histogram.MINUTE: true, histogram.HOUR: true, histogram.DAY: false},
1533529977, "test_source", map[string]string{"env": "test"}, "")
expected = "!M 1533529977 #20 30 \"request.latency\" source=\"test_source\" \"env\"=\"test\"\n" +
"!H 1533529977 #20 30 \"request.latency\" source=\"test_source\" \"env\"=\"test\"\n"
if len(line) != len(expected) {
t.Errorf("lines don't match. expected: %s, actual: %s", expected, line)
}
}

func makeCentroids() []histogram.Centroid {
centroids := []histogram.Centroid{
{
Value: 30.0,
Count: 20,
},
}
return centroids
}
48 changes: 48 additions & 0 deletions internal/metric/formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package metric

import (
"errors"
"fmt"
"github.com/wavefronthq/wavefront-sdk-go/internal"
"strconv"
)

// Gets a metric line in the Wavefront metrics data format:
// <metricName> <metricValue> [<timestamp>] source=<source> [pointTags]
// Example: "new-york.power.usage 42422.0 1533531013 source=localhost datacenter=dc1"
func Line(name string, value float64, ts int64, source string, tags map[string]string, defaultSource string) (string, error) {
if name == "" {
return "", errors.New("empty metric name")
}

if source == "" {
source = defaultSource
}

sb := internal.GetBuffer()
defer internal.PutBuffer(sb)

sb.WriteString(strconv.Quote(internal.Sanitize(name)))
sb.WriteString(" ")
sb.WriteString(strconv.FormatFloat(value, 'f', -1, 64))

if ts != 0 {
sb.WriteString(" ")
sb.WriteString(strconv.FormatInt(ts, 10))
}

sb.WriteString(" source=")
sb.WriteString(internal.SanitizeValue(source))

for k, v := range tags {
if v == "" {
return "", fmt.Errorf("tag values cannot be empty: metric=%s tag=%s", name, k)
}
sb.WriteString(" ")
sb.WriteString(strconv.Quote(internal.Sanitize(k)))
sb.WriteString("=")
sb.WriteString(internal.SanitizeValue(v))
}
sb.WriteString("\n")
return sb.String(), nil
}
42 changes: 42 additions & 0 deletions internal/metric/formatter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package metric

import (
"github.com/stretchr/testify/assert"
"testing"
)

var line string

func BenchmarkMetricLine(b *testing.B) {
name := "foo.metric"
value := 1.2
ts := int64(1533529977)
src := "test_source"
tags := map[string]string{"env": "test"}

var r string
for n := 0; n < b.N; n++ {
r, _ = Line(name, value, ts, src, tags, "")
}
line = r
}

func TestMetricLine(t *testing.T) {
line, err := Line("foo.metric", 1.2, 1533529977, "test_source",
map[string]string{"env": "test"}, "")
expected := "\"foo.metric\" 1.2 1533529977 source=\"test_source\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = Line("foo.metric", 1.2, 1533529977, "",
map[string]string{"env": "test"}, "default")
expected = "\"foo.metric\" 1.2 1533529977 source=\"default\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)

line, err = Line("foo.metric", 1.2, 1533529977, "1.2.3.4:8080",
map[string]string{"env": "test"}, "default")
expected = "\"foo.metric\" 1.2 1533529977 source=\"1.2.3.4:8080\" \"env\"=\"test\"\n"
assert.Nil(t, err)
assert.Equal(t, expected, line)
}
Loading