github.com/MerlinKodo/quic-go@v0.39.2/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/MerlinKodo/quic-go/internal/protocol"
    14  	"github.com/MerlinKodo/quic-go/internal/utils"
    15  	"github.com/MerlinKodo/quic-go/internal/wire"
    16  	"github.com/MerlinKodo/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/MerlinKodo/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/MerlinKodo/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  // NewConnectionTracer creates a new tracer to record a qlog for a connection.
    67  func NewConnectionTracer(w io.WriteCloser, p protocol.Perspective, odcid protocol.ConnectionID) *logging.ConnectionTracer {
    68  	t := connectionTracer{
    69  		w:             w,
    70  		perspective:   p,
    71  		odcid:         odcid,
    72  		runStopped:    make(chan struct{}),
    73  		events:        make(chan event, eventChanSize),
    74  		referenceTime: time.Now(),
    75  	}
    76  	go t.run()
    77  	return &logging.ConnectionTracer{
    78  		StartedConnection: func(local, remote net.Addr, srcConnID, destConnID logging.ConnectionID) {
    79  			t.StartedConnection(local, remote, srcConnID, destConnID)
    80  		},
    81  		NegotiatedVersion: func(chosen logging.VersionNumber, clientVersions, serverVersions []logging.VersionNumber) {
    82  			t.NegotiatedVersion(chosen, clientVersions, serverVersions)
    83  		},
    84  		ClosedConnection:            func(e error) { t.ClosedConnection(e) },
    85  		SentTransportParameters:     func(tp *wire.TransportParameters) { t.SentTransportParameters(tp) },
    86  		ReceivedTransportParameters: func(tp *wire.TransportParameters) { t.ReceivedTransportParameters(tp) },
    87  		RestoredTransportParameters: func(tp *wire.TransportParameters) { t.RestoredTransportParameters(tp) },
    88  		SentLongHeaderPacket: func(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
    89  			t.SentLongHeaderPacket(hdr, size, ecn, ack, frames)
    90  		},
    91  		SentShortHeaderPacket: func(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
    92  			t.SentShortHeaderPacket(hdr, size, ecn, ack, frames)
    93  		},
    94  		ReceivedLongHeaderPacket: func(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
    95  			t.ReceivedLongHeaderPacket(hdr, size, ecn, frames)
    96  		},
    97  		ReceivedShortHeaderPacket: func(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
    98  			t.ReceivedShortHeaderPacket(hdr, size, ecn, frames)
    99  		},
   100  		ReceivedRetry: func(hdr *wire.Header) {
   101  			t.ReceivedRetry(hdr)
   102  		},
   103  		ReceivedVersionNegotiationPacket: func(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) {
   104  			t.ReceivedVersionNegotiationPacket(dest, src, versions)
   105  		},
   106  		BufferedPacket: func(pt logging.PacketType, size protocol.ByteCount) {
   107  			t.BufferedPacket(pt, size)
   108  		},
   109  		DroppedPacket: func(pt logging.PacketType, size protocol.ByteCount, reason logging.PacketDropReason) {
   110  			t.DroppedPacket(pt, size, reason)
   111  		},
   112  		UpdatedMetrics: func(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) {
   113  			t.UpdatedMetrics(rttStats, cwnd, bytesInFlight, packetsInFlight)
   114  		},
   115  		LostPacket: func(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) {
   116  			t.LostPacket(encLevel, pn, lossReason)
   117  		},
   118  		UpdatedCongestionState: func(state logging.CongestionState) {
   119  			t.UpdatedCongestionState(state)
   120  		},
   121  		UpdatedPTOCount: func(value uint32) {
   122  			t.UpdatedPTOCount(value)
   123  		},
   124  		UpdatedKeyFromTLS: func(encLevel protocol.EncryptionLevel, pers protocol.Perspective) {
   125  			t.UpdatedKeyFromTLS(encLevel, pers)
   126  		},
   127  		UpdatedKey: func(generation protocol.KeyPhase, remote bool) {
   128  			t.UpdatedKey(generation, remote)
   129  		},
   130  		DroppedEncryptionLevel: func(encLevel protocol.EncryptionLevel) {
   131  			t.DroppedEncryptionLevel(encLevel)
   132  		},
   133  		DroppedKey: func(generation protocol.KeyPhase) {
   134  			t.DroppedKey(generation)
   135  		},
   136  		SetLossTimer: func(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) {
   137  			t.SetLossTimer(tt, encLevel, timeout)
   138  		},
   139  		LossTimerExpired: func(tt logging.TimerType, encLevel protocol.EncryptionLevel) {
   140  			t.LossTimerExpired(tt, encLevel)
   141  		},
   142  		LossTimerCanceled: func() {
   143  			t.LossTimerCanceled()
   144  		},
   145  		ECNStateUpdated: func(state logging.ECNState, trigger logging.ECNStateTrigger) {
   146  			t.ECNStateUpdated(state, trigger)
   147  		},
   148  		Debug: func(name, msg string) {
   149  			t.Debug(name, msg)
   150  		},
   151  		Close: func() {
   152  			t.Close()
   153  		},
   154  	}
   155  }
   156  
   157  func (t *connectionTracer) run() {
   158  	defer close(t.runStopped)
   159  	buf := &bytes.Buffer{}
   160  	enc := gojay.NewEncoder(buf)
   161  	tl := &topLevel{
   162  		trace: trace{
   163  			VantagePoint: vantagePoint{Type: t.perspective},
   164  			CommonFields: commonFields{
   165  				ODCID:         t.odcid,
   166  				GroupID:       t.odcid,
   167  				ReferenceTime: t.referenceTime,
   168  			},
   169  		},
   170  	}
   171  	if err := enc.Encode(tl); err != nil {
   172  		panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
   173  	}
   174  	if err := buf.WriteByte('\n'); err != nil {
   175  		panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
   176  	}
   177  	if _, err := t.w.Write(buf.Bytes()); err != nil {
   178  		t.encodeErr = err
   179  	}
   180  	enc = gojay.NewEncoder(t.w)
   181  	for ev := range t.events {
   182  		if t.encodeErr != nil { // if encoding failed, just continue draining the event channel
   183  			continue
   184  		}
   185  		if err := enc.Encode(ev); err != nil {
   186  			t.encodeErr = err
   187  			continue
   188  		}
   189  		if _, err := t.w.Write([]byte{'\n'}); err != nil {
   190  			t.encodeErr = err
   191  		}
   192  	}
   193  }
   194  
   195  func (t *connectionTracer) Close() {
   196  	if err := t.export(); err != nil {
   197  		log.Printf("exporting qlog failed: %s\n", err)
   198  	}
   199  }
   200  
   201  // export writes a qlog.
   202  func (t *connectionTracer) export() error {
   203  	close(t.events)
   204  	<-t.runStopped
   205  	if t.encodeErr != nil {
   206  		return t.encodeErr
   207  	}
   208  	return t.w.Close()
   209  }
   210  
   211  func (t *connectionTracer) recordEvent(eventTime time.Time, details eventDetails) {
   212  	t.events <- event{
   213  		RelativeTime: eventTime.Sub(t.referenceTime),
   214  		eventDetails: details,
   215  	}
   216  }
   217  
   218  func (t *connectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID protocol.ConnectionID) {
   219  	// ignore this event if we're not dealing with UDP addresses here
   220  	localAddr, ok := local.(*net.UDPAddr)
   221  	if !ok {
   222  		return
   223  	}
   224  	remoteAddr, ok := remote.(*net.UDPAddr)
   225  	if !ok {
   226  		return
   227  	}
   228  	t.mutex.Lock()
   229  	t.recordEvent(time.Now(), &eventConnectionStarted{
   230  		SrcAddr:          localAddr,
   231  		DestAddr:         remoteAddr,
   232  		SrcConnectionID:  srcConnID,
   233  		DestConnectionID: destConnID,
   234  	})
   235  	t.mutex.Unlock()
   236  }
   237  
   238  func (t *connectionTracer) NegotiatedVersion(chosen logging.VersionNumber, client, server []logging.VersionNumber) {
   239  	var clientVersions, serverVersions []versionNumber
   240  	if len(client) > 0 {
   241  		clientVersions = make([]versionNumber, len(client))
   242  		for i, v := range client {
   243  			clientVersions[i] = versionNumber(v)
   244  		}
   245  	}
   246  	if len(server) > 0 {
   247  		serverVersions = make([]versionNumber, len(server))
   248  		for i, v := range server {
   249  			serverVersions[i] = versionNumber(v)
   250  		}
   251  	}
   252  	t.mutex.Lock()
   253  	t.recordEvent(time.Now(), &eventVersionNegotiated{
   254  		clientVersions: clientVersions,
   255  		serverVersions: serverVersions,
   256  		chosenVersion:  versionNumber(chosen),
   257  	})
   258  	t.mutex.Unlock()
   259  }
   260  
   261  func (t *connectionTracer) ClosedConnection(e error) {
   262  	t.mutex.Lock()
   263  	t.recordEvent(time.Now(), &eventConnectionClosed{e: e})
   264  	t.mutex.Unlock()
   265  }
   266  
   267  func (t *connectionTracer) SentTransportParameters(tp *wire.TransportParameters) {
   268  	t.recordTransportParameters(t.perspective, tp)
   269  }
   270  
   271  func (t *connectionTracer) ReceivedTransportParameters(tp *wire.TransportParameters) {
   272  	t.recordTransportParameters(t.perspective.Opposite(), tp)
   273  }
   274  
   275  func (t *connectionTracer) RestoredTransportParameters(tp *wire.TransportParameters) {
   276  	ev := t.toTransportParameters(tp)
   277  	ev.Restore = true
   278  
   279  	t.mutex.Lock()
   280  	t.recordEvent(time.Now(), ev)
   281  	t.mutex.Unlock()
   282  }
   283  
   284  func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective, tp *wire.TransportParameters) {
   285  	ev := t.toTransportParameters(tp)
   286  	ev.Owner = ownerLocal
   287  	if sentBy != t.perspective {
   288  		ev.Owner = ownerRemote
   289  	}
   290  	ev.SentBy = sentBy
   291  
   292  	t.mutex.Lock()
   293  	t.recordEvent(time.Now(), ev)
   294  	t.mutex.Unlock()
   295  }
   296  
   297  func (t *connectionTracer) toTransportParameters(tp *wire.TransportParameters) *eventTransportParameters {
   298  	var pa *preferredAddress
   299  	if tp.PreferredAddress != nil {
   300  		pa = &preferredAddress{
   301  			IPv4:                tp.PreferredAddress.IPv4,
   302  			PortV4:              tp.PreferredAddress.IPv4Port,
   303  			IPv6:                tp.PreferredAddress.IPv6,
   304  			PortV6:              tp.PreferredAddress.IPv6Port,
   305  			ConnectionID:        tp.PreferredAddress.ConnectionID,
   306  			StatelessResetToken: tp.PreferredAddress.StatelessResetToken,
   307  		}
   308  	}
   309  	return &eventTransportParameters{
   310  		OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID,
   311  		InitialSourceConnectionID:       tp.InitialSourceConnectionID,
   312  		RetrySourceConnectionID:         tp.RetrySourceConnectionID,
   313  		StatelessResetToken:             tp.StatelessResetToken,
   314  		DisableActiveMigration:          tp.DisableActiveMigration,
   315  		MaxIdleTimeout:                  tp.MaxIdleTimeout,
   316  		MaxUDPPayloadSize:               tp.MaxUDPPayloadSize,
   317  		AckDelayExponent:                tp.AckDelayExponent,
   318  		MaxAckDelay:                     tp.MaxAckDelay,
   319  		ActiveConnectionIDLimit:         tp.ActiveConnectionIDLimit,
   320  		InitialMaxData:                  tp.InitialMaxData,
   321  		InitialMaxStreamDataBidiLocal:   tp.InitialMaxStreamDataBidiLocal,
   322  		InitialMaxStreamDataBidiRemote:  tp.InitialMaxStreamDataBidiRemote,
   323  		InitialMaxStreamDataUni:         tp.InitialMaxStreamDataUni,
   324  		InitialMaxStreamsBidi:           int64(tp.MaxBidiStreamNum),
   325  		InitialMaxStreamsUni:            int64(tp.MaxUniStreamNum),
   326  		PreferredAddress:                pa,
   327  		MaxDatagramFrameSize:            tp.MaxDatagramFrameSize,
   328  	}
   329  }
   330  
   331  func (t *connectionTracer) SentLongHeaderPacket(
   332  	hdr *logging.ExtendedHeader,
   333  	size logging.ByteCount,
   334  	ecn logging.ECN,
   335  	ack *logging.AckFrame,
   336  	frames []logging.Frame,
   337  ) {
   338  	t.sentPacket(*transformLongHeader(hdr), size, hdr.Length, ecn, ack, frames)
   339  }
   340  
   341  func (t *connectionTracer) SentShortHeaderPacket(
   342  	hdr *logging.ShortHeader,
   343  	size logging.ByteCount,
   344  	ecn logging.ECN,
   345  	ack *logging.AckFrame,
   346  	frames []logging.Frame,
   347  ) {
   348  	t.sentPacket(*transformShortHeader(hdr), size, 0, ecn, ack, frames)
   349  }
   350  
   351  func (t *connectionTracer) sentPacket(
   352  	hdr gojay.MarshalerJSONObject,
   353  	size, payloadLen logging.ByteCount,
   354  	ecn logging.ECN,
   355  	ack *logging.AckFrame,
   356  	frames []logging.Frame,
   357  ) {
   358  	numFrames := len(frames)
   359  	if ack != nil {
   360  		numFrames++
   361  	}
   362  	fs := make([]frame, 0, numFrames)
   363  	if ack != nil {
   364  		fs = append(fs, frame{Frame: ack})
   365  	}
   366  	for _, f := range frames {
   367  		fs = append(fs, frame{Frame: f})
   368  	}
   369  	t.mutex.Lock()
   370  	t.recordEvent(time.Now(), &eventPacketSent{
   371  		Header:        hdr,
   372  		Length:        size,
   373  		PayloadLength: payloadLen,
   374  		ECN:           ecn,
   375  		Frames:        fs,
   376  	})
   377  	t.mutex.Unlock()
   378  }
   379  
   380  func (t *connectionTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
   381  	fs := make([]frame, len(frames))
   382  	for i, f := range frames {
   383  		fs[i] = frame{Frame: f}
   384  	}
   385  	header := *transformLongHeader(hdr)
   386  	t.mutex.Lock()
   387  	t.recordEvent(time.Now(), &eventPacketReceived{
   388  		Header:        header,
   389  		Length:        size,
   390  		PayloadLength: hdr.Length,
   391  		ECN:           ecn,
   392  		Frames:        fs,
   393  	})
   394  	t.mutex.Unlock()
   395  }
   396  
   397  func (t *connectionTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
   398  	fs := make([]frame, len(frames))
   399  	for i, f := range frames {
   400  		fs[i] = frame{Frame: f}
   401  	}
   402  	header := *transformShortHeader(hdr)
   403  	t.mutex.Lock()
   404  	t.recordEvent(time.Now(), &eventPacketReceived{
   405  		Header:        header,
   406  		Length:        size,
   407  		PayloadLength: size - wire.ShortHeaderLen(hdr.DestConnectionID, hdr.PacketNumberLen),
   408  		ECN:           ecn,
   409  		Frames:        fs,
   410  	})
   411  	t.mutex.Unlock()
   412  }
   413  
   414  func (t *connectionTracer) ReceivedRetry(hdr *wire.Header) {
   415  	t.mutex.Lock()
   416  	t.recordEvent(time.Now(), &eventRetryReceived{
   417  		Header: *transformHeader(hdr),
   418  	})
   419  	t.mutex.Unlock()
   420  }
   421  
   422  func (t *connectionTracer) ReceivedVersionNegotiationPacket(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) {
   423  	ver := make([]versionNumber, len(versions))
   424  	for i, v := range versions {
   425  		ver[i] = versionNumber(v)
   426  	}
   427  	t.mutex.Lock()
   428  	t.recordEvent(time.Now(), &eventVersionNegotiationReceived{
   429  		Header: packetHeaderVersionNegotiation{
   430  			SrcConnectionID:  src,
   431  			DestConnectionID: dest,
   432  		},
   433  		SupportedVersions: ver,
   434  	})
   435  	t.mutex.Unlock()
   436  }
   437  
   438  func (t *connectionTracer) BufferedPacket(pt logging.PacketType, size protocol.ByteCount) {
   439  	t.mutex.Lock()
   440  	t.recordEvent(time.Now(), &eventPacketBuffered{
   441  		PacketType: pt,
   442  		PacketSize: size,
   443  	})
   444  	t.mutex.Unlock()
   445  }
   446  
   447  func (t *connectionTracer) DroppedPacket(pt logging.PacketType, size protocol.ByteCount, reason logging.PacketDropReason) {
   448  	t.mutex.Lock()
   449  	t.recordEvent(time.Now(), &eventPacketDropped{
   450  		PacketType: pt,
   451  		PacketSize: size,
   452  		Trigger:    packetDropReason(reason),
   453  	})
   454  	t.mutex.Unlock()
   455  }
   456  
   457  func (t *connectionTracer) UpdatedMetrics(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) {
   458  	m := &metrics{
   459  		MinRTT:           rttStats.MinRTT(),
   460  		SmoothedRTT:      rttStats.SmoothedRTT(),
   461  		LatestRTT:        rttStats.LatestRTT(),
   462  		RTTVariance:      rttStats.MeanDeviation(),
   463  		CongestionWindow: cwnd,
   464  		BytesInFlight:    bytesInFlight,
   465  		PacketsInFlight:  packetsInFlight,
   466  	}
   467  	t.mutex.Lock()
   468  	t.recordEvent(time.Now(), &eventMetricsUpdated{
   469  		Last:    t.lastMetrics,
   470  		Current: m,
   471  	})
   472  	t.lastMetrics = m
   473  	t.mutex.Unlock()
   474  }
   475  
   476  func (t *connectionTracer) AcknowledgedPacket(protocol.EncryptionLevel, protocol.PacketNumber) {}
   477  
   478  func (t *connectionTracer) LostPacket(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) {
   479  	t.mutex.Lock()
   480  	t.recordEvent(time.Now(), &eventPacketLost{
   481  		PacketType:   getPacketTypeFromEncryptionLevel(encLevel),
   482  		PacketNumber: pn,
   483  		Trigger:      packetLossReason(lossReason),
   484  	})
   485  	t.mutex.Unlock()
   486  }
   487  
   488  func (t *connectionTracer) UpdatedCongestionState(state logging.CongestionState) {
   489  	t.mutex.Lock()
   490  	t.recordEvent(time.Now(), &eventCongestionStateUpdated{state: congestionState(state)})
   491  	t.mutex.Unlock()
   492  }
   493  
   494  func (t *connectionTracer) UpdatedPTOCount(value uint32) {
   495  	t.mutex.Lock()
   496  	t.recordEvent(time.Now(), &eventUpdatedPTO{Value: value})
   497  	t.mutex.Unlock()
   498  }
   499  
   500  func (t *connectionTracer) UpdatedKeyFromTLS(encLevel protocol.EncryptionLevel, pers protocol.Perspective) {
   501  	t.mutex.Lock()
   502  	t.recordEvent(time.Now(), &eventKeyUpdated{
   503  		Trigger: keyUpdateTLS,
   504  		KeyType: encLevelToKeyType(encLevel, pers),
   505  	})
   506  	t.mutex.Unlock()
   507  }
   508  
   509  func (t *connectionTracer) UpdatedKey(generation protocol.KeyPhase, remote bool) {
   510  	trigger := keyUpdateLocal
   511  	if remote {
   512  		trigger = keyUpdateRemote
   513  	}
   514  	t.mutex.Lock()
   515  	now := time.Now()
   516  	t.recordEvent(now, &eventKeyUpdated{
   517  		Trigger:    trigger,
   518  		KeyType:    keyTypeClient1RTT,
   519  		Generation: generation,
   520  	})
   521  	t.recordEvent(now, &eventKeyUpdated{
   522  		Trigger:    trigger,
   523  		KeyType:    keyTypeServer1RTT,
   524  		Generation: generation,
   525  	})
   526  	t.mutex.Unlock()
   527  }
   528  
   529  func (t *connectionTracer) DroppedEncryptionLevel(encLevel protocol.EncryptionLevel) {
   530  	t.mutex.Lock()
   531  	now := time.Now()
   532  	if encLevel == protocol.Encryption0RTT {
   533  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, t.perspective)})
   534  	} else {
   535  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveServer)})
   536  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveClient)})
   537  	}
   538  	t.mutex.Unlock()
   539  }
   540  
   541  func (t *connectionTracer) DroppedKey(generation protocol.KeyPhase) {
   542  	t.mutex.Lock()
   543  	now := time.Now()
   544  	t.recordEvent(now, &eventKeyDiscarded{
   545  		KeyType:    encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveServer),
   546  		Generation: generation,
   547  	})
   548  	t.recordEvent(now, &eventKeyDiscarded{
   549  		KeyType:    encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveClient),
   550  		Generation: generation,
   551  	})
   552  	t.mutex.Unlock()
   553  }
   554  
   555  func (t *connectionTracer) SetLossTimer(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) {
   556  	t.mutex.Lock()
   557  	now := time.Now()
   558  	t.recordEvent(now, &eventLossTimerSet{
   559  		TimerType: timerType(tt),
   560  		EncLevel:  encLevel,
   561  		Delta:     timeout.Sub(now),
   562  	})
   563  	t.mutex.Unlock()
   564  }
   565  
   566  func (t *connectionTracer) LossTimerExpired(tt logging.TimerType, encLevel protocol.EncryptionLevel) {
   567  	t.mutex.Lock()
   568  	t.recordEvent(time.Now(), &eventLossTimerExpired{
   569  		TimerType: timerType(tt),
   570  		EncLevel:  encLevel,
   571  	})
   572  	t.mutex.Unlock()
   573  }
   574  
   575  func (t *connectionTracer) LossTimerCanceled() {
   576  	t.mutex.Lock()
   577  	t.recordEvent(time.Now(), &eventLossTimerCanceled{})
   578  	t.mutex.Unlock()
   579  }
   580  
   581  func (t *connectionTracer) ECNStateUpdated(state logging.ECNState, trigger logging.ECNStateTrigger) {
   582  	t.mutex.Lock()
   583  	t.recordEvent(time.Now(), &eventECNStateUpdated{state: state, trigger: trigger})
   584  	t.mutex.Unlock()
   585  }
   586  
   587  func (t *connectionTracer) Debug(name, msg string) {
   588  	t.mutex.Lock()
   589  	t.recordEvent(time.Now(), &eventGeneric{
   590  		name: name,
   591  		msg:  msg,
   592  	})
   593  	t.mutex.Unlock()
   594  }