For our rhq-metrics project (and actually for RHQ proper) I wanted to be able to receive syslog messages, parse them and in case of content in the form of
type=metric thread.count=11 thread.active=1 heap.permgen.size=20040000
forward the individual key-value pairs (e.g. thread.count=11) to a rest endpoint for further processing.
After I started with the usual plain Java ServerSocket..
code I realized that this may become cumbersome and that this would be the perfect opportunity to check out Netty. Luckily I already had an Early Access copy of Netty in Action lying around and was ready to start.
Writing the first server that listens on TCP port 5140 to receive messages was easy and modifying /etc/syslog.conf
to forward messages to that port as well.
Unfortunately I did not get any message.
I turned out that on OS/X syslog message forwarding is only UDP. So I sat down, converted the code to use UDP and was sort of happy. I was also able to create the backend connection to the REST server, but here I was missing the piece on how to "forward" the incoming data to the rest-client connection.
Luckily my colleague Norman Maurer, one of the Netty gurus helped me a lot and so I got that going.
After this worked, I continued and added a TCP server too, so that it is now possible to receive messages over TCP and UDP.
The (current) final setup looks like this:
I need two different decoders here, as for TCP the (payload) data received is directly contained in a
ByteBuf
while for UDP it is inside a
DatagramPacker
and needs to be pulled out into a
ByteBuf
for further decoding.
One larger issue I had during development (aside from wrapping my head around "The Netty Way" of doing things) was that I wrote a Decoder like
public class UdpSyslogEventDecoder extends
MessageToMessageDecoder<DatagramPacket>{
protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception {
and it never got called by Netty. I could see that it was instantiated when the pipeline was set up, but for incoming messages it was just bypassed.
After I added a method
public boolean acceptInboundMessage(Object msg) throws Exception {
return true;
}
my decoder was called, but Netty was throwing ClassCastException
s, but they were pretty helpful, as it turned out that the IDE automatically imported java.net.DatagramPacket
, which is not what Netty wants here. As Netty checks for the signature of the decode()
and this did not match, Netty just ignored the decoder.
You can find the source of this server on GitHub.