Add more information to the `quic_send_alarm_postponed` QUIC_BUG.

PiperOrigin-RevId: 576169564
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 513f4d0..d9f48cc 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -2413,7 +2413,10 @@
     if (send_alarm_->deadline() > max_deadline) {
       QUIC_BUG(quic_send_alarm_postponed)
           << "previous deadline:" << max_deadline
-          << ", deadline from CanWrite:" << send_alarm_->deadline();
+          << ", deadline from CanWrite:" << send_alarm_->deadline()
+          << ", last_can_write_reason:" << last_can_write_reason_
+          << ", packets_sent_on_last_successful_can_write:"
+          << packets_sent_on_last_successful_can_write_;
       QUIC_DVLOG(1) << "Send alarm restored after processing packet.";
       QUIC_RELOADABLE_FLAG_COUNT_N(quic_no_send_alarm_unless_necessary, 4, 7);
       // Restore to the previous, earlier deadline.
@@ -3227,6 +3230,11 @@
   return frames;
 }
 
+void QuicConnection::RecordLastCanWriteReason(LastCanWriteReason reason) {
+  last_can_write_reason_ = reason;
+  packets_sent_on_last_successful_can_write_ = stats_.packets_sent;
+}
+
 bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
   if (!connected_) {
     return false;
@@ -3252,6 +3260,9 @@
     // Try to coalesce packet, only allow to write when creator is on soft max
     // packet length. Given the next created packet is going to fill current
     // coalesced packet, do not check amplification factor.
+    if (packet_creator_.HasSoftMaxPacketLength()) {
+      RecordLastCanWriteReason(LAST_CAN_WRITE_REASON_COALESCE_PACKET);
+    }
     return packet_creator_.HasSoftMaxPacketLength();
   }
 
@@ -3260,6 +3271,7 @@
     // 1) firing PTO,
     // 2) bundling CRYPTO data with ACKs,
     // 3) coalescing CRYPTO data of higher space.
+    RecordLastCanWriteReason(LAST_CAN_WRITE_REASON_PENDING_TIMER);
     return true;
   }
 
@@ -3282,6 +3294,7 @@
 
   // Allow acks and probing frames to be sent immediately.
   if (retransmittable == NO_RETRANSMITTABLE_DATA) {
+    RecordLastCanWriteReason(LAST_CAN_WRITE_REASON_NO_RETRANSMITTABLE_DATA);
     return true;
   }
   // If the send alarm is set, wait for it to fire.
@@ -3300,6 +3313,7 @@
   if (!delay.IsZero()) {
     if (delay <= release_time_into_future_) {
       // Required delay is within pace time into future, send now.
+      RecordLastCanWriteReason(LAST_CAN_WRITE_REASON_DELAY_WITHIN_RELEASE_TIME);
       return true;
     }
     // Cannot send packet now because delay is too far in the future.
@@ -3308,6 +3322,8 @@
                   << "ms";
     return false;
   }
+
+  RecordLastCanWriteReason(LAST_CAN_WRITE_REASON_NO_DELAY);
   return true;
 }
 
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 469e40a..0108c76 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -2410,6 +2410,21 @@
   // The ECN codepoint of the last packet to be sent to the writer, which
   // might be different from the next codepoint in per_packet_options_.
   QuicEcnCodepoint last_ecn_codepoint_sent_ = ECN_NOT_ECT;
+
+  // The reason for the last call to CanWrite with a true return value.
+  enum LastCanWriteReason : uint8_t {
+    LAST_CAN_WRITE_REASON_NONE = 0,
+    LAST_CAN_WRITE_REASON_COALESCE_PACKET,
+    LAST_CAN_WRITE_REASON_PENDING_TIMER,
+    LAST_CAN_WRITE_REASON_NO_RETRANSMITTABLE_DATA,
+    LAST_CAN_WRITE_REASON_DELAY_WITHIN_RELEASE_TIME,
+    LAST_CAN_WRITE_REASON_NO_DELAY,
+  };
+  void RecordLastCanWriteReason(LastCanWriteReason reason);
+  // TODO(b/299071230): Delete |packets_sent_on_last_successful_can_write_| and
+  // |last_can_write_reason_| after debugging.
+  LastCanWriteReason last_can_write_reason_ = LAST_CAN_WRITE_REASON_NONE;
+  QuicPacketCount packets_sent_on_last_successful_can_write_ = 0;
 };
 
 }  // namespace quic