brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [08/16] git commit: more cleanup of leaks and wastage, including SshMachineLocation's sshPoolCache and frequent enrichers which can suppress duplicates, also fix some demotion items, and fix some logic flaws which assumed enrichers would be run, but they
Date Sun, 19 Oct 2014 00:59:55 GMT
more cleanup of leaks and wastage, including SshMachineLocation's sshPoolCache and frequent
enrichers which can suppress duplicates, also fix some demotion items, and fix some logic
flaws which assumed enrichers would be run, but they might not of if it had been a duplicate,
by initializing them with a value which will certainly be changed


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/31f430eb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/31f430eb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/31f430eb

Branch: refs/heads/master
Commit: 31f430ebffa7385eab6361eb7ce5d31e5b9a02a4
Parents: 8b838c3
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Sat Oct 18 05:48:46 2014 +0100
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Sat Oct 18 07:14:12 2014 +0100

----------------------------------------------------------------------
 api/src/main/java/brooklyn/entity/Feed.java     |  2 --
 .../enricher/basic/AbstractEnricher.java        |  4 +++-
 .../brooklyn/entity/basic/AbstractEntity.java   | 17 +++++++++++++---
 .../entity/basic/ServiceStateLogic.java         |  5 +++--
 .../entity/rebind/BasicEntityRebindSupport.java | 21 ++++++++++----------
 .../entity/rebind/RebindManagerImpl.java        | 10 ++++++----
 .../ha/HighAvailabilityManagerImpl.java         | 19 ++++++++++++------
 .../management/internal/LocalEntityManager.java |  3 ++-
 .../entity/basic/SoftwareProcessImpl.java       |  3 +++
 .../brooklyn/rest/resources/ScriptResource.java |  4 ++--
 10 files changed, 56 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/api/src/main/java/brooklyn/entity/Feed.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/Feed.java b/api/src/main/java/brooklyn/entity/Feed.java
index d24be0d..390b01f 100644
--- a/api/src/main/java/brooklyn/entity/Feed.java
+++ b/api/src/main/java/brooklyn/entity/Feed.java
@@ -18,10 +18,8 @@
  */
 package brooklyn.entity;
 
-import brooklyn.basic.BrooklynObject;
 import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.entity.rebind.Rebindable;
-import brooklyn.entity.trait.Configurable;
 import brooklyn.mementos.FeedMemento;
 import brooklyn.policy.EntityAdjunct;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index d462a0c..14c1426 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -78,7 +78,9 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
     @Override
     public void setEntity(EntityLocal entity) {
         super.setEntity(entity);
-        this.suppressDuplicates = getConfig(SUPPRESS_DUPLICATES);
+        Boolean suppressDuplicates = getConfig(SUPPRESS_DUPLICATES);
+        if (suppressDuplicates!=null) 
+            this.suppressDuplicates = suppressDuplicates;
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 46383c0..412ded0 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -21,6 +21,7 @@ package brooklyn.entity.basic;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -70,7 +71,6 @@ import brooklyn.management.internal.EffectorUtils;
 import brooklyn.management.internal.EntityManagementSupport;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.management.internal.SubscriptionTracker;
-import brooklyn.management.internal.NonDeploymentManagementContext.NonDeploymentManagementContextMode;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
@@ -82,13 +82,13 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.BrooklynLanguageExtensions;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.DeferredSupplier;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
@@ -787,11 +787,20 @@ public abstract class AbstractEntity extends AbstractBrooklynObject
implements E
         return (T) attributesInternal.getValue(nameParts);
     }
     
+    static Set<String> WARNED_READ_ONLY_ATTRIBUTES = Collections.synchronizedSet(MutableSet.<String>of());
+    
     @Override
     public <T> T setAttribute(AttributeSensor<T> attribute, T val) {
         if (LOG.isTraceEnabled())
             LOG.trace(""+this+" setAttribute "+attribute+" "+val);
         
+        if (Boolean.TRUE.equals(getManagementSupport().isReadOnlyRaw())) {
+            if (WARNED_READ_ONLY_ATTRIBUTES.add(attribute.getName())) {
+                LOG.warn(""+this+" setting "+attribute+" = "+val+" in read only mode; will
have no effect (future messages for this sensor logged at trace)");
+            } else if (LOG.isTraceEnabled()) {
+                LOG.trace(""+this+" setting "+attribute+" = "+val+" in read only mode; will
have no effect");
+            }
+        }
         T result = attributesInternal.update(attribute, val);
         if (result == null) {
             // could be this is a new sensor
@@ -1441,7 +1450,9 @@ public abstract class AbstractEntity extends AbstractBrooklynObject
implements E
     public boolean containsTag(Object tag) {
         return getTagSupport().containsTag(tag);
     }    
-    
+
+    // this is not recommended because -- especially in rebind-read-only mode, we create
a lot of large such entities
+    // and the phantom references that finalize uses are not GC'd very quickly, so it *looks*
like a memory leak
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
index ac1bfb2..a3cef01 100644
--- a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
+++ b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
@@ -158,6 +158,7 @@ public class ServiceStateLogic {
         public static final EnricherSpec<?> newEnricherForServiceUpIfNotUpIndicatorsEmpty()
{
             return Enrichers.builder()
                 .transforming(SERVICE_NOT_UP_INDICATORS).publishing(Attributes.SERVICE_UP)
+                .suppressDuplicates(true)
                 .computing( /* cast hacks to support removing */ (Function)
                     Functionals.<Map<String,?>>
                         ifNotEquals(null).<Object>apply(Functions.forPredicate(CollectionFunctionals.<String>mapSizeEquals(0)))
@@ -224,7 +225,7 @@ public class ServiceStateLogic {
             super.setEntity(entity);
             if (suppressDuplicates==null) {
                 // only publish on changes, unless it is configured otherwise
-                suppressDuplicates = Boolean.TRUE;
+                suppressDuplicates = true;
             }
             
             subscribe(entity, SERVICE_PROBLEMS, this);
@@ -381,7 +382,7 @@ public class ServiceStateLogic {
             super.setEntity(entity);
             if (suppressDuplicates==null) {
                 // only publish on changes, unless it is configured otherwise
-                suppressDuplicates = Boolean.TRUE;
+                suppressDuplicates = true;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
index 849ef05..02ba317 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -30,8 +30,8 @@ import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
-import brooklyn.entity.Group;
 import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.AbstractGroupImpl;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.rebind.dto.MementosGenerators;
@@ -82,6 +82,7 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
             try {
                 AttributeSensor<?> key = entry.getKey();
                 Object value = entry.getValue();
+                @SuppressWarnings("unused") // just to ensure we can load the declared type?
or maybe not needed
                 Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName());
                 ((EntityInternal)entity).setAttributeWithoutPublishing((AttributeSensor<Object>)key,
value);
             } catch (ClassNotFoundException e) {
@@ -95,12 +96,14 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
         addLocations(rebindContext, memento);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     protected void addConfig(RebindContext rebindContext, EntityMemento memento) {
         for (Map.Entry<ConfigKey<?>, Object> entry : memento.getConfig().entrySet())
{
             try {
                 ConfigKey<?> key = entry.getKey();
                 Object value = entry.getValue();
+                @SuppressWarnings("unused") // just to ensure we can load the declared type?
or maybe not needed
                 Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName());
                 entity.setConfig((ConfigKey<Object>)key, value);
             } catch (ClassNotFoundException e) {
@@ -156,31 +159,27 @@ public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSuppor
                 } catch (Exception e) {
                     rebindContext.getExceptionHandler().onAddFeedFailed(entity, feed, e);
                 }
-            } else {
-                LOG.warn("Feed not found; discarding feed {} of entity {}({})",
-                        new Object[] {feedId, memento.getType(), memento.getId()});
-            }
-            
-            if (feed != null) {
+                
                 try {
+                    // XXX
                     feed.start();
                 } catch (Exception e) {
                     rebindContext.getExceptionHandler().onRebindFailed(BrooklynObjectType.ENTITY,
entity, e);
                 }
             } else {
-                LOG.warn("Feed not found; discarding feed of entity {}({})",
-                        new Object[] {memento.getType(), memento.getId()});
+                LOG.warn("Feed not found; discarding feed {} of entity {}({})",
+                        new Object[] {feedId, memento.getType(), memento.getId()});
             }
         }
     }
     
     protected void addMembers(RebindContext rebindContext, EntityMemento memento) {
         if (memento.getMembers().size() > 0) {
-            if (entity instanceof Group) {
+            if (entity instanceof AbstractGroupImpl) {
                 for (String memberId : memento.getMembers()) {
                     Entity member = rebindContext.getEntity(memberId);
                     if (member != null) {
-                        ((Group)entity).addMember(member);
+                        ((AbstractGroupImpl)entity).addMemberInternal(member);
                     } else {
                         LOG.warn("Entity not found; discarding member {} of group {}({})",
                                 new Object[] {memberId, memento.getType(), memento.getId()});

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 2e0cd99..d9ce494 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -255,11 +255,11 @@ public class RebindManagerImpl implements RebindManager {
     
     @Override
     public void stopPersistence() {
-        LOG.debug("Stopping persistence, mgmt "+managementContext.getManagementNodeId());
+        LOG.debug("Stopping rebind (persistence), mgmt "+managementContext.getManagementNodeId());
         persistenceRunning = false;
         if (persistenceRealChangeListener != null) persistenceRealChangeListener.stop();
         if (persistenceStoreAccess != null) persistenceStoreAccess.disableWriteAccess(true);
-        LOG.debug("Stopped persistence, mgmt "+managementContext.getManagementNodeId());
+        LOG.debug("Stopped rebind (persistence), mgmt "+managementContext.getManagementNodeId());
     }
     
     @SuppressWarnings("unchecked")
@@ -321,9 +321,9 @@ public class RebindManagerImpl implements RebindManager {
     
     @Override
     public void stopReadOnly() {
-        LOG.debug("Stopping read-only rebinding, mgmt "+managementContext.getManagementNodeId());
         readOnlyRunning = false;
         if (readOnlyTask!=null) {
+            LOG.debug("Stopping read-only rebinding, mgmt "+managementContext.getManagementNodeId());
             readOnlyTask.cancel(true);
             readOnlyTask.blockUntilEnded();
             boolean reallyEnded = Tasks.blockUntilInternalTasksEnded(readOnlyTask, Duration.TEN_SECONDS);
@@ -331,8 +331,8 @@ public class RebindManagerImpl implements RebindManager {
                 LOG.warn("Rebind (read-only) tasks took too long to die after interrupt (ignoring):
"+readOnlyTask);
             }
             readOnlyTask = null;
+            LOG.debug("Stopped read-only rebinding, mgmt "+managementContext.getManagementNodeId());
         }
-        LOG.debug("Stopped read-only rebinding, mgmt "+managementContext.getManagementNodeId());
     }
     
     @Override
@@ -773,6 +773,8 @@ public class RebindManagerImpl implements RebindManager {
                 } else {
                     try {
                         entityMemento.injectTypeClass(entity.getClass());
+                        // TODO these call to the entity which in turn sets the entity on
the underlying feeds and enrichers;
+                        // that is taken as the cue to start, but it should not be. start
should be a separate call.
                         ((EntityInternal)entity).getRebindSupport().addPolicies(rebindContext,
entityMemento);
                         ((EntityInternal)entity).getRebindSupport().addEnrichers(rebindContext,
entityMemento);
                         ((EntityInternal)entity).getRebindSupport().addFeeds(rebindContext,
entityMemento);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
index 9bb1c2a..8dd8091 100644
--- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
@@ -324,6 +324,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
             break;
         case DISABLED:
             // safe just to run even if we weren't master
+            LOG.info("Management node "+ownNodeId+" HA DISABLED (was "+nodeState+")");
             demoteToFailed();
             if (pollingTask!=null) pollingTask.cancel(true);
             break;
@@ -483,7 +484,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
         if (LOG.isTraceEnabled()) LOG.trace("Published management-node health: {}", memento);
     }
     
-    protected synchronized void publishDemotionFromMaster() {
+    protected synchronized void publishDemotion(boolean demotingFromMaster) {
         checkState(getNodeState() != ManagementNodeState.MASTER, "node status must not be
master when demoting", getNodeState());
         
         if (persister == null) {
@@ -494,7 +495,9 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
         ManagementNodeSyncRecord memento = createManagementNodeSyncRecord(false);
         ManagementPlaneSyncRecordDeltaImpl.Builder deltaBuilder = ManagementPlaneSyncRecordDeltaImpl.builder()
                 .node(memento);
-        deltaBuilder.clearMaster(ownNodeId);
+        if (demotingFromMaster) {
+            deltaBuilder.clearMaster(ownNodeId);
+        }
         
         Delta delta = deltaBuilder.build();
         persister.delta(delta);
@@ -680,11 +683,13 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
     }
     
     protected void demoteToFailed() {
-        ManagementTransitionMode mode = (nodeState == ManagementNodeState.MASTER ? ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY
: ManagementTransitionMode.REBINDING_DESTROYED);
+        // TODO merge this method with the one below
+        boolean wasMaster = nodeState == ManagementNodeState.MASTER;
+        ManagementTransitionMode mode = (wasMaster ? ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY
: ManagementTransitionMode.REBINDING_DESTROYED);
         nodeState = ManagementNodeState.FAILED;
         onDemotionStopItems(mode);
         nodeStateTransitionComplete = true;
-        publishDemotionFromMaster();
+        publishDemotion(wasMaster);
     }
 
     protected void demoteToStandby(boolean hot) {
@@ -692,13 +697,14 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
             LOG.warn("Ignoring demote-from-master request, as HighAvailabilityManager is
no longer running");
             return;
         }
-        ManagementTransitionMode mode = (nodeState == ManagementNodeState.MASTER ? ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY
: ManagementTransitionMode.REBINDING_DESTROYED);
+        boolean wasMaster = nodeState == ManagementNodeState.MASTER;
+        ManagementTransitionMode mode = (wasMaster ? ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY
: ManagementTransitionMode.REBINDING_DESTROYED);
 
         nodeStateTransitionComplete = false;
         nodeState = ManagementNodeState.STANDBY;
         onDemotionStopItems(mode);
         nodeStateTransitionComplete = true;
-        publishDemotionFromMaster();
+        publishDemotion(wasMaster);
         
         if (hot) {
             nodeStateTransitionComplete = false;
@@ -711,6 +717,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager
{
     protected void onDemotionStopItems(ManagementTransitionMode mode) {
         // stop persistence and remove all apps etc
         managementContext.getRebindManager().stopPersistence();
+        managementContext.getRebindManager().stopReadOnly();
         clearManagedItems(mode);
         
         // tasks are cleared as part of unmanaging entities above

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
index 9438759..36999ee 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
@@ -588,7 +588,8 @@ public class LocalEntityManager implements EntityManagerInternal {
             applications.add((Application)proxyE);
             applicationIds.add(e.getId());
         }
-        entities.add(proxyE);
+        if (!entities.contains(proxyE)) 
+            entities.add(proxyE);
         
         if (old!=null && old!=e) {
             // passing the transition info will ensure the right shutdown steps invoked for
old instance

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
index df20ee2..596fc6d 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic;
 import brooklyn.entity.drivers.DriverDependentEntity;
 import brooklyn.entity.drivers.EntityDriverManager;
 import brooklyn.event.feed.function.FunctionFeed;
@@ -119,6 +120,8 @@ public abstract class SoftwareProcessImpl extends AbstractEntity implements
Soft
     @Override
     protected void initEnrichers() {
         super.initEnrichers();
+        ServiceNotUpLogic.updateNotUpIndicator(this, SERVICE_PROCESS_IS_RUNNING, "No information
yet about whether this service is running");
+        // add an indicator above so that if is_running comes through it clears the map and
guarantees an update
         addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
             .from(SERVICE_PROCESS_IS_RUNNING)
             .computing(Functionals.ifNotEquals(true).value("The software process for this
entity does not appear to be running"))

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/31f430eb/usage/rest-server/src/main/java/brooklyn/rest/resources/ScriptResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/ScriptResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/ScriptResource.java
index b531d09..917d7f6 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/ScriptResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/ScriptResource.java
@@ -65,8 +65,8 @@ public class ScriptResource extends AbstractBrooklynRestResource implements
Scri
         
         GroovyShell shell = new GroovyShell(binding);
 
-        OutputCapturingContext stdout = ThreadLocalPrintStream.stdout().capture();
-        OutputCapturingContext stderr = ThreadLocalPrintStream.stderr().capture();
+        OutputCapturingContext stdout = ThreadLocalPrintStream.stdout().captureTee();
+        OutputCapturingContext stderr = ThreadLocalPrintStream.stderr().captureTee();
 
         Object value = null;
         Throwable problem = null;


Mime
View raw message