killbill-aplcache

Details

diff --git a/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java b/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
index f84d013..52d1ec3 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingInternalApi.java
@@ -22,12 +22,12 @@ import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.invoice.api.DryRunArguments;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 
 public interface BillingInternalApi {
 
     /**
      * @return an ordered list of billing event for the given accounts
      */
-    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId, DryRunArguments dryRunArguments, InternalCallContext context) throws CatalogApiException, AccountApiException;
-
+    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId, DryRunArguments dryRunArguments, InternalCallContext context) throws CatalogApiException, AccountApiException, SubscriptionBaseApiException;
 }
diff --git a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
index b1a56b4..03b8543 100644
--- a/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
+++ b/beatrix/src/main/java/org/killbill/billing/beatrix/extbus/BeatrixListener.java
@@ -57,6 +57,7 @@ import org.killbill.billing.lifecycle.glue.BusModule;
 import org.killbill.billing.notification.plugin.api.BlockingStateMetadata;
 import org.killbill.billing.notification.plugin.api.BroadcastMetadata;
 import org.killbill.billing.notification.plugin.api.ExtBusEventType;
+import org.killbill.billing.notification.plugin.api.PaymentMetadata;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -231,6 +232,8 @@ public class BeatrixListener {
                 objectType = ObjectType.PAYMENT;
                 objectId = realEventPay.getPaymentId();
                 eventBusType = ExtBusEventType.PAYMENT_SUCCESS;
+                final PaymentMetadata paymentInfoMetaDataObj = new PaymentMetadata(realEventPay.getPaymentTransactionId(), realEventPay.getAmount(), realEventPay.getCurrency(), realEventPay.getStatus(), realEventPay.getTransactionType(), realEventPay.getEffectiveDate());
+                metaData = objectMapper.writeValueAsString(paymentInfoMetaDataObj);
                 break;
 
             case PAYMENT_ERROR:
@@ -239,6 +242,8 @@ public class BeatrixListener {
                 objectId = realEventPayErr.getPaymentId();
                 eventBusType = ExtBusEventType.PAYMENT_FAILED;
                 accountId = realEventPayErr.getAccountId();
+                final PaymentMetadata paymentErrorMetaDataObj = new PaymentMetadata(realEventPayErr.getPaymentTransactionId(), realEventPayErr.getAmount(), realEventPayErr.getCurrency(), realEventPayErr.getStatus(), realEventPayErr.getTransactionType(), realEventPayErr.getEffectiveDate());
+                metaData = objectMapper.writeValueAsString(paymentErrorMetaDataObj);
                 break;
 
             case PAYMENT_PLUGIN_ERROR:
@@ -246,6 +251,8 @@ public class BeatrixListener {
                 objectType = ObjectType.PAYMENT;
                 objectId = realEventPayPluginErr.getPaymentId();
                 eventBusType = ExtBusEventType.PAYMENT_FAILED;
+                final PaymentMetadata pluginErrorMetaDataObj = new PaymentMetadata(realEventPayPluginErr.getPaymentTransactionId(), realEventPayPluginErr.getAmount(), realEventPayPluginErr.getCurrency(), realEventPayPluginErr.getStatus(), realEventPayPluginErr.getTransactionType(), realEventPayPluginErr.getEffectiveDate());
+                metaData = objectMapper.writeValueAsString(pluginErrorMetaDataObj);
                 break;
 
             case OVERDUE_CHANGE:
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index a4b7d54..c29c28a 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -263,10 +263,13 @@ public class InvoiceDispatcher {
             }
             return null;
         } catch (final CatalogApiException e) {
-            log.error("Failed handling SubscriptionBase change.", e);
+            log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
             return null;
         } catch (final AccountApiException e) {
-            log.error("Failed handling SubscriptionBase change.", e);
+            log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
+            return null;
+        } catch (final SubscriptionBaseApiException e) {
+            log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
             return null;
         }
     }
@@ -708,6 +711,14 @@ public class InvoiceDispatcher {
         public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return null;
         }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("TargetDateDryRunArguments{");
+            sb.append("dryRunType=").append(DryRunType.TARGET_DATE);
+            sb.append('}');
+            return sb.toString();
+        }
     }
 
     public void processParentInvoiceForInvoiceGeneration(final ImmutableAccountData account, final UUID childInvoiceId, final InternalCallContext context) throws InvoiceApiException {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index 7fbb972..cfedd3c 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -48,6 +48,7 @@ import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -69,7 +70,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testDryRunInvoice() throws InvoiceApiException, AccountApiException, CatalogApiException {
+    public void testDryRunInvoice() throws InvoiceApiException, AccountApiException, CatalogApiException, SubscriptionBaseApiException {
         final UUID accountId = account.getId();
 
         final BillingEventSet events = new MockBillingEventSet();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index ba275b6..2b6f285 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -1107,5 +1107,20 @@ public class InvoiceResource extends JaxRsResourceBase {
         public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
             return overrides;
         }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("DefaultDryRunArguments{");
+            sb.append("dryRunType=").append(dryRunType);
+            sb.append(", action=").append(action);
+            sb.append(", subscriptionId=").append(subscriptionId);
+            sb.append(", effectiveDate=").append(effectiveDate);
+            sb.append(", specifier=").append(specifier);
+            sb.append(", bundleId=").append(bundleId);
+            sb.append(", billingPolicy=").append(billingPolicy);
+            sb.append(", overrides=").append(overrides);
+            sb.append('}');
+            return sb.toString();
+        }
     }
 }
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index fa032bb..85691aa 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -32,14 +32,12 @@ import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingAlignment;
-import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
@@ -88,26 +86,25 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
     }
 
     @Override
-    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final DryRunArguments dryRunArguments, final InternalCallContext context) throws CatalogApiException, AccountApiException {
+    public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final DryRunArguments dryRunArguments, final InternalCallContext context) throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
+
         final StaticCatalog currentCatalog = catalogService.getCurrentCatalog(true, true, context);
 
         // Check to see if billing is off for the account
         final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
         final boolean found_AUTO_INVOICING_OFF = is_AUTO_INVOICING_OFF(accountTags);
-        if (found_AUTO_INVOICING_OFF) {
-            return new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode()); // billing is off, we are done
-        }
 
-        final List<SubscriptionBaseBundle> bundles = subscriptionApi.getBundlesForAccount(accountId, context);
+        final Set<UUID> skippedSubscriptions = new HashSet<UUID>();
+        final DefaultBillingEventSet result;
 
-        final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
-        final DefaultBillingEventSet result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode());
+        if (found_AUTO_INVOICING_OFF) {
+            result = new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode()); // billing is off, we are done
+        } else {
+            final List<SubscriptionBaseBundle> bundles = subscriptionApi.getBundlesForAccount(accountId, context);
 
-        final Set<UUID> skippedSubscriptions = new HashSet<UUID>();
-        try {
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
+            result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode());
             addBillingEventsForBundles(bundles, account, dryRunArguments, context, result, skippedSubscriptions);
-        } catch (final SubscriptionBaseApiException e) {
-            log.warn("Failed while getting BillingEvent", e);
         }
 
         if (result.isEmpty()) {
@@ -188,6 +185,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
             // The subscription did not even start, so there is nothing to do yet, we can skip and avoid some NPE down the line when calculating the BCD
             if (subscription.getState() == EntitlementState.PENDING) {
+                log.info("Skipping subscription id='{}', state = EntitlementState.PENDING", subscription.getId());
                 continue;
             }
 
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
index 331a0dd..eddb672 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
@@ -53,6 +53,7 @@ import org.killbill.billing.mock.MockEffectiveSubscriptionEvent;
 import org.killbill.billing.mock.MockSubscription;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.tag.ControlTagType;
@@ -115,13 +116,13 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsEmpty() throws AccountApiException, CatalogApiException {
+    public void testBillingEventsEmpty() throws AccountApiException, CatalogApiException, SubscriptionBaseApiException {
         final SortedSet<BillingEvent> events = billingInternalApi.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L, 0L), null, internalCallContext);
         Assert.assertEquals(events.size(), 0);
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsNoBillingPeriod() throws CatalogApiException, AccountApiException {
+    public void testBillingEventsNoBillingPeriod() throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         // The trial has no billing period
         final PlanPhase nextPhase = nextPlan.getAllPhases()[0];
@@ -134,7 +135,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsSubscriptionAligned() throws CatalogApiException, AccountApiException {
+    public void testBillingEventsSubscriptionAligned() throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final DateTime now = createSubscriptionCreationEvent(nextPlan, nextPhase);
@@ -149,7 +150,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsAccountAligned() throws CatalogApiException, AccountApiException {
+    public void testBillingEventsAccountAligned() throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final DateTime now = createSubscriptionCreationEvent(nextPlan, nextPhase);
@@ -162,7 +163,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsBundleAligned() throws CatalogApiException, AccountApiException {
+    public void testBillingEventsBundleAligned() throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("7-Horn1USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[0];
         final DateTime now = createSubscriptionCreationEvent(nextPlan, nextPhase);
@@ -178,7 +179,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsWithBlock() throws CatalogApiException, AccountApiException {
+    public void testBillingEventsWithBlock() throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         final DateTime now = createSubscriptionCreationEvent(nextPlan, nextPhase);
@@ -200,7 +201,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsAutoInvoicingOffAccount() throws CatalogApiException, AccountApiException, TagApiException {
+    public void testBillingEventsAutoInvoicingOffAccount() throws CatalogApiException, AccountApiException, TagApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         createSubscriptionCreationEvent(nextPlan, nextPhase);
@@ -216,7 +217,7 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testBillingEventsAutoInvoicingOffBundle() throws CatalogApiException, AccountApiException, TagApiException {
+    public void testBillingEventsAutoInvoicingOffBundle() throws CatalogApiException, AccountApiException, TagApiException, SubscriptionBaseApiException {
         final Plan nextPlan = catalog.findPlan("3-PickupTrialEvergreen10USD", clock.getUTCNow());
         final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
         createSubscriptionCreationEvent(nextPlan, nextPhase);
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 96ad05e..b4bb5f4 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -84,6 +84,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.AUTHORIZE.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
@@ -94,6 +95,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -106,7 +110,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -132,16 +137,20 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createAuthorization(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
-                                                                                      properties, paymentControlPluginNames, callContext, internalCallContext);
+                                                                        properties, paymentControlPluginNames, callContext, internalCallContext);
 
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -154,7 +163,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -172,6 +182,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CAPTURE.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
@@ -182,6 +193,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -194,7 +208,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -216,6 +231,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CAPTURE.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -226,6 +242,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -238,7 +257,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
 
     }
@@ -258,6 +278,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.PURCHASE.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
@@ -268,6 +289,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -280,7 +304,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -316,7 +341,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.PURCHASE.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
-
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -326,6 +351,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -338,7 +366,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -354,6 +383,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.VOID.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
 
@@ -364,6 +394,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -376,7 +409,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
 
     }
@@ -396,6 +430,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.VOID.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -406,6 +441,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -418,7 +456,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -436,6 +475,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.REFUND.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
@@ -446,6 +486,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -458,7 +501,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -481,6 +525,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.REFUND.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -491,6 +536,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -503,7 +551,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -522,6 +571,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CREDIT.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
@@ -536,6 +586,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -548,7 +601,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -572,6 +626,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CREDIT.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -590,6 +645,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -602,7 +660,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -626,6 +685,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = "NOTIFY_STATE_CHANGE";
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, null, paymentTransactionId, null, null, null, null, null, null);
 
@@ -640,6 +700,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                                                                                                     }
                                                                                                 }).orNull();
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -652,7 +715,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -672,6 +736,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CHARGEBACK.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
@@ -682,6 +747,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -694,7 +762,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -713,6 +782,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CHARGEBACK.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -723,6 +793,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -735,7 +808,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
@@ -748,6 +822,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CHARGEBACK.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
 
@@ -757,6 +832,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
             paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -769,7 +847,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           null);
+                           null,
+                           exception);
         }
     }
 
@@ -787,6 +866,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         final String transactionType = TransactionType.CHARGEBACK.name();
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
+        PaymentApiException exception = null;
         try {
             logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
@@ -803,6 +883,9 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                                                                     });
 
             return payment;
+        } catch (PaymentApiException e) {
+            exception = e;
+            throw e;
         } finally {
             logExitAPICall(log,
                            transactionType,
@@ -815,7 +898,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
         }
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java b/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
index fd9cebe..58f91ca 100644
--- a/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
+++ b/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
@@ -154,7 +154,8 @@ public class PaymentBusEventHandler {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           null);
         }
     }
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
index b1dffa6..b83cc69 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
@@ -306,7 +306,8 @@ public class PluginControlPaymentProcessor extends ProcessorBase {
                            payment != null ? payment.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
                            paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           null);
         }
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java b/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java
index c3ac9c2..e61101a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java
@@ -23,8 +23,10 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
+import org.killbill.billing.ErrorCode;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.slf4j.Logger;
 
@@ -58,7 +60,8 @@ public abstract class PaymentLoggingHelper {
                            paymentExternalKey,
                            paymentTransactionExternalKey,
                            transactionStatus,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           null);
     }
 
     public static void logExitAPICall(final Logger log,
@@ -72,7 +75,8 @@ public abstract class PaymentLoggingHelper {
                                       @Nullable final String paymentExternalKey,
                                       @Nullable final String paymentTransactionExternalKey,
                                       @Nullable final TransactionStatus transactionStatus,
-                                      @Nullable final List<String> paymentControlPluginNames) {
+                                      @Nullable final List<String> paymentControlPluginNames,
+                                      @Nullable final PaymentApiException exception) {
         logAPICallInternal(log,
                            "EXITING ",
                            transactionType,
@@ -85,7 +89,8 @@ public abstract class PaymentLoggingHelper {
                            paymentExternalKey,
                            paymentTransactionExternalKey,
                            transactionStatus,
-                           paymentControlPluginNames);
+                           paymentControlPluginNames,
+                           exception);
     }
 
     public static void logAPICallInternal(final Logger log,
@@ -100,7 +105,8 @@ public abstract class PaymentLoggingHelper {
                                           @Nullable final String paymentExternalKey,
                                           @Nullable final String paymentTransactionExternalKey,
                                           @Nullable final TransactionStatus transactionStatus,
-                                          @Nullable final List<String> paymentControlPluginNames) {
+                                          @Nullable final List<String> paymentControlPluginNames,
+                                          @Nullable final PaymentApiException exception) {
         if (log.isInfoEnabled()) {
             final StringBuilder logLine = new StringBuilder(prefixMsg);
             logLine.append("PaymentApi: transactionType='")
@@ -153,6 +159,17 @@ public abstract class PaymentLoggingHelper {
                        .append(JOINER.join(paymentControlPluginNames))
                        .append("'");
             }
+            if (exception != null) {
+                final ErrorCode error = ErrorCode.fromCode(exception.getCode());
+                if (error == ErrorCode.PAYMENT_PLUGIN_API_ABORTED) {
+                    logLine.append(", aborted=true");
+                }
+                logLine.append(", error='")
+                       .append(error)
+                       .append("', exception='")
+                       .append(exception.getMessage())
+                       .append("'");
+            }
             log.info(logLine.toString());
         }
     }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 8884d34..7092424 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.134-SNAPSHOT</version>
+        <version>0.135-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.17.7-SNAPSHOT</version>