
The current idiom forever := make(chan bool) gives the impression that booleans will be sent through `forever`. But the channel never has anything sent through it; its purpose is just to block indefinitely. Go doesn't have any bottom type (empty type; ⊥), but it does have a unit type, namely `struct{}`. Because not even such values will be sent, the channel need not even exist at all, leaving no doubts as to its purpose.
75 lines
1.4 KiB
Go
75 lines
1.4 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
|
|
amqp "github.com/rabbitmq/amqp091-go"
|
|
)
|
|
|
|
func failOnError(err error, msg string) {
|
|
if err != nil {
|
|
log.Panicf("%s: %s", msg, err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
|
|
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(
|
|
"logs", // name
|
|
"fanout", // type
|
|
true, // durable
|
|
false, // auto-deleted
|
|
false, // internal
|
|
false, // no-wait
|
|
nil, // arguments
|
|
)
|
|
failOnError(err, "Failed to declare an exchange")
|
|
|
|
q, err := ch.QueueDeclare(
|
|
"", // name
|
|
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, // queue name
|
|
"", // routing key
|
|
"logs", // exchange
|
|
false,
|
|
nil)
|
|
failOnError(err, "Failed to bind a queue")
|
|
|
|
msgs, err := ch.Consume(
|
|
q.Name, // queue
|
|
"", // consumer
|
|
true, // auto-ack
|
|
false, // exclusive
|
|
false, // no-local
|
|
false, // no-wait
|
|
nil, // args
|
|
)
|
|
failOnError(err, "Failed to register a consumer")
|
|
|
|
var forever chan struct{}
|
|
|
|
go func() {
|
|
for d := range msgs {
|
|
log.Printf(" [x] %s", d.Body)
|
|
}
|
|
}()
|
|
|
|
log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
|
|
<-forever
|
|
}
|