Although using the direct exchange improved our system, it still has limitations - it can't do routing based on multiple criteria.
We want to subscribe to not only logs based on severity, but also based on the source which emitted the log.
Severity info/warn/critical
Facility auth/cron/kern
Topic exchange
For topic exchange, routing_key must be a list of words.
The binding key must also be in the same form. The logic behind the topic exchange is similar to a direct one. A message sent with a particular rouing key will be delivered to all the queues that are bound with a matching binding key.
* (star) can substitute for exactly one word.
#(hash) can substitute for zero or more words.
We plan our routing key like this '<speed>.<colour>.<species>'.
Q1 "*.orange.*" is interested in all the orange animals
Q2 "*.*.rabbit" and "lazy.#" wants to hear everything about rabbits, and everything about lazy animals.
All come together
package com.sillycat.easytalker.rabbitmq.topic;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class EmitLogTopic {
private static final String EXCHANGE_NAME = "topic_logs";
private final static String SERVER_HOST = "localhost";
public static void main(String[] argv) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);
connection = factory.newConnection();
channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
channel.basicPublish(EXCHANGE_NAME, "bird.white.fly", null,
"fly bird, haha.".getBytes());
channel.basicPublish(EXCHANGE_NAME, "bird.black.walk", null,
"walking cock!".getBytes());
channel.basicPublish(EXCHANGE_NAME, "lazy.black.sleep", null,
"sleep warm!".getBytes());
channel.basicPublish(EXCHANGE_NAME, "fast.white.rabbit", null,
"running fast rabbit!".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (Exception ignore) {
}
}
}
}
}
package com.sillycat.easytalker.rabbitmq.topic;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
public class ReceiveLogsTopic1 {
private static final String EXCHANGE_NAME = "topic_logs";
private final static String SERVER_HOST = "rd.digby.com";
public static void main(String[] argv) {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);
connection = factory.newConnection();
channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, EXCHANGE_NAME, "lazy.#");
System.out
.println("
channel.basicConsume(queueName, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey();
System.out.println(" [x] Received '" + routingKey + "':'"
+ message + "'");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (Exception ignore) {
}
}
}
}
}
ReceiveLogsTopic1 will receive all lazy animals. The only difference from ReceiveLogsTopic2 to ReceiveLogsTopic1 is as follow:
channel.queueBind(queueName, EXCHANGE_NAME, "*.white.*");
And ReceiveLogsTopic2 will focus on all the white colour animals.
references:
http://www.rabbitmq.com/tutorials/tutorial-five-java.html