551 lines
14 KiB
Go
551 lines
14 KiB
Go
|
|
package starnet
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"crypto/tls"
|
|||
|
|
"net"
|
|||
|
|
"net/http"
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// TraceSummary 是一次请求执行的 trace 摘要。
|
|||
|
|
type TraceSummary struct {
|
|||
|
|
Method string
|
|||
|
|
URL string
|
|||
|
|
StartedAt time.Time
|
|||
|
|
ResponseAt time.Time
|
|||
|
|
StatusCode int
|
|||
|
|
ResponseProto string
|
|||
|
|
Conn TraceConnSummary
|
|||
|
|
DNS *TraceDNSSummary
|
|||
|
|
DNSEvents []TraceDNSSummary
|
|||
|
|
Connect []TraceConnectSummary
|
|||
|
|
TLS *TraceTLSSummary
|
|||
|
|
RequestWrittenAt time.Time
|
|||
|
|
RequestWriteErr error
|
|||
|
|
FirstResponseByteAt time.Time
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceConnSummary 是连接复用与套接字信息摘要。
|
|||
|
|
type TraceConnSummary struct {
|
|||
|
|
Addr string
|
|||
|
|
LocalAddr string
|
|||
|
|
RemoteAddr string
|
|||
|
|
Reused bool
|
|||
|
|
WasIdle bool
|
|||
|
|
IdleTime time.Duration
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceDNSSummary 是 DNS 解析摘要。
|
|||
|
|
type TraceDNSSummary struct {
|
|||
|
|
Host string
|
|||
|
|
Addrs []string
|
|||
|
|
Coalesced bool
|
|||
|
|
StartedAt time.Time
|
|||
|
|
CompletedAt time.Time
|
|||
|
|
Duration time.Duration
|
|||
|
|
Err error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceConnectSummary 是单次建连尝试摘要。
|
|||
|
|
type TraceConnectSummary struct {
|
|||
|
|
Network string
|
|||
|
|
Addr string
|
|||
|
|
StartedAt time.Time
|
|||
|
|
CompletedAt time.Time
|
|||
|
|
Duration time.Duration
|
|||
|
|
Err error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceTLSSummary 是 TLS 握手与连接状态摘要。
|
|||
|
|
type TraceTLSSummary struct {
|
|||
|
|
Network string
|
|||
|
|
Addr string
|
|||
|
|
ServerName string
|
|||
|
|
Version uint16
|
|||
|
|
VersionName string
|
|||
|
|
CipherSuite uint16
|
|||
|
|
CipherSuiteName string
|
|||
|
|
CurveID tls.CurveID
|
|||
|
|
CurveName string
|
|||
|
|
NegotiatedProtocol string
|
|||
|
|
DidResume bool
|
|||
|
|
ECHAccepted bool
|
|||
|
|
VerifiedChains int
|
|||
|
|
StartedAt time.Time
|
|||
|
|
CompletedAt time.Time
|
|||
|
|
Duration time.Duration
|
|||
|
|
Err error
|
|||
|
|
PeerCertificates []TraceCertificateSummary
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceCertificateSummary 是单张证书的关键信息摘要。
|
|||
|
|
type TraceCertificateSummary struct {
|
|||
|
|
Subject string
|
|||
|
|
Issuer string
|
|||
|
|
DNSNames []string
|
|||
|
|
IPAddresses []string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TraceRecorder 聚合最近一次发布的 trace 摘要。
|
|||
|
|
// 通过 Request/Client 绑定时,starnet 会为每次执行创建私有运行态并在完成后发布摘要;
|
|||
|
|
// 直接使用 Hooks() 时,调用方仍需自行管理 Reset 与生命周期。
|
|||
|
|
type TraceRecorder struct {
|
|||
|
|
mu sync.Mutex
|
|||
|
|
|
|||
|
|
summary TraceSummary
|
|||
|
|
pendingDNS []TraceDNSSummary
|
|||
|
|
pendingConnectStarts map[string][]time.Time
|
|||
|
|
pendingTLSStart time.Time
|
|||
|
|
hooks *TraceHooks
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewTraceRecorder 创建请求级 trace 记录器。
|
|||
|
|
func NewTraceRecorder() *TraceRecorder {
|
|||
|
|
recorder := &TraceRecorder{}
|
|||
|
|
recorder.hooks = &TraceHooks{
|
|||
|
|
GetConn: recorder.onGetConn,
|
|||
|
|
GotConn: recorder.onGotConn,
|
|||
|
|
DNSStart: recorder.onDNSStart,
|
|||
|
|
DNSDone: recorder.onDNSDone,
|
|||
|
|
ConnectStart: recorder.onConnectStart,
|
|||
|
|
ConnectDone: recorder.onConnectDone,
|
|||
|
|
TLSHandshakeStart: recorder.onTLSHandshakeStart,
|
|||
|
|
TLSHandshakeDone: recorder.onTLSHandshakeDone,
|
|||
|
|
WroteRequest: recorder.onWroteRequest,
|
|||
|
|
GotFirstResponseByte: recorder.onGotFirstResponseByte,
|
|||
|
|
}
|
|||
|
|
return recorder
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Hooks 返回可挂到请求上的底层 trace hooks。
|
|||
|
|
func (r *TraceRecorder) Hooks() *TraceHooks {
|
|||
|
|
if r == nil {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
if r.hooks == nil {
|
|||
|
|
r.hooks = &TraceHooks{
|
|||
|
|
GetConn: r.onGetConn,
|
|||
|
|
GotConn: r.onGotConn,
|
|||
|
|
DNSStart: r.onDNSStart,
|
|||
|
|
DNSDone: r.onDNSDone,
|
|||
|
|
ConnectStart: r.onConnectStart,
|
|||
|
|
ConnectDone: r.onConnectDone,
|
|||
|
|
TLSHandshakeStart: r.onTLSHandshakeStart,
|
|||
|
|
TLSHandshakeDone: r.onTLSHandshakeDone,
|
|||
|
|
WroteRequest: r.onWroteRequest,
|
|||
|
|
GotFirstResponseByte: r.onGotFirstResponseByte,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return r.hooks
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Reset 清空当前摘要和内部状态。
|
|||
|
|
func (r *TraceRecorder) Reset() {
|
|||
|
|
if r == nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
r.resetLocked()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Summary 返回当前 trace 摘要的快照。
|
|||
|
|
func (r *TraceRecorder) Summary() TraceSummary {
|
|||
|
|
if r == nil {
|
|||
|
|
return TraceSummary{}
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
return cloneTraceSummary(r.summary)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) forkExecution() *TraceRecorder {
|
|||
|
|
if r == nil {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
return NewTraceRecorder()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) publishSummary(summary TraceSummary) {
|
|||
|
|
if r == nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
r.summary = cloneTraceSummary(summary)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) startRequest() {
|
|||
|
|
if r == nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
r.resetLocked()
|
|||
|
|
r.summary.StartedAt = time.Now()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) observePreparedRequest(req *http.Request) {
|
|||
|
|
if r == nil || req == nil || req.URL == nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
r.ensureStartedLocked(time.Now())
|
|||
|
|
r.summary.Method = req.Method
|
|||
|
|
r.summary.URL = req.URL.String()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) observeResponse(resp *http.Response) {
|
|||
|
|
if r == nil || resp == nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
r.summary.ResponseAt = now
|
|||
|
|
r.summary.StatusCode = resp.StatusCode
|
|||
|
|
r.summary.ResponseProto = resp.Proto
|
|||
|
|
if resp.TLS != nil {
|
|||
|
|
r.summary.TLS = mergeTraceTLSSummary(r.summary.TLS, *resp.TLS)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) ensureStartedLocked(now time.Time) {
|
|||
|
|
if r.summary.StartedAt.IsZero() {
|
|||
|
|
r.summary.StartedAt = now
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) resetLocked() {
|
|||
|
|
r.summary = TraceSummary{}
|
|||
|
|
r.pendingDNS = nil
|
|||
|
|
r.pendingTLSStart = time.Time{}
|
|||
|
|
if len(r.pendingConnectStarts) == 0 {
|
|||
|
|
r.pendingConnectStarts = nil
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
for key := range r.pendingConnectStarts {
|
|||
|
|
delete(r.pendingConnectStarts, key)
|
|||
|
|
}
|
|||
|
|
r.pendingConnectStarts = nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onGetConn(info TraceGetConnInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
r.ensureStartedLocked(time.Now())
|
|||
|
|
r.summary.Conn.Addr = info.Addr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onGotConn(info TraceGotConnInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
r.summary.Conn.Reused = info.Reused
|
|||
|
|
r.summary.Conn.WasIdle = info.WasIdle
|
|||
|
|
r.summary.Conn.IdleTime = info.IdleTime
|
|||
|
|
if info.Conn != nil {
|
|||
|
|
r.summary.Conn.LocalAddr = traceAddrString(info.Conn.LocalAddr())
|
|||
|
|
r.summary.Conn.RemoteAddr = traceAddrString(info.Conn.RemoteAddr())
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onDNSStart(info TraceDNSStartInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
dns := TraceDNSSummary{
|
|||
|
|
Host: info.Host,
|
|||
|
|
StartedAt: now,
|
|||
|
|
}
|
|||
|
|
r.pendingDNS = append(r.pendingDNS, dns)
|
|||
|
|
copyDNS := dns
|
|||
|
|
r.summary.DNS = ©DNS
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onDNSDone(info TraceDNSDoneInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
|
|||
|
|
dns := TraceDNSSummary{
|
|||
|
|
Host: "",
|
|||
|
|
Addrs: traceIPAddrsToStrings(info.Addrs),
|
|||
|
|
Coalesced: info.Coalesced,
|
|||
|
|
CompletedAt: now,
|
|||
|
|
Err: info.Err,
|
|||
|
|
}
|
|||
|
|
if len(r.pendingDNS) > 0 {
|
|||
|
|
dns.Host = r.pendingDNS[0].Host
|
|||
|
|
dns.StartedAt = r.pendingDNS[0].StartedAt
|
|||
|
|
if len(r.pendingDNS) == 1 {
|
|||
|
|
r.pendingDNS = nil
|
|||
|
|
} else {
|
|||
|
|
r.pendingDNS = append([]TraceDNSSummary(nil), r.pendingDNS[1:]...)
|
|||
|
|
}
|
|||
|
|
} else if r.summary.DNS != nil {
|
|||
|
|
dns.Host = r.summary.DNS.Host
|
|||
|
|
dns.StartedAt = r.summary.DNS.StartedAt
|
|||
|
|
}
|
|||
|
|
if !dns.StartedAt.IsZero() {
|
|||
|
|
dns.Duration = now.Sub(dns.StartedAt)
|
|||
|
|
}
|
|||
|
|
r.summary.DNSEvents = append(r.summary.DNSEvents, dns)
|
|||
|
|
copyDNS := dns
|
|||
|
|
r.summary.DNS = ©DNS
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onConnectStart(info TraceConnectStartInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
if r.pendingConnectStarts == nil {
|
|||
|
|
r.pendingConnectStarts = make(map[string][]time.Time)
|
|||
|
|
}
|
|||
|
|
key := traceConnectKey(info.Network, info.Addr)
|
|||
|
|
r.pendingConnectStarts[key] = append(r.pendingConnectStarts[key], now)
|
|||
|
|
r.summary.Connect = append(r.summary.Connect, TraceConnectSummary{
|
|||
|
|
Network: info.Network,
|
|||
|
|
Addr: info.Addr,
|
|||
|
|
StartedAt: now,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onConnectDone(info TraceConnectDoneInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
|
|||
|
|
start := time.Time{}
|
|||
|
|
key := traceConnectKey(info.Network, info.Addr)
|
|||
|
|
if starts := r.pendingConnectStarts[key]; len(starts) > 0 {
|
|||
|
|
start = starts[0]
|
|||
|
|
if len(starts) == 1 {
|
|||
|
|
delete(r.pendingConnectStarts, key)
|
|||
|
|
} else {
|
|||
|
|
r.pendingConnectStarts[key] = starts[1:]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
connect := TraceConnectSummary{
|
|||
|
|
Network: info.Network,
|
|||
|
|
Addr: info.Addr,
|
|||
|
|
StartedAt: start,
|
|||
|
|
CompletedAt: now,
|
|||
|
|
Err: info.Err,
|
|||
|
|
}
|
|||
|
|
if !start.IsZero() {
|
|||
|
|
connect.Duration = now.Sub(start)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for index := len(r.summary.Connect) - 1; index >= 0; index-- {
|
|||
|
|
item := &r.summary.Connect[index]
|
|||
|
|
if item.Network != info.Network || item.Addr != info.Addr || !item.CompletedAt.IsZero() {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
item.CompletedAt = now
|
|||
|
|
item.Duration = connect.Duration
|
|||
|
|
item.Err = info.Err
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
r.summary.Connect = append(r.summary.Connect, connect)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onTLSHandshakeStart(info TraceTLSHandshakeStartInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
r.pendingTLSStart = now
|
|||
|
|
r.summary.TLS = &TraceTLSSummary{
|
|||
|
|
Network: info.Network,
|
|||
|
|
Addr: info.Addr,
|
|||
|
|
ServerName: info.ServerName,
|
|||
|
|
StartedAt: now,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onTLSHandshakeDone(info TraceTLSHandshakeDoneInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
|
|||
|
|
var tlsSummary *TraceTLSSummary
|
|||
|
|
if r.summary.TLS != nil {
|
|||
|
|
copied := *r.summary.TLS
|
|||
|
|
tlsSummary = &copied
|
|||
|
|
} else {
|
|||
|
|
tlsSummary = &TraceTLSSummary{}
|
|||
|
|
}
|
|||
|
|
if tlsSummary.Network == "" {
|
|||
|
|
tlsSummary.Network = info.Network
|
|||
|
|
}
|
|||
|
|
if tlsSummary.Addr == "" {
|
|||
|
|
tlsSummary.Addr = info.Addr
|
|||
|
|
}
|
|||
|
|
if tlsSummary.ServerName == "" {
|
|||
|
|
tlsSummary.ServerName = info.ServerName
|
|||
|
|
}
|
|||
|
|
if tlsSummary.StartedAt.IsZero() {
|
|||
|
|
tlsSummary.StartedAt = r.pendingTLSStart
|
|||
|
|
}
|
|||
|
|
tlsSummary.CompletedAt = now
|
|||
|
|
if !tlsSummary.StartedAt.IsZero() {
|
|||
|
|
tlsSummary.Duration = now.Sub(tlsSummary.StartedAt)
|
|||
|
|
}
|
|||
|
|
tlsSummary.Err = info.Err
|
|||
|
|
tlsSummary = mergeTraceTLSSummary(tlsSummary, info.ConnectionState)
|
|||
|
|
if tlsSummary.ServerName == "" {
|
|||
|
|
tlsSummary.ServerName = info.ServerName
|
|||
|
|
}
|
|||
|
|
if tlsSummary.Addr == "" {
|
|||
|
|
tlsSummary.Addr = info.Addr
|
|||
|
|
}
|
|||
|
|
if tlsSummary.Network == "" {
|
|||
|
|
tlsSummary.Network = info.Network
|
|||
|
|
}
|
|||
|
|
r.pendingTLSStart = time.Time{}
|
|||
|
|
r.summary.TLS = tlsSummary
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onWroteRequest(info TraceWroteRequestInfo) {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
r.summary.RequestWrittenAt = now
|
|||
|
|
r.summary.RequestWriteErr = info.Err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *TraceRecorder) onGotFirstResponseByte() {
|
|||
|
|
r.mu.Lock()
|
|||
|
|
defer r.mu.Unlock()
|
|||
|
|
now := time.Now()
|
|||
|
|
r.ensureStartedLocked(now)
|
|||
|
|
r.summary.FirstResponseByteAt = now
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func traceAddrString(addr net.Addr) string {
|
|||
|
|
if addr == nil {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
return addr.String()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func traceConnectKey(network, addr string) string {
|
|||
|
|
return network + "\x00" + addr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func traceIPAddrsToStrings(addrs []net.IPAddr) []string {
|
|||
|
|
if len(addrs) == 0 {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
out := make([]string, 0, len(addrs))
|
|||
|
|
for _, addr := range addrs {
|
|||
|
|
out = append(out, addr.String())
|
|||
|
|
}
|
|||
|
|
return out
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func mergeTraceTLSSummary(summary *TraceTLSSummary, state tls.ConnectionState) *TraceTLSSummary {
|
|||
|
|
if summary == nil {
|
|||
|
|
summary = &TraceTLSSummary{}
|
|||
|
|
}
|
|||
|
|
if state.Version != 0 {
|
|||
|
|
summary.Version = state.Version
|
|||
|
|
summary.VersionName = tls.VersionName(state.Version)
|
|||
|
|
}
|
|||
|
|
if state.CipherSuite != 0 {
|
|||
|
|
summary.CipherSuite = state.CipherSuite
|
|||
|
|
summary.CipherSuiteName = tls.CipherSuiteName(state.CipherSuite)
|
|||
|
|
}
|
|||
|
|
if state.CurveID != 0 {
|
|||
|
|
summary.CurveID = state.CurveID
|
|||
|
|
summary.CurveName = state.CurveID.String()
|
|||
|
|
}
|
|||
|
|
if state.ServerName != "" {
|
|||
|
|
summary.ServerName = state.ServerName
|
|||
|
|
}
|
|||
|
|
if state.NegotiatedProtocol != "" {
|
|||
|
|
summary.NegotiatedProtocol = state.NegotiatedProtocol
|
|||
|
|
}
|
|||
|
|
summary.DidResume = state.DidResume
|
|||
|
|
summary.ECHAccepted = state.ECHAccepted
|
|||
|
|
summary.VerifiedChains = len(state.VerifiedChains)
|
|||
|
|
if len(state.PeerCertificates) > 0 {
|
|||
|
|
summary.PeerCertificates = make([]TraceCertificateSummary, 0, len(state.PeerCertificates))
|
|||
|
|
for _, cert := range state.PeerCertificates {
|
|||
|
|
certSummary := TraceCertificateSummary{
|
|||
|
|
Subject: cert.Subject.String(),
|
|||
|
|
Issuer: cert.Issuer.String(),
|
|||
|
|
DNSNames: append([]string(nil), cert.DNSNames...),
|
|||
|
|
}
|
|||
|
|
if len(cert.IPAddresses) > 0 {
|
|||
|
|
certSummary.IPAddresses = make([]string, 0, len(cert.IPAddresses))
|
|||
|
|
for _, ip := range cert.IPAddresses {
|
|||
|
|
certSummary.IPAddresses = append(certSummary.IPAddresses, ip.String())
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
summary.PeerCertificates = append(summary.PeerCertificates, certSummary)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return summary
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func cloneTraceSummary(summary TraceSummary) TraceSummary {
|
|||
|
|
cloned := summary
|
|||
|
|
if summary.DNS != nil {
|
|||
|
|
dns := *summary.DNS
|
|||
|
|
dns.Addrs = append([]string(nil), summary.DNS.Addrs...)
|
|||
|
|
cloned.DNS = &dns
|
|||
|
|
}
|
|||
|
|
if len(summary.DNSEvents) > 0 {
|
|||
|
|
cloned.DNSEvents = make([]TraceDNSSummary, 0, len(summary.DNSEvents))
|
|||
|
|
for _, dns := range summary.DNSEvents {
|
|||
|
|
cloned.DNSEvents = append(cloned.DNSEvents, TraceDNSSummary{
|
|||
|
|
Host: dns.Host,
|
|||
|
|
Addrs: append([]string(nil), dns.Addrs...),
|
|||
|
|
Coalesced: dns.Coalesced,
|
|||
|
|
StartedAt: dns.StartedAt,
|
|||
|
|
CompletedAt: dns.CompletedAt,
|
|||
|
|
Duration: dns.Duration,
|
|||
|
|
Err: dns.Err,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if len(summary.Connect) > 0 {
|
|||
|
|
cloned.Connect = append([]TraceConnectSummary(nil), summary.Connect...)
|
|||
|
|
}
|
|||
|
|
if summary.TLS != nil {
|
|||
|
|
tlsSummary := *summary.TLS
|
|||
|
|
if len(summary.TLS.PeerCertificates) > 0 {
|
|||
|
|
tlsSummary.PeerCertificates = make([]TraceCertificateSummary, 0, len(summary.TLS.PeerCertificates))
|
|||
|
|
for _, cert := range summary.TLS.PeerCertificates {
|
|||
|
|
tlsSummary.PeerCertificates = append(tlsSummary.PeerCertificates, TraceCertificateSummary{
|
|||
|
|
Subject: cert.Subject,
|
|||
|
|
Issuer: cert.Issuer,
|
|||
|
|
DNSNames: append([]string(nil), cert.DNSNames...),
|
|||
|
|
IPAddresses: append([]string(nil), cert.IPAddresses...),
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
cloned.TLS = &tlsSummary
|
|||
|
|
}
|
|||
|
|
return cloned
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func cloneTraceSummaryPtr(summary TraceSummary) *TraceSummary {
|
|||
|
|
cloned := cloneTraceSummary(summary)
|
|||
|
|
return &cloned
|
|||
|
|
}
|