001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.broker.util; 018 019import java.util.Set; 020 021import javax.annotation.PostConstruct; 022 023import org.apache.activemq.broker.BrokerPluginSupport; 024import org.apache.activemq.broker.Connection; 025import org.apache.activemq.broker.ConnectionContext; 026import org.apache.activemq.broker.ConsumerBrokerExchange; 027import org.apache.activemq.broker.ProducerBrokerExchange; 028import org.apache.activemq.broker.region.Destination; 029import org.apache.activemq.broker.region.MessageReference; 030import org.apache.activemq.broker.region.Subscription; 031import org.apache.activemq.command.*; 032import org.apache.activemq.usage.Usage; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * A simple Broker intercepter which allows you to enable/disable logging. 038 * 039 * @org.apache.xbean.XBean 040 */ 041public class LoggingBrokerPlugin extends BrokerPluginSupport { 042 043 private static final Logger LOG = LoggerFactory.getLogger(LoggingBrokerPlugin.class); 044 045 private boolean logAll = false; 046 private boolean logConnectionEvents = true; 047 private boolean logSessionEvents = true; 048 private boolean logTransactionEvents = false; 049 private boolean logConsumerEvents = false; 050 private boolean logProducerEvents = false; 051 private boolean logInternalEvents = false; 052 private boolean perDestinationLogger = false; 053 054 /** 055 * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions 056 * 057 * delegates to afterPropertiesSet, done to prevent backwards incompatible signature change 058 */ 059 @PostConstruct 060 private void postConstruct() { 061 try { 062 afterPropertiesSet(); 063 } catch (Exception ex) { 064 throw new RuntimeException(ex); 065 } 066 } 067 068 /** 069 * @throws Exception 070 * @org.apache.xbean.InitMethod 071 */ 072 public void afterPropertiesSet() throws Exception { 073 LOG.info("Created LoggingBrokerPlugin: {}", this.toString()); 074 } 075 076 public boolean isLogAll() { 077 return logAll; 078 } 079 080 /** 081 * Logger all Events that go through the Plugin 082 */ 083 public void setLogAll(boolean logAll) { 084 this.logAll = logAll; 085 } 086 087 088 public boolean isLogConnectionEvents() { 089 return logConnectionEvents; 090 } 091 092 /** 093 * Logger Events that are related to connections 094 */ 095 public void setLogConnectionEvents(boolean logConnectionEvents) { 096 this.logConnectionEvents = logConnectionEvents; 097 } 098 099 public boolean isLogSessionEvents() { 100 return logSessionEvents; 101 } 102 103 /** 104 * Logger Events that are related to sessions 105 */ 106 public void setLogSessionEvents(boolean logSessionEvents) { 107 this.logSessionEvents = logSessionEvents; 108 } 109 110 public boolean isLogTransactionEvents() { 111 return logTransactionEvents; 112 } 113 114 /** 115 * Logger Events that are related to transaction processing 116 */ 117 public void setLogTransactionEvents(boolean logTransactionEvents) { 118 this.logTransactionEvents = logTransactionEvents; 119 } 120 121 public boolean isLogConsumerEvents() { 122 return logConsumerEvents; 123 } 124 125 /** 126 * Logger Events that are related to Consumers 127 */ 128 public void setLogConsumerEvents(boolean logConsumerEvents) { 129 this.logConsumerEvents = logConsumerEvents; 130 } 131 132 public boolean isLogProducerEvents() { 133 return logProducerEvents; 134 } 135 136 /** 137 * Logger Events that are related to Producers 138 */ 139 public void setLogProducerEvents(boolean logProducerEvents) { 140 this.logProducerEvents = logProducerEvents; 141 } 142 143 public boolean isLogInternalEvents() { 144 return logInternalEvents; 145 } 146 147 /** 148 * Logger Events that are normally internal to the broker 149 */ 150 public void setLogInternalEvents(boolean logInternalEvents) { 151 this.logInternalEvents = logInternalEvents; 152 } 153 154 @Override 155 public void acknowledge(ConsumerBrokerExchange consumerExchange, MessageAck ack) throws Exception { 156 if (isLogAll() || isLogConsumerEvents()) { 157 LOG.info("Acknowledging message for client ID: {}{}", consumerExchange.getConnectionContext().getClientId(), (ack.getMessageCount() == 1 ? ", " + ack.getLastMessageId() : "")); 158 if (ack.getMessageCount() > 1) { 159 LOG.trace("Message count: {}, First Message Id: {}, Last Message Id: {}", 160 ack.getMessageCount(), ack.getFirstMessageId(), ack.getLastMessageId()); 161 } 162 } 163 super.acknowledge(consumerExchange, ack); 164 } 165 166 @Override 167 public Response messagePull(ConnectionContext context, MessagePull pull) throws Exception { 168 if (isLogAll() || isLogConsumerEvents()) { 169 LOG.info("Message Pull from: {} on {}", context.getClientId(), pull.getDestination().getPhysicalName()); 170 } 171 return super.messagePull(context, pull); 172 } 173 174 @Override 175 public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 176 if (isLogAll() || isLogConnectionEvents()) { 177 LOG.info("Adding Connection: {}", info); 178 } 179 super.addConnection(context, info); 180 } 181 182 @Override 183 public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 184 if (isLogAll() || isLogConsumerEvents()) { 185 LOG.info("Adding Consumer: {}", info); 186 } 187 return super.addConsumer(context, info); 188 } 189 190 @Override 191 public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { 192 if (isLogAll() || isLogProducerEvents()) { 193 LOG.info("Adding Producer: {}", info); 194 } 195 super.addProducer(context, info); 196 } 197 198 @Override 199 public void commitTransaction(ConnectionContext context, TransactionId xid, boolean onePhase) throws Exception { 200 if (isLogAll() || isLogTransactionEvents()) { 201 LOG.info("Committing transaction: {}", xid.getTransactionKey()); 202 } 203 super.commitTransaction(context, xid, onePhase); 204 } 205 206 @Override 207 public void removeSubscription(ConnectionContext context, RemoveSubscriptionInfo info) throws Exception { 208 if (isLogAll() || isLogConsumerEvents()) { 209 LOG.info("Removing subscription: {}", info); 210 } 211 super.removeSubscription(context, info); 212 } 213 214 @Override 215 public TransactionId[] getPreparedTransactions(ConnectionContext context) throws Exception { 216 217 TransactionId[] result = super.getPreparedTransactions(context); 218 if ((isLogAll() || isLogTransactionEvents()) && result != null) { 219 StringBuffer tids = new StringBuffer(); 220 for (TransactionId tid : result) { 221 if (tids.length() > 0) { 222 tids.append(", "); 223 } 224 tids.append(tid.getTransactionKey()); 225 } 226 LOG.info("Prepared transactions: {}", tids); 227 } 228 return result; 229 } 230 231 @Override 232 public int prepareTransaction(ConnectionContext context, TransactionId xid) throws Exception { 233 if (isLogAll() || isLogTransactionEvents()) { 234 LOG.info("Preparing transaction: {}", xid.getTransactionKey()); 235 } 236 return super.prepareTransaction(context, xid); 237 } 238 239 @Override 240 public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception { 241 if (isLogAll() || isLogConnectionEvents()) { 242 LOG.info("Removing Connection: {}", info); 243 } 244 super.removeConnection(context, info, error); 245 } 246 247 @Override 248 public void removeConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 249 if (isLogAll() || isLogConsumerEvents()) { 250 LOG.info("Removing Consumer: {}", info); 251 } 252 super.removeConsumer(context, info); 253 } 254 255 @Override 256 public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception { 257 if (isLogAll() || isLogProducerEvents()) { 258 LOG.info("Removing Producer: {}", info); 259 } 260 super.removeProducer(context, info); 261 } 262 263 @Override 264 public void rollbackTransaction(ConnectionContext context, TransactionId xid) throws Exception { 265 if (isLogAll() || isLogTransactionEvents()) { 266 LOG.info("Rolling back Transaction: {}", xid.getTransactionKey()); 267 } 268 super.rollbackTransaction(context, xid); 269 } 270 271 @Override 272 public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception { 273 if (isLogAll() || isLogProducerEvents()) { 274 logSend(messageSend.copy()); 275 } 276 super.send(producerExchange, messageSend); 277 } 278 279 private void logSend(Message copy) { 280 copy.getSize(); 281 Logger perDestinationsLogger = LOG; 282 if (isPerDestinationLogger()) { 283 ActiveMQDestination destination = copy.getDestination(); 284 perDestinationsLogger = LoggerFactory.getLogger(LOG.getName() + 285 "." + destination.getDestinationTypeAsString() + "." + destination.getPhysicalName()); 286 } 287 perDestinationsLogger.info("Sending message: {}", copy); 288 } 289 290 @Override 291 public void beginTransaction(ConnectionContext context, TransactionId xid) throws Exception { 292 if (isLogAll() || isLogTransactionEvents()) { 293 LOG.info("Beginning transaction: {}", xid.getTransactionKey()); 294 } 295 super.beginTransaction(context, xid); 296 } 297 298 @Override 299 public void forgetTransaction(ConnectionContext context, TransactionId transactionId) throws Exception { 300 if (isLogAll() || isLogTransactionEvents()) { 301 LOG.info("Forgetting transaction: {}", transactionId.getTransactionKey()); 302 } 303 super.forgetTransaction(context, transactionId); 304 } 305 306 @Override 307 public Connection[] getClients() throws Exception { 308 Connection[] result = super.getClients(); 309 310 if (isLogAll() || isLogInternalEvents()) { 311 if (result == null) { 312 LOG.info("Get Clients returned empty list."); 313 } else { 314 StringBuffer cids = new StringBuffer(); 315 for (Connection c : result) { 316 cids.append(cids.length() > 0 ? ", " : ""); 317 cids.append(c.getConnectionId()); 318 } 319 LOG.info("Connected clients: {}", cids); 320 } 321 } 322 return super.getClients(); 323 } 324 325 @Override 326 public org.apache.activemq.broker.region.Destination addDestination(ConnectionContext context, 327 ActiveMQDestination destination, boolean create) throws Exception { 328 if (isLogAll() || isLogInternalEvents()) { 329 LOG.info("Adding destination: {}:{}", destination.getDestinationTypeAsString(), destination.getPhysicalName()); 330 } 331 return super.addDestination(context, destination, create); 332 } 333 334 @Override 335 public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout) 336 throws Exception { 337 if (isLogAll() || isLogInternalEvents()) { 338 LOG.info("Removing destination: {}:{}", destination.getDestinationTypeAsString(), destination.getPhysicalName()); 339 } 340 super.removeDestination(context, destination, timeout); 341 } 342 343 @Override 344 public ActiveMQDestination[] getDestinations() throws Exception { 345 ActiveMQDestination[] result = super.getDestinations(); 346 if (isLogAll() || isLogInternalEvents()) { 347 if (result == null) { 348 LOG.info("Get Destinations returned empty list."); 349 } else { 350 StringBuffer destinations = new StringBuffer(); 351 for (ActiveMQDestination dest : result) { 352 destinations.append(destinations.length() > 0 ? ", " : ""); 353 destinations.append(dest.getPhysicalName()); 354 } 355 LOG.info("Get Destinations: {}", destinations); 356 } 357 } 358 return result; 359 } 360 361 @Override 362 public void start() throws Exception { 363 if (isLogAll() || isLogInternalEvents()) { 364 LOG.info("Starting {}", getBrokerName()); 365 } 366 super.start(); 367 } 368 369 @Override 370 public void stop() throws Exception { 371 if (isLogAll() || isLogInternalEvents()) { 372 LOG.info("Stopping {}", getBrokerName()); 373 } 374 super.stop(); 375 } 376 377 @Override 378 public void addSession(ConnectionContext context, SessionInfo info) throws Exception { 379 if (isLogAll() || isLogSessionEvents()) { 380 LOG.info("Adding Session: {}", info); 381 } 382 super.addSession(context, info); 383 } 384 385 @Override 386 public void removeSession(ConnectionContext context, SessionInfo info) throws Exception { 387 if (isLogAll() || isLogSessionEvents()) { 388 LOG.info("Removing Session: {}", info); 389 } 390 super.removeSession(context, info); 391 } 392 393 @Override 394 public void addBroker(Connection connection, BrokerInfo info) { 395 if (isLogAll() || isLogInternalEvents()) { 396 LOG.info("Adding Broker {}", info.getBrokerName()); 397 } 398 super.addBroker(connection, info); 399 } 400 401 @Override 402 public void removeBroker(Connection connection, BrokerInfo info) { 403 if (isLogAll() || isLogInternalEvents()) { 404 LOG.info("Removing Broker {}", info.getBrokerName()); 405 } 406 super.removeBroker(connection, info); 407 } 408 409 @Override 410 public BrokerInfo[] getPeerBrokerInfos() { 411 BrokerInfo[] result = super.getPeerBrokerInfos(); 412 if (isLogAll() || isLogInternalEvents()) { 413 if (result == null) { 414 LOG.info("Get Peer Broker Infos returned empty list."); 415 } else { 416 StringBuffer peers = new StringBuffer(); 417 for (BrokerInfo bi : result) { 418 peers.append(peers.length() > 0 ? ", " : ""); 419 peers.append(bi.getBrokerName()); 420 } 421 LOG.info("Get Peer Broker Infos: {}", peers); 422 } 423 } 424 return result; 425 } 426 427 @Override 428 public void preProcessDispatch(MessageDispatch messageDispatch) { 429 if (isLogAll() || isLogInternalEvents() || isLogConsumerEvents()) { 430 LOG.info("preProcessDispatch: {}", messageDispatch); 431 } 432 super.preProcessDispatch(messageDispatch); 433 } 434 435 @Override 436 public void postProcessDispatch(MessageDispatch messageDispatch) { 437 if (isLogAll() || isLogInternalEvents() || isLogConsumerEvents()) { 438 LOG.info("postProcessDispatch: {}", messageDispatch); 439 } 440 super.postProcessDispatch(messageDispatch); 441 } 442 443 @Override 444 public void processDispatchNotification(MessageDispatchNotification messageDispatchNotification) throws Exception { 445 if (isLogAll() || isLogInternalEvents() || isLogConsumerEvents()) { 446 LOG.info("ProcessDispatchNotification: {}", messageDispatchNotification); 447 } 448 super.processDispatchNotification(messageDispatchNotification); 449 } 450 451 @Override 452 public Set<ActiveMQDestination> getDurableDestinations() { 453 Set<ActiveMQDestination> result = super.getDurableDestinations(); 454 if (isLogAll() || isLogInternalEvents()) { 455 if (result == null) { 456 LOG.info("Get Durable Destinations returned empty list."); 457 } else { 458 StringBuffer destinations = new StringBuffer(); 459 for (ActiveMQDestination dest : result) { 460 destinations.append(destinations.length() > 0 ? ", " : ""); 461 destinations.append(dest.getPhysicalName()); 462 } 463 LOG.info("Get Durable Destinations: {}", destinations); 464 } 465 } 466 return result; 467 } 468 469 @Override 470 public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception { 471 if (isLogAll() || isLogInternalEvents()) { 472 LOG.info("Adding destination info: {}", info); 473 } 474 super.addDestinationInfo(context, info); 475 } 476 477 @Override 478 public void removeDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception { 479 if (isLogAll() || isLogInternalEvents()) { 480 LOG.info("Removing destination info: {}", info); 481 } 482 super.removeDestinationInfo(context, info); 483 } 484 485 @Override 486 public void messageExpired(ConnectionContext context, MessageReference message, Subscription subscription) { 487 if (isLogAll() || isLogInternalEvents()) { 488 String msg = "Unable to display message."; 489 490 msg = message.getMessage().toString(); 491 492 LOG.info("Message has expired: {}", msg); 493 } 494 super.messageExpired(context, message, subscription); 495 } 496 497 @Override 498 public boolean sendToDeadLetterQueue(ConnectionContext context, MessageReference messageReference, 499 Subscription subscription, Throwable poisonCause) { 500 if (isLogAll() || isLogInternalEvents()) { 501 String msg = "Unable to display message."; 502 503 msg = messageReference.getMessage().toString(); 504 505 LOG.info("Sending to DLQ: {}", msg); 506 } 507 return super.sendToDeadLetterQueue(context, messageReference, subscription, poisonCause); 508 } 509 510 @Override 511 public void fastProducer(ConnectionContext context, ProducerInfo producerInfo,ActiveMQDestination destination) { 512 if (isLogAll() || isLogProducerEvents() || isLogInternalEvents()) { 513 LOG.info("Fast Producer: {}", producerInfo); 514 } 515 super.fastProducer(context, producerInfo, destination); 516 } 517 518 @Override 519 public void isFull(ConnectionContext context, Destination destination, Usage<?> usage) { 520 if (isLogAll() || isLogProducerEvents() || isLogInternalEvents()) { 521 LOG.info("Destination is full: {}", destination.getName()); 522 } 523 super.isFull(context, destination, usage); 524 } 525 526 @Override 527 public void messageConsumed(ConnectionContext context, MessageReference messageReference) { 528 if (isLogAll() || isLogConsumerEvents() || isLogInternalEvents()) { 529 String msg = "Unable to display message."; 530 531 msg = messageReference.getMessage().toString(); 532 533 LOG.info("Message consumed: {}", msg); 534 } 535 super.messageConsumed(context, messageReference); 536 } 537 538 @Override 539 public void messageDelivered(ConnectionContext context, MessageReference messageReference) { 540 if (isLogAll() || isLogConsumerEvents() || isLogInternalEvents()) { 541 String msg = "Unable to display message."; 542 543 msg = messageReference.getMessage().toString(); 544 545 LOG.info("Message delivered: {}", msg); 546 } 547 super.messageDelivered(context, messageReference); 548 } 549 550 @Override 551 public void messageDiscarded(ConnectionContext context, Subscription sub, MessageReference messageReference) { 552 if (isLogAll() || isLogInternalEvents()) { 553 String msg = "Unable to display message."; 554 555 msg = messageReference.getMessage().toString(); 556 557 LOG.info("Message discarded: {}", msg); 558 } 559 super.messageDiscarded(context, sub, messageReference); 560 } 561 562 @Override 563 public void slowConsumer(ConnectionContext context, Destination destination, Subscription subs) { 564 if (isLogAll() || isLogConsumerEvents() || isLogInternalEvents()) { 565 LOG.info("Detected slow consumer on {}", destination.getName()); 566 StringBuffer buf = new StringBuffer("Connection("); 567 buf.append(subs.getConsumerInfo().getConsumerId().getConnectionId()); 568 buf.append(") Session("); 569 buf.append(subs.getConsumerInfo().getConsumerId().getSessionId()); 570 buf.append(")"); 571 LOG.info(buf.toString()); 572 } 573 super.slowConsumer(context, destination, subs); 574 } 575 576 @Override 577 public void nowMasterBroker() { 578 if (isLogAll() || isLogInternalEvents()) { 579 LOG.info("Is now the master broker: {}", getBrokerName()); 580 } 581 super.nowMasterBroker(); 582 } 583 584 @Override 585 public String toString() { 586 StringBuffer buf = new StringBuffer(); 587 buf.append("LoggingBrokerPlugin("); 588 buf.append("logAll="); 589 buf.append(isLogAll()); 590 buf.append(", logConnectionEvents="); 591 buf.append(isLogConnectionEvents()); 592 buf.append(", logSessionEvents="); 593 buf.append(isLogSessionEvents()); 594 buf.append(", logConsumerEvents="); 595 buf.append(isLogConsumerEvents()); 596 buf.append(", logProducerEvents="); 597 buf.append(isLogProducerEvents()); 598 buf.append(", logTransactionEvents="); 599 buf.append(isLogTransactionEvents()); 600 buf.append(", logInternalEvents="); 601 buf.append(isLogInternalEvents()); 602 buf.append(")"); 603 return buf.toString(); 604 } 605 606 public void setPerDestinationLogger(boolean perDestinationLogger) { 607 this.perDestinationLogger = perDestinationLogger; 608 } 609 610 public boolean isPerDestinationLogger() { 611 return perDestinationLogger; 612 } 613}