-
Notifications
You must be signed in to change notification settings - Fork 233
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
Conversation
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.") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Instead of making this UDP or TCP, I would just have it listen for both. |
sorry, misunderstand you. really make more sense to listen on both. |
This reverts commit 4108c77.
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.") |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Ping @juliusv Any more comments? |
|
||
r := bufio.NewReader(c) | ||
for { | ||
line, isPrefix, err := r.ReadLine() |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. :)
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
@juliusv care to take one last look? |
There was a problem hiding this 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) { |
There was a problem hiding this comment.
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.
exporter.go
Outdated
line, isPrefix, err := r.ReadLine() | ||
if err != nil { | ||
if err != io.EOF { | ||
log.Errorf("Read %s failed: %v", c.RemoteAddr(), err) |
There was a problem hiding this comment.
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.") |
There was a problem hiding this comment.
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.") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
- 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;
- 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) |
There was a problem hiding this comment.
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.
@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 |
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). |
@grobie add test for TCP listener in the same place as UDP except benchmarks. |
Thanks a lot for your contribution @jwfang! |
support TCP StatsD, on port 9125