一、前言
刚才我们做了一个区分,把error、warning绑定级别把消息区分了。我们回到日志上,如果想做的更细致的区分,比如说,你现在搜索的有error,有warning等,在Linux上有一个系统日志,这个系统日志搜索所有应用的系统日志。所有程序都在这个日志里面打日志。那如果我想划分出来。什么是mysql的发出来的日志,什么是apache发出来的日志。然后mysql日志里面同时是info,又包含warning,error。Apache也是一样,所以我们要做更细的区分,更细致的消息过滤。
二、英文解释
Although using the direct exchange improved our system, it still has limitations - it can't do routing based on multiple criteria.
In our logging system we might want to subscribe to not only logs based on severity, but also based on the source which emitted the log. You might know this concept from the syslog unix tool, which routes logs based on both severity (info/warn/crit...) and facility (auth/cron/kern...).
That would give us a lot of flexibility - we may want to listen to just critical errors coming from 'cron' but also all logs from 'kern'.
三、topic广播模式逻辑图
四、topic广播方式的代码实现
4.1、生产者(publicer)
import pika,sys
connection = pika.BlockingConnection(pika.ConnectionParameters
("localhost"))
channel = connection.channel()
#声明一个topic的exchange
channel.exchange_declare(exchange="topic_logs",
exchange_type="topic")
routing_key = sys.argv[1] if len(sys.argv) > 1 else "anonymous.info"
message = " ".join(sys.argv[2:]) or "hello world"
channel.basic_publish(exchange="topic_logs",
routing_key=routing_key,
body=message)
print(" [x] Sent %r:%r" % (routing_key, message))
connection.close()
注:这边修改了exchange的类型,类型为topic,topic=>话题,意思是:你对什么话题感兴趣,就收什么消息。
4.2、消费者(consumer)
import pika,sys
connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
#声明topic类型的exchange
channel.exchange_declare(exchange="topic_logs",
exchange_type="topic")
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue
banding_keys = sys.argv[1:]
if not banding_keys:
sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
sys.exit(1)
#循环绑定queue
for banding_key in banding_keys:
channel.queue_bind(exchange="topic_logs",
queue=queue_name,
routing_key=banding_key)
print(' [*] Waiting for logs. To exit press CTRL+C')
#回调函数
def callback(ch,method,properites,body):
"回调函数"
print(" [x] %r:%r" % (method.routing_key, body))
#消费者消费
channel.basic_consume(callback,queue=queue_name,no_ack=True)
channel.start_consuming()
注:这边除了定义exchange的类型变了,其他的都没有改变。
五、运行效果
5.1、客户端匹配mysql.*,*.error
客户端:
服务端:
5.2、客户端匹配所有的
服务端发送消息:
客户端接收消息:
六、匹配规则
To receive all the logs run: =># 是匹配所有的
python receive_logs_topic.py "#"
To receive all logs from the facility "kern": =>只匹配kern开头的
python receive_logs_topic.py "kern.*"
Or if you want to hear only about "critical" logs: =>匹配critical结尾的
python receive_logs_topic.py "*.critical"
You can create multiple bindings:
python receive_logs_topic.py "kern.*" "*.critical"
And to emit a log with a routing key "kern.critical" type:
python emit_log_topic.py "kern.critical" "A critical kernel error"