use zerolog
Kim committed
Oct 21, 2025 at 11:44 UTC
615ce777b41078b67932801a3483006183689e00
7 files changed
+112
-93
cmd/example_client/main.go
+7
-7
@@ -3,7 +3,6 @@ package main
3
import (
4
"context"
5
"fmt"
6
- "log"
6
"net/http"
7
"os"
8
"os/signal"
@@ -12,6 +11,7 @@ import (
11
"time"
12
13
"github.com/gosuda/relaydns/relaydns"
14
+ "github.com/rs/zerolog/log"
15
"github.com/spf13/cobra"
16
)
17
@@ -48,7 +48,7 @@ func init() {
48
49
func main() {
50
if err := rootCmd.Execute(); err != nil {
51
- log.Fatal(err)
51
+ log.Fatal().Err(err).Msg("execute root command")
52
}
53
}
54
@@ -76,9 +76,9 @@ func runClient(cmd *cobra.Command, args []string) error {
76
_, _ = w.Write([]byte("ok"))
77
})
78
79
- log.Println("[client] local backend http", flagBackendHTTP)
79
+ log.Info().Msgf("[client] local backend http %s", flagBackendHTTP)
80
if err := http.ListenAndServe(flagBackendHTTP, mux); err != nil {
81
- log.Println("[client] http backend error:", err)
81
+ log.Error().Err(err).Msg("[client] http backend error")
82
cancel()
83
}
84
}()
@@ -111,17 +111,17 @@ func runClient(cmd *cobra.Command, args []string) error {
111
// 자기 주소/피어ID 로그로 찍어서 디버깅 편하게
112
if addrs := h.Addrs(); len(addrs) > 0 {
113
for _, a := range addrs {
114
- log.Printf("[client] host addr: %s/p2p/%s", a.String(), h.ID().String())
114
+ log.Info().Msgf("[client] host addr: %s/p2p/%s", a.String(), h.ID().String())
115
}
116
} else {
117
- log.Printf("[client] host peer: %s (no listen addrs yet)", h.ID().String())
117
+ log.Info().Msgf("[client] host peer: %s (no listen addrs yet)", h.ID().String())
118
}
119
120
// 종료 대기
121
sig := make(chan os.Signal, 1)
122
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
123
<-sig
124
- log.Println("[client] shutting down")
124
+ log.Info().Msg("[client] shutting down")
125
time.Sleep(200 * time.Millisecond)
126
return nil
127
}
cmd/server/main.go
+8
-8
@@ -2,13 +2,13 @@ package main
2
3
import (
4
"context"
5
- "log"
5
"os"
6
"os/signal"
7
"syscall"
8
"time"
9
10
"github.com/gosuda/relaydns/relaydns"
11
+ "github.com/rs/zerolog/log"
12
"github.com/spf13/cobra"
13
)
14
@@ -46,7 +46,7 @@ func init() {
46
47
func main() {
48
if err := rootCmd.Execute(); err != nil {
49
- log.Fatal(err)
49
+ log.Fatal().Err(err).Msg("execute root command")
50
}
51
}
52
@@ -70,9 +70,9 @@ func runServer(cmd *cobra.Command, args []string) error {
70
if adminHTTP == "" {
71
return
72
}
73
- log.Println("[server] admin http:", adminHTTP)
73
+ log.Info().Msgf("[server] admin http: %s", adminHTTP)
74
if err := d.ServeHTTP(adminHTTP); err != nil {
75
- log.Println("[server] admin http error:", err)
75
+ log.Error().Err(err).Msg("[server] admin http error")
76
cancel()
77
}
78
}()
@@ -82,9 +82,9 @@ func runServer(cmd *cobra.Command, args []string) error {
82
if ingressTCP == "" {
83
return
84
}
85
- log.Println("[server] tcp ingress:", ingressTCP)
85
+ log.Info().Msgf("[server] tcp ingress: %s", ingressTCP)
86
if err := d.ServeTCP(ingressTCP); err != nil {
87
- log.Println("[server] tcp ingress error:", err)
87
+ log.Error().Err(err).Msg("[server] tcp ingress error")
88
cancel()
89
}
90
}()
@@ -94,9 +94,9 @@ func runServer(cmd *cobra.Command, args []string) error {
94
if ingressHTTP == "" {
95
return
96
}
97
- log.Println("[server] http ingress (tcp-level):", ingressHTTP)
97
+ log.Info().Msgf("[server] http ingress (tcp-level): %s", ingressHTTP)
98
if err := d.ServeTCP(ingressHTTP); err != nil {
99
- log.Println("[server] http ingress error:", err)
99
+ log.Error().Err(err).Msg("[server] http ingress error")
100
cancel()
101
}
102
}()
go.mod
+3
@@ -6,6 +6,7 @@ require (
6
github.com/libp2p/go-libp2p v0.44.0
7
github.com/libp2p/go-libp2p-pubsub v0.15.0
8
github.com/multiformats/go-multiaddr v0.16.0
9
+ github.com/rs/zerolog v1.34.0
10
github.com/spf13/cobra v1.10.1
11
)
12
@@ -37,6 +38,8 @@ require (
38
github.com/libp2p/go-reuseport v0.4.0 // indirect
39
github.com/libp2p/go-yamux/v5 v5.0.1 // indirect
40
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
41
+ github.com/mattn/go-colorable v0.1.13 // indirect
42
+ github.com/mattn/go-isatty v0.0.20 // indirect
43
github.com/miekg/dns v1.1.66 // indirect
44
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
45
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
go.sum
+15
@@ -20,6 +20,7 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
20
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
21
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
22
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
23
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
24
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
25
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
26
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -40,6 +41,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
41
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
42
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
43
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
44
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
45
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
46
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
47
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -124,6 +126,12 @@ github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxf
126
github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs=
127
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
128
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
129
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
130
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
131
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
132
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
133
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
134
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
135
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
136
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
137
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
@@ -215,6 +223,7 @@ github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7ITo
223
github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54=
224
github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U=
225
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
226
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
227
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
228
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
229
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -237,6 +246,9 @@ github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssk
246
github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
247
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
248
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
249
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
250
+github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
251
+github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
252
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
253
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
254
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@@ -381,10 +393,13 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
393
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
394
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
395
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
396
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
397
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
398
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
399
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
400
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
401
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
402
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
403
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
404
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
405
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
relaydns/client.go
+46
-46
@@ -1,25 +1,25 @@
1
package relaydns
2
3
-import (
4
- "context"
5
- "encoding/json"
6
- "errors"
7
- "fmt"
8
- "io"
9
- "log"
10
- "net"
11
- "net/http"
12
- "net/url"
13
- "sort"
14
- "strings"
15
- "sync"
16
- "time"
17
-
18
- pubsub "github.com/libp2p/go-libp2p-pubsub"
19
- "github.com/libp2p/go-libp2p/core/host"
20
- "github.com/libp2p/go-libp2p/core/network"
21
- "github.com/libp2p/go-libp2p/core/protocol"
22
-)
3
+import (
4
+ "context"
5
+ "encoding/json"
6
+ "errors"
7
+ "fmt"
8
+ "io"
9
+ "net"
10
+ "net/http"
11
+ "net/url"
12
+ "sort"
13
+ "strings"
14
+ "sync"
15
+ "time"
16
+
17
+ pubsub "github.com/libp2p/go-libp2p-pubsub"
18
+ "github.com/libp2p/go-libp2p/core/host"
19
+ "github.com/libp2p/go-libp2p/core/network"
20
+ "github.com/libp2p/go-libp2p/core/protocol"
21
+ "github.com/rs/zerolog/log"
22
+)
23
24
type ClientConfig struct {
25
ServerURL string
@@ -82,38 +82,38 @@ func NewClient(ctx context.Context, h host.Host, cfg ClientConfig) (*RelayClient
82
if len(cfg.Bootstraps) > 0 {
83
boot = append(boot, cfg.Bootstraps...)
84
}
85
- if cfg.ServerURL != "" {
86
- if addrs, err := fetchMultiaddrsFromHealth(cfg.ServerURL, cfg.HTTPTimeout); err != nil {
87
- log.Printf("relaydns: fetch /health from %s failed: %v", cfg.ServerURL, err)
88
- } else {
89
- sortMultiaddrs(addrs, cfg.PreferQUIC, cfg.PreferLocal)
90
- boot = append(boot, addrs...)
91
- }
92
- }
93
- boot = uniq(boot)
94
- if len(boot) > 0 {
95
- ConnectBootstraps(ctx, h, boot)
96
- } else {
97
- log.Printf("relaydns: no bootstrap sources provided (Bootstraps/ServerURL); discovery may fail")
98
- }
85
+ if cfg.ServerURL != "" {
86
+ if addrs, err := fetchMultiaddrsFromHealth(cfg.ServerURL, cfg.HTTPTimeout); err != nil {
87
+ log.Warn().Err(err).Msgf("relaydns: fetch /health from %s failed", cfg.ServerURL)
88
+ } else {
89
+ sortMultiaddrs(addrs, cfg.PreferQUIC, cfg.PreferLocal)
90
+ boot = append(boot, addrs...)
91
+ }
92
+ }
93
+ boot = uniq(boot)
94
+ if len(boot) > 0 {
95
+ ConnectBootstraps(ctx, h, boot)
96
+ } else {
97
+ log.Warn().Msg("relaydns: no bootstrap sources provided (Bootstraps/ServerURL); discovery may fail")
98
+ }
99
100
// 1) stream handler
101
switch {
102
case cfg.Handler != nil:
103
h.SetStreamHandler(b.protoID, cfg.Handler)
104
case cfg.TargetTCP != "":
105
- h.SetStreamHandler(b.protoID, func(s network.Stream) {
106
- defer s.Close()
107
- c, err := net.Dial("tcp", cfg.TargetTCP)
108
- if err != nil {
109
- log.Printf("relaydns: dial %s: %v", cfg.TargetTCP, err)
110
- return
111
- }
112
- defer c.Close()
113
- // raw byte pipe
114
- go io.Copy(c, s)
115
- io.Copy(s, c)
116
- })
105
+ h.SetStreamHandler(b.protoID, func(s network.Stream) {
106
+ defer s.Close()
107
+ c, err := net.Dial("tcp", cfg.TargetTCP)
108
+ if err != nil {
109
+ log.Error().Err(err).Msgf("relaydns: dial %s", cfg.TargetTCP)
110
+ return
111
+ }
112
+ defer c.Close()
113
+ // raw byte pipe
114
+ go io.Copy(c, s)
115
+ io.Copy(s, c)
116
+ })
117
default:
118
return nil, fmt.Errorf("relaydns: either Handler or TargetTCP must be set")
119
}
relaydns/director.go
+7
-6
@@ -5,7 +5,6 @@ import (
5
"encoding/json"
6
"fmt"
7
"io"
8
- "log"
8
"net"
9
"net/http"
10
"sync"
@@ -15,6 +14,7 @@ import (
14
"github.com/libp2p/go-libp2p/core/host"
15
"github.com/libp2p/go-libp2p/core/peer"
16
ma "github.com/multiformats/go-multiaddr"
17
+ "github.com/rs/zerolog/log"
18
)
19
20
type Director struct {
@@ -130,7 +130,8 @@ func (d *Director) ServeTCP(addr string) error {
130
if err != nil {
131
return err
132
}
133
- log.Printf("director TCP listening on %s (protocol %s)", addr, d.protocol)
133
+
134
+ log.Info().Msgf("director TCP listening on %s (protocol %s)", addr, d.protocol)
135
for {
136
c, err := ln.Accept()
137
if err != nil {
@@ -144,17 +145,17 @@ func (d *Director) handleConn(c net.Conn) {
145
defer c.Close()
146
entry, ok := d.pick.choose()
147
if !ok {
147
- log.Println("no backend peers available")
148
+ log.Warn().Msg("no backend peers available")
149
return
150
}
151
// ensure we're connected (AddrInfo contains addrs)
152
if err := d.h.Connect(d.ctx, *entry.AddrInfo); err != nil {
152
- log.Printf("connect %s failed: %v", entry.AddrInfo.ID, err)
153
+ log.Error().Err(err).Msgf("connect %s failed", entry.AddrInfo.ID)
154
return
155
}
156
s, err := d.h.NewStream(d.ctx, entry.AddrInfo.ID, protocolID(d.protocol))
157
if err != nil {
157
- log.Printf("new stream: %v", err)
158
+ log.Error().Err(err).Msg("new stream")
159
return
160
}
161
defer s.Close()
@@ -209,6 +210,6 @@ func (d *Director) ServeHTTP(addr string) error {
210
w.Header().Set("Content-Type", "application/json")
211
_ = json.NewEncoder(w).Encode(resp)
212
})
212
- log.Printf("director HTTP API on %s", addr)
213
+ log.Info().Msgf("director HTTP API on %s", addr)
214
return http.ListenAndServe(addr, mux)
215
}
relaydns/host.go
+26
-26
@@ -1,15 +1,15 @@
1
package relaydns
2
3
-import (
4
- "context"
5
- "fmt"
6
- "log"
7
-
8
- "github.com/libp2p/go-libp2p"
9
- "github.com/libp2p/go-libp2p/core/host"
10
- "github.com/libp2p/go-libp2p/core/peer"
11
- ma "github.com/multiformats/go-multiaddr"
12
-)
3
+import (
4
+ "context"
5
+ "fmt"
6
+
7
+ "github.com/libp2p/go-libp2p"
8
+ "github.com/libp2p/go-libp2p/core/host"
9
+ "github.com/libp2p/go-libp2p/core/peer"
10
+ ma "github.com/multiformats/go-multiaddr"
11
+ "github.com/rs/zerolog/log"
12
+)
13
14
func MakeHost(ctx context.Context, port int, enableRelay bool) (host.Host, error) {
15
addrs := []string{
@@ -41,19 +41,19 @@ func MakeHost(ctx context.Context, port int, enableRelay bool) (host.Host, error
41
func ConnectBootstraps(ctx context.Context, h host.Host, addrs []string) {
42
for _, s := range addrs {
43
m, err := ma.NewMultiaddr(s)
44
- if err != nil {
45
- log.Printf("bootstrap bad multiaddr %q: %v", s, err)
46
- continue
47
- }
48
- ai, err := peer.AddrInfoFromP2pAddr(m)
49
- if err != nil {
50
- log.Printf("bootstrap missing /p2p/ in %q: %v", s, err)
51
- continue
52
- }
53
- if err := h.Connect(ctx, *ai); err != nil {
54
- log.Printf("bootstrap connect %s: %v", ai.ID, err)
55
- } else {
56
- log.Printf("connected bootstrap %s", ai.ID)
57
- }
58
- }
59
-}
44
+ if err != nil {
45
+ log.Warn().Err(err).Msgf("bootstrap bad multiaddr %q", s)
46
+ continue
47
+ }
48
+ ai, err := peer.AddrInfoFromP2pAddr(m)
49
+ if err != nil {
50
+ log.Warn().Err(err).Msgf("bootstrap missing /p2p/ in %q", s)
51
+ continue
52
+ }
53
+ if err := h.Connect(ctx, *ai); err != nil {
54
+ log.Warn().Err(err).Msgf("bootstrap connect %s", ai.ID)
55
+ } else {
56
+ log.Info().Msgf("connected bootstrap %s", ai.ID)
57
+ }
58
+ }
59
+}