日誌子系統 AMQP 附加器

此框架為一些熱門的日誌子系統提供日誌附加器

  • logback (自 Spring AMQP 1.4 版起)

  • log4j2 (自 Spring AMQP 1.6 版起)

附加器透過使用日誌子系統的正常機制進行設定,可用屬性在以下章節中指定。

通用屬性

以下屬性適用於所有附加器

表 1. 通用附加器屬性
屬性 預設值 描述
 exchangeName
 logs

要發布日誌事件的交換器名稱。

 exchangeType
 topic

要發布日誌事件的交換器類型 — 僅在附加器宣告交換器時才需要。請參閱 declareExchange

 routingKeyPattern
 %c.%p

用於產生路由金鑰的日誌子系統模式格式。

 applicationId

應用程式 ID — 如果模式包含 %X{applicationId},則會新增至路由金鑰。

 senderPoolSize
 2

用於發布日誌事件的執行緒數。

 maxSenderRetries
 30

如果 Broker 無法使用或發生其他錯誤,則重試傳送訊息的次數。重試會延遲如下:N ^ log(N),其中 N 是重試次數。

 addresses

以逗號分隔的 Broker 位址清單,格式如下:host:port[,host:port]* - 覆寫 hostport

 host
 localhost

要連線的 RabbitMQ 主機。

 port
 5672

要連線的 RabbitMQ 連接埠。

 virtualHost
 /

要連線的 RabbitMQ 虛擬主機。

 username
 guest

連線時要使用的 RabbitMQ 使用者。

 password
 guest

此使用者的 RabbitMQ 密碼。

 useSsl
 false

是否為 RabbitMQ 連線使用 SSL。請參閱 RabbitConnectionFactoryBean 和設定 SSL

 verifyHostname
 true

為 TLS 連線啟用伺服器主機名稱驗證。請參閱 RabbitConnectionFactoryBean 和設定 SSL

 sslAlgorithm
 null

要使用的 SSL 演算法。

 sslPropertiesLocation
 null

SSL 屬性檔案的位置。

 keyStore
 null

金鑰儲存庫的位置。

 keyStorePassphrase
 null

金鑰儲存庫的密碼。

 keyStoreType
 JKS

金鑰儲存庫類型。

 trustStore
 null

信任儲存庫的位置。

 trustStorePassphrase
 null

信任儲存庫的密碼。

 trustStoreType
 JKS

信任儲存庫類型。

 saslConfig
 null (RabbitMQ client default applies)

saslConfig - 有效值請參閱 RabbitUtils.stringToSaslConfig 的 javadoc。

 contentType
 text/plain

日誌訊息的 content-type 屬性。

 contentEncoding

日誌訊息的 content-encoding 屬性。

 declareExchange
 false

是否在此附加器啟動時宣告設定的交換器。另請參閱 durableautoDelete

 durable
 true

declareExchangetrue 時,持久標誌會設定為此值。

 autoDelete
 false

declareExchangetrue 時,自動刪除標誌會設定為此值。

 charset
 null

String 轉換為 byte[] 時要使用的字元集。預設值:null (使用系統預設字元集)。如果目前的平台上不支援該字元集,我們會退回使用系統字元集。

 deliveryMode
 PERSISTENT

PERSISTENTNON_PERSISTENT,以判斷 RabbitMQ 是否應持久化訊息。

 generateId
 false

用於判斷是否將 messageId 屬性設定為唯一值。

 clientConnectionProperties
 null

以逗號分隔的 key:value 配對清單,用於 RabbitMQ 連線的自訂用戶端屬性。

 addMdcAsHeaders
 true

MDC 屬性在引入此屬性之前,一律會新增至 RabbitMQ 訊息標頭。對於大型 MDC,這可能會導致問題,因為 RabbitMQ 對所有標頭的緩衝區大小有限制,而且此緩衝區非常小。引入此屬性是為了避免在大型 MDC 的情況下發生問題。預設情況下,為了向後相容性,此值設定為 truefalse 會關閉將 MDC 序列化為標頭的功能。請注意,JsonLayout 預設會將 MDC 新增至訊息中。

Log4j 2 附加器

以下範例顯示如何設定 Log4j 2 附加器

<Appenders>
    ...
    <RabbitMQ name="rabbitmq"
        addresses="foo:5672,bar:5672" user="guest" password="guest" virtualHost="/"
        exchange="log4j2" exchangeType="topic" declareExchange="true" durable="true" autoDelete="false"
        applicationId="myAppId" routingKeyPattern="%X{applicationId}.%c.%p"
        contentType="text/plain" contentEncoding="UTF-8" generateId="true" deliveryMode="NON_PERSISTENT"
        charset="UTF-8"
        senderPoolSize="3" maxSenderRetries="5"
        addMdcAsHeaders="false">
    </RabbitMQ>
</Appenders>

從 1.6.10 和 1.7.3 版開始,預設情況下,log4j2 附加器會在呼叫執行緒上將訊息發布到 RabbitMQ。這是因為 Log4j 2 預設不會建立執行緒安全事件。如果 Broker 關閉,則會使用 maxSenderRetries 進行重試,且重試之間沒有延遲。如果您希望還原在個別執行緒 (senderPoolSize) 上發布訊息的先前行為,您可以將 async 屬性設定為 true。但是,您也需要設定 Log4j 2 以使用 DefaultLogEventFactory 而非 ReusableLogEventFactory。其中一種方法是設定系統屬性 -Dlog4j2.enable.threadlocals=false。如果您搭配 ReusableLogEventFactory 使用非同步發布,則事件非常有可能因串擾而損毀。

Logback 附加器

以下範例顯示如何設定 logback 附加器

<appender name="AMQP" class="org.springframework.amqp.rabbit.logback.AmqpAppender">
    <layout>
        <pattern><![CDATA[ %d %p %t [%c] - <%m>%n ]]></pattern>
    </layout>
    <addresses>foo:5672,bar:5672</addresses>
    <abbreviation>36</abbreviation>
    <includeCallerData>false</includeCallerData>
    <applicationId>myApplication</applicationId>
    <routingKeyPattern>%property{applicationId}.%c.%p</routingKeyPattern>
    <generateId>true</generateId>
    <charset>UTF-8</charset>
    <durable>false</durable>
    <deliveryMode>NON_PERSISTENT</deliveryMode>
    <declareExchange>true</declareExchange>
    <addMdcAsHeaders>false</addMdcAsHeaders>
</appender>

從 1.7.1 版開始,Logback AmqpAppender 提供 includeCallerData 選項,預設為 false。擷取呼叫者資料可能相當耗費資源,因為日誌事件必須建立可拋出的物件並檢查它,才能判斷呼叫位置。因此,預設情況下,當事件新增至事件佇列時,不會擷取與事件相關聯的呼叫者資料。您可以將 includeCallerData 屬性設定為 true,以設定附加器來包含呼叫者資料。

從 2.0.0 版開始,Logback AmqpAppender 支援具有 encoder 選項的 Logback 編碼器encoderlayout 選項互斥。

自訂訊息

預設情況下,AMQP 附加器會填入下列訊息屬性

  • deliveryMode

  • contentType

  • contentEncoding (如果已設定)

  • messageId (如果已設定 generateId)

  • 日誌事件的 timestamp

  • appId (如果已設定 applicationId)

此外,它們還會使用下列值填入標頭

  • 日誌事件的 categoryName

  • 日誌事件的層級

  • thread:發生日誌事件的執行緒名稱

  • 日誌事件呼叫堆疊追蹤的位置

  • 所有 MDC 屬性的副本 (除非 addMdcAsHeaders 設定為 false)

每個附加器都可以子類化,讓您在發布之前修改訊息。以下範例顯示如何自訂日誌訊息

public class MyEnhancedAppender extends AmqpAppender {

    @Override
    public Message postProcessMessageBeforeSend(Message message, Event event) {
        message.getMessageProperties().setHeader("foo", "bar");
        return message;
    }

}

從 2.2.4 版開始,log4j2 AmqpAppender 可以使用 @PluginBuilderFactory 擴充,並同時擴充 AmqpAppender.Builder

@Plugin(name = "MyEnhancedAppender", category = "Core", elementType = "appender", printObject = true)
public class MyEnhancedAppender extends AmqpAppender {

	public MyEnhancedAppender(String name, Filter filter, Layout<? extends Serializable> layout,
			boolean ignoreExceptions, AmqpManager manager, BlockingQueue<Event> eventQueue, String foo, String bar) {
		super(name, filter, layout, ignoreExceptions, manager, eventQueue);

	@Override
	public Message postProcessMessageBeforeSend(Message message, Event event) {
			message.getMessageProperties().setHeader("foo", "bar");
		return message;
	}

	@PluginBuilderFactory
	public static Builder newBuilder() {
		return new Builder();
	}

	protected static class Builder extends AmqpAppender.Builder {

		@Override
		protected AmqpAppender buildInstance(String name, Filter filter, Layout<? extends Serializable> layout,
				boolean ignoreExceptions, AmqpManager manager, BlockingQueue<Event> eventQueue) {
			return new MyEnhancedAppender(name, filter, layout, ignoreExceptions, manager, eventQueue);
		}
	}

}

自訂用戶端屬性

您可以透過新增字串屬性或更複雜的屬性來新增自訂用戶端屬性。

簡單字串屬性

每個附加器都支援將用戶端屬性新增至 RabbitMQ 連線。

以下範例顯示如何為 logback 新增自訂用戶端屬性

<appender name="AMQP" ...>
    ...
    <clientConnectionProperties>thing1:thing2,cat:hat</clientConnectionProperties>
    ...
</appender>
log4j2
<Appenders>
    ...
    <RabbitMQ name="rabbitmq"
        ...
        clientConnectionProperties="thing1:thing2,cat:hat"
        ...
    </RabbitMQ>
</Appenders>

屬性是以逗號分隔的 key:value 配對清單。金鑰和值不能包含逗號或冒號。

當檢視連線時,這些屬性會出現在 RabbitMQ Admin UI 上。

Logback 的進階技術

您可以子類化 Logback 附加器。這樣做可讓您在建立連線之前修改用戶端連線屬性。以下範例顯示如何執行此操作

public class MyEnhancedAppender extends AmqpAppender {

    private String thing1;

    @Override
    protected void updateConnectionClientProperties(Map<String, Object> clientProperties) {
        clientProperties.put("thing1", this.thing1);
    }

    public void setThing1(String thing1) {
        this.thing1 = thing1;
    }

}

然後您可以將 <thing1>thing2</thing1> 新增至 logback.xml。

對於前述範例中顯示的字串屬性,可以使用先前的技術。子類別允許新增更豐富的屬性 (例如新增 Map 或數值屬性)。

提供自訂佇列實作

AmqpAppenders 使用 BlockingQueue 以非同步方式將日誌事件發布至 RabbitMQ。預設情況下,會使用 LinkedBlockingQueue。但是,您可以提供任何種類的自訂 BlockingQueue 實作。

以下範例顯示如何為 Logback 執行此操作

public class MyEnhancedAppender extends AmqpAppender {

    @Override
    protected BlockingQueue<Event> createEventQueue() {
        return new ArrayBlockingQueue();
    }

}

Log4j 2 附加器支援使用 BlockingQueueFactory,如下列範例所示

<Appenders>
    ...
    <RabbitMQ name="rabbitmq"
              bufferSize="10" ... >
        <ArrayBlockingQueue/>
    </RabbitMQ>
</Appenders>