improve logging for persistence and rebind

a few more detailed messages, including timings;
and lots of suppression of messages during redind-read-only


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

Branch: refs/heads/master
Commit: 28150112ebf66c1caef1c281a3589a32e1299148
Parents: 283d170
Author: Alex Heneveld <[email protected]>
Authored: Wed Nov 5 22:16:32 2014 +0000
Committer: Alex Heneveld <[email protected]>
Committed: Thu Nov 6 02:02:34 2014 +0000

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  |   6 +-
 .../brooklyn/catalog/internal/CatalogDo.java    |   3 +-
 .../brooklyn/catalog/internal/CatalogDto.java   |  11 +-
 .../catalog/internal/CatalogItemDo.java         |   3 +-
 .../catalog/internal/CatalogLibrariesDto.java   |   7 +-
 .../brooklyn/catalog/internal/CatalogUtils.java |  32 ++++-
 .../java/brooklyn/config/BrooklynLogging.java   |  46 +++++++
 .../basic/AbstractMultipleSensorAggregator.java |   7 +-
 .../brooklyn/enricher/basic/Aggregator.java     |   8 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |  32 ++++-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |   5 +-
 .../entity/basic/ServiceStateLogic.java         |  10 +-
 .../group/AbstractMembershipTrackingPolicy.java |   4 +-
 .../rebind/PeriodicDeltaChangeListener.java     |   4 +-
 .../entity/rebind/RebindManagerImpl.java        | 136 +++++++++++--------
 .../BrooklynMementoPersisterToObjectStore.java  |  16 ++-
 .../java/brooklyn/event/basic/AttributeMap.java |   6 +-
 .../ha/ManagementPlaneSyncRecordDeltaImpl.java  |  11 ++
 ...ntPlaneSyncRecordPersisterToObjectStore.java |  12 +-
 .../brooklyn/management/ha/OsgiManager.java     |  11 +-
 .../management/internal/LocalEntityManager.java |   4 +-
 .../internal/LocalLocationManager.java          |  12 +-
 .../management/usage/LocationUsage.java         |   2 +-
 .../brooklyn/location/jclouds/JcloudsUtil.java  |   2 +-
 .../java/brooklyn/util/javalang/Equals.java     |  59 ++++++++
 .../src/main/java/brooklyn/util/time/Time.java  |   4 +-
 .../test/java/brooklyn/util/time/TimeTest.java  |   4 +-
 27 files changed, 344 insertions(+), 113 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java 
b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
index 0236999..4d31964 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -123,9 +123,9 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
             mgmt.getRebindManager().getChangeListener().onUnmanaged(toRemove);
         }
         CatalogDo catalog = new CatalogDo(mgmt, dto);
-        log.debug("Resetting "+this+" catalog to "+dto);
+        CatalogUtils.logDebugOrTraceIfRebinding(log, "Resetting "+this+" 
catalog to "+dto);
         catalog.load(mgmt, null);
-        log.debug("Reloaded catalog for "+this+", now switching");
+        CatalogUtils.logDebugOrTraceIfRebinding(log, "Reloaded catalog for 
"+this+", now switching");
         this.catalog = catalog;
 
         // Inject management context into and persist all the new entries.
@@ -158,7 +158,7 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
      */
     @Override
     public void reset(Collection<CatalogItem<?, ?>> entries) {
-        CatalogDto newDto = CatalogDto.newDtoFromCatalogItems(entries);
+        CatalogDto newDto = CatalogDto.newDtoFromCatalogItems(entries, 
"explicit-catalog-reset");
         reset(newDto);
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
index 0ac65fc..33552f0 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogDo.java
@@ -94,6 +94,7 @@ public class CatalogDo {
 
     protected synchronized void loadThisCatalog(ManagementContext mgmt, 
CatalogDo parent) {
         if (isLoaded()) return;
+        CatalogUtils.logDebugOrTraceIfRebinding(log, "Loading catalog {} into 
{}", this, parent);
         if (this.parent!=null && !this.parent.equals(parent))
             log.warn("Catalog "+this+" being initialised with different parent 
"+parent+" when already parented by "+this.parent, new Throwable("source of 
reparented "+this));
         if (this.mgmt!=null && !this.mgmt.equals(mgmt))
@@ -173,7 +174,7 @@ public class CatalogDo {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     protected synchronized Map<String, CatalogItemDo<?,?>> buildCaches() {
         if (cacheById != null) return cacheById;
-        log.debug("Building cache for "+this);
+        CatalogUtils.logDebugOrTraceIfRebinding(log, "Building cache for {}", 
this);
         if (!isLoaded()) 
             log.debug("Catalog not fully loaded when loading cache of "+this);
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
index 88c8901..0d98c82 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogDto.java
@@ -120,9 +120,16 @@ public class CatalogDto {
         return result;
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
+    /** @deprecated since 0.7.0 use {@link #newDtoFromCatalogItems(Collection, 
String)}, supplying a description for tracking */
+    @Deprecated
     public static CatalogDto newDtoFromCatalogItems(Collection<CatalogItem<?, 
?>> entries) {
+        return newDtoFromCatalogItems(entries, null);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static CatalogDto newDtoFromCatalogItems(Collection<CatalogItem<?, 
?>> entries, String description) {
         CatalogDto result = new CatalogDto();
+        result.contentsDescription = description;
         // Weird casts because compiler does not seem to like
         // .copyInto(Lists.<CatalogItemDtoAbstract<?, 
?>>newArrayListWithExpectedSize(entries.size()));
         result.entries = (List<CatalogItemDtoAbstract<?, ?>>) (List) 
FluentIterable.from(entries)
@@ -140,7 +147,7 @@ public class CatalogDto {
                 LOG.debug("Catalog DTO has no contents and no description; 
ignoring call to populate it. Description should be set to suppress this 
message.");
                 return;
             } else {
-                LOG.debug("Nothing needs doing (no contents or URL) for 
catalog with contents described as "+contentsDescription+".");
+                LOG.trace("Nothing needs doing (no contents or URL) for 
catalog with contents described as "+contentsDescription+".");
                 return;
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
index 7bcf9ec..b3ac88d 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.management.ManagementContext;
+import brooklyn.mementos.CatalogItemMemento;
 
 import com.google.common.base.Preconditions;
 
@@ -152,7 +153,7 @@ public class CatalogItemDo<T,SpecT> implements 
CatalogItem<T,SpecT> {
     }
 
     @Override
-    public RebindSupport getRebindSupport() {
+    public RebindSupport<CatalogItemMemento> getRebindSupport() {
         return itemDto.getRebindSupport();
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java
index ba07c21..bcbd25b 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java
@@ -63,9 +63,11 @@ public class CatalogLibrariesDto implements 
CatalogItem.CatalogItemLibraries {
         CatalogLibrariesDto dto = new CatalogLibrariesDto();
         for (Object object : possibleLibraries) {
             if (object instanceof Map) {
+                @SuppressWarnings("rawtypes")
                 Map entry = (Map) object;
-                String name = stringValOrNull(entry, "name");
-                String version = stringValOrNull(entry, "version");
+                // these might be useful in the future
+//                String name = stringValOrNull(entry, "name");
+//                String version = stringValOrNull(entry, "version");
                 String url = stringValOrNull(entry, "url");
                 dto.addBundle(url);
             } else if (object instanceof String) {
@@ -77,6 +79,7 @@ public class CatalogLibrariesDto implements 
CatalogItem.CatalogItemLibraries {
         return dto;
     }
 
+    @SuppressWarnings("rawtypes")
     private static String stringValOrNull(Map map, String key) {
         Object val = map.get(key);
         return val != null ? String.valueOf(val) : null;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
index 5b6b81d..6fd1f94 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Joiner;
 import com.google.common.base.Stopwatch;
 
@@ -33,7 +34,9 @@ import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogItem.CatalogItemLibraries;
 import brooklyn.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+import brooklyn.config.BrooklynLogging;
 import brooklyn.entity.Entity;
+import brooklyn.entity.rebind.RebindManagerImpl.RebindTracker;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.classloading.BrooklynClassLoadingContextSequential;
@@ -89,14 +92,18 @@ public class CatalogUtils {
             if (osgi.isAbsent()) {
                 throw new IllegalStateException("Unable to load bundles 
"+bundles+" because OSGi is not running.");
             }
-            if (log.isDebugEnabled()) log.debug("Loading bundles in {}: {}", 
+            if (log.isDebugEnabled()) 
+                logDebugOrTraceIfRebinding(log, 
+                    "Loading bundles in {}: {}", 
                     new Object[] {managementContext, Joiner.on(", 
").join(bundles)});
             Stopwatch timer = Stopwatch.createStarted();
             for (String bundleUrl : bundles) {
                 osgi.get().registerBundle(bundleUrl);
             }
-            if (log.isDebugEnabled()) log.debug("Registered {} bundles in {}",
-                new Object[]{bundles.size(), 
Time.makeTimeStringRounded(timer)});
+            if (log.isDebugEnabled()) 
+                logDebugOrTraceIfRebinding(log, 
+                    "Registered {} bundles in {}",
+                    new Object[]{bundles.size(), 
Time.makeTimeStringRounded(timer)});
         }
     }
 
@@ -112,7 +119,9 @@ public class CatalogUtils {
     public static void setCatalogItemIdOnAddition(Entity entity, 
BrooklynObject itemBeingAdded) {
         if (entity.getCatalogItemId()!=null) {
             if (itemBeingAdded.getCatalogItemId()==null) {
-                log.debug("Catalog item addition: "+entity+" from 
"+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded);
+                if (log.isDebugEnabled())
+                    BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+                        "Catalog item addition: "+entity+" from 
"+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded);
                 
((BrooklynObjectInternal)itemBeingAdded).setCatalogItemId(entity.getCatalogItemId());
             } else {
                 if 
(!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) {
@@ -120,9 +129,20 @@ public class CatalogUtils {
                     log.debug("Cross-catalog item detected: "+entity+" from 
"+entity.getCatalogItemId()+" has "+itemBeingAdded+" from 
"+itemBeingAdded.getCatalogItemId());
                 }
             }
-        } else if (itemBeingAdded.getCatalogItemId()==null) {
-            log.debug("Catalog item addition: "+entity+" without catalog item 
ID has "+itemBeingAdded+" from "+itemBeingAdded.getCatalogItemId());
+        } else if (itemBeingAdded.getCatalogItemId()!=null) {
+            if (log.isDebugEnabled())
+                BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+                    "Catalog item addition: "+entity+" without catalog item ID 
has "+itemBeingAdded+" from "+itemBeingAdded.getCatalogItemId());
         }
     }
 
+    @Beta
+    public static void logDebugOrTraceIfRebinding(Logger log, String message, 
Object ...args) {
+        if (RebindTracker.isRebinding())
+            log.trace(message, args);
+        else
+            log.debug(message, args);
+    }
+    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/config/BrooklynLogging.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/config/BrooklynLogging.java 
b/core/src/main/java/brooklyn/config/BrooklynLogging.java
index 729d819..8a27ebd 100644
--- a/core/src/main/java/brooklyn/config/BrooklynLogging.java
+++ b/core/src/main/java/brooklyn/config/BrooklynLogging.java
@@ -18,6 +18,11 @@
  */
 package brooklyn.config;
 
+import org.slf4j.Logger;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityInternal;
+
 /** contains common logging categories */
 public class BrooklynLogging {
 
@@ -25,4 +30,45 @@ public class BrooklynLogging {
 
     public static final String REST = "brooklyn.REST";
 
+    /** For convenience here, since SLF4J does not define such an enum */
+    public static enum LoggingLevel { ERROR, WARN, INFO, DEBUG, TRACE }
+
+    /** As methods on {@link Logger} but taking the level as an argument */
+    public static final void log(Logger logger, LoggingLevel level, String 
message, Object... args) {
+        switch (level) {
+        case ERROR: logger.error(message, args); break;
+        case WARN: logger.warn(message, args); break;
+        case INFO: logger.info(message, args); break;
+        case DEBUG: logger.debug(message, args); break;
+        case TRACE: logger.trace(message, args); break;
+        }
+    }
+
+    /** As methods on {@link Logger} but taking the level as an argument */
+    public static final void log(Logger logger, LoggingLevel level, String 
message, Throwable t) {
+        switch (level) {
+        case ERROR: logger.error(message, t); break;
+        case WARN: logger.warn(message, t); break;
+        case INFO: logger.info(message, t); break;
+        case DEBUG: logger.debug(message, t); break;
+        case TRACE: logger.trace(message, t); break;
+        }
+    }
+
+    /** returns one of three log levels depending on the read-only status of 
the entity;
+     * unknown should only be the case very early in the management cycle */
+    public static LoggingLevel levelDependingIfReadOnly(Entity entity, 
LoggingLevel levelIfWriting, LoggingLevel levelIfReadOnly, LoggingLevel 
levelIfUnknown) {
+        if (entity==null) return levelIfUnknown;
+        Boolean ro = 
((EntityInternal)entity).getManagementSupport().isReadOnlyRaw();
+        if (ro==null) return levelIfUnknown;
+        if (ro) return levelIfReadOnly;
+        return levelIfWriting;
+    }
+
+    /** as {@link #levelDependendingIfReadOnly(Entity)} with {@link 
LoggingLevel#DEBUG} as the default,
+     * but {@link LoggingLevel#TRACE} for read-only */
+    public static LoggingLevel levelDebugOrTraceIfReadOnly(Entity entity) {
+        return levelDependingIfReadOnly(entity, LoggingLevel.DEBUG, 
LoggingLevel.TRACE, LoggingLevel.DEBUG);
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
 
b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
index 486307c..b40c234 100644
--- 
a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
+++ 
b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
 import brooklyn.entity.Entity;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -57,7 +58,8 @@ public abstract class AbstractMultipleSensorAggregator<U> 
extends AbstractAggreg
     
     @Override
     protected void setEntityBeforeSubscribingProducerChildrenEvents() {
-        if (LOG.isDebugEnabled()) LOG.debug("{} subscribing to children of 
{}", new Object[] {this, producer });
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} subscribing to children of {}", this, producer);
         for (Sensor<?> sourceSensor: getSourceSensors()) {
             subscribeToChildren(producer, sourceSensor, this);
         }
@@ -84,7 +86,8 @@ public abstract class AbstractMultipleSensorAggregator<U> 
extends AbstractAggreg
 
     @Override
     protected void onProducerAdded(Entity producer) {
-        if (LOG.isDebugEnabled()) LOG.debug("{} listening to {}", new Object[] 
{this, producer});
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} listening to {}", this, producer);
         synchronized (values) {
             for (Sensor<?> sensor: getSourceSensors()) {
                 Map<Entity,Object> vs = values.get(sensor.getName());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java 
b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
index fc20033..3e896db 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
@@ -28,7 +28,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.catalog.Catalog;
+import brooklyn.config.BrooklynLogging;
 import brooklyn.config.ConfigKey;
+import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.AttributeSensor;
@@ -74,7 +76,8 @@ public class Aggregator<T,U> extends AbstractAggregator<T,U> 
implements SensorEv
         
     @Override
     protected void setEntityBeforeSubscribingProducerChildrenEvents() {
-        if (LOG.isDebugEnabled()) LOG.debug("{} subscribing to children of 
{}", new Object[] {this, producer });
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} subscribing to children of {}", this, producer);
         subscribeToChildren(producer, sourceSensor, this);
     }
 
@@ -98,7 +101,8 @@ public class Aggregator<T,U> extends AbstractAggregator<T,U> 
implements SensorEv
 
     @Override
     protected void onProducerAdded(Entity producer) {
-        if (LOG.isDebugEnabled()) LOG.debug("{} listening to {}", new Object[] 
{this, producer});
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
+            "{} listening to {}", this, producer);
         synchronized (values) {
             T vo = values.get(producer);
             if (vo==null) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/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 034bea7..c5ca83a 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.catalog.internal.CatalogUtils;
+import brooklyn.config.BrooklynLogging;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.config.render.RendererHints;
@@ -89,6 +90,7 @@ import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
+import brooklyn.util.javalang.Equals;
 import brooklyn.util.task.DeferredSupplier;
 import brooklyn.util.text.Strings;
 
@@ -802,10 +804,20 @@ public abstract class AbstractEntity extends 
AbstractBrooklynObject implements E
             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 oldVal = getAttribute(attribute);
+            if (Equals.approximately(val, oldVal)) {
+                // ignore, probably an enricher resetting values or something 
on init
+            } else {
+                String message = this+" setting "+attribute+" = "+val+" (was 
"+oldVal+") in read only mode; will have very little effect"; 
+                if (!getManagementSupport().isDeployed()) {
+                    if (getManagementSupport().wasDeployed()) message += " (no 
longer deployed)"; 
+                    else message += " (not yet deployed)";
+                }
+                if (WARNED_READ_ONLY_ATTRIBUTES.add(attribute.getName())) {
+                    LOG.warn(message + " (future messages for this sensor 
logged at trace)");
+                } else if (LOG.isTraceEnabled()) {
+                    LOG.trace(message);
+                }
             }
         }
         T result = attributesInternal.update(attribute, val);
@@ -840,10 +852,15 @@ public abstract class AbstractEntity extends 
AbstractBrooklynObject implements E
             LOG.trace(""+this+" modifyAttribute "+attribute+" "+modifier);
         
         if (Boolean.TRUE.equals(getManagementSupport().isReadOnlyRaw())) {
+            String message = this+" modifying "+attribute+" = "+modifier+" in 
read only mode; will have very little effect"; 
+            if (!getManagementSupport().isDeployed()) {
+                if (getManagementSupport().wasDeployed()) message += " (no 
longer deployed)"; 
+                else message += " (not yet deployed)";
+            }
             if (WARNED_READ_ONLY_ATTRIBUTES.add(attribute.getName())) {
-                LOG.warn(""+this+" modifying "+attribute+" = "+modifier+" in 
read only mode; will have no effect (future messages for this sensor logged at 
trace)");
+                LOG.warn(message + " (future messages for this sensor logged 
at trace)");
             } else if (LOG.isTraceEnabled()) {
-                LOG.trace(""+this+" setting "+attribute+" = "+modifier+" in 
read only mode; will have no effect");
+                LOG.trace(message);
             }
         }
         T result = attributesInternal.modify(attribute, modifier);
@@ -1356,7 +1373,8 @@ public abstract class AbstractEntity extends 
AbstractBrooklynObject implements E
             LOG.warn("Strongly discouraged use of emit with sensor event as 
value "+sensor+" "+val+"; value should be unpacked!",
                 new Throwable("location of discouraged event "+sensor+" 
emit"));
         }
-        if (LOG.isDebugEnabled()) LOG.debug("Emitting sensor notification {} 
value {} on {}", new Object[] {sensor.getName(), val, this});
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(this),
+            "Emitting sensor notification {} value {} on {}", 
sensor.getName(), val, this);
         emitInternal(sensor, val);
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java 
b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 2d5a76f..5241d74 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -26,6 +26,8 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
+import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.entity.Entity;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
@@ -192,7 +194,8 @@ public class DynamicGroupImpl extends AbstractGroupImpl 
implements DynamicGroup
                 return;
             }
             if (getApplication() == null) {
-                log.warn("{} not (yet) scanning for children: no application 
defined", this);
+                BrooklynLogging.log(log, 
BrooklynLogging.levelDependingIfReadOnly(this, LoggingLevel.WARN, 
LoggingLevel.TRACE, LoggingLevel.TRACE),
+                    "{} not (yet) scanning for children: no application 
defined", this);
                 return;
             }
             boolean changed = false;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/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 7ceab81..898de8f 100644
--- a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
+++ b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
@@ -29,7 +29,9 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
 import brooklyn.config.ConfigKey;
+import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.enricher.Enrichers;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.enricher.basic.AbstractMultipleSensorAggregator;
@@ -142,7 +144,7 @@ public class ServiceStateLogic {
     public static void setExpectedState(Entity entity, Lifecycle state) {
         if (state==Lifecycle.RUNNING) {
             Boolean up = 
((EntityInternal)entity).getAttribute(Attributes.SERVICE_UP);
-            if (!Boolean.TRUE.equals(up)) {
+            if (!Boolean.TRUE.equals(up) && 
!Boolean.TRUE.equals(Entities.isReadOnly(entity))) {
                 // pause briefly to allow any recent problem-clearing 
processing to complete
                 Stopwatch timer = Stopwatch.createStarted();
                 boolean nowUp = 
Repeater.create().every(Duration.millis(10)).limitTimeTo(Duration.millis(200)).until(entity,
 
@@ -313,7 +315,8 @@ public class ServiceStateLogic {
             if (log.isTraceEnabled()) log.trace("{} setting actual state {}", 
this, state);
             if 
(((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) {
                 // won't catch everything, but catches some
-                log.debug(entity+" is no longer managed when told to set 
actual state to "+state+"; suppressing");
+                BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+                    entity+" is no longer managed when told to set actual 
state to "+state+"; suppressing");
                 return;
             }
             emit(SERVICE_STATE_ACTUAL, (state==null ? Entities.REMOVE : 
state));
@@ -440,7 +443,8 @@ public class ServiceStateLogic {
         protected void onUpdated() {
             if (entity==null || !Entities.isManaged(entity)) {
                 // either invoked during setup or entity has become unmanaged; 
just ignore
-                if (log.isDebugEnabled()) log.debug("Ignoring {} onUpdated 
when entity is not in valid state ({})", this, entity);
+                BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+                    "Ignoring {} onUpdated when entity is not in valid state 
({})", this, entity);
                 return;
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
 
b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
index 12100cd..abc5e9d 100644
--- 
a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
+++ 
b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
@@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
@@ -162,7 +163,8 @@ public abstract class AbstractMembershipTrackingPolicy 
extends AbstractPolicy {
     protected void subscribeToGroup(final Group group) {
         Preconditions.checkNotNull(group, "The group must not be null");
 
-        LOG.debug("Subscribing to group "+group+", for memberAdded, 
memberRemoved, and {}", getSensorsToTrack());
+        BrooklynLogging.log(LOG, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(group),
+            "Subscribing to group "+group+", for memberAdded, memberRemoved, 
and {}", getSensorsToTrack());
         
         subscribe(group, DynamicGroup.MEMBER_ADDED, new 
SensorEventListener<Entity>() {
             @Override public void onEvent(SensorEvent<Entity> event) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java 
b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
index 3ae6916..1696767 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -168,7 +168,7 @@ public class PeriodicDeltaChangeListener implements 
ChangeListener {
                             } catch (Exception e) {
                                 // Don't rethrow: the behaviour of 
executionManager is different from a scheduledExecutorService,
                                 // if we throw an exception, then our task 
will never get executed again
-                                LOG.warn("Problem persisting change-delta", e);
+                                LOG.error("Problem persisting change-delta", 
e);
                                 return null;
                             } catch (Throwable t) {
                                 LOG.warn("Problem persisting change-delta 
(rethrowing)", t);
@@ -332,7 +332,7 @@ public class PeriodicDeltaChangeListener implements 
ChangeListener {
 
             addReferencedObjects(prevDeltaCollector);
 
-            if (LOG.isDebugEnabled()) LOG.debug("Persister delta with 
references: "
+            if (LOG.isTraceEnabled()) LOG.trace("Persister delta with 
references: "
                     + "updating {} entities, {} locations, {} policies, {} 
enrichers, {} catalog items; "
                     + "removing {} entities, {} locations, {} policies, {} 
enrichers, {} catalog items",
                     new Object[] {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/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 09101f6..c2b271e 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -39,8 +39,10 @@ import brooklyn.catalog.CatalogItem;
 import brooklyn.catalog.CatalogLoadMode;
 import brooklyn.catalog.internal.BasicBrooklynCatalog;
 import brooklyn.catalog.internal.CatalogUtils;
+import brooklyn.config.BrooklynLogging;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.ConfigKey;
+import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
@@ -95,10 +97,13 @@ import brooklyn.util.task.ScheduledTask;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
 
 import com.google.api.client.repackaged.com.google.common.base.Preconditions;
+import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
+import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -141,6 +146,7 @@ public class RebindManagerImpl implements RebindManager {
     private volatile boolean readOnlyRunning = false;
     private volatile ScheduledTask readOnlyTask = null;
     private transient Semaphore rebindActive = new Semaphore(1);
+    private transient int readOnlyRebindCount = Integer.MIN_VALUE;
     
     private volatile BrooklynMementoPersister persistenceStoreAccess;
 
@@ -161,6 +167,7 @@ public class RebindManagerImpl implements RebindManager {
      * 
      * @author aled
      */
+    @Beta
     public static class RebindTracker {
         private static ThreadLocal<Boolean> rebinding = new 
ThreadLocal<Boolean>();
         
@@ -191,7 +198,7 @@ public class RebindManagerImpl implements RebindManager {
         addPolicyFailureMode = 
managementContext.getConfig().getConfig(ADD_POLICY_FAILURE_MODE);
         loadPolicyFailureMode = 
managementContext.getConfig().getConfig(LOAD_POLICY_FAILURE_MODE);
 
-        LOG.debug("Persistence in {} of: policies={}, enrichers={}, feeds={}, 
catalog={}",
+        LOG.debug("{} initialized, settings: policies={}, enrichers={}, 
feeds={}, catalog={}",
                 new Object[]{this, persistPoliciesEnabled, 
persistEnrichersEnabled, persistFeedsEnabled, persistCatalogItemsEnabled});
     }
 
@@ -251,15 +258,16 @@ public class RebindManagerImpl implements RebindManager {
         if (readOnlyRunning) {
             throw new IllegalStateException("Cannot start read-only when 
already running with persistence");
         }
-        LOG.debug("Starting persistence, mgmt 
"+managementContext.getManagementNodeId());
+        LOG.debug("Starting persistence ("+this+"), mgmt 
"+managementContext.getManagementNodeId());
         persistenceRunning = true;
+        readOnlyRebindCount = Integer.MIN_VALUE;
         persistenceStoreAccess.enableWriteAccess();
         if (persistenceRealChangeListener != null) 
persistenceRealChangeListener.start();
     }
     
     @Override
     public void stopPersistence() {
-        LOG.debug("Stopping rebind (persistence), mgmt 
"+managementContext.getManagementNodeId());
+        LOG.debug("Stopping persistence ("+this+"), mgmt 
"+managementContext.getManagementNodeId());
         persistenceRunning = false;
         if (persistenceRealChangeListener != null) 
persistenceRealChangeListener.stop();
         if (persistenceStoreAccess != null) 
persistenceStoreAccess.disableWriteAccess(true);
@@ -276,12 +284,13 @@ public class RebindManagerImpl implements RebindManager {
             LOG.warn("Cannot request read-only mode for "+this+" when already 
running - "+readOnlyTask+"; ignoring");
             return;
         }
-        LOG.debug("Starting read-only rebinding, mgmt 
"+managementContext.getManagementNodeId());
+        LOG.debug("Starting read-only rebinding ("+this+"), mgmt 
"+managementContext.getManagementNodeId());
         
         if (persistenceRealChangeListener != null) 
persistenceRealChangeListener.stop();
         if (persistenceStoreAccess != null) 
persistenceStoreAccess.disableWriteAccess(true);
         
         readOnlyRunning = true;
+        readOnlyRebindCount = 0;
 
         try {
             rebind(null, null, ManagementNodeState.HOT_STANDBY);
@@ -295,21 +304,24 @@ public class RebindManagerImpl implements RebindManager {
                     public Void call() {
                         try {
                             rebind(null, null, 
ManagementNodeState.HOT_STANDBY);
+                            readOnlyRebindCount++;
                             return null;
                         } catch (RuntimeInterruptedException e) {
                             LOG.debug("Interrupted rebinding 
(re-interrupting): "+e);
                             if (LOG.isTraceEnabled())
-                                LOG.trace("Interrupted rebinding 
(re-interrupting): "+e, e);
+                                LOG.trace("Interrupted rebinding 
(re-interrupting), details: "+e, e);
                             Thread.currentThread().interrupt();
                             return null;
                         } catch (Exception e) {
                             // Don't rethrow: the behaviour of 
executionManager is different from a scheduledExecutorService,
                             // if we throw an exception, then our task will 
never get executed again
                             if (!readOnlyRunning) {
-                                if (LOG.isTraceEnabled())
-                                    LOG.trace("Problem rebinding (read-only 
running turned off): "+e, e);
+                                LOG.debug("Problem rebinding (read-only 
running has probably just been turned off): "+e);
+                                if (LOG.isTraceEnabled()) {
+                                    LOG.trace("Problem rebinding (read-only 
running has probably just been turned off), details: "+e, e);
+                                }
                             } else {
-                                LOG.warn("Problem rebinding: 
"+Exceptions.collapseText(e), e);
+                                LOG.error("Problem rebinding: 
"+Exceptions.collapseText(e), e);
                             }
                             return null;
                         } catch (Throwable t) {
@@ -327,7 +339,7 @@ public class RebindManagerImpl implements RebindManager {
     public void stopReadOnly() {
         readOnlyRunning = false;
         if (readOnlyTask!=null) {
-            LOG.debug("Stopping read-only rebinding, mgmt 
"+managementContext.getManagementNodeId());
+            LOG.debug("Stopping read-only rebinding ("+this+"), mgmt 
"+managementContext.getManagementNodeId());
             readOnlyTask.cancel(true);
             readOnlyTask.blockUntilEnded();
             boolean reallyEnded = 
Tasks.blockUntilInternalTasksEnded(readOnlyTask, Duration.TEN_SECONDS);
@@ -335,7 +347,7 @@ 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 ("+this+"), mgmt 
"+managementContext.getManagementNodeId());
         }
     }
     
@@ -476,6 +488,7 @@ public class RebindManagerImpl implements RebindManager {
         } catch (InterruptedException e1) { Exceptions.propagate(e1); }
         RebindTracker.setRebinding();
         try {
+            Stopwatch timer = Stopwatch.createStarted();
             exceptionHandler.onStart();
             
             Reflections reflections = new Reflections(classLoader);
@@ -527,20 +540,18 @@ public class RebindManagerImpl implements RebindManager {
 
             //The manifest contains full catalog items mementos. Reading them 
at this stage means that
             //we don't support references to entities/locations withing tags.
+            
+            LOG.debug("Rebinding ("+mode+", iteration "+readOnlyRebindCount+") 
from "+getPersister().getBackingStoreDescription()+"...");
 
             BrooklynMementoManifest mementoManifest = 
persistenceStoreAccess.loadMementoManifest(exceptionHandler);
 
             boolean isEmpty = mementoManifest.isEmpty();
-            if (!isEmpty) {
-                if (mode==ManagementNodeState.HOT_STANDBY)
-                    LOG.debug("Rebinding (read-only) from 
"+getPersister().getBackingStoreDescription()+"...");
-                else
+            if (mode!=ManagementNodeState.HOT_STANDBY) {
+                if (!isEmpty) { 
                     LOG.info("Rebinding from 
"+getPersister().getBackingStoreDescription()+"...");
-            } else {
-                if (mode==ManagementNodeState.HOT_STANDBY)
-                    LOG.debug("Rebind check (read-only): no existing state, 
reading from "+getPersister().getBackingStoreDescription());
-                else
+                } else {
                     LOG.info("Rebind check: no existing state; will persist 
new items to "+getPersister().getBackingStoreDescription());
+                }
             }
 
             //
@@ -549,7 +560,7 @@ public class RebindManagerImpl implements RebindManager {
             
             // Instantiate catalog items
             if (persistCatalogItemsEnabled) {
-                LOG.debug("RebindManager instantiating catalog items: {}", 
mementoManifest.getCatalogItemIds());
+                logRebindingDebug("RebindManager instantiating catalog items: 
{}", mementoManifest.getCatalogItemIds());
                 for (CatalogItemMemento catalogItemMemento : 
mementoManifest.getCatalogItemMementos().values()) {
                     if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
instantiating catalog item {}", catalogItemMemento);
                     try {
@@ -560,15 +571,15 @@ public class RebindManagerImpl implements RebindManager {
                     }
                 }
             } else {
-                LOG.debug("Not rebinding catalog; feature disabled: {}", 
mementoManifest.getCatalogItemIds());
+                logRebindingDebug("Not rebinding catalog; feature disabled: 
{}", mementoManifest.getCatalogItemIds());
             }
 
             // Reconstruct catalog entries
             if (persistCatalogItemsEnabled) {
-                LOG.debug("RebindManager reconstructing catalog items");
+                logRebindingDebug("RebindManager reconstructing catalog 
items");
                 for (CatalogItemMemento catalogItemMemento : 
mementoManifest.getCatalogItemMementos().values()) {
                     CatalogItem<?, ?> item = 
rebindContext.getCatalogItem(catalogItemMemento.getId());
-                    LOG.debug("RebindManager reconstructing catalog item {}", 
catalogItemMemento);
+                    logRebindingDebug("RebindManager reconstructing catalog 
item {}", catalogItemMemento);
                     if (item == null) {
                         
exceptionHandler.onNotFound(BrooklynObjectType.CATALOG_ITEM, 
catalogItemMemento.getId());
                     } else {
@@ -593,27 +604,27 @@ public class RebindManagerImpl implements RebindManager {
                         || (isEmpty && catalogLoadMode == 
CatalogLoadMode.LOAD_BROOKLYN_CATALOG_URL_IF_NO_PERSISTED_STATE);
                 if (shouldResetCatalog) {
                     // Reset catalog with previously persisted state
-                    LOG.debug("RebindManager resetting management context 
catalog to previously persisted state");
+                    logRebindingDebug("RebindManager resetting management 
context catalog to previously persisted state");
                     
managementContext.getCatalog().reset(rebindContext.getCatalogItems());
                 } else if (shouldLoadDefaultCatalog) {
                     // Load catalogue as normal
                     // TODO in read-only mode, should do this less frequently 
than entities etc
-                    LOG.debug("RebindManager loading default catalog");
+                    logRebindingDebug("RebindManager loading default catalog");
                     ((BasicBrooklynCatalog) 
managementContext.getCatalog()).resetCatalogToContentsAtConfiguredUrl();
                 } else {
                     // Management context should have taken care of loading 
the catalogue
                     Collection<CatalogItem<?, ?>> catalogItems = 
rebindContext.getCatalogItems();
                     String message = "RebindManager not resetting catalog to 
persisted state. Catalog load mode is {}.";
-                    if (!catalogItems.isEmpty()) {
+                    if (!catalogItems.isEmpty() && shouldLogRebinding()) {
                         LOG.info(message + " There {} {} item{} persisted.", 
new Object[]{
                                 catalogLoadMode, catalogItems.size() == 1 ? 
"was" : "were", catalogItems.size(), Strings.s(catalogItems)});
                     } else if (LOG.isDebugEnabled()) {
-                        LOG.debug(message, catalogLoadMode);
+                        logRebindingDebug(message, catalogLoadMode);
                     }
                 }
                 // TODO destroy old (as above)
             } else {
-                LOG.debug("RebindManager not resetting catalog because catalog 
persistence is disabled");
+                logRebindingDebug("RebindManager not resetting catalog because 
catalog persistence is disabled");
             }
             
             
@@ -622,7 +633,7 @@ public class RebindManagerImpl implements RebindManager {
             //
             
             // Instantiate locations
-            LOG.debug("RebindManager instantiating locations: {}", 
mementoManifest.getLocationIdToType().keySet());
+            logRebindingDebug("RebindManager instantiating locations: {}", 
mementoManifest.getLocationIdToType().keySet());
             for (Map.Entry<String, String> entry : 
mementoManifest.getLocationIdToType().entrySet()) {
                 String locId = entry.getKey();
                 String locType = entry.getValue();
@@ -637,7 +648,7 @@ public class RebindManagerImpl implements RebindManager {
             }
             
             // Instantiate entities
-            LOG.debug("RebindManager instantiating entities: {}", 
mementoManifest.getEntityIdToManifest().keySet());
+            logRebindingDebug("RebindManager instantiating entities: {}", 
mementoManifest.getEntityIdToManifest().keySet());
             for (Map.Entry<String, EntityMementoManifest> entry : 
mementoManifest.getEntityIdToManifest().entrySet()) {
                 String entityId = entry.getKey();
                 EntityMementoManifest entityManifest = entry.getValue();
@@ -668,9 +679,9 @@ public class RebindManagerImpl implements RebindManager {
             
             // Instantiate policies
             if (persistPoliciesEnabled) {
-                LOG.debug("RebindManager instantiating policies: {}", 
memento.getPolicyIds());
+                logRebindingDebug("RebindManager instantiating policies: {}", 
memento.getPolicyIds());
                 for (PolicyMemento policyMemento : 
memento.getPolicyMementos().values()) {
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
instantiating policy {}", policyMemento);
+                    logRebindingDebug("RebindManager instantiating policy {}", 
policyMemento);
                     
                     try {
                         Policy policy = newPolicy(policyMemento, 
getLoadingContextFromCatalogItemId(policyMemento.getCatalogItemId(), 
classLoader, rebindContext));
@@ -680,14 +691,14 @@ public class RebindManagerImpl implements RebindManager {
                     }
                 }
             } else {
-                LOG.debug("Not rebinding policies; feature disabled: {}", 
memento.getPolicyIds());
+                logRebindingDebug("Not rebinding policies; feature disabled: 
{}", memento.getPolicyIds());
             }
             
             // Instantiate enrichers
             if (persistEnrichersEnabled) {
-                LOG.debug("RebindManager instantiating enrichers: {}", 
memento.getEnricherIds());
+                logRebindingDebug("RebindManager instantiating enrichers: {}", 
memento.getEnricherIds());
                 for (EnricherMemento enricherMemento : 
memento.getEnricherMementos().values()) {
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
instantiating enricher {}", enricherMemento);
+                    logRebindingDebug("RebindManager instantiating enricher 
{}", enricherMemento);
 
                     try {
                         Enricher enricher = newEnricher(enricherMemento, 
reflections);
@@ -697,12 +708,12 @@ public class RebindManagerImpl implements RebindManager {
                     }
                 }
             } else {
-                LOG.debug("Not rebinding enrichers; feature disabled: {}", 
memento.getEnricherIds());
+                logRebindingDebug("Not rebinding enrichers; feature disabled: 
{}", memento.getEnricherIds());
             } 
             
             // Instantiate feeds
             if (persistFeedsEnabled) {
-                LOG.debug("RebindManager instantiating feeds: {}", 
memento.getFeedIds());
+                logRebindingDebug("RebindManager instantiating feeds: {}", 
memento.getFeedIds());
                 for (FeedMemento feedMemento : 
memento.getFeedMementos().values()) {
                     if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
instantiating feed {}", feedMemento);
 
@@ -714,7 +725,7 @@ public class RebindManagerImpl implements RebindManager {
                     }
                 }
             } else {
-                LOG.debug("Not rebinding feeds; feature disabled: {}", 
memento.getFeedIds());
+                logRebindingDebug("Not rebinding feeds; feature disabled: {}", 
memento.getFeedIds());
             } 
 
             //
@@ -722,10 +733,10 @@ public class RebindManagerImpl implements RebindManager {
             //
             
             // Reconstruct locations
-            LOG.debug("RebindManager reconstructing locations");
+            logRebindingDebug("RebindManager reconstructing locations");
             for (LocationMemento locMemento : 
sortParentFirst(memento.getLocationMementos()).values()) {
                 Location location = 
rebindContext.getLocation(locMemento.getId());
-                if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing location {}", locMemento);
+                logRebindingDebug("RebindManager reconstructing location {}", 
locMemento);
                 if (location == null) {
                     // usually because of creation-failure, when not using 
fail-fast
                     exceptionHandler.onNotFound(BrooklynObjectType.LOCATION, 
locMemento.getId());
@@ -740,10 +751,10 @@ public class RebindManagerImpl implements RebindManager {
 
             // Reconstruct policies
             if (persistPoliciesEnabled) {
-                LOG.debug("RebindManager reconstructing policies");
+                logRebindingDebug("RebindManager reconstructing policies");
                 for (PolicyMemento policyMemento : 
memento.getPolicyMementos().values()) {
                     Policy policy = 
rebindContext.getPolicy(policyMemento.getId());
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing policy {}", policyMemento);
+                    logRebindingDebug("RebindManager reconstructing policy 
{}", policyMemento);
     
                     if (policy == null) {
                         // usually because of creation-failure, when not using 
fail-fast
@@ -761,10 +772,10 @@ public class RebindManagerImpl implements RebindManager {
 
             // Reconstruct enrichers
             if (persistEnrichersEnabled) {
-                LOG.debug("RebindManager reconstructing enrichers");
+                logRebindingDebug("RebindManager reconstructing enrichers");
                 for (EnricherMemento enricherMemento : 
memento.getEnricherMementos().values()) {
                     Enricher enricher = 
rebindContext.getEnricher(enricherMemento.getId());
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing enricher {}", enricherMemento);
+                    logRebindingDebug("RebindManager reconstructing enricher 
{}", enricherMemento);
         
                     if (enricher == null) {
                         // usually because of creation-failure, when not using 
fail-fast
@@ -782,10 +793,10 @@ public class RebindManagerImpl implements RebindManager {
     
             // Reconstruct feeds
             if (persistFeedsEnabled) {
-                LOG.debug("RebindManager reconstructing feeds");
+                logRebindingDebug("RebindManager reconstructing feeds");
                 for (FeedMemento feedMemento : 
memento.getFeedMementos().values()) {
                     Feed feed = rebindContext.getFeed(feedMemento.getId());
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing feed {}", feedMemento);
+                    logRebindingDebug("RebindManager reconstructing feed {}", 
feedMemento);
         
                     if (feed == null) {
                         // usually because of creation-failure, when not using 
fail-fast
@@ -803,10 +814,10 @@ public class RebindManagerImpl implements RebindManager {
             }
     
             // Reconstruct entities
-            LOG.debug("RebindManager reconstructing entities");
+            logRebindingDebug("RebindManager reconstructing entities");
             for (EntityMemento entityMemento : 
sortParentFirst(memento.getEntityMementos()).values()) {
                 Entity entity = rebindContext.getEntity(entityMemento.getId());
-                if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing entity {}", entityMemento);
+                logRebindingDebug("RebindManager reconstructing entity {}", 
entityMemento);
     
                 if (entity == null) {
                     // usually because of creation-failure, when not using 
fail-fast
@@ -826,10 +837,10 @@ public class RebindManagerImpl implements RebindManager {
             //
             
             // Associate policies+enrichers+feeds with entities
-            LOG.debug("RebindManager reconstructing entities");
+            logRebindingDebug("RebindManager reconstructing entities");
             for (EntityMemento entityMemento : 
sortParentFirst(memento.getEntityMementos()).values()) {
                 Entity entity = rebindContext.getEntity(entityMemento.getId());
-                if (LOG.isDebugEnabled()) LOG.debug("RebindManager 
reconstructing entity {}", entityMemento);
+                logRebindingDebug("RebindManager reconstructing entity {}", 
entityMemento);
     
                 if (entity == null) {
                     // usually because of creation-failure, when not using 
fail-fast
@@ -853,7 +864,7 @@ public class RebindManagerImpl implements RebindManager {
             // PHASE EIGHT
             //
 
-            LOG.debug("RebindManager managing locations");
+            logRebindingDebug("RebindManager managing locations");
             LocationManagerInternal locationManager = 
(LocationManagerInternal)managementContext.getLocationManager();
             Set<String> oldLocations = 
Sets.newLinkedHashSet(locationManager.getLocationIds());
             for (Location location: rebindContext.getLocations()) {
@@ -878,7 +889,7 @@ public class RebindManagerImpl implements RebindManager {
             }
             
             // Manage the top-level apps (causing everything under them to 
become managed)
-            LOG.debug("RebindManager managing entities");
+            logRebindingDebug("RebindManager managing entities");
             EntityManagerInternal entityManager = 
(EntityManagerInternal)managementContext.getEntityManager();
             Set<String> oldEntities = 
Sets.newLinkedHashSet(entityManager.getEntityIds());
             for (Entity entity: rebindContext.getEntities()) {
@@ -909,9 +920,11 @@ public class RebindManagerImpl implements RebindManager {
 
             exceptionHandler.onDone();
 
-            if (!isEmpty && mode!=ManagementNodeState.HOT_STANDBY) {
-                LOG.info("Rebind complete: {} app{}, {} entit{}, {} 
location{}, {} polic{}, {} enricher{}, {} feed{}, {} catalog item{}", new 
Object[]{
-                    apps.size(), Strings.s(apps),
+            if (!isEmpty) {
+                BrooklynLogging.log(LOG, shouldLogRebinding() ? 
LoggingLevel.INFO : LoggingLevel.DEBUG, 
+                    "Rebind complete " + "("+mode+(readOnlyRebindCount>=0 ? ", 
iteration "+readOnlyRebindCount : "")+")" +
+                        " in {}: {} app{}, {} entit{}, {} location{}, {} 
polic{}, {} enricher{}, {} feed{}, {} catalog item{}", new Object[]{
+                    Time.makeTimeStringRounded(timer), apps.size(), 
Strings.s(apps),
                     rebindContext.getEntities().size(), 
Strings.ies(rebindContext.getEntities()),
                     rebindContext.getLocations().size(), 
Strings.s(rebindContext.getLocations()),
                     rebindContext.getPolicies().size(), 
Strings.ies(rebindContext.getPolicies()),
@@ -922,7 +935,7 @@ public class RebindManagerImpl implements RebindManager {
             }
 
             // Return the top-level applications
-            LOG.debug("RebindManager complete; return apps: {}", 
memento.getApplicationIds());
+            logRebindingDebug("RebindManager complete; apps: {}", 
memento.getApplicationIds());
             return apps;
 
         } catch (Exception e) {
@@ -1235,7 +1248,20 @@ public class RebindManagerImpl implements RebindManager {
             }
         }
     }
+
+    /** logs at debug, except during subsequent read-only rebinds, in which it 
logs trace */
+    private void logRebindingDebug(String message, Object... args) {
+        if (shouldLogRebinding()) {
+            LOG.debug(message, args);
+        } else {
+            LOG.trace(message, args);
+        }
+    }
     
+    protected boolean shouldLogRebinding() {
+        return (readOnlyRebindCount < 5) || (readOnlyRebindCount%1000==0);
+    }
+
     @Override
     public String toString() {
         return 
super.toString()+"[mgmt="+managementContext.getManagementNodeId()+"]";

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
 
b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
index 6ab8a7c..8faa80f 100644
--- 
a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
+++ 
b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
@@ -301,10 +301,11 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         BrooklynMementoManifest result = builder.build();
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Loaded memento manifest; took {}; {} entities, {} 
locations, {} policies, {} enrichers, {} feeds, {} catalog items, from {}", new 
Object[]{
-                     
Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), 
result.getEntityIdToManifest().size(), 
-                     result.getLocationIdToType().size(), 
result.getPolicyIdToType().size(), result.getEnricherIdToType().size(), 
-                     result.getFeedIdToType().size(), 
result.getCatalogItemMementos().size(),
+            LOG.debug("Loaded rebind manifests; took {}: {} entities, {} 
locations, {} policies, {} enrichers, {} feeds, {} catalog items; from {}", new 
Object[]{
+                     Time.makeTimeStringRounded(stopwatch), 
+                     result.getEntityIdToManifest().size(), 
result.getLocationIdToType().size(), 
+                     result.getPolicyIdToType().size(), 
result.getEnricherIdToType().size(), result.getFeedIdToType().size(), 
+                     result.getCatalogItemMementos().size(),
                      objectStore.getSummaryName() });
         }
 
@@ -343,7 +344,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         BrooklynMemento result = builder.build();
         
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Loaded memento; took {}; {} entities, {} locations, {} 
policies, {} enrichers, {} feeds, {} catalog items, from {}", new Object[]{
+            LOG.debug("Loaded rebind mementos; took {}: {} entities, {} 
locations, {} policies, {} enrichers, {} feeds, {} catalog items, from {}", new 
Object[]{
                       
Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), 
result.getEntityIds().size(), 
                       result.getLocationIds().size(), 
result.getPolicyIds().size(), result.getEnricherIds().size(), 
                       result.getFeedIds().size(), 
result.getCatalogItemIds().size(),
@@ -364,6 +365,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         List<String> feedSubPathList;
         List<String> catalogSubPathList;
         
+        Stopwatch stopwatch = Stopwatch.createStarted();
         try {
             entitySubPathList = 
objectStore.listContentsWithSubPath("entities");
             locationSubPathList = 
objectStore.listContentsWithSubPath("locations");
@@ -377,7 +379,8 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
             throw new IllegalStateException("Failed to list memento files in 
"+objectStore, e);
         }
 
-        LOG.debug("Scanning persisted state: {} entities, {} locations, {} 
policies, {} enrichers, {} feeds, {} catalog items from {}", new Object[]{
+        LOG.debug("Loaded rebind lists; took {}: {} entities, {} locations, {} 
policies, {} enrichers, {} feeds, {} catalog items; from {}", new Object[]{
+            Time.makeTimeStringRounded(stopwatch),
             entitySubPathList.size(), locationSubPathList.size(), 
policySubPathList.size(), enricherSubPathList.size(), 
             feedSubPathList.size(), catalogSubPathList.size(),
             objectStore.getSummaryName() });
@@ -498,7 +501,6 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
                 Futures.successfulAsList(futures).get();
                 Futures.allAsList(futures).get();
             } catch (Exception e) {
-                // TODO is the logging here as good as it was prior to 
https://github.com/apache/incubator-brooklyn/pull/177/files ?
                 throw Exceptions.propagate(e);
             }
             

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/event/basic/AttributeMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/AttributeMap.java 
b/core/src/main/java/brooklyn/event/basic/AttributeMap.java
index 08f1f91..da933c7 100644
--- a/core/src/main/java/brooklyn/event/basic/AttributeMap.java
+++ b/core/src/main/java/brooklyn/event/basic/AttributeMap.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.event.AttributeSensor;
@@ -153,9 +154,8 @@ public final class AttributeMap implements Serializable {
     }
 
     public void remove(AttributeSensor<?> attribute) {
-        if (log.isDebugEnabled()) {
-            log.debug("removing attribute {} on {}", attribute.getName(), 
entity);
-        }
+        BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+            "removing attribute {} on {}", attribute.getName(), entity);
 
         remove(attribute.getNameParts());
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordDeltaImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordDeltaImpl.java
 
b/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordDeltaImpl.java
index b54b9ef..6b026bc 100644
--- 
a/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordDeltaImpl.java
+++ 
b/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordDeltaImpl.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 
 import brooklyn.management.ha.ManagementPlaneSyncRecordPersister.Delta;
 
+import com.google.api.client.repackaged.com.google.common.base.Objects;
 import com.google.common.annotations.Beta;
 import com.google.common.collect.Sets;
 
@@ -108,4 +109,14 @@ public class ManagementPlaneSyncRecordDeltaImpl implements 
Delta {
     public String getExpectedMasterToClear() {
         return expectedOldMaster;
     }
+    
+    @Override
+    public String toString() {
+        return getClass().getCanonicalName()+"["+
+            (masterChange!=null && masterChange != MasterChange.NO_CHANGE ? 
+                masterChange+": "+expectedOldMaster+"->"+masterId+"; " : "")+
+            "nodes: "+nodes+
+            (removedNodeIds!=null && !removedNodeIds.isEmpty() ? "; removing: 
"+removedNodeIds : "")
+            +"]";
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordPersisterToObjectStore.java
 
b/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordPersisterToObjectStore.java
index 950f2b8..b9cf465 100644
--- 
a/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordPersisterToObjectStore.java
+++ 
b/core/src/main/java/brooklyn/management/ha/ManagementPlaneSyncRecordPersisterToObjectStore.java
@@ -236,7 +236,8 @@ public class 
ManagementPlaneSyncRecordPersisterToObjectStore implements Manageme
         }
         init();
         
-        if (LOG.isDebugEnabled()) LOG.debug("Checkpointed delta of 
manager-memento; updating {}", delta);
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        if (LOG.isTraceEnabled()) LOG.trace("Checkpointing delta of 
manager-memento; updating {}", delta);
         
         for (ManagementNodeSyncRecord m : delta.getNodes()) {
             persist(m);
@@ -256,15 +257,18 @@ public class 
ManagementPlaneSyncRecordPersisterToObjectStore implements Manageme
         default:
             throw new IllegalStateException("Unknown state for master-change: 
"+delta.getMasterChange());
         }
+        if (LOG.isDebugEnabled()) LOG.debug("Checkpointed delta of 
manager-memento in "+Time.makeTimeStringRounded(stopwatch)+": "+delta);
     }
 
     private void persistMaster(String nodeId, String optionalExpectedId) {
         if (optionalExpectedId!=null) {
             String currentRemoteMaster = masterWriter.get();
             if (currentRemoteMaster==null) {
-                // nothing at remote is okay
+                // okay to have nothing at remote
             } else if 
(!currentRemoteMaster.trim().equals(optionalExpectedId.trim())) {
-                LOG.warn("Master at server is "+currentRemoteMaster+"; 
expected "+optionalExpectedId+" in order to set as "+nodeId+", so not applying 
(yet)");
+                LOG.warn("Master at server is "+currentRemoteMaster+"; 
expected "+optionalExpectedId+" "
+                    + (Strings.isNonBlank(nodeId) ? "and would set as "+nodeId 
: "and would clear") 
+                    + ", so not applying (yet)");
                 return;
             }
         }
@@ -333,5 +337,5 @@ public class 
ManagementPlaneSyncRecordPersisterToObjectStore implements Manageme
         }
         return writer;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/management/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/OsgiManager.java 
b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
index 7f6ca52..3dea979 100644
--- a/core/src/main/java/brooklyn/management/ha/OsgiManager.java
+++ b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
@@ -35,6 +35,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
+import brooklyn.util.os.Os.DeletionResult;
 import brooklyn.util.osgi.Osgis;
 
 import com.google.common.base.Throwables;
@@ -76,7 +77,11 @@ public class OsgiManager {
         } catch (InterruptedException e) {
             throw Exceptions.propagate(e);
         }
-        osgiTempDir = Os.deleteRecursively(osgiTempDir).asNullOrThrowing();
+        DeletionResult deleteRecursively = Os.deleteRecursively(osgiTempDir);
+        if (deleteRecursively.getThrowable()!=null) {
+            log.debug("Unable to delete "+osgiTempDir+" (possibly already 
deleted?): "+deleteRecursively.getThrowable());
+        }
+        osgiTempDir = null;
         framework = null;
     }
 
@@ -85,12 +90,14 @@ public class OsgiManager {
             String nv = bundleUrlToNameVersionString.get(bundleUrl);
             if (nv!=null) {
                 if (Osgis.getBundle(framework, nv).isPresent()) {
-                    log.debug("Bundle from "+bundleUrl+" already installed as 
"+nv+"; not re-registering");
+                    log.trace("Bundle from "+bundleUrl+" already installed as 
"+nv+"; not re-registering");
                     return;
                 }
             }
             Bundle b = Osgis.install(framework, bundleUrl);
             nv = b.getSymbolicName()+":"+b.getVersion().toString();
+            // TODO if there is another entry for name:version we should log a 
warning at the very least,
+            // or better provide a way to get back *this* bundle
             bundleUrlToNameVersionString.put(bundleUrl, nv);
             log.debug("Bundle from "+bundleUrl+" successfully installed as " + 
nv + " ("+b+")");
         } catch (BundleException e) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/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 8a10727..fdb087b 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
@@ -34,6 +34,7 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
@@ -575,7 +576,8 @@ public class LocalEntityManager implements 
EntityManagerInternal {
             return false;
         }
         
-        if (log.isDebugEnabled()) log.debug("{} starting management of entity 
{}", this, e);
+        BrooklynLogging.log(log, 
BrooklynLogging.levelDebugOrTraceIfReadOnly(e), 
+            "{} starting management of entity {}", this, e);
         Entity realE = toRealEntity(e);
         
         Entity oldProxy = entityProxiesById.get(e.getId());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java 
b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
index bbb5c19..f81cb98 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
@@ -28,6 +28,8 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.config.BrooklynLogging;
+import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Lifecycle;
@@ -212,11 +214,13 @@ public class LocalLocationManager implements 
LocationManagerInternal {
         long count = LOCATION_CNT.incrementAndGet();
         if (log.isDebugEnabled()) {
             String msg = "Managing location " + loc + " ("+initialMode+"), 
from " + Tasks.current()+" / "+Entitlements.getEntitlementContext();
+            LoggingLevel level = 
(initialMode==ManagementTransitionMode.REBINDING_READONLY ? LoggingLevel.TRACE 
: LoggingLevel.DEBUG);
             if (count % 100 == 0) {
                 // include trace periodically in case we get leaks or too much 
location management
-                log.debug(msg, new Exception("Informational stack trace of 
call to manage location "+loc+" ("+count+" calls; "+getLocations().size()+" 
currently managed)"));
+                BrooklynLogging.log(log, level,
+                    msg, new Exception("Informational stack trace of call to 
manage location "+loc+" ("+count+" calls; "+getLocations().size()+" currently 
managed)"));
             } else {
-                log.debug(msg);
+                BrooklynLogging.log(log, level, msg);
             }
         }
 
@@ -240,7 +244,9 @@ public class LocalLocationManager implements 
LocationManagerInternal {
                 it.setManagementContext(managementContext);
                 if (!mode.isReadOnly()) {
                     it.onManagementStarted();
-                    recordLocationEvent(it, Lifecycle.CREATED);
+                    if (!mode.wasReadOnly()) {
+                        recordLocationEvent(it, Lifecycle.CREATED);
+                    }
                 }
                 
managementContext.getRebindManager().getChangeListener().onManaged(it);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/core/src/main/java/brooklyn/management/usage/LocationUsage.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/usage/LocationUsage.java 
b/core/src/main/java/brooklyn/management/usage/LocationUsage.java
index 8757404..f04055e 100644
--- a/core/src/main/java/brooklyn/management/usage/LocationUsage.java
+++ b/core/src/main/java/brooklyn/management/usage/LocationUsage.java
@@ -47,7 +47,7 @@ public class LocationUsage {
             this.state = checkNotNull(state, "state");
             this.entityId = checkNotNull(entityId, "entityId");
             this.entityType = checkNotNull(entityType, "entityType");
-            this.applicationId = checkNotNull(applicationId, "applicationId");
+            this.applicationId = checkNotNull(applicationId, "applicationId 
(entity "+entityId+")");
         }
 
         public Date getDate() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
index 540c707..e707495 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
@@ -277,7 +277,7 @@ public class JcloudsUtil implements JcloudsLocationConfig {
         if (allowReuse) {
             ComputeService result = cachedComputeServices.get(cacheKey);
             if (result!=null) {
-                LOG.debug("jclouds ComputeService cache hit for compute 
service, for "+Entities.sanitize(properties));
+                LOG.trace("jclouds ComputeService cache hit for compute 
service, for "+Entities.sanitize(properties));
                 return result;
             }
             LOG.debug("jclouds ComputeService cache miss for compute service, 
creating, for "+Entities.sanitize(properties));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/utils/common/src/main/java/brooklyn/util/javalang/Equals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/javalang/Equals.java 
b/utils/common/src/main/java/brooklyn/util/javalang/Equals.java
new file mode 100644
index 0000000..89736b4
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/javalang/Equals.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.util.javalang;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+
+public class Equals {
+
+    /** Tests whether the objects given are either all null or all equal to 
the first argument */
+    public static boolean objects(Object o1, Object o2, Object... oo) {
+        if (!Objects.equal(o1, o2)) return false;
+        for (Object o: oo) 
+            if (!Objects.equal(o1, o)) return false;
+        return true;
+    }
+
+    /** Tests whether the two objects given are either all null or all 
approximately equal 
+     * (tolerance of 0.001 for floating point, but subject to change) */
+    // relatively high tolerance mainly due to enrichers such as Tomcat 
windowed average, in hot standby;
+    // could make smaller
+    @Beta
+    public static boolean approximately(Object o1, Object o2) {
+        if (o1 instanceof Number) {
+            if (o2 instanceof Number) {
+                return Math.abs( 
((Number)o2).doubleValue()-((Number)o1).doubleValue() ) < 0.001;
+            }
+        }
+        return Objects.equal(o1, o2);
+    }
+
+    /** As {@link #approximately(Object, Object)} but testing all the 
arguments given. */
+    @Beta
+    public static boolean approximately(Object o1, Object o2, Object o3, 
Object... oo) {
+        if (!approximately(o1, o2)) return false;
+        if (!approximately(o1, o3)) return false;
+        for (Object o: oo) 
+            if (!approximately(o1, o)) return false;
+        return true;        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/utils/common/src/main/java/brooklyn/util/time/Time.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/time/Time.java 
b/utils/common/src/main/java/brooklyn/util/time/Time.java
index 60025a4..7c0612f 100644
--- a/utils/common/src/main/java/brooklyn/util/time/Time.java
+++ b/utils/common/src/main/java/brooklyn/util/time/Time.java
@@ -134,7 +134,9 @@ public class Time {
     /** @see #makeTimeString(long, boolean) */
     public static String makeTimeStringNano(long tn, boolean round) {
         if (tn<0) return "-"+makeTimeStringNano(-tn, round);
-        if (tn==0) return "0";
+        // units don't matter, but since ms is the usual finest granularity 
let's use it
+        // (previously was just "0" but that was too ambiguous in contexts 
like "took 0")
+        if (tn==0) return "0ms";
         
         long tnm = tn % 1000000;
         long t = tn/1000000;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28150112/utils/common/src/test/java/brooklyn/util/time/TimeTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/brooklyn/util/time/TimeTest.java 
b/utils/common/src/test/java/brooklyn/util/time/TimeTest.java
index 363abce..0771b90 100644
--- a/utils/common/src/test/java/brooklyn/util/time/TimeTest.java
+++ b/utils/common/src/test/java/brooklyn/util/time/TimeTest.java
@@ -129,11 +129,11 @@ public class TimeTest {
     }
 
     @Test
-    public void testMakeStringExactZero() { check(0, "0"); }
+    public void testMakeStringExactZero() { check(0, "0ms"); }
     @Test
     public void testMakeStringExactNegative() { check(-1, "-1ms"); }
     @Test
-    public void testMakeStringRoundedZero() { checkR(0, "0"); }
+    public void testMakeStringRoundedZero() { checkR(0, "0ms"); }
     @Test
     public void testMakeStringRoundedNegative() { checkR(-1, "-1ms"); }
 

Reply via email to