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

Adds Prometheus Remote Write #388

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
43 changes: 43 additions & 0 deletions BACKENDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,46 @@ Additional options are available to rename attributes if required.
timer-sum = "samples_sum"
timer-sumsquare = "samples_sum_squares"
```

Prometheus Remote Writer Backend
--------------------------------
The `promremotewriter` backend supports sending metrics to a Prometheus Remote Writer compatible backend. It currently
drops events. At present there is no authentication supported.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should be expected with dropped events?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prometheus doesn't do events, they need to be managed by something external (ie, grafana). So that will probably end up as a grafana-events backend which drops metrics or something. Haven't really thought about it too hard.


### Settings
The following settings apply to all versions:
- `api-endpoint`: the API endpoint to use, should include the full path. Required with No default.
- `max-request-elapsed-time`: the maximum amount of time to retry before giving up and dropping data, defaults to `15s`
- `max-requests`: the maximum number of parallel requests. This is primarily network I/O, with very little CPU, it
should be capped if it is overwhelming the remote server. Defaults to 10 times the number of logical cores.
- `metrics-per-batch`: the number of metrics to send per request. Defaults to `1000`.
- `transport`: the HTTP transport to use, see [TRANSPORT.md](TRANSPORT.md) for further information.
- `user-agent`: configures the user-agent, defaults to `gostatsd`

##### Example configuration
```toml
[promremotewriter]
api-endpoint='https://prometheus.local/'
max-request-elapsed-time='15s'
max-requests=20
metrics-per-batch=7500
transport='default'
```

### Tag normalization
As the dogstatsd protocol doesn't have exact parity with Prometheus Remote Write protocol, there is some cleanup
applied to the tags before sending them. Specifically:
- tags with only a value (`value`) are normalized as `unnamed:value`
- tags with an empty key (`:value`) are normalized as `unnamed:value`
- tags with an empty value (`key:`) are normalized as `key:__unset__`
- multiple values for duplicate keys are sorted
- keys with multiple values have their values concatenated with `__`
- metric and label names have invalid characters replaced with `_`

For example, given the tags `foo, key:bar, unnamed:baz, key:thing, other:something`, the result will be normalized
as `key=bar__thing,other=something,unnamed=baz__foo`.


### Events
Events are dropped, as Prometheus Remote Write doesn't support them. A Grafana specific events backend may be added
to fill this gap at some point.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
29.1.0
------
- Initial Prometheus Remote Write support added

29.0.2
------
- New Relic backend handles infinities and NaN better
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change part of this change set?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it was an "unreleased" change in 29.0.2, this just documents when the behavior went in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No wokkas

- Update to Alpine 3.14.1

29.0.1
Expand Down
39 changes: 22 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,23 @@ setup-ci: tools/bin/protoc
build-cluster: fmt
go build -i -v -o build/bin/$(ARCH)/cluster $(GOBUILD_VERSION_ARGS) $(CLUSTER_PKG)

pb/remote_write.pb.go: pb/remote_write.proto
go build -o protoc-gen-go github.com/golang/protobuf/protoc-gen-go/ && \
tools/bin/protoc --go_out=. $< && \
rm protoc-gen-go

pb/gostatsd.pb.go: pb/gostatsd.proto
go build -o protoc-gen-go github.com/golang/protobuf/protoc-gen-go/ && \
tools/bin/protoc --go_out=. $< && \
rm protoc-gen-go

build: pb/gostatsd.pb.go fmt
build: pb/gostatsd.pb.go pb/remote_write.pb.go fmt
go build -i -v -o build/bin/$(ARCH)/$(BINARY_NAME) $(GOBUILD_VERSION_ARGS) $(MAIN_PKG)

build-race: fmt
go build -i -v -race -o build/bin/$(ARCH)/$(BINARY_NAME) $(GOBUILD_VERSION_ARGS) $(MAIN_PKG)

build-all: pb/gostatsd.pb.go
build-all: pb/gostatsd.pb.go pb/remote_write.pb.go
go install -v ./...

test-all: fmt cover test-race bench bench-race check
Expand All @@ -56,49 +61,49 @@ fmt:
gofmt -w=true -s $$(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./pb/*")
goimports -w=true -d -local github.com/atlassian/gostatsd $$(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./pb/*")

test-full: pb/gostatsd.pb.go
test-full: pb/gostatsd.pb.go pb/remote_write.pb.go
go test ./...

test-race-full: pb/gostatsd.pb.go
test-race-full: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -race ./...

bench-full: pb/gostatsd.pb.go
bench-full: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -bench=. -run=XXX ./...

bench-race-full: pb/gostatsd.pb.go
bench-race-full: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -race -bench=. -run=XXX ./...

test: pb/gostatsd.pb.go
test: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -short ./...

test-race: pb/gostatsd.pb.go
test-race: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -short -race ./...

bench: pb/gostatsd.pb.go
bench: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -short -bench=. -run=XXX ./...

bench-race: pb/gostatsd.pb.go
bench-race: pb/gostatsd.pb.go pb/remote_write.pb.go
go test -short -race -bench=. -run=XXX ./...

cover: pb/gostatsd.pb.go
cover: pb/gostatsd.pb.go pb/remote_write.pb.go
./cover.sh
go tool cover -func=coverage.out
go tool cover -html=coverage.out

coveralls: pb/gostatsd.pb.go
coveralls: pb/gostatsd.pb.go pb/remote_write.pb.go
./cover.sh
goveralls -coverprofile=coverage.out -service=travis-ci

junit-test: build
go test -short -v ./... | go-junit-report > test-report.xml

check: pb/gostatsd.pb.go
check: pb/gostatsd.pb.go pb/remote_write.pb.go
go install ./cmd/gostatsd
go install ./cmd/tester
golangci-lint run --deadline=600s --enable=gocyclo --enable=dupl \
--disable=interfacer --disable=golint

check-all: pb/gostatsd.pb.go
check-all: pb/gostatsd.pb.go pb/remote_write.pb.go
go install ./cmd/gostatsd
go install ./cmd/tester
golangci-lint run --deadline=600s --enable=gocyclo --enable=dupl
Expand All @@ -117,7 +122,7 @@ git-hook:
cp dev/push-hook.sh .git/hooks/pre-push

# Compile a static binary. Cannot be used with -race
docker: pb/gostatsd.pb.go
docker: pb/gostatsd.pb.go pb/remote_write.pb.go
docker pull golang:$(GOVERSION)
docker run \
--rm \
Expand All @@ -130,7 +135,7 @@ docker: pb/gostatsd.pb.go
docker build --pull -t $(IMAGE_NAME):$(GIT_HASH) build

# Compile a binary with -race. Needs to be run on a glibc-based system.
docker-race: pb/gostatsd.pb.go
docker-race: pb/gostatsd.pb.go pb/remote_write.pb.go
docker pull golang:$(GOVERSION)
docker run \
--rm \
Expand All @@ -142,7 +147,7 @@ docker-race: pb/gostatsd.pb.go
docker build --pull -t $(IMAGE_NAME):$(GIT_HASH)-race -f build/Dockerfile-glibc build

# Compile a static binary with symbols. Cannot be used with -race
docker-symbols: pb/gostatsd.pb.go
docker-symbols: pb/gostatsd.pb.go pb/remote_write.pb.go
docker pull golang:$(GOVERSION)
docker run \
--rm \
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/githubnemo/CompileDaemon v1.0.0
github.com/go-redis/redis v6.15.7+incompatible
github.com/golang/protobuf v1.3.3
github.com/golang/snappy v0.0.4
github.com/golangci/golangci-lint v1.23.3
github.com/gorilla/mux v1.7.3
github.com/howeyc/fsnotify v0.9.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
Expand Down
10 changes: 1 addition & 9 deletions internal/lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestMetricsLexer(t *testing.T) {
"a:1|g|#": {Name: "a", Value: 1, Type: gostatsd.GAUGE, Rate: 1.0},
"a:1|g|#,": {Name: "a", Value: 1, Type: gostatsd.GAUGE, Rate: 1.0},
"a:1|g|#,,": {Name: "a", Value: 1, Type: gostatsd.GAUGE, Rate: 1.0},
"foo:10|g|#a:b,c:,:d": {Name: "foo", Value: 10, Type: gostatsd.GAUGE, Rate: 1.0, Tags: gostatsd.Tags{"a:b", "c:", ":d"}},
}

compareMetric(t, tests, "")
Expand All @@ -55,15 +56,6 @@ func TestInvalidMetricsLexer(t *testing.T) {
assert.Error(t, err, result)
})
}

tests := map[string]gostatsd.Metric{
"foo.bar.baz:2|c": {Name: "stats.foo.bar.baz", Value: 2, Type: gostatsd.COUNTER, Rate: 1.0},
"abc.def.g:3|g": {Name: "stats.abc.def.g", Value: 3, Type: gostatsd.GAUGE, Rate: 1.0},
"def.g:10|ms": {Name: "stats.def.g", Value: 10, Type: gostatsd.TIMER, Rate: 1.0},
"uniq.usr:joe|s": {Name: "stats.uniq.usr", StringValue: "joe", Type: gostatsd.SET, Rate: 1.0},
}

compareMetric(t, tests, "stats")
}

func TestEventsLexer(t *testing.T) {
Expand Down
Loading