Skip to content

Commit 34e614a

Browse files
egusevartembilan
authored andcommitted
GH-1014: Add addMdcAsHeaders into appenders
Fixes #1014 **Cherry-pick to 2.1.x, 2.0.x & 1.7.x** GH-1014 minor changes GH-1014 renamed property to addMdcAsHeaders GH-1014 added addMdcAsHeaders into documentation GH-1014 added addMdcAsHeaders into logback appender. added integration test GH-1014 updated documentation GH-1014 minor fix GH-1014 updated documentation GH-1014 minor fix GH-1014 removed this prefix * Made addMdcAsHeaders true by default * Polishing # Conflicts: # spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j2/AmqpAppenderTests.java # spring-rabbit/src/test/java/org/springframework/amqp/rabbit/logback/AmqpAppenderIntegrationTests.java # Conflicts: # spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java # spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java # src/reference/asciidoc/logging.adoc # src/reference/asciidoc/whats-new.adoc # Conflicts: # spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java # spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java # spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j2/AmqpAppenderTests.java # spring-rabbit/src/test/java/org/springframework/amqp/rabbit/logback/AmqpAppenderIntegrationTests.java # spring-rabbit/src/test/resources/log4j2-amqp-appender.xml # spring-rabbit/src/test/resources/logback-test.xml
1 parent 3fa628e commit 34e614a

File tree

6 files changed

+149
-14
lines changed

6 files changed

+149
-14
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
* @author Stephen Oakey
7676
* @author Artem Bilan
7777
* @author Nicolas Ristock
78+
* @author Eugene Gusev
7879
*
7980
* @since 1.6
8081
*/
@@ -156,7 +157,8 @@ public static AmqpAppender createAppender(
156157
@PluginAttribute("contentEncoding") String contentEncoding,
157158
@PluginAttribute("clientConnectionProperties") String clientConnectionProperties,
158159
@PluginAttribute("async") boolean async,
159-
@PluginAttribute("charset") String charset) {
160+
@PluginAttribute("charset") String charset,
161+
@PluginAttribute(value = "addMdcAsHeaders", defaultBoolean = true) boolean addMdcAsHeaders) {
160162
if (name == null) {
161163
LOGGER.error("No name for AmqpAppender");
162164
}
@@ -187,6 +189,7 @@ public static AmqpAppender createAppender(
187189
manager.clientConnectionProperties = clientConnectionProperties;
188190
manager.charset = charset;
189191
manager.async = async;
192+
manager.addMdcAsHeaders = addMdcAsHeaders;
190193
AmqpAppender appender = new AmqpAppender(name, filter, theLayout, ignoreExceptions, manager);
191194
if (manager.activateOptions()) {
192195
appender.startSenders();
@@ -235,7 +238,7 @@ protected Message postProcessMessageBeforeSend(Message message, Event event) {
235238
return message;
236239
}
237240

238-
private void sendEvent(final Event event, Map<?, ?> properties) {
241+
protected void sendEvent(Event event, Map<?, ?> properties) {
239242
LogEvent logEvent = event.getEvent();
240243
String name = logEvent.getLoggerName();
241244
Level level = logEvent.getLevel();
@@ -264,8 +267,10 @@ private void sendEvent(final Event event, Map<?, ?> properties) {
264267
amqpProps.setTimestamp(tstamp.getTime());
265268

266269
// Copy properties in from MDC
267-
for (Entry<?, ?> entry : properties.entrySet()) {
268-
amqpProps.setHeader(entry.getKey().toString(), entry.getValue());
270+
if (this.manager.addMdcAsHeaders) {
271+
for (Entry<?, ?> entry : properties.entrySet()) {
272+
amqpProps.setHeader(entry.getKey().toString(), entry.getValue());
273+
}
269274
}
270275
if (logEvent.getSource() != null) {
271276
amqpProps.setHeader(
@@ -275,6 +280,10 @@ private void sendEvent(final Event event, Map<?, ?> properties) {
275280
logEvent.getSource().getLineNumber()));
276281
}
277282

283+
doSend(event, logEvent, amqpProps);
284+
}
285+
286+
protected void doSend(final Event event, LogEvent logEvent, MessageProperties amqpProps) {
278287
StringBuilder msgBody;
279288
String routingKey;
280289

@@ -491,6 +500,11 @@ protected static class AmqpManager extends AbstractManager {
491500
*/
492501
private String charset = Charset.defaultCharset().name();
493502

503+
/**
504+
* Whether or not add MDC properties into message headers. true by default for backward compatibility
505+
*/
506+
private boolean addMdcAsHeaders = true;
507+
494508
private boolean durable = true;
495509

496510
private MessageDeliveryMode deliveryMode = MessageDeliveryMode.PERSISTENT;

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
* @author Artem Bilan
7878
* @author Gary Russell
7979
* @author Nicolas Ristock
80+
* @author Eugene Gusev
8081
*
8182
* @since 1.4
8283
*/
@@ -222,6 +223,11 @@ public class AmqpAppender extends AppenderBase<ILoggingEvent> {
222223
*/
223224
private String charset;
224225

226+
/**
227+
* Whether or not add MDC properties into message headers. true by default for backward compatibility
228+
*/
229+
private boolean addMdcAsHeaders = true;
230+
225231
private boolean durable = true;
226232

227233
private MessageDeliveryMode deliveryMode = MessageDeliveryMode.PERSISTENT;
@@ -359,6 +365,14 @@ public void setMaxSenderRetries(int maxSenderRetries) {
359365
this.maxSenderRetries = maxSenderRetries;
360366
}
361367

368+
public boolean isAddMdcAsHeaders() {
369+
return this.addMdcAsHeaders;
370+
}
371+
372+
public void setAddMdcAsHeaders(boolean addMdcAsHeaders) {
373+
this.addMdcAsHeaders = addMdcAsHeaders;
374+
}
375+
362376
public boolean isDurable() {
363377
return this.durable;
364378
}
@@ -579,10 +593,12 @@ public void run() {
579593
amqpProps.setTimestamp(tstamp.getTime());
580594

581595
// Copy properties in from MDC
582-
Map<String, String> props = event.getProperties();
583-
Set<Entry<String, String>> entrySet = props.entrySet();
584-
for (Entry<String, String> entry : entrySet) {
585-
amqpProps.setHeader(entry.getKey(), entry.getValue());
596+
if (AmqpAppender.this.addMdcAsHeaders) {
597+
Map<String, String> props = event.getProperties();
598+
Set<Entry<String, String>> entrySet = props.entrySet();
599+
for (Entry<String, String> entry : entrySet) {
600+
amqpProps.setHeader(entry.getKey(), entry.getValue());
601+
}
586602
}
587603
String[] location = AmqpAppender.this.locationLayout.doLayout(logEvent).split("\\|");
588604
if (!"?".equals(location[0])) {
@@ -629,6 +645,7 @@ public void run() {
629645
if (retries < AmqpAppender.this.maxSenderRetries) {
630646
// Schedule a retry based on the number of times I've tried to re-send this
631647
AmqpAppender.this.retryTimer.schedule(new TimerTask() {
648+
632649
@Override
633650
public void run() {
634651
AmqpAppender.this.events.add(event);
@@ -646,6 +663,7 @@ public void run() {
646663
Thread.currentThread().interrupt();
647664
}
648665
}
666+
649667
}
650668

651669
/**

spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j/AmqpAppenderConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.amqp.core.TopicExchange;
2626
import org.springframework.amqp.rabbit.connection.SingleConnectionFactory;
2727
import org.springframework.amqp.rabbit.core.RabbitAdmin;
28+
import org.springframework.amqp.rabbit.core.RabbitTemplate;
2829
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
2930
import org.springframework.beans.factory.config.BeanDefinition;
3031
import org.springframework.context.annotation.Bean;
@@ -33,6 +34,7 @@
3334

3435
/**
3536
* @author Jon Brisbin
37+
* @author Artem Bilan
3638
*/
3739
@Configuration
3840
public class AmqpAppenderConfiguration {
@@ -104,4 +106,12 @@ public SimpleMessageListenerContainer listenerContainer() {
104106
public TestListener testListener(int count) {
105107
return new TestListener(count);
106108
}
109+
110+
@Bean
111+
public RabbitTemplate rabbitTemplate() {
112+
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
113+
rabbitTemplate.setReceiveTimeout(10_000);
114+
return rabbitTemplate;
115+
}
116+
107117
}

spring-rabbit/src/test/java/org/springframework/amqp/rabbit/logback/AmqpAppenderIntegrationTests.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.amqp.rabbit.logback;
1818

19+
import static org.hamcrest.Matchers.hasEntry;
1920
import static org.hamcrest.Matchers.instanceOf;
2021
import static org.hamcrest.Matchers.is;
2122
import static org.hamcrest.Matchers.startsWith;
@@ -37,6 +38,9 @@
3738

3839
import org.springframework.amqp.core.Message;
3940
import org.springframework.amqp.core.MessageProperties;
41+
import org.springframework.amqp.core.Queue;
42+
import org.springframework.amqp.rabbit.connection.SingleConnectionFactory;
43+
import org.springframework.amqp.rabbit.core.RabbitTemplate;
4044
import org.springframework.amqp.rabbit.junit.BrokerRunning;
4145
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
4246
import org.springframework.amqp.rabbit.log4j.AmqpAppenderConfiguration;
@@ -52,6 +56,7 @@
5256
/**
5357
* @author Artem Bilan
5458
* @author Nicolas Ristock
59+
* @author Eugene Gusev
5560
*
5661
* @since 1.4
5762
*/
@@ -69,15 +74,23 @@ public class AmqpAppenderIntegrationTests {
6974
@Autowired
7075
private ApplicationContext applicationContext;
7176

77+
@Autowired
78+
private RabbitTemplate template;
79+
80+
@Autowired
81+
private Queue testQueue;
82+
7283
private SimpleMessageListenerContainer listenerContainer;
7384

7485
@Before
75-
public void setUp() throws Exception {
76-
listenerContainer = applicationContext.getBean(SimpleMessageListenerContainer.class);
86+
public void setUp() {
87+
this.listenerContainer = this.applicationContext.getBean(SimpleMessageListenerContainer.class);
88+
MDC.clear();
7789
}
7890

7991
@After
8092
public void tearDown() {
93+
MDC.clear();
8194
listenerContainer.shutdown();
8295
}
8396

@@ -120,7 +133,9 @@ public void testAppenderWithProps() throws InterruptedException {
120133
assertNotNull(location);
121134
assertThat(location, instanceOf(String.class));
122135
assertThat((String) location,
123-
startsWith("org.springframework.amqp.rabbit.logback.AmqpAppenderIntegrationTests.testAppenderWithProps()"));
136+
startsWith("org.springframework.amqp.rabbit.logback.AmqpAppenderIntegrationTests" +
137+
".testAppenderWithProps" +
138+
"()"));
124139
Object threadName = messageProperties.getHeaders().get("thread");
125140
assertNotNull(threadName);
126141
assertThat(threadName, instanceOf(String.class));
@@ -144,6 +159,32 @@ public void testCharset() throws InterruptedException {
144159
assertEquals(0xbf, body[body.length - 3 - lineSeparatorExtraBytes] & 0xff);
145160
}
146161

162+
@Test
163+
public void testAddMdcAsHeaders() {
164+
this.applicationContext.getBean(SingleConnectionFactory.class).createConnection().close();
165+
166+
Logger logWithMdc = (Logger) LoggerFactory.getLogger("withMdc");
167+
Logger logWithoutMdc = (Logger) LoggerFactory.getLogger("withoutMdc");
168+
MDC.put("mdc1", "test1");
169+
MDC.put("mdc2", "test2");
170+
171+
logWithMdc.info("test message with MDC in headers");
172+
Message received1 = this.template.receive(this.testQueue.getName());
173+
174+
assertNotNull(received1);
175+
assertEquals("test message with MDC in headers", new String(received1.getBody()));
176+
assertThat(received1.getMessageProperties().getHeaders(), hasEntry("mdc1", "test1"));
177+
assertThat(received1.getMessageProperties().getHeaders(), hasEntry("mdc2", "test2"));
178+
179+
logWithoutMdc.info("test message without MDC in headers");
180+
Message received2 = this.template.receive(this.testQueue.getName());
181+
182+
assertNotNull(received2);
183+
assertEquals("test message without MDC in headers", new String(received2.getBody()));
184+
assertThat(received1.getMessageProperties().getHeaders(), hasEntry("mdc1", "test1"));
185+
assertThat(received1.getMessageProperties().getHeaders(), hasEntry("mdc2", "test2"));
186+
}
187+
147188
public static class EnhancedAppender extends AmqpAppender {
148189

149190
private String foo;

spring-rabbit/src/test/resources/logback-test.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,52 @@
2525
<foo>bar</foo>
2626
</appender>
2727

28+
<appender name="AMQPWithMdc" class="org.springframework.amqp.rabbit.logback.AmqpAppender">
29+
<layout>
30+
<pattern>%m</pattern>
31+
</layout>
32+
<addresses>localhost:5672</addresses>
33+
<abbreviation>36</abbreviation>
34+
<includeCallerData>true</includeCallerData>
35+
<applicationId>AmqpAppenderTest</applicationId>
36+
<routingKeyPattern>%property{applicationId}.%c.%p</routingKeyPattern>
37+
<generateId>true</generateId>
38+
<charset>UTF-8</charset>
39+
<durable>false</durable>
40+
<deliveryMode>NON_PERSISTENT</deliveryMode>
41+
<declareExchange>false</declareExchange>
42+
<addMdcAsHeaders>true</addMdcAsHeaders>
43+
</appender>
44+
45+
<appender name="AMQPWithoutMdc" class="org.springframework.amqp.rabbit.logback.AmqpAppender">
46+
<layout>
47+
<pattern>%m</pattern>
48+
</layout>
49+
<addresses>localhost:5672</addresses>
50+
<abbreviation>36</abbreviation>
51+
<includeCallerData>true</includeCallerData>
52+
<applicationId>AmqpAppenderTest</applicationId>
53+
<routingKeyPattern>%property{applicationId}.%c.%p</routingKeyPattern>
54+
<generateId>true</generateId>
55+
<charset>UTF-8</charset>
56+
<durable>false</durable>
57+
<deliveryMode>NON_PERSISTENT</deliveryMode>
58+
<declareExchange>false</declareExchange>
59+
<addMdcAsHeaders>false</addMdcAsHeaders>
60+
</appender>
61+
2862
<logger name="org.springframework.amqp.rabbit.logback" level="DEBUG" additivity="false">
2963
<appender-ref ref="AMQP"/>
3064
</logger>
3165

66+
<logger name="withMdc" level="DEBUG" additivity="false">
67+
<appender-ref ref="AMQPWithMdc"/>
68+
</logger>
69+
70+
<logger name="withoutMdc" level="DEBUG" additivity="false">
71+
<appender-ref ref="AMQPWithoutMdc"/>
72+
</logger>
73+
3274
<root level="INFO">
3375
<appender-ref ref="CONSOLE"/>
3476
</root>

src/reference/asciidoc/logging.adoc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ The framework provides logging appenders for several popular logging subsystems:
77
- logback (since Spring AMQP _version 1.4_)
88
- log4j2 (since Spring AMQP _version 1.6_)
99

10-
The appenders are configured using the normal mechanisms for the logging subsystem, available properties are specified
11-
in the following sections.
10+
The appenders are configured by using the normal mechanisms for the logging subsystem, available properties are specified in the following sections.
1211

1312
==== Common properties
1413

@@ -109,6 +108,15 @@ If the charset is unsupported on the current platform, we fall back to using the
109108
| null
110109
| A comma-delimited list of `key:value` pairs for custom client properties to the RabbitMQ connection.
111110

111+
| addMdcAsHeaders
112+
| true
113+
| MDC properties were always added into RabbitMQ message headers until this property was introduced.
114+
It can lead to issues for big MDC as while RabbitMQ has limited buffer size for all headers and this buffer is pretty small.
115+
This property was introduced to avoid issues in cases of big MDC.
116+
By default this value set to `true` for backward compatibility.
117+
The `false` turns off serialization MDC into headers.
118+
Please note, the `JsonLayout` adds MDC into the message by default.
119+
112120
|===
113121

114122
==== Log4j Appender
@@ -144,7 +152,8 @@ NOTE: This appender is deprecated and will be removed in _version 2.0_.
144152
applicationId="myAppId" routingKeyPattern="%X{applicationId}.%c.%p"
145153
contentType="text/plain" contentEncoding="UTF-8" generateId="true" deliveryMode="NON_PERSISTENT"
146154
charset="UTF-8"
147-
senderPoolSize="3" maxSenderRetries="5">
155+
senderPoolSize="3" maxSenderRetries="5"
156+
addMdcAsHeaders="false">
148157
</RabbitMQ>
149158
</Appenders>
150159
----
@@ -179,6 +188,7 @@ If async publishing is used with the `ReusableLogEventFactory`, events will have
179188
<durable>false</durable>
180189
<deliveryMode>NON_PERSISTENT</deliveryMode>
181190
<declareExchange>true</declareExchange>
191+
<addMdcAsHeaders>false</addMdcAsHeaders>
182192
</appender>
183193
----
184194

0 commit comments

Comments
 (0)