github.com/tumi8/quic-go@v0.37.4-tum/qlog/qlog.go (about)

     1  package qlog
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"net"
     9  	"runtime/debug"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/tumi8/quic-go/noninternal/protocol"
    14  	"github.com/tumi8/quic-go/noninternal/utils"
    15  	"github.com/tumi8/quic-go/noninternal/wire"
    16  	"github.com/tumi8/quic-go/logging"
    17  
    18  	"github.com/francoispqt/gojay"
    19  )
    20  
    21  // Setting of this only works when quic-go is used as a library.
    22  // When building a binary from this repository, the version can be set using the following go build flag:
    23  // -ldflags="-X github.com/tumi8/quic-go/qlog.quicGoVersion=foobar"
    24  var quicGoVersion = "(devel)"
    25  
    26  func init() {
    27  	if quicGoVersion != "(devel)" { // variable set by ldflags
    28  		return
    29  	}
    30  	info, ok := debug.ReadBuildInfo()
    31  	if !ok { // no build info available. This happens when quic-go is not used as a library.
    32  		return
    33  	}
    34  	for _, d := range info.Deps {
    35  		if d.Path == "github.com/tumi8/quic-go" {
    36  			quicGoVersion = d.Version
    37  			if d.Replace != nil {
    38  				if len(d.Replace.Version) > 0 {
    39  					quicGoVersion = d.Version
    40  				} else {
    41  					quicGoVersion += " (replaced)"
    42  				}
    43  			}
    44  			break
    45  		}
    46  	}
    47  }
    48  
    49  const eventChanSize = 50
    50  
    51  type connectionTracer struct {
    52  	mutex sync.Mutex
    53  
    54  	w             io.WriteCloser
    55  	odcid         protocol.ConnectionID
    56  	perspective   protocol.Perspective
    57  	referenceTime time.Time
    58  
    59  	events     chan event
    60  	encodeErr  error
    61  	runStopped chan struct{}
    62  
    63  	lastMetrics *metrics
    64  }
    65  
    66  var _ logging.ConnectionTracer = &connectionTracer{}
    67  
    68  // NewConnectionTracer creates a new tracer to record a qlog for a connection.
    69  func NewConnectionTracer(w io.WriteCloser, p protocol.Perspective, odcid protocol.ConnectionID) logging.ConnectionTracer {
    70  	t := &connectionTracer{
    71  		w:             w,
    72  		perspective:   p,
    73  		odcid:         odcid,
    74  		runStopped:    make(chan struct{}),
    75  		events:        make(chan event, eventChanSize),
    76  		referenceTime: time.Now(),
    77  	}
    78  	go t.run()
    79  	return t
    80  }
    81  
    82  func (t *connectionTracer) run() {
    83  	defer close(t.runStopped)
    84  	buf := &bytes.Buffer{}
    85  	enc := gojay.NewEncoder(buf)
    86  	tl := &topLevel{
    87  		trace: trace{
    88  			VantagePoint: vantagePoint{Type: t.perspective},
    89  			CommonFields: commonFields{
    90  				ODCID:         t.odcid,
    91  				GroupID:       t.odcid,
    92  				ReferenceTime: t.referenceTime,
    93  			},
    94  		},
    95  	}
    96  	if err := enc.Encode(tl); err != nil {
    97  		panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
    98  	}
    99  	if err := buf.WriteByte('\n'); err != nil {
   100  		panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
   101  	}
   102  	if _, err := t.w.Write(buf.Bytes()); err != nil {
   103  		t.encodeErr = err
   104  	}
   105  	enc = gojay.NewEncoder(t.w)
   106  	for ev := range t.events {
   107  		if t.encodeErr != nil { // if encoding failed, just continue draining the event channel
   108  			continue
   109  		}
   110  		if err := enc.Encode(ev); err != nil {
   111  			t.encodeErr = err
   112  			continue
   113  		}
   114  		if _, err := t.w.Write([]byte{'\n'}); err != nil {
   115  			t.encodeErr = err
   116  		}
   117  	}
   118  }
   119  
   120  func (t *connectionTracer) Close() {
   121  	if err := t.export(); err != nil {
   122  		log.Printf("exporting qlog failed: %s\n", err)
   123  	}
   124  }
   125  
   126  // export writes a qlog.
   127  func (t *connectionTracer) export() error {
   128  	close(t.events)
   129  	<-t.runStopped
   130  	if t.encodeErr != nil {
   131  		return t.encodeErr
   132  	}
   133  	return t.w.Close()
   134  }
   135  
   136  func (t *connectionTracer) recordEvent(eventTime time.Time, details eventDetails) {
   137  	t.events <- event{
   138  		RelativeTime: eventTime.Sub(t.referenceTime),
   139  		eventDetails: details,
   140  	}
   141  }
   142  
   143  func (t *connectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID protocol.ConnectionID) {
   144  	// ignore this event if we're not dealing with UDP addresses here
   145  	localAddr, ok := local.(*net.UDPAddr)
   146  	if !ok {
   147  		return
   148  	}
   149  	remoteAddr, ok := remote.(*net.UDPAddr)
   150  	if !ok {
   151  		return
   152  	}
   153  	t.mutex.Lock()
   154  	t.recordEvent(time.Now(), &eventConnectionStarted{
   155  		SrcAddr:          localAddr,
   156  		DestAddr:         remoteAddr,
   157  		SrcConnectionID:  srcConnID,
   158  		DestConnectionID: destConnID,
   159  	})
   160  	t.mutex.Unlock()
   161  }
   162  
   163  func (t *connectionTracer) NegotiatedVersion(chosen logging.VersionNumber, client, server []logging.VersionNumber) {
   164  	var clientVersions, serverVersions []versionNumber
   165  	if len(client) > 0 {
   166  		clientVersions = make([]versionNumber, len(client))
   167  		for i, v := range client {
   168  			clientVersions[i] = versionNumber(v)
   169  		}
   170  	}
   171  	if len(server) > 0 {
   172  		serverVersions = make([]versionNumber, len(server))
   173  		for i, v := range server {
   174  			serverVersions[i] = versionNumber(v)
   175  		}
   176  	}
   177  	t.mutex.Lock()
   178  	t.recordEvent(time.Now(), &eventVersionNegotiated{
   179  		clientVersions: clientVersions,
   180  		serverVersions: serverVersions,
   181  		chosenVersion:  versionNumber(chosen),
   182  	})
   183  	t.mutex.Unlock()
   184  }
   185  
   186  func (t *connectionTracer) ClosedConnection(e error) {
   187  	t.mutex.Lock()
   188  	t.recordEvent(time.Now(), &eventConnectionClosed{e: e})
   189  	t.mutex.Unlock()
   190  }
   191  
   192  func (t *connectionTracer) SentTransportParameters(tp *wire.TransportParameters) {
   193  	t.recordTransportParameters(t.perspective, tp)
   194  }
   195  
   196  func (t *connectionTracer) ReceivedTransportParameters(tp *wire.TransportParameters) {
   197  	t.recordTransportParameters(t.perspective.Opposite(), tp)
   198  }
   199  
   200  func (t *connectionTracer) RestoredTransportParameters(tp *wire.TransportParameters) {
   201  	ev := t.toTransportParameters(tp)
   202  	ev.Restore = true
   203  
   204  	t.mutex.Lock()
   205  	t.recordEvent(time.Now(), ev)
   206  	t.mutex.Unlock()
   207  }
   208  
   209  func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective, tp *wire.TransportParameters) {
   210  	ev := t.toTransportParameters(tp)
   211  	ev.Owner = ownerLocal
   212  	if sentBy != t.perspective {
   213  		ev.Owner = ownerRemote
   214  	}
   215  	ev.SentBy = sentBy
   216  
   217  	t.mutex.Lock()
   218  	t.recordEvent(time.Now(), ev)
   219  	t.mutex.Unlock()
   220  }
   221  
   222  func (t *connectionTracer) toTransportParameters(tp *wire.TransportParameters) *eventTransportParameters {
   223  	var pa *preferredAddress
   224  	if tp.PreferredAddress != nil {
   225  		pa = &preferredAddress{
   226  			IPv4:                tp.PreferredAddress.IPv4,
   227  			PortV4:              tp.PreferredAddress.IPv4Port,
   228  			IPv6:                tp.PreferredAddress.IPv6,
   229  			PortV6:              tp.PreferredAddress.IPv6Port,
   230  			ConnectionID:        tp.PreferredAddress.ConnectionID,
   231  			StatelessResetToken: tp.PreferredAddress.StatelessResetToken,
   232  		}
   233  	}
   234  	return &eventTransportParameters{
   235  		OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID,
   236  		InitialSourceConnectionID:       tp.InitialSourceConnectionID,
   237  		RetrySourceConnectionID:         tp.RetrySourceConnectionID,
   238  		StatelessResetToken:             tp.StatelessResetToken,
   239  		DisableActiveMigration:          tp.DisableActiveMigration,
   240  		MaxIdleTimeout:                  tp.MaxIdleTimeout,
   241  		MaxUDPPayloadSize:               tp.MaxUDPPayloadSize,
   242  		AckDelayExponent:                tp.AckDelayExponent,
   243  		MaxAckDelay:                     tp.MaxAckDelay,
   244  		ActiveConnectionIDLimit:         tp.ActiveConnectionIDLimit,
   245  		InitialMaxData:                  tp.InitialMaxData,
   246  		InitialMaxStreamDataBidiLocal:   tp.InitialMaxStreamDataBidiLocal,
   247  		InitialMaxStreamDataBidiRemote:  tp.InitialMaxStreamDataBidiRemote,
   248  		InitialMaxStreamDataUni:         tp.InitialMaxStreamDataUni,
   249  		InitialMaxStreamsBidi:           int64(tp.MaxBidiStreamNum),
   250  		InitialMaxStreamsUni:            int64(tp.MaxUniStreamNum),
   251  		PreferredAddress:                pa,
   252  		MaxDatagramFrameSize:            tp.MaxDatagramFrameSize,
   253  	}
   254  }
   255  
   256  func (t *connectionTracer) SentLongHeaderPacket(hdr *logging.ExtendedHeader, packetSize logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) {
   257  	t.sentPacket(*transformLongHeader(hdr), packetSize, hdr.Length, ack, frames)
   258  }
   259  
   260  func (t *connectionTracer) SentShortHeaderPacket(hdr *logging.ShortHeader, packetSize logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) {
   261  	t.sentPacket(*transformShortHeader(hdr), packetSize, 0, ack, frames)
   262  }
   263  
   264  func (t *connectionTracer) sentPacket(hdr gojay.MarshalerJSONObject, packetSize, payloadLen logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) {
   265  	numFrames := len(frames)
   266  	if ack != nil {
   267  		numFrames++
   268  	}
   269  	fs := make([]frame, 0, numFrames)
   270  	if ack != nil {
   271  		fs = append(fs, frame{Frame: ack})
   272  	}
   273  	for _, f := range frames {
   274  		fs = append(fs, frame{Frame: f})
   275  	}
   276  	t.mutex.Lock()
   277  	t.recordEvent(time.Now(), &eventPacketSent{
   278  		Header:        hdr,
   279  		Length:        packetSize,
   280  		PayloadLength: payloadLen,
   281  		Frames:        fs,
   282  	})
   283  	t.mutex.Unlock()
   284  }
   285  
   286  func (t *connectionTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, packetSize logging.ByteCount, frames []logging.Frame) {
   287  	fs := make([]frame, len(frames))
   288  	for i, f := range frames {
   289  		fs[i] = frame{Frame: f}
   290  	}
   291  	header := *transformLongHeader(hdr)
   292  	t.mutex.Lock()
   293  	t.recordEvent(time.Now(), &eventPacketReceived{
   294  		Header:        header,
   295  		Length:        packetSize,
   296  		PayloadLength: hdr.Length,
   297  		Frames:        fs,
   298  	})
   299  	t.mutex.Unlock()
   300  }
   301  
   302  func (t *connectionTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, packetSize logging.ByteCount, frames []logging.Frame) {
   303  	fs := make([]frame, len(frames))
   304  	for i, f := range frames {
   305  		fs[i] = frame{Frame: f}
   306  	}
   307  	header := *transformShortHeader(hdr)
   308  	t.mutex.Lock()
   309  	t.recordEvent(time.Now(), &eventPacketReceived{
   310  		Header:        header,
   311  		Length:        packetSize,
   312  		PayloadLength: packetSize - wire.ShortHeaderLen(hdr.DestConnectionID, hdr.PacketNumberLen),
   313  		Frames:        fs,
   314  	})
   315  	t.mutex.Unlock()
   316  }
   317  
   318  func (t *connectionTracer) ReceivedRetry(hdr *wire.Header) {
   319  	t.mutex.Lock()
   320  	t.recordEvent(time.Now(), &eventRetryReceived{
   321  		Header: *transformHeader(hdr),
   322  	})
   323  	t.mutex.Unlock()
   324  }
   325  
   326  func (t *connectionTracer) ReceivedVersionNegotiationPacket(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) {
   327  	ver := make([]versionNumber, len(versions))
   328  	for i, v := range versions {
   329  		ver[i] = versionNumber(v)
   330  	}
   331  	t.mutex.Lock()
   332  	t.recordEvent(time.Now(), &eventVersionNegotiationReceived{
   333  		Header: packetHeaderVersionNegotiation{
   334  			SrcConnectionID:  src,
   335  			DestConnectionID: dest,
   336  		},
   337  		SupportedVersions: ver,
   338  	})
   339  	t.mutex.Unlock()
   340  }
   341  
   342  func (t *connectionTracer) BufferedPacket(pt logging.PacketType, size protocol.ByteCount) {
   343  	t.mutex.Lock()
   344  	t.recordEvent(time.Now(), &eventPacketBuffered{
   345  		PacketType: pt,
   346  		PacketSize: size,
   347  	})
   348  	t.mutex.Unlock()
   349  }
   350  
   351  func (t *connectionTracer) DroppedPacket(pt logging.PacketType, size protocol.ByteCount, reason logging.PacketDropReason) {
   352  	t.mutex.Lock()
   353  	t.recordEvent(time.Now(), &eventPacketDropped{
   354  		PacketType: pt,
   355  		PacketSize: size,
   356  		Trigger:    packetDropReason(reason),
   357  	})
   358  	t.mutex.Unlock()
   359  }
   360  
   361  func (t *connectionTracer) UpdatedMetrics(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) {
   362  	m := &metrics{
   363  		MinRTT:           rttStats.MinRTT(),
   364  		SmoothedRTT:      rttStats.SmoothedRTT(),
   365  		LatestRTT:        rttStats.LatestRTT(),
   366  		RTTVariance:      rttStats.MeanDeviation(),
   367  		CongestionWindow: cwnd,
   368  		BytesInFlight:    bytesInFlight,
   369  		PacketsInFlight:  packetsInFlight,
   370  	}
   371  	t.mutex.Lock()
   372  	t.recordEvent(time.Now(), &eventMetricsUpdated{
   373  		Last:    t.lastMetrics,
   374  		Current: m,
   375  	})
   376  	t.lastMetrics = m
   377  	t.mutex.Unlock()
   378  }
   379  
   380  func (t *connectionTracer) AcknowledgedPacket(protocol.EncryptionLevel, protocol.PacketNumber) {}
   381  
   382  func (t *connectionTracer) LostPacket(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) {
   383  	t.mutex.Lock()
   384  	t.recordEvent(time.Now(), &eventPacketLost{
   385  		PacketType:   getPacketTypeFromEncryptionLevel(encLevel),
   386  		PacketNumber: pn,
   387  		Trigger:      packetLossReason(lossReason),
   388  	})
   389  	t.mutex.Unlock()
   390  }
   391  
   392  func (t *connectionTracer) UpdatedCongestionState(state logging.CongestionState) {
   393  	t.mutex.Lock()
   394  	t.recordEvent(time.Now(), &eventCongestionStateUpdated{state: congestionState(state)})
   395  	t.mutex.Unlock()
   396  }
   397  
   398  func (t *connectionTracer) UpdatedPTOCount(value uint32) {
   399  	t.mutex.Lock()
   400  	t.recordEvent(time.Now(), &eventUpdatedPTO{Value: value})
   401  	t.mutex.Unlock()
   402  }
   403  
   404  func (t *connectionTracer) UpdatedKeyFromTLS(encLevel protocol.EncryptionLevel, pers protocol.Perspective) {
   405  	t.mutex.Lock()
   406  	t.recordEvent(time.Now(), &eventKeyUpdated{
   407  		Trigger: keyUpdateTLS,
   408  		KeyType: encLevelToKeyType(encLevel, pers),
   409  	})
   410  	t.mutex.Unlock()
   411  }
   412  
   413  func (t *connectionTracer) UpdatedKey(generation protocol.KeyPhase, remote bool) {
   414  	trigger := keyUpdateLocal
   415  	if remote {
   416  		trigger = keyUpdateRemote
   417  	}
   418  	t.mutex.Lock()
   419  	now := time.Now()
   420  	t.recordEvent(now, &eventKeyUpdated{
   421  		Trigger:    trigger,
   422  		KeyType:    keyTypeClient1RTT,
   423  		Generation: generation,
   424  	})
   425  	t.recordEvent(now, &eventKeyUpdated{
   426  		Trigger:    trigger,
   427  		KeyType:    keyTypeServer1RTT,
   428  		Generation: generation,
   429  	})
   430  	t.mutex.Unlock()
   431  }
   432  
   433  func (t *connectionTracer) DroppedEncryptionLevel(encLevel protocol.EncryptionLevel) {
   434  	t.mutex.Lock()
   435  	now := time.Now()
   436  	if encLevel == protocol.Encryption0RTT {
   437  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, t.perspective)})
   438  	} else {
   439  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveServer)})
   440  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveClient)})
   441  	}
   442  	t.mutex.Unlock()
   443  }
   444  
   445  func (t *connectionTracer) DroppedKey(generation protocol.KeyPhase) {
   446  	t.mutex.Lock()
   447  	now := time.Now()
   448  	t.recordEvent(now, &eventKeyDiscarded{
   449  		KeyType:    encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveServer),
   450  		Generation: generation,
   451  	})
   452  	t.recordEvent(now, &eventKeyDiscarded{
   453  		KeyType:    encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveClient),
   454  		Generation: generation,
   455  	})
   456  	t.mutex.Unlock()
   457  }
   458  
   459  func (t *connectionTracer) SetLossTimer(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) {
   460  	t.mutex.Lock()
   461  	now := time.Now()
   462  	t.recordEvent(now, &eventLossTimerSet{
   463  		TimerType: timerType(tt),
   464  		EncLevel:  encLevel,
   465  		Delta:     timeout.Sub(now),
   466  	})
   467  	t.mutex.Unlock()
   468  }
   469  
   470  func (t *connectionTracer) LossTimerExpired(tt logging.TimerType, encLevel protocol.EncryptionLevel) {
   471  	t.mutex.Lock()
   472  	t.recordEvent(time.Now(), &eventLossTimerExpired{
   473  		TimerType: timerType(tt),
   474  		EncLevel:  encLevel,
   475  	})
   476  	t.mutex.Unlock()
   477  }
   478  
   479  func (t *connectionTracer) LossTimerCanceled() {
   480  	t.mutex.Lock()
   481  	t.recordEvent(time.Now(), &eventLossTimerCanceled{})
   482  	t.mutex.Unlock()
   483  }
   484  
   485  func (t *connectionTracer) Debug(name, msg string) {
   486  	t.mutex.Lock()
   487  	t.recordEvent(time.Now(), &eventGeneric{
   488  		name: name,
   489  		msg:  msg,
   490  	})
   491  	t.mutex.Unlock()
   492  }