The previous articles mentioned the fanout type exchange similar to broadcast, which supports the classified direct type exchange. Using the example of log in the exchange of direct type, we can distinguish the logs of info, debug, warn and error types. However, there may be further requirements in practice. I hope to see the error log information of the system kernel and the debug log of the interface that takes the longest to request. For such a requirement, you can use the exchange of topic type.
The exchange method using topic type is as follows
(1) exchange of the same topic type is declared in both producer and consumer
err = ch.ExchangeDeclare( "logs_topic", // name "topic", // type true, // durable false, // auto-deleted false, // internal false, // no-wait nil, // arguments )
(2) specify the routing key when publishing messages in producer
err = ch.Publish( "logs_topic", // exchange "error.kernel", // routing key false, // mandatory false, // immediate amqp.Publishing{ ContentType: "text/plain", Body: []byte(body), })
(3) bind queue to exchange in consumer
err = ch.QueueBind( q.Name, // queue name "error.kernel", // routing key "logs_topic", // exchange false, nil)
routing key definition
routing key can explicitly specify an explicit match or use wildcards to match.
The wildcard "ා" represents zero or more words
The wildcard "*" represents a word
If the routing key is specified as ා, all messages will be accepted, similar to the exchange of fanout type
The routing key without the wildcard "ා" or "*" accepts the specified message, similar to the exchange of direct type
routing key uses a hierarchy separated by ".".
For example: "info.payment.vip" is an info message that only uses vip payment. "info.payment. *" accepts all payment info messages
The specific code is as follows
conf.go
consumer.go
package main import ( config "binTest/rabbitmqTest/t1/l5/conf" "fmt" "log" "os" "github.com/streadway/amqp" ) /* ./consumer "#" info.payment.* *.log debug.payment.# */ 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 "topic", //exchange kind true, //durable false, //autodelete false, false, nil, ) failOnError(err, "Failed to declare exchange") if len(os.Args) < 2 { log.Println(len(os.Args)) log.Println(`"Arguments error(Example: ./consumer "#" info.payment.* *.log debug.payment.#"`) return } topics := os.Args[1:] topicsCnt := len(topics) for routing := 0; routing < topicsCnt; routing++ { go func(routingNum int) { q, err := ch.QueueDeclare( "", false, //durable false, //delete when unused true, //exclusive false, //no-wait nil, //arguments ) failOnError(err, "Failed to declare a queue") err = ch.QueueBind( q.Name, topics[routingNum], config.EXCHANGENAME, false, nil, ) failOnError(err, "Failed to bind exchange") msgs, err := ch.Consume( q.Name, "", true, //Auto Ack false, false, false, nil, ) failOnError(err, "Failed to register a consumer") for msg := range msgs { log.Printf("In %s consume a message: %s\n", topics[routingNum], msg.Body) } }(routing) } <-forever } func failOnError(err error, msg string) { if err != nil { fmt.Printf("%s: %s\n", msg, err) } }
producer.go
package main import ( config "binTest/rabbitmqTest/t1/l5/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 "topic", //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 topic msg1 msg2 msg3") return } routingKey := os.Args[1] 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) } }
Operation result
consumer
producer
According to the results, we can see that
consumer specifies 4 routing key s
- Receive all messages All messages from producer will be received
- "info.payment. *" accepts all info.payment messages.
The following message from producer will be received
./producer info.payment.googlepay "start payment at 16:00" - "*. Log" accepts all messages with log as the second level
The following message from producer will be received
./producer info.log "start recording payment log" - "Debug.payment. ා" receives all messages sent to the routing key starting with debug.payment.
The following message from producer will be received
./producer debug.payment.Alipay "10 yuan payment at 15:25" "1000 dollors payment at 15:26" "10 pounds payment at 15:27"
The following messages will also be received (because ා represents zero or more words)
./producer debug.payment.payinfo.Alipay "test payment info"
The detailed code is as follows
https://github.com/BinWang-sh...