When we using rabbitMQ topic exchange, We can send a message at everywhere. And our project is very large, when I receive a message, and we found there is a problem in the message and we want to modify the message at where it was sent. But it is hardly be found where the message was sent.
Is there a method or a command tool in rabbitMQ to find out where that message sent from.
there are a few information that you can take using the envelop, as exchange, delivery_tag, routing_key :
Consumer consumer_a = new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
long delivery_tag = envelope.getDeliveryTag();
String exchange_from = envelope.getExchange();
String routing_key = envelope.getRoutingKey();
}
};
if you need more info you can use the headers to add custom information as:
var properties = new BasicProperties();
properties.Headers = new Dictionary<string, object>();
properties.Headers.Add("mysender_user", "my_server");
properties.Headers.Add("my_custom_info", "my_info");
channel.BasicPublish(ExchangeName, "", properties, message);
Related
The header of my message in RabbitMQ Queue has this specification:
headers={
httpHeaders={transactionID=123, sessionID=451554},
contentType=text/plain,
timestamp=1539607167303
}
so I have an embedded Hashmap in the key named httpHeaders.
I want replicate this behaviour using the RabbitMQ UI, but I do not understand how to set it
The select List options are only: String, Boolean, Number and List
This is my test that replicate programmatically the Message Header:
#Test
public void getTransactionId() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String payload = "payload";
Map messageHeader = new HashMap();
Map httpHeader = new HashMap();
httpHeader.put(HttpHeaderKeys.TRANSACTION_ID_KEY, "123");
messageHeader.put(HTTP_HEADER_KEY, httpHeader);
MessageHeaders messageHeaders = new MessageHeaders(messageHeader);
GenericMessage message = new GenericMessage(payload, messageHeaders);
Method method = MDCUtils.class.getDeclaredMethod("getTransactionId", Message.class);
method.setAccessible(true);
Object result = method.invoke(null, message);
assertEquals("123", result);
}
You can add the headers in this way:
I want to set message header while sending a message to rabbit.
I am using below code, but confused how to set message header in it.
public static <T> void sendMessage(String routingKey,final Object message,Class<T> type){
DefaultClassMapper typeMapper = new DefaultClassMapper();
typeMapper.setDefaultType(type);
Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
converter.setClassMapper(typeMapper);
RabbitTemplate template = new RabbitTemplate(getConnectionFactory));
template.setMessageConverter(converter);
template.convertAndSend(routingKey, message);
}
In above method i am simply arguementing java POJO object and its type to send. I want to know where should i set message header here.
How to listen the message properties at listener end?
Java 8:
template.convertAndSend(routingKey, message, m -> {
m.getMessageProperties().getHeaders().put("foo", "bar");
m.getMessageProperties().setPriority(priority);
return m;
});
Java 6,7:
template.convertAndSend(routingKey, message, new MessagePostProcessor() {
#Override
public Message postProcessMessage(Message m) throws AmqpException {
m.getMessageProperties().getHeaders().put("foo", "bar");
m.getMessageProperties().setPriority(priority);
return m;
}
});
I'm reading data from RabbitMQ (java client) in this way.
while(true)
{
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(message);
}
Can I read all the data in the queue without while loop?
Have you read the tutorials on the RabbitMQ website?
this looks like the basic java code for consuming messages:
Consumer consumer = new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
this should send all messages to the specified consumer.
I have a wcf service and I am trying to call it from other client, but the response I am getting as a reply is incomplete. It stops from the
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
if (Log.IsDebugEnabled)
{
Log.Debug("VisService SOAP Response >>>");
//create a copy of the response for logging purpose
MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
reply = buffer.CreateMessage();
//log the copy to avoid removal of the actual response object
System.ServiceModel.Channels.Message replyCopy = buffer.CreateMessage();
MemoryStream ms = new MemoryStream();
System.Xml.XmlDictionaryWriter writer = System.Xml.XmlDictionaryWriter.CreateTextWriter(ms);
replyCopy.WriteMessage(writer);
//move the position of the cursor to the begining to
//read the entire message from start
ms.Position = 0;
string visServiceSOAPResponse = new StreamReader(ms, Encoding.UTF8).ReadLine();
Log.Debug(visServiceSOAPResponse);
//For displaying the message in the mail confirmation box
SaveResponseToLog("\nVisService SOAP Response >>>\n" + visServiceSOAPResponse);
}
}
//This function logs the SOAP
//request in the application log file
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
if (Log.IsDebugEnabled)
{
string visServiceSOAPRequest = request.ToString();
Log.Debug("VisService SOAP Request >>>");
Log.Debug(visServiceSOAPRequest);
//For displaying the message in the mail confirmation box
SaveResponseToLog("\nVisService SOAP Request >>>\n" + visServiceSOAPRequest);
}
return null;
}
}
and the response from the wcf is only till the "...xmlns="
Your log writing function is buggy. Please scrap it alltogether. Use AppendAllText if you want to append text to a file.
In addition, you seem to read only the first line of the response. You need to read the whole response before writing it to the file.
Edit:
Your log function has too many bugs and weird things to actually fix it. Replace it with:
private void SaveResponseToLog(string msg)
{
System.IO.File.AppendAllText(filename, msg, Encoding.UTF8);
}
I have a Custom ClientMessageInspector that records requests but not replies to my service.
The code is:
namespace MessageListener.Instrumentation
{
public class MessageInspector : IClientMessageInspector
{
private Message TraceMessage(MessageBuffer buffer)
{
// Must use a buffer rather than the original message, because the Message's body can be processed only once.
Message msg = buffer.CreateMessage();
using (RREM_GilbaneEntities3 entities3 = new RREM_GilbaneEntities3())
{
SOAPMessage soapMessages = new SOAPMessage
{
SOAPMessage1 = msg.ToString(),
created = DateTime.Now,
source = "Interface12",
sourceIP = "Interface12"
};
entities3.SOAPMessages.Add(soapMessages);
entities3.SaveChanges();
}
//Return copy of origonal message with unalterd State
return buffer.CreateMessage();
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
reply = TraceMessage(reply.CreateBufferedCopy(int.MaxValue));
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request = TraceMessage(request.CreateBufferedCopy(int.MaxValue));
return null;
}
}
}
What seems to be happening is both AfterRecievReply and BeforeSendRequest are being called. In AfterRecieveReply before I call TraceMessage, I can see the whole reply. Inside TraceMessage, when I do:
// Must use a buffer rather than the original message, because the Message's body can be processed only once.
Message msg = buffer.CreateMessage();
it turns the reply into junk:
msg {<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header />
<soap:Body>... stream ...</soap:Body>
</soap:Envelope>}
What's going on?
The reply isn't a junk message - it's just when you call ToString on it that it doesn't show the body of the message. Remember that a message can only be consumed once; once its body is read, it cannot be read again. Since many places (including the watch window of debuggers) will call ToString on an object, this method is implemented in a way that if it doesn't know for sure that a message body can be read multiple times, then it won't, which seems to be your case. If you want to really write out the message, try using this code:
public string MessageToString(Message message) {
using (MemoryStream ms = new MemoryStream()) {
XmlWriterSettings ws = new XmlWriterSettings();
ws.Encoding = new UTF8Encoding(false);
using (XmlWriter w = XmlWriter.Create(ms)) {
message.WriteMessage(w);
w.Flush();
return ws.Encoding.GetString(ms.ToArray());
}
}
}