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

add TCP StatsD listener support #71

Merged
merged 14 commits into from
Aug 1, 2017
Merged

add TCP StatsD listener support #71

merged 14 commits into from
Aug 1, 2017

Conversation

jwfang
Copy link
Contributor

@jwfang jwfang commented Jul 11, 2017

support TCP StatsD, on port 9125

main.go Outdated
listenAddress = flag.String("web.listen-address", ":9102", "The address on which to expose the web interface and generated Prometheus metrics.")
metricsEndpoint = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
statsdListenAddress = flag.String("statsd.listen-address", ":9125", "The UDP address on which to receive statsd metric lines.")
statsdTCPListenAddress = flag.String("statsd.tcp-listen-address", ":9126", "The TCP address on which to receive statsd metric lines.")
Copy link
Member

Choose a reason for hiding this comment

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

I'd rather keep this one flag, so that it listens on the same TCP/UDP port. Also it looks like you have a typo, it's listening on 9126 here.

Copy link
Contributor Author

@jwfang jwfang Jul 11, 2017

Choose a reason for hiding this comment

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

good catch, i fixed it.

i will make this a flag.

@SuperQ
Copy link
Member

SuperQ commented Jul 11, 2017

Instead of making this UDP or TCP, I would just have it listen for both.

@jwfang
Copy link
Contributor Author

jwfang commented Jul 11, 2017

sorry, misunderstand you.

really make more sense to listen on both.

@SuperQ
Copy link
Member

SuperQ commented Jul 11, 2017

No problem, thanks for working on this feature! 😃

main.go Outdated
statsdListenAddress = flag.String("statsd.listen-address", ":9125", "The UDP address on which to receive statsd metric lines.")
statsdListenAddress = flag.String("statsd.listen-address", ":9125", "The UDP/TCP address on which to receive statsd metric lines.")
statsdListenUDP = flag.Bool("statsd.listen-udp", true, "Whether to receive UDP statsd metrics.")
statsdListenTCP = flag.Bool("statsd.listen-tcp", false, "Whether to receive TCP statsd metrics.")
Copy link
Member

Choose a reason for hiding this comment

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

This can be true by default.

exporter.go Outdated
return
}

type StatsDListener struct {
Copy link
Member

Choose a reason for hiding this comment

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

Can we make this StatsDUDPListener for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i thought UDP is primary and TCP is secondary originally.

done rename.

Copy link
Member

@SuperQ SuperQ left a comment

Choose a reason for hiding this comment

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

LGTM

@SuperQ SuperQ requested a review from juliusv July 13, 2017 12:23
@SuperQ SuperQ mentioned this pull request Jul 20, 2017
@SuperQ
Copy link
Member

SuperQ commented Jul 20, 2017

Ping @juliusv Any more comments?


r := bufio.NewReader(c)
for {
line, isPrefix, err := r.ReadLine()
Copy link
Contributor

Choose a reason for hiding this comment

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

ReadBytes (https://golang.org/pkg/bufio/#Reader.ReadBytes) would be a better method to use-- from the docs: ReadLine is a low-level line-reading primitive. Most callers should use ReadBytes('\n') or ReadString('\n') instead or use a Scanner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ReadBytes will read till delimiter or eof, so i think ReadLine is more safe for bogus input with really long line, or no line delimiter at all. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough, LGTM then :) Lets merge it!

if err != nil {
log.Fatalf("AcceptTCP failed: %v", err)
}
go l.handleConn(c, e)
Copy link
Contributor

Choose a reason for hiding this comment

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

Before calling handleconn (or immediately in it) -- we should probably call SetReadBuffer -- to be consistent with UDP

Copy link
Contributor Author

Choose a reason for hiding this comment

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

UDP needs a 64K buffer, since it will recv all data in one packet.
but for TCP, i guess the underlying bufio is manage the buffer for us.

@SuperQ
Copy link
Member

SuperQ commented Jul 22, 2017

@juliusv care to take one last look?

Copy link
Member

@grobie grobie left a comment

Choose a reason for hiding this comment

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

It'd be great to have some tests for this new feature.

exporter.go Outdated
if line == "" {
continue
}
func lineToEvents(line string) (events Events) {
Copy link
Member

Choose a reason for hiding this comment

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

Please remove the named return variable here as it adds stutter to the function signature and use explicit returns below. It's not a go idiom to use naked returns in such long functions.

Named returned values should only be used on public funcs and methods
when it contributes to the documentation.

https://go-review.googlesource.com/c/20024/

exporter.go Outdated
line, isPrefix, err := r.ReadLine()
if err != nil {
if err != io.EOF {
log.Errorf("Read %s failed: %v", c.RemoteAddr(), err)
Copy link
Member

Choose a reason for hiding this comment

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

It'd be cool to have metrics for these errors so that operators can set up alerts on misbehaving clients.

main.go Outdated
@@ -122,34 +138,53 @@ func main() {
os.Exit(0)
}

if !*statsdListenUDP && !*statsdListenTCP {
log.Fatalln("At least one of UDP/TCP listeners should be specified.")
Copy link
Member

Choose a reason for hiding this comment

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

Sounds like a must then.

main.go Outdated
@@ -34,7 +34,9 @@ func init() {
var (
listenAddress = flag.String("web.listen-address", ":9102", "The address on which to expose the web interface and generated Prometheus metrics.")
metricsEndpoint = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
statsdListenAddress = flag.String("statsd.listen-address", ":9125", "The UDP address on which to receive statsd metric lines.")
statsdListenAddress = flag.String("statsd.listen-address", ":9125", "The UDP/TCP address on which to receive statsd metric lines.")
statsdListenUDP = flag.Bool("statsd.listen-udp", true, "Whether to receive UDP statsd metrics.")
Copy link
Member

Choose a reason for hiding this comment

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

Instead of boolean flags and introducing a dependency between flags, it'd be simpler to just have to flags with the addresses for each protocol, like -statsd.listen-address-udp=":9125" -statsd.listen-address-tcp=":9125". An empty value signals disables the server on that protocol.

Copy link
Contributor Author

@jwfang jwfang Jul 24, 2017

Choose a reason for hiding this comment

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

doing it like what you mentioned have two conerns for me:

  1. a bit uncomfortable for setting something to "" to disable it; and since we're default both UDP/TCP to on, use have to explicitly disable it;
  2. the flags changes will break the user interface, from statsd.listen-address to statsd.listen-udp.

i have no strong feeling for 1; and for 2, if that's OK, i will do the flags changes.

EDIT: i think we can also support statsd.listen-address as statsd.listen-udp.

main.go Outdated
log.Infoln("Starting StatsD -> Prometheus Exporter", version.Info())
log.Infoln("Build context", version.BuildContext())
log.Infoln("Accepting StatsD Traffic on", *statsdListenAddress)
log.Infof("Accepting StatsD Traffic on %s, UDP %v, TCP %v", *statsdListenAddress, *statsdListenUDP, *statsdListenTCP)
Copy link
Member

Choose a reason for hiding this comment

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

That's not longer printing the address it's listening on, but true/false, but would be fixed with the comment above.

@jwfang
Copy link
Contributor Author

jwfang commented Jul 24, 2017

@grobie thanks for your reivew, addressed most of your comments except for the test for TCPListener.

can't find some easy way to mock the TCPConnection. maybe we can make a
func (l *StatsDTCPListener) handleConn(r *io.Reader, e chan<- Events)
but that made the stats/logging a bit awkward. :(

@grobie
Copy link
Member

grobie commented Jul 24, 2017

can't find some easy way to mock the TCPConnection

I'd say, then don't mock for now and just start the server, send it a statsd line via TCP and check that it was ingested properly (by looking at the exported metrics).

@jwfang
Copy link
Contributor Author

jwfang commented Jul 26, 2017

@grobie add test for TCP listener in the same place as UDP except benchmarks.

@grobie grobie merged commit 07543ac into prometheus:master Aug 1, 2017
@grobie
Copy link
Member

grobie commented Aug 1, 2017

Thanks a lot for your contribution @jwfang!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants