From 6ec699509d736576cc6aea54a362772b9e5c9b84 Mon Sep 17 00:00:00 2001 From: Devin Carr Date: Tue, 1 Jul 2025 13:26:34 -0700 Subject: [PATCH] TUN-9511: Add metrics for virtual DNS origin Closes TUN-9511 --- cmd/cloudflared/tunnel/configuration.go | 6 ++-- ingress/origins/dns.go | 10 +++++-- ingress/origins/dns_test.go | 16 +++++----- ingress/origins/metrics.go | 40 +++++++++++++++++++++++++ ingress/origins/metrics_test.go | 6 ++++ 5 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 ingress/origins/metrics.go create mode 100644 ingress/origins/metrics_test.go diff --git a/cmd/cloudflared/tunnel/configuration.go b/cmd/cloudflared/tunnel/configuration.go index de41184f..63f78426 100644 --- a/cmd/cloudflared/tunnel/configuration.go +++ b/cmd/cloudflared/tunnel/configuration.go @@ -11,6 +11,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "github.com/rs/zerolog" "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" @@ -229,14 +230,15 @@ func prepareTunnelConfig( }, log) // Setup DNS Resolver Service + originMetrics := origins.NewMetrics(prometheus.DefaultRegisterer) dnsResolverAddrs := c.StringSlice(flags.VirtualDNSServiceResolverAddresses) - dnsService := origins.NewDNSResolverService(origins.NewDNSDialer(), log) + dnsService := origins.NewDNSResolverService(origins.NewDNSDialer(), log, originMetrics) if len(dnsResolverAddrs) > 0 { addrs, err := parseResolverAddrPorts(dnsResolverAddrs) if err != nil { return nil, nil, fmt.Errorf("invalid %s provided: %w", flags.VirtualDNSServiceResolverAddresses, err) } - dnsService = origins.NewStaticDNSResolverService(addrs, origins.NewDNSDialer(), log) + dnsService = origins.NewStaticDNSResolverService(addrs, origins.NewDNSDialer(), log, originMetrics) } originDialerService.AddReservedService(dnsService, []netip.AddrPort{origins.VirtualDNSServiceAddr}) diff --git a/ingress/origins/dns.go b/ingress/origins/dns.go index b5599f89..c09c581d 100644 --- a/ingress/origins/dns.go +++ b/ingress/origins/dns.go @@ -51,31 +51,35 @@ type DNSResolverService struct { dialer ingress.OriginDialer resolver peekResolver logger *zerolog.Logger + metrics Metrics } -func NewDNSResolverService(dialer ingress.OriginDialer, logger *zerolog.Logger) *DNSResolverService { +func NewDNSResolverService(dialer ingress.OriginDialer, logger *zerolog.Logger, metrics Metrics) *DNSResolverService { return &DNSResolverService{ addresses: []netip.AddrPort{defaultResolverAddr}, dialer: dialer, resolver: &resolver{dialFunc: net.Dial}, logger: logger, + metrics: metrics, } } -func NewStaticDNSResolverService(resolverAddrs []netip.AddrPort, dialer ingress.OriginDialer, logger *zerolog.Logger) *DNSResolverService { - s := NewDNSResolverService(dialer, logger) +func NewStaticDNSResolverService(resolverAddrs []netip.AddrPort, dialer ingress.OriginDialer, logger *zerolog.Logger, metrics Metrics) *DNSResolverService { + s := NewDNSResolverService(dialer, logger, metrics) s.addresses = resolverAddrs s.static = true return s } func (s *DNSResolverService) DialTCP(ctx context.Context, _ netip.AddrPort) (net.Conn, error) { + s.metrics.IncrementDNSTCPRequests() dest := s.getAddress() // The dialer ignores the provided address because the request will instead go to the local DNS resolver. return s.dialer.DialTCP(ctx, dest) } func (s *DNSResolverService) DialUDP(_ netip.AddrPort) (net.Conn, error) { + s.metrics.IncrementDNSUDPRequests() dest := s.getAddress() // The dialer ignores the provided address because the request will instead go to the local DNS resolver. return s.dialer.DialUDP(dest) diff --git a/ingress/origins/dns_test.go b/ingress/origins/dns_test.go index 3ea24510..c44db1ea 100644 --- a/ingress/origins/dns_test.go +++ b/ingress/origins/dns_test.go @@ -14,7 +14,7 @@ import ( func TestDNSResolver_DefaultResolver(t *testing.T) { log := zerolog.Nop() - service := NewDNSResolverService(NewDNSDialer(), &log) + service := NewDNSResolverService(NewDNSDialer(), &log, &noopMetrics{}) mockResolver := &mockPeekResolver{ address: "127.0.0.2:53", } @@ -25,7 +25,7 @@ func TestDNSResolver_DefaultResolver(t *testing.T) { func TestStaticDNSResolver_DefaultResolver(t *testing.T) { log := zerolog.Nop() addresses := []netip.AddrPort{netip.MustParseAddrPort("1.1.1.1:53"), netip.MustParseAddrPort("1.0.0.1:53")} - service := NewStaticDNSResolverService(addresses, NewDNSDialer(), &log) + service := NewStaticDNSResolverService(addresses, NewDNSDialer(), &log, &noopMetrics{}) mockResolver := &mockPeekResolver{ address: "127.0.0.2:53", } @@ -35,7 +35,7 @@ func TestStaticDNSResolver_DefaultResolver(t *testing.T) { func TestDNSResolver_UpdateResolverAddress(t *testing.T) { log := zerolog.Nop() - service := NewDNSResolverService(NewDNSDialer(), &log) + service := NewDNSResolverService(NewDNSDialer(), &log, &noopMetrics{}) mockResolver := &mockPeekResolver{} service.resolver = mockResolver @@ -64,7 +64,7 @@ func TestDNSResolver_UpdateResolverAddress(t *testing.T) { func TestStaticDNSResolver_RefreshLoopExits(t *testing.T) { log := zerolog.Nop() addresses := []netip.AddrPort{netip.MustParseAddrPort("1.1.1.1:53"), netip.MustParseAddrPort("1.0.0.1:53")} - service := NewStaticDNSResolverService(addresses, NewDNSDialer(), &log) + service := NewStaticDNSResolverService(addresses, NewDNSDialer(), &log, &noopMetrics{}) mockResolver := &mockPeekResolver{ address: "127.0.0.2:53", @@ -85,7 +85,7 @@ func TestStaticDNSResolver_RefreshLoopExits(t *testing.T) { func TestDNSResolver_UpdateResolverAddressInvalid(t *testing.T) { log := zerolog.Nop() - service := NewDNSResolverService(NewDNSDialer(), &log) + service := NewDNSResolverService(NewDNSDialer(), &log, &noopMetrics{}) mockResolver := &mockPeekResolver{} service.resolver = mockResolver @@ -109,7 +109,7 @@ func TestDNSResolver_UpdateResolverAddressInvalid(t *testing.T) { func TestDNSResolver_UpdateResolverErrorIgnored(t *testing.T) { log := zerolog.Nop() - service := NewDNSResolverService(NewDNSDialer(), &log) + service := NewDNSResolverService(NewDNSDialer(), &log, &noopMetrics{}) resolverErr := errors.New("test resolver error") mockResolver := &mockPeekResolver{err: resolverErr} service.resolver = mockResolver @@ -126,7 +126,7 @@ func TestDNSResolver_UpdateResolverErrorIgnored(t *testing.T) { func TestDNSResolver_DialUDPUsesResolvedAddress(t *testing.T) { log := zerolog.Nop() mockDialer := &mockDialer{expected: defaultResolverAddr} - service := NewDNSResolverService(mockDialer, &log) + service := NewDNSResolverService(mockDialer, &log, &noopMetrics{}) mockResolver := &mockPeekResolver{} service.resolver = mockResolver @@ -140,7 +140,7 @@ func TestDNSResolver_DialUDPUsesResolvedAddress(t *testing.T) { func TestDNSResolver_DialTCPUsesResolvedAddress(t *testing.T) { log := zerolog.Nop() mockDialer := &mockDialer{expected: defaultResolverAddr} - service := NewDNSResolverService(mockDialer, &log) + service := NewDNSResolverService(mockDialer, &log, &noopMetrics{}) mockResolver := &mockPeekResolver{} service.resolver = mockResolver diff --git a/ingress/origins/metrics.go b/ingress/origins/metrics.go new file mode 100644 index 00000000..8586ec29 --- /dev/null +++ b/ingress/origins/metrics.go @@ -0,0 +1,40 @@ +package origins + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +const ( + namespace = "cloudflared" + subsystem = "virtual_origins" +) + +type Metrics interface { + IncrementDNSUDPRequests() + IncrementDNSTCPRequests() +} + +type metrics struct { + dnsResolverRequests *prometheus.CounterVec +} + +func (m *metrics) IncrementDNSUDPRequests() { + m.dnsResolverRequests.WithLabelValues("udp").Inc() +} + +func (m *metrics) IncrementDNSTCPRequests() { + m.dnsResolverRequests.WithLabelValues("tcp").Inc() +} + +func NewMetrics(registerer prometheus.Registerer) Metrics { + m := &metrics{ + dnsResolverRequests: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "dns_requests_total", + Help: "Total count of DNS requests that have been proxied to the virtual DNS resolver origin", + }, []string{"protocol"}), + } + registerer.MustRegister(m.dnsResolverRequests) + return m +} diff --git a/ingress/origins/metrics_test.go b/ingress/origins/metrics_test.go new file mode 100644 index 00000000..311b1fa0 --- /dev/null +++ b/ingress/origins/metrics_test.go @@ -0,0 +1,6 @@ +package origins + +type noopMetrics struct{} + +func (noopMetrics) IncrementDNSUDPRequests() {} +func (noopMetrics) IncrementDNSTCPRequests() {}