上一節,我們創建了一個日志系統,我們能夠分發log信息給每個訂閱者。
這一節,我們在其上添加額外的功能——只訂閱log信息的一個子集。例如:我們只把至關重要的錯誤日志信息,記錄到文件,而所有的日志信息都可以在控制帶輸出。
##Bindings
上一節,我們已經定義了綁定,你可以回憶代碼如下:
```
channel.QueueBind(queue: queueName,
exchange: "logs",
routingKey: "");
```
binding是exchange與queue之間的關系,簡單的來說就是。queue對message來自指定的exchange的感興趣。
Binding可以指定routingKey參數。為了避免和BasicPublish參數疑惑,我們可以叫它 binding key。因此我們可以創建一個帶key的bingding
```
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: "black");
```
bingding key的意義取決于 exchange的類型。fanout類型的exchange會忽略這個值。
##Direct exchange
之前的日志系統只能給分發message給所有的consumer。我們想根據message的log lever來過濾message。例如,我們只想記錄重要的錯誤日志信息到FILE,其他的不記錄到文件。
但是fanout類型exchange 不夠靈活,它只能盲目的分發。
因此這里我們使用 direct類型的exchange來替代。direct 類型exchange背后的算法很簡單——一個消息只會發送給queue的bingding key 完全匹配message的routing key的隊列。
大體結構如下所示:

我們看到 direct類型的exchange X 有兩個queue綁定到它。第一個 bingding key是orange。第二個有兩個bingding Key:black和green。
因此,如果一個message的routing key是orange會發送給Q1隊列,如果是blcak或green則會發送給Q2,其他的消息則會被丟棄掉。
##Multiple bindings

多個隊列綁定同樣的key是合法的。在這種情況下,direct 類型的exchage的行為和fanout表現的一樣。
##Emitting logs
首先創建 exchange
```
channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");
```
接下來發送 message
```
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
routingKey: severity,
basicProperties: null,
body: body);
```
為了簡化,我們的serverity 可以是"info","warning","error"。
##Subscribing 訂閱
接收消息的工作就像在前面的教程中,有一個例外,我們要創建一個新綁定,綁定到每個嚴重性我們感興趣的。
```
var queueName = channel.QueueDeclare().QueueName;
foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);
}
```
##putting ti all together

EmitLogDirect.cs
```
using System;
using System.Linq;
using RabbitMQ.Client;
using System.Text;
class EmitLogDirect
{
public static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "direct_logs",
type: "direct");
var severity = (args.Length > 0) ? args[0] : "info";
var message = (args.Length > 1)
? string.Join(" ", args.Skip( 1 ).ToArray())
: "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
routingKey: severity,
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent '{0}':'{1}'", severity, message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
```
ReceiveLogsDirect.cs
```
using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
class ReceiveLogsDirect
{
public static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "direct_logs",
type: "direct");
var queueName = channel.QueueDeclare().QueueName;
if(args.Length < 1)
{
Console.Error.WriteLine("Usage: {0} [info] [warning] [error]",
Environment.GetCommandLineArgs()[0]);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
Environment.ExitCode = 1;
return;
}
foreach(var severity in args)
{
channel.QueueBind(queue: queueName,
exchange: "direct_logs",
routingKey: severity);
}
Console.WriteLine(" [*] Waiting for messages.");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'",
routingKey, message);
};
channel.BasicConsume(queue: queueName,
noAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
```
編譯他們。
如果你想保存warning,error的log到file。
```
$ ReceiveLogsDirect.exe warning error > logs_from_rabbit.log
```
如果你想 發射一條 error log message
```
$ EmitLogDirect.exe error "Run. Run. Or it will explode."
[x] Sent 'error':'Run. Run. Or it will explode.'
```