In the second chapter, we talked about the exchange of fanout type. The fanout type exchange will send messages to all the queues that are bound with it, without distinguishing and filtering. But in reality, we often need to have filtering conditions to separate different messages and send them to different queues. For example, the log of the system. We need to send the received logs to different queues according to info, debug, warn, err, and use different consumer s to handle these different logs.
In order to achieve this function, we can
- ExchangeDeclare specifies type as direct
err = ch.ExchangeDeclare( "syslog_direct", //exchange name "direct", //exchange kind true, //durable false, //autodelete false, false, nil, )
- Producer specifies routing key when publishing
err = ch.Publish( "syslog_direct", //exchange routingKey, //routing key false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte(msgBody), })
- Consumer specifies routing key when QueueBind
err = ch.QueueBind( q.Name, routingKey, //routing key "syslog_direct", //exchange false, nil, )
The specific test code is as follows:
conf.go
package config const ( RMQADDR = "amqp://guest:guest@172.17.84.205:5672/" EXCHANGENAME = "syslog_direct" CONSUMERCNT = 4 ) var ( RoutingKeys [4]string = [4]string{"info", "debug", "warn", "error"} )
producer.go
package main import ( config "binTest/rabbitmqTest/t1/l4/conf" "fmt" "log" "os" "github.com/streadway/amqp" ) func main() { conn, err := amqp.Dial(config.RMQADDR) failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close() ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close() err = ch.ExchangeDeclare( config.EXCHANGENAME, //exchange name "direct", //exchange kind true, //durable false, //autodelete false, false, nil, ) failOnError(err, "Failed to declare exchange") if len(os.Args) < 3 { fmt.Println("Arguments error(ex:producer info/debug/warn/error msg1 msg2 msg3") return } routingKey := os.Args[1] validKey := false for _, item := range config.RoutingKeys { if routingKey == item { validKey = true break } } if validKey == false { fmt.Println("Arguments error, no valid routing key specified.(ex:producer info/debug/warn/error msg1 msg2 msg3") return } msgs := os.Args[2:] msgNum := len(msgs) for cnt := 0; cnt < msgNum; cnt++ { msgBody := msgs[cnt] err = ch.Publish( config.EXCHANGENAME, //exchange routingKey, //routing key false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte(msgBody), }) log.Printf(" [x] Sent %s", msgBody) } failOnError(err, "Failed to publish a message") } func failOnError(err error, msg string) { if err != nil { fmt.Printf("%s: %s\n", msg, err) } }
consumer.go
package main import ( config "binTest/rabbitmqTest/t1/l4/conf" "fmt" "log" "github.com/streadway/amqp" ) func main() { conn, err := amqp.Dial(config.RMQADDR) failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close() forever := make(chan bool) ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close() err = ch.ExchangeDeclare( config.EXCHANGENAME, //exchange name "direct", //exchange kind true, //durable false, //autodelete false, false, nil, ) failOnError(err, "Failed to declare exchange") for routing := 0; routing < config.CONSUMERCNT; routing++ { go func(routingNum int) { q, err := ch.QueueDeclare( "", false, //durable false, true, false, nil, ) failOnError(err, "Failed to declare a queue") err = ch.QueueBind( q.Name, config.RoutingKeys[routingNum], config.EXCHANGENAME, false, nil, ) failOnError(err, "Failed to bind exchange") msgs, err := ch.Consume( q.Name, "", true, //Auto Ack false, false, false, nil, ) if err != nil { log.Fatal(err) } for msg := range msgs { log.Printf("In %s consume a message: %s\n", config.RoutingKeys[routingNum], msg.Body) } }(routing) } <-forever } func failOnError(err error, msg string) { if err != nil { fmt.Printf("%s: %s\n", msg, err) } }
The detailed code can be obtained from here (l4):
https://github.com/BinWang-sh...