diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index e17207a9dce75b8b0e102f3a5ac64cce5a742601..cd6a765434db2fee81e322c4fdf36400a61b3ca2 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -70,12 +70,18 @@ from allmydata.interfaces import (
 from allmydata.storage.common import (
     storage_index_to_dir,
 )
+from allmydata.util.base32 import (
+    b2a,
+)
 from challenge_bypass_ristretto import (
     TokenPreimage,
     VerificationSignature,
     SigningKey,
 )
 
+from twisted.internet.defer import (
+    Deferred,
+)
 from twisted.python.reflect import (
     namedAny,
 )
@@ -83,6 +89,10 @@ from twisted.internet.interfaces import (
     IReactorTime,
 )
 
+from eliot import (
+    start_action,
+)
+
 from .foolscap import (
     ShareStat,
     RIPrivacyPassAuthorizedStorageServer,
@@ -318,9 +328,13 @@ class ZKAPAuthorizerStorageServer(Referenceable):
         return self._original.remote_advise_corrupt_share(*a, **kw)
 
     def remote_share_sizes(self, storage_index_or_slot, sharenums):
-        return dict(
-            get_share_sizes(self._original, storage_index_or_slot, sharenums)
-        )
+        with start_action(
+                action_type=u"zkapauthorizer:storage-server:remote:share-sizes",
+                storage_index_or_slot=storage_index_or_slot,
+        ):
+            return dict(
+                get_share_sizes(self._original, storage_index_or_slot, sharenums)
+            )
 
     def remote_stat_shares(self, storage_indexes_or_slots):
         return list(
@@ -345,6 +359,30 @@ class ZKAPAuthorizerStorageServer(Referenceable):
             data in already-allocated storage.  These cases may not be the
             same from the perspective of pass validation.
         """
+        with start_action(
+                action_type=u"zkapauthorizer:storage-server:remote:slot-testv-and-readv-and-writev",
+                storage_index=b2a(storage_index),
+                path=storage_index_to_dir(storage_index),
+        ):
+            result = self._slot_testv_and_readv_and_writev(
+                passes,
+                storage_index,
+                secrets,
+                tw_vectors,
+                r_vector,
+            )
+            if isinstance(result, Deferred):
+                raise TypeError("_slot_testv_and_readv_and_writev returned Deferred")
+            return result
+
+    def _slot_testv_and_readv_and_writev(
+            self,
+            passes,
+            storage_index,
+            secrets,
+            tw_vectors,
+            r_vector,
+    ):
         # Only writes to shares without an active lease will result in a lease
         # renewal.
         renew_leases = False
diff --git a/src/_zkapauthorizer/eliot.py b/src/_zkapauthorizer/eliot.py
index 0d52a6246685dcddcea498c421bea8b6d8e96591..1cd64008f3bfc1b1a8670d67c496660c4d8824f0 100644
--- a/src/_zkapauthorizer/eliot.py
+++ b/src/_zkapauthorizer/eliot.py
@@ -80,3 +80,33 @@ CALL_WITH_PASSES = ActionType(
     [],
     u"A storage operation is being started which may spend some passes.",
 )
+
+CURRENT_SIZES = Field(
+    u"current_sizes",
+    dict,
+    u"A dictionary mapping the numbers of existing shares to their existing sizes.",
+)
+
+TW_VECTORS_SUMMARY = Field(
+    u"tw_vectors_summary",
+    dict,
+    u"A dictionary mapping share numbers from tw_vectors to test and write vector summaries.",
+)
+
+NEW_SIZES = Field(
+    u"new_sizes",
+    dict,
+    u"A dictionary like that of CURRENT_SIZES but for the sizes computed for the shares after applying tw_vectors.",
+)
+
+NEW_PASSES = Field(
+    u"new_passes",
+    int,
+    u"The number of passes computed as being required for the change in size.",
+)
+
+MUTABLE_PASSES_REQUIRED = MessageType(
+    u"zkapauthorizer:storage:mutable-passes-required",
+    [CURRENT_SIZES, TW_VECTORS_SUMMARY, NEW_SIZES, NEW_PASSES],
+    u"Some number of passes has been computed as the cost of updating a mutable.",
+)
diff --git a/src/_zkapauthorizer/storage_common.py b/src/_zkapauthorizer/storage_common.py
index 80707f226b892c96cfa5fefd278e68b9146dc7e1..1f429dd50a924557d73950c458f071bd4e9f9721 100644
--- a/src/_zkapauthorizer/storage_common.py
+++ b/src/_zkapauthorizer/storage_common.py
@@ -30,6 +30,10 @@ from .validators import (
     greater_than,
 )
 
+from .eliot import (
+    MUTABLE_PASSES_REQUIRED,
+)
+
 @attr.s(frozen=True)
 class MorePassesRequired(Exception):
     """
@@ -180,8 +184,9 @@ def get_implied_data_length(data_vector, new_length):
 def get_required_new_passes_for_mutable_write(pass_value, current_sizes, tw_vectors):
     """
     :param int pass_value: The value of a single pass in byte-months.
+
+    :param current_sizes:
     """
-    # print("get_required_new_passes_for_mutable_write({}, {})".format(current_sizes, summarize(tw_vectors)))
     current_passes = required_passes(
         pass_value,
         current_sizes.values(),
@@ -204,16 +209,23 @@ def get_required_new_passes_for_mutable_write(pass_value, current_sizes, tw_vect
     )
     required_new_passes = new_passes - current_passes
 
-    # print("Current sizes: {}".format(current_sizes))
-    # print("Current passes: {}".format(current_passes))
-    # print("New sizes: {}".format(new_sizes))
-    # print("New passes: {}".format(new_passes))
+    MUTABLE_PASSES_REQUIRED.log(
+        current_sizes=current_sizes,
+        tw_vectors_summary=summarize(tw_vectors),
+        current_passes=current_passes,
+        new_sizes=new_sizes,
+        new_passes=new_passes,
+    )
     return required_new_passes
 
 def summarize(tw_vectors):
     return {
         sharenum: (
-            test_vector,
+            list(
+                (offset, length, operator, len(specimen))
+                for (offset, length, operator, specimen)
+                in test_vector
+            ),
             list(
                 (offset, len(data))
                 for (offset, data)