@@ -220,8 +220,11 @@ type P2P struct {
220220 // the rate for that interval rather than a running total.
221221 statDroppedBudget atomic.Int64
222222 statDroppedFull atomic.Int64
223- statMergedDocs atomic.Int64
224- statDroppedDocs atomic.Int64
223+ // dropSample holds a topic from the interval's drops, so the line reporting them can
224+ // name something to go and look at without logging every dropped message.
225+ dropSample atomic.Pointer [string ]
226+ statMergedDocs atomic.Int64
227+ statDroppedDocs atomic.Int64
225228 // statSkippedDocs counts documents deliberately not merged: already held, or
226229 // excluded by access or the replication filter. Not a loss, so kept apart.
227230 statSkippedDocs atomic.Int64
@@ -730,10 +733,7 @@ func (p *P2P) pubSubMessageHandler(from string, topic string, msg []byte) ([]byt
730733 p .dedup .observe (msg )
731734 if ! p .claimQueueBytes (size ) {
732735 p .statDroppedBudget .Add (1 )
733- log .Info ("pubsub message queue over byte budget, dropping message" ,
734- corelog .Any ("topic" , topic ),
735- corelog .Int64 ("bytes" , size ),
736- corelog .Int64 ("budget" , p .msgQueueMaxBytes ))
736+ p .dropSample .Store (& topic )
737737 return nil , nil
738738 }
739739
@@ -751,7 +751,7 @@ func (p *P2P) pubSubMessageHandler(from string, topic string, msg []byte) ([]byt
751751 default :
752752 p .releaseQueueBytes (size )
753753 p .statDroppedFull .Add (1 )
754- log . Info ( "pubsub message queue full, dropping message" , corelog . Any ( " topic" , topic ) )
754+ p . dropSample . Store ( & topic )
755755 }
756756 return nil , nil
757757}
@@ -791,13 +791,15 @@ func (p *P2P) reportStats() {
791791 return
792792 case <- ticker .C :
793793 msgsIn , msgsDistinct , dedupTruncated := p .dedup .drain ()
794+ droppedOverBudget := p .statDroppedBudget .Swap (0 )
795+ droppedQueueFull := p .statDroppedFull .Swap (0 )
794796 log .Info ("p2p stats" ,
795797 corelog .Int ("queueDepth" , len (p .msgQueue )),
796798 corelog .Int ("queueSlots" , msgQueueSize ),
797799 corelog .Int64 ("queueBytes" , p .msgQueueBytes .Load ()),
798800 corelog .Int64 ("queueBudget" , p .msgQueueMaxBytes ),
799- corelog .Int64 ("droppedOverBudget" , p . statDroppedBudget . Swap ( 0 ) ),
800- corelog .Int64 ("droppedQueueFull" , p . statDroppedFull . Swap ( 0 ) ),
801+ corelog .Int64 ("droppedOverBudget" , droppedOverBudget ),
802+ corelog .Int64 ("droppedQueueFull" , droppedQueueFull ),
801803 corelog .Int64 ("batches" , p .statBatches .Swap (0 )),
802804 corelog .Int64 ("batchFailures" , p .statBatchFailures .Swap (0 )),
803805 corelog .Int64 ("docsMerged" , p .statMergedDocs .Swap (0 )),
@@ -821,6 +823,17 @@ func (p *P2P) reportStats() {
821823 corelog .Int64 ("syncDAGBlocks" , p .statSyncDAGBlocks .Swap (0 )),
822824 corelog .Int64 ("syncDAGAbandoned" , p .statSyncDAGAbandoned .Swap (0 )),
823825 )
826+ // A drop at the door is data this node will not hold. The stats line above is at
827+ // info and corelog has no level between info and error, so a node running at error
828+ // level only sees this. It carries a sampled topic rather than a line per message,
829+ // which on a saturated node is tens per second.
830+ if sample := p .dropSample .Swap (nil ); sample != nil {
831+ log .Error ("dropped inbound pubsub messages" ,
832+ corelog .Int64 ("overBudget" , droppedOverBudget ),
833+ corelog .Int64 ("queueFull" , droppedQueueFull ),
834+ corelog .String ("sampleTopic" , * sample ))
835+ }
836+
824837 reportFailureReasons ("car failures" , p .carFailureReason .drain ())
825838 reportFailureReasons ("syncDAG failures" , p .syncDAGFailureReason .drain ())
826839 reportFailureReasons ("document drops" , p .docDropReason .drain ())
0 commit comments