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

engine: report go version on startup #159

Merged
merged 2 commits into from
Dec 17, 2024
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
1 change: 0 additions & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ jobs:
lint:
name: lint
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/setup-go@v5
with:
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
test:
go test -trimpath ./...

ci:
go test -race -trimpath ./...

lint:
golangci-lint run --config .golangci.yml
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Monitoring

> 🚧 Go metrics reported with the `procstats` package were previously tagged with a
> `version` label that reported the Go runtime version. This label was renamed to
> `go_version` in v5.6.0.
> `go_version` in v4.6.0.

The
[github.com/segmentio/stats/procstats](https://godoc.org/github.com/segmentio/stats/procstats)
Expand Down Expand Up @@ -385,3 +385,16 @@ func main() {
// ...
}
```

### Addendum

By default, the stats library will report the running go version when you
invoke NewEngine() as a metric:

- `go_version` with value 1 and a `tag` set to the current version.
- `stats_version` with value ` and a `tag` set to the tag value of
segmentio/stats.

Set `STATS_DISABLE_GO_VERSION_REPORTING` to `true` in your environment, or set
`stats.GoVersionReportingEnabled` to `false` before collecting any metrics, to
disable this behavior.
2 changes: 1 addition & 1 deletion cmd/dogstatsd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"strings"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/datadog"
)

Expand Down
2 changes: 1 addition & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

// ContextWithTags returns a new child context with the given tags. If the
// parent context already has tags set on it, they are _not_ propegated into
// parent context already has tags set on it, they are _not_ propagated into
// the context children.
func ContextWithTags(ctx context.Context, tags ...Tag) context.Context {
// initialize the context reference and return a new context
Expand Down
2 changes: 1 addition & 1 deletion datadog/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"strconv"
"strings"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

func appendMetric(b []byte, m Metric) []byte {
Expand Down
2 changes: 1 addition & 1 deletion datadog/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"

"golang.org/x/sys/unix"
)
Expand Down
2 changes: 1 addition & 1 deletion datadog/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"testing"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"

"github.com/stretchr/testify/assert"
)
Expand Down
2 changes: 1 addition & 1 deletion datadog/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package datadog
import (
"fmt"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// EventPriority is an enumeration providing the available datadog event
Expand Down
2 changes: 1 addition & 1 deletion datadog/event_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package datadog

import (
"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

var testEvents = []struct {
Expand Down
2 changes: 1 addition & 1 deletion datadog/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"sync"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// MetricType is an enumeration providing symbols to represent the different
Expand Down
2 changes: 1 addition & 1 deletion datadog/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package datadog
import (
"testing"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

var testMetrics = []struct {
Expand Down
2 changes: 1 addition & 1 deletion datadog/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strconv"
"strings"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// Adapted from https://github.com/DataDog/datadog-agent/blob/6789e98a1e41e98700fa1783df62238bb23cb454/pkg/dogstatsd/parser.go#L141
Expand Down
2 changes: 1 addition & 1 deletion datadog/serializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strings"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// Datagram format: https://docs.datadoghq.com/developers/dogstatsd/datagram_shell
Expand Down
2 changes: 1 addition & 1 deletion datadog/serializer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

var testMeasures = []struct {
Expand Down
6 changes: 5 additions & 1 deletion datadog/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import (
"testing"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

func TestServer(t *testing.T) {
initValue := stats.GoVersionReportingEnabled
stats.GoVersionReportingEnabled = false
defer func() { stats.GoVersionReportingEnabled = initValue }()
engine := stats.NewEngine("datadog.test", nil)

a := uint32(0)
Expand Down Expand Up @@ -97,6 +100,7 @@ func TestServer(t *testing.T) {
}

func startUDPTestServer(t *testing.T, handler Handler) (addr string, closer io.Closer) {
t.Helper()
conn, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Error(err)
Expand Down
60 changes: 56 additions & 4 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import (
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"sync"
"time"

"github.com/segmentio/stats/v5/version"
)

// An Engine carries the context for producing metrics, it is configured by
// An Engine carries the context for producing metrics. It is configured by
// setting the exported fields or using the helper methods to create sub-engines
// that inherit the configuration of the base they were created from.
//
// The program must not modify the engine's handler, prefix, or tags after it
// started using it. If changes need to be made new engines must be created by
// starts using them. If changes need to be made new engines must be created by
// calls to WithPrefix or WithTags.
type Engine struct {
// The measure handler that the engine forwards measures to.
Expand All @@ -26,7 +30,7 @@ type Engine struct {
//
// The list of tags has to be sorted. This is automatically managed by the
// helper methods WithPrefix, WithTags and the NewEngine function. A program
// that manipulates this field directly has to respect this requirement.
// that manipulates this field directly must respect this requirement.
Tags []Tag

// Indicates whether to allow duplicated tags from the tags list before sending.
Expand All @@ -41,16 +45,19 @@ type Engine struct {
// The cached values include the engine prefix in the measure names, which
// is why the cache must be local to the engine.
cache measureCache

once sync.Once
}

// NewEngine creates and returns a new engine configured with prefix, handler,
// and tags.
func NewEngine(prefix string, handler Handler, tags ...Tag) *Engine {
return &Engine{
e := &Engine{
Handler: handler,
Prefix: prefix,
Tags: SortTags(copyTags(tags)),
}
return e
}

// Register adds handler to eng.
Expand Down Expand Up @@ -144,7 +151,52 @@ func (eng *Engine) ClockAt(name string, start time.Time, tags ...Tag) *Clock {
}
}

var truthyValues = map[string]bool{
"true": true,
"TRUE": true,
"yes": true,
"1": true,
"on": true,
}

var GoVersionReportingEnabled = !truthyValues[os.Getenv("STATS_DISABLE_GO_VERSION_REPORTING")]

func (eng *Engine) measure(t time.Time, name string, value interface{}, ftype FieldType, tags ...Tag) {
if GoVersionReportingEnabled {
eng.once.Do(func() {
vsn := strings.TrimPrefix(runtime.Version(), "go")
parts := strings.Split(vsn, ".")
// this filters out weird compiled Go versions like tip. len(parts)
// may equal 2 because older Go version might be "go1.13"
if len(parts) == 2 || len(parts) == 3 {
eng.Handler.HandleMeasures(t, Measure{
Name: "go_version",
Fields: []Field{{
Name: "go_version",
Value: intValue(1),
}},
Tags: []Tag{
{"go_version", vsn},
},
},
Measure{
Name: "stats_version",
Fields: []Field{{
Name: "stats_version",
Value: intValue(1),
}},
Tags: []Tag{
{"stats_version", version.Version},
},
},
)
}
})
}
eng.measureOne(t, name, value, ftype, tags...)
}

func (eng *Engine) measureOne(t time.Time, name string, value interface{}, ftype FieldType, tags ...Tag) {
name, field := splitMeasureField(name)
mp := measureArrayPool.Get().(*[1]Measure)

Expand Down
28 changes: 18 additions & 10 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/datadog"
"github.com/segmentio/stats/v5/influxdb"
"github.com/segmentio/stats/v5/prometheus"
Expand Down Expand Up @@ -74,14 +74,21 @@ func TestEngine(t *testing.T) {
},
}

for _, test := range tests {
testFunc := test.function
t.Run(test.scenario, func(t *testing.T) {
t.Parallel()
h := &statstest.Handler{}
testFunc(t, stats.NewEngine("test", h, stats.T("service", "test-service")))
})
}
initValue := stats.GoVersionReportingEnabled
stats.GoVersionReportingEnabled = false
defer func() { stats.GoVersionReportingEnabled = initValue }()
// Extra t.Run is necessary so above defer runs after parallel tests
// complete.
t.Run("subtests", func(t *testing.T) {
for _, test := range tests {
testFunc := test.function
t.Run(test.scenario, func(t *testing.T) {
t.Parallel()
h := &statstest.Handler{}
testFunc(t, stats.NewEngine("test", h, stats.T("service", "test-service")))
})
}
})
}

func testEngineWithPrefix(t *testing.T, eng *stats.Engine) {
Expand Down Expand Up @@ -369,7 +376,8 @@ func BenchmarkEngine(b *testing.B) {
},
}

for _, eng := range engines {
for i := range engines {
eng := &engines[i]
b.Run(eng.name, func(b *testing.B) {
tests := []struct {
scenario string
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ module github.com/segmentio/stats/v5

go 1.22.0

toolchain go1.23.1

require (
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072
github.com/segmentio/fasthash v1.0.3
Expand Down
2 changes: 1 addition & 1 deletion handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/statstest"

"github.com/stretchr/testify/assert"
Expand Down
2 changes: 1 addition & 1 deletion httpstats/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package httpstats
import (
"net/http"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// RequestWithTags returns a shallow copy of req with its context updated to
Expand Down
8 changes: 4 additions & 4 deletions httpstats/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import (
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
stats "github.com/segmentio/stats/v5"

"github.com/segmentio/stats/v5"
"github.com/stretchr/testify/assert"
)

// TestRequestContextTagPropegation verifies that the root ancestor tags are
// TestRequestContextTagPropagation verifies that the root ancestor tags are
// updated in the event the context or request has children. It's nearly
// identical to the context_test in the stats package itself, but we want to
// keep this to ensure that changes to the request context code doesn't drift
// and cause bugs.
func TestRequestContextTagPropegation(t *testing.T) {
func TestRequestContextTagPropagation(t *testing.T) {
// dummy request
x := httptest.NewRequest(http.MethodGet, "http://example.com/blah", nil)

Expand Down
2 changes: 1 addition & 1 deletion httpstats/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"
"time"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
)

// NewHandler wraps h to produce metrics on the default engine for every request
Expand Down
2 changes: 1 addition & 1 deletion httpstats/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
"testing"

"github.com/segmentio/stats/v5"
stats "github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/statstest"
)

Expand Down
Loading
Loading