func NewFailure(err error) *string {
	if err == nil {
		return nil
	}
	err = errorx.SafeErrWrapperBuilder{
		Error:     err,
		Operation: errorx.TopLevelOperation,
	}.MaybeBuild()
	errWrapper := err.(*errorx.ErrWrapper)
	s := errWrapper.Failure
	if s == "" {
		s = "unknown_failure: errWrapper.Failure is empty"
	}
	return &s
}
NewFailure creates a failure nullable string from the given error
package archival
import (
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"errors"
	"net"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
	"github.com/ooni/probe-engine/geolocate"
	"github.com/ooni/probe-engine/model"
	"github.com/ooni/probe-engine/netx/errorx"
	"github.com/ooni/probe-engine/netx/trace"
)
type ExtSpec struct {
	Name string  
	V    int64   
}
func (spec ExtSpec) AddTo(m *model.Measurement) {
	if m.Extensions == nil {
		m.Extensions = make(map[string]int64)
	}
	m.Extensions[spec.Name] = spec.V
}
var (
	ExtDNS = ExtSpec{Name: "dnst", V: 0}
	ExtNetevents = ExtSpec{Name: "netevents", V: 0}
	ExtHTTP = ExtSpec{Name: "httpt", V: 0}
	ExtTCPConnect = ExtSpec{Name: "tcpconnect", V: 0}
	ExtTLSHandshake = ExtSpec{Name: "tlshandshake", V: 0}
	ExtTunnel = ExtSpec{Name: "tunnel", V: 0}
)
type TCPConnectStatus struct {
	Blocked *bool   `json:"blocked,omitempty"`  
	Failure *string `json:"failure"`
	Success bool    `json:"success"`
}
type TCPConnectEntry struct {
	ConnID        int64            `json:"conn_id,omitempty"`
	DialID        int64            `json:"dial_id,omitempty"`
	IP            string           `json:"ip"`
	Port          int              `json:"port"`
	Status        TCPConnectStatus `json:"status"`
	T             float64          `json:"t"`
	TransactionID int64            `json:"transaction_id,omitempty"`
}
func NewTCPConnectList(begin time.Time, events []trace.Event) []TCPConnectEntry {
	var out []TCPConnectEntry
	for _, event := range events {
		if event.Name != errorx.ConnectOperation {
			continue
		}
		if event.Proto != "tcp" {
			continue
		}
		ip, sport, _ := net.SplitHostPort(event.Address)
		iport, _ := strconv.Atoi(sport)
		out = append(out, TCPConnectEntry{
			IP:   ip,
			Port: iport,
			Status: TCPConnectStatus{
				Failure: NewFailure(event.Err),
				Success: event.Err == nil,
			},
			T: event.Time.Sub(begin).Seconds(),
		})
	}
	return out
}