go get github.com/streadway/amqp
Packaging producers and consumers:
package rabbitmq
import (
"context"
"fmt"
"github.com/opentracing/opentracing-go"
"github.com/streadway/amqp"
srcLog "log"
"time"
"why/config"
"why/log"
"why/util"
)
// 定义接收者接口
type ConsumeMsg interface {
// 消费逻辑
Do(d amqp.Delivery, header *log.LogFormat) error
}
// 定义RabbitMQ对象
type Consumer struct {
connection *amqp.Connection
channel *amqp.Channel
queueName string //队列名
amqpURI string
tag string
done chan error // 业务逻辑结束标识
}
func NewConsumer(amqpURI, queueName, tag string, consumeMsg ConsumeMsg) (*Consumer, error) {
c := &Consumer{
amqpURI: amqpURI,
queueName: queueName,
tag: tag,
done: make(chan error),
}
var err error
srcLog.Printf("dialing %q", c.amqpURI)
c.connection, err = amqp.Dial(c.amqpURI)
if err != nil {
return nil, fmt.Errorf("Dial:%s", err)
}
defer c.connection.Close()
go func() {
fmt.Printf("closing: %s", <-c.connection.NotifyClose(make(chan *amqp.Error)))
}()
srcLog.Printf("got Connection, getting Channel")
c.channel, err = c.connection.Channel()
if err != nil {
return nil, fmt.Errorf("Channel: %s", err)
}
defer c.channel.Close()
deliveries, err := c.channel.Consume(
queueName, // name
c.tag, // consumerTag,
false, // noAck
false, // exclusive
false, // noLocal
false, // noWait
nil, // arguments
)
if err != nil {
return nil, fmt.Errorf("Queue Consume: %s", err)
}
srcLog.Printf("consumer:(%q) started", queueName)
for d := range deliveries {
go consume(d, consumeMsg)
}
<- c.done
return c, nil
}
func consume(d amqp.Delivery, consumeMsg ConsumeMsg){
logId := log.NewObjectId().Hex()
logFormat := &log.LogFormat{
LogId: logId,
CallerIp: "",
HostIp: "",
Port: 0,
Product: "",
Module: "",
UriPath: "",
XHop: nil,
Env: "",
}
err := consumeMsg.Do(d, logFormat)
util.Must(err)
if err != nil {
log.Errorf(logFormat, "failed to consumer msg:%s, err%s", d.Body, err.Error())
util.Must(err)
return
}
writeInfoLog(logFormat, d, consumeMsg)
}
func writeInfoLog(logFormat *log.LogFormat, d amqp.Delivery, consumeMsg ConsumeMsg){
runLogConfig := make(map[string]string)
runLogSection := "amqp"
runLogConfig = config.GetConfigEntrance("log", runLogSection)
runLogdir := runLogConfig[runLogSection+"_dir"]
file := util.FileNameByDate(runLogdir)
log.Init(&log.LogConfig{
File: file,
Path: runLogdir,
Mode: 1,
AsyncFormatter: false,
Debug: true,
})
log.Info(logFormat, map[string]interface{}{
"msg": string(d.Body),
})
}
func NewProducer(msg, amqpURI, exchangeName, exchangeType, queueName, routeName, tag string, ctx context.Context) error {
var (
parent = opentracing.SpanFromContext(ctx)
operationName = "producer"
statement = fmt.Sprintf("amqpUri:%s, exchange:%s, exchange_type:%s, queue:%s, route_name:%s, msg:%s ",
amqpURI, exchangeName, exchangeType, queueName, routeName, msg)
span = func() opentracing.Span {
if parent == nil {
return opentracing.StartSpan(operationName)
}
return opentracing.StartSpan(operationName, opentracing.ChildOf(parent.Context()))
}()
logFormat = log.LogHeaderFromContext(ctx)
startAt = time.Now()
endAt time.Time
)
var err error
lastModule := logFormat.Module
defer func() {logFormat.Module = lastModule}()
defer span.Finish()
defer func() {
endAt = time.Now()
logFormat.StartTime = startAt
logFormat.EndTime = endAt
latencyTime := logFormat.EndTime.Sub(logFormat.StartTime).Microseconds()// 执行时间
logFormat.LatencyTime = latencyTime
span.SetTag("error", err != nil)
span.SetTag("db.type", "sql")
span.SetTag("db.statement", statement)
if err != nil {
log.Errorf(logFormat, "%s:[%s], error: %s", operationName, statement, err)
}else {
log.Warnf(logFormat, statement)
}
logFormat.Module = "databus/rabbitmq"
}()
if parent == nil {
span = opentracing.StartSpan("redisDo")
} else {
span = opentracing.StartSpan("redisDo", opentracing.ChildOf(parent.Context()))
}
defer span.Finish()
span.SetTag("db.type", "redis")
span.SetTag("db.statement", statement)
span.SetTag("error", err != nil)
c := &Consumer{
amqpURI: amqpURI,
queueName: queueName,
tag: tag,
done: make(chan error),
}
srcLog.Printf("dialing %q", c.amqpURI)
c.connection, err = amqp.Dial(c.amqpURI)
if err != nil {
return fmt.Errorf("Dial:%s", err)
}
defer c.connection.Close()
srcLog.Printf("got Connection, getting Channel")
c.channel, err = c.connection.Channel()
if err != nil {
return fmt.Errorf("Channel: %s", err)
}
defer c.channel.Close()
err = c.channel.ExchangeDeclare(exchangeName, exchangeType, true, false, false, false, nil)
util.Must(err)
_, err = c.channel.QueueDeclare(
queueName, // routing_key
true, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
util.Must(err)
err = c.channel.QueueBind(queueName, routeName, exchangeName, false, nil)
util.Must(err)
err = c.channel.Publish(
exchangeName, // exchange
routeName, // routing key
false, // mandatory
false, // immediate
amqp.Publishing {
ContentType: "text/plain",
Body: []byte(msg),
})
util.Must(err)
return nil
}
func NewProducerCmd(msg, amqpURI, exchangeName, exchangeType, queueName, routeName, tag string) error {
c := &Consumer{
amqpURI: amqpURI,
queueName: queueName,
tag: tag,
done: make(chan error),
}
var err error
srcLog.Printf("dialing %q", c.amqpURI)
c.connection, err = amqp.Dial(c.amqpURI)
if err != nil {
return fmt.Errorf("Dial:%s", err)
}
c.connection.Close()
srcLog.Printf("got Connection, getting Channel")
c.channel, err = c.connection.Channel()
if err != nil {
return fmt.Errorf("Channel: %s", err)
}
c.channel.Close()
err = c.channel.ExchangeDeclare(exchangeName, exchangeType, true, false, false, false, nil)
util.Must(err)
_, err = c.channel.QueueDeclare(
queueName, // routing_key
true, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
util.Must(err)
err = c.channel.QueueBind(queueName, routeName, exchangeName, false, nil)
util.Must(err)
err = c.channel.Publish(
exchangeName, // exchange
routeName, // routing key
false, // mandatory
false, // immediate
amqp.Publishing {
ContentType: "text/plain",
Body: []byte(msg),
})
util.Must(err)
return nil
}
func (c *Consumer) Shutdown() {
// will close() the deliveries channel
if err := c.channel.Cancel(c.tag, true); err != nil {
fmt.Print(fmt.Sprintf("Consumer cancel failed: %s", err.Error()))
return
}
if err := c.connection.Close(); err != nil {
fmt.Print(fmt.Sprintf("AMQP connection close error: %s", err.Error()))
return
}
defer srcLog.Printf("AMQP shutdown OK")
// wait for handle() to exit
<-c.done
}
application:
package rabbitmq
import (
"why/util"
)
func consumer(){
connUri := "amqp://why:why@localhost:5672/why"
queueName := "why_queue"
testConsumer := &TestConsumer{}
c, err := NewConsumer(connUri, queueName, "", testConsumer)
util.Must(err)
defer c.Shutdown()
}
func producer(){
connUri := "amqp://why:why@localhost:5672/why"
queueName := "why_queue"
exchangeName := "why_exchange"
routeName := "why_route"
err := NewProducerCmd("hello world!", connUri, exchangeName, "direct", queueName, routeName, "")
util.Must(err)
}
func main(){
producer()
consumer()
}
util Reference: https://blog.csdn.net/why444216978/article/details/103992579
config Reference: https://blog.csdn.net/why444216978/article/details/103978355