Skip to content

Commit 393d01c

Browse files
committed
internal/server: serve prometheus metrics
This commit makes it possible to serve prometheus metrics on a configurable bind address. In a default setup, this is exposed at 0.0.0.0:9100. Signed-off-by: David Bond <davidsbond93@gmail.com>
1 parent 075d2b9 commit 393d01c

File tree

8 files changed

+90
-3
lines changed

8 files changed

+90
-3
lines changed

dev.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ bind = "127.0.0.1:4000"
1010

1111
[transport.tcp]
1212
bind = "127.0.0.1:4000"
13+
14+
[metrics]
15+
bind = "127.0.0.1:9100"

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,16 @@ github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3
6161
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6262
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
6363
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
64+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
65+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
6466
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
6567
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
6668
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
6769
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
6870
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
6971
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
72+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
73+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
7074
github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc=
7175
github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g=
7276
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=

internal/server/config.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ type (
1414
DNS DNSConfig `toml:"dns"`
1515
// Individual transports used by the DNS server.
1616
Transport TransportConfig `toml:"transport"`
17+
// Prometheus metric configuration.
18+
Metrics *MetricsConfig `toml:"metrics"`
1719
}
1820

1921
// The DNSConfig type contains fields for configuring specific DNS behavior.
@@ -85,6 +87,12 @@ type (
8587
// The path to the key file.
8688
Key string `toml:"key"`
8789
}
90+
91+
// The MetricsConfig type contains fields for configuring the Prometheus metrics endpoint.
92+
MetricsConfig struct {
93+
// The bind address of the metrics HTTP listener.
94+
Bind string `toml:"bind"`
95+
}
8896
)
8997

9098
// DefaultConfig returns a Config type containing default working values for the DNS server. By default, it will
@@ -106,6 +114,9 @@ func DefaultConfig() Config {
106114
Bind: "0.0.0.0:53",
107115
},
108116
},
117+
Metrics: &MetricsConfig{
118+
Bind: "0.0.0.0:9100",
119+
},
109120
}
110121
}
111122

@@ -124,10 +135,15 @@ func (c *Config) Validate() error {
124135
return errors.Join(
125136
c.DNS.validate(),
126137
c.Transport.validate(),
138+
c.Metrics.validate(),
127139
)
128140
}
129141

130142
func (c *DNSConfig) validate() error {
143+
if c == nil {
144+
return errors.New("no DNS configuration specified")
145+
}
146+
131147
if len(c.Upstreams) == 0 {
132148
return errors.New("no dns upstreams specified")
133149
}
@@ -144,6 +160,10 @@ func (c *DNSConfig) validate() error {
144160
}
145161

146162
func (t *TransportConfig) validate() error {
163+
if t == nil {
164+
return errors.New("no transport configuration specified")
165+
}
166+
147167
// We never want a server that does nothing at all.
148168
if t.UDP == nil && t.TCP == nil && t.DOT == nil && t.DOH == nil {
149169
return errors.New("at least one transport must be specified")
@@ -183,3 +203,15 @@ func (t *TransportConfig) validate() error {
183203

184204
return nil
185205
}
206+
207+
func (c *MetricsConfig) validate() error {
208+
if c == nil {
209+
return nil
210+
}
211+
212+
if c.Bind == "" {
213+
return errors.New("metrics bind address must be specified")
214+
}
215+
216+
return nil
217+
}

internal/server/config_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ func TestLoadConfig(t *testing.T) {
4949
},
5050
},
5151
},
52+
Metrics: &server.MetricsConfig{
53+
Bind: "127.0.0.1:9100",
54+
},
5255
},
5356
},
5457
{

internal/server/server.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,20 @@ import (
1212

1313
"github.com/miekg/dns"
1414
"github.com/prometheus/client_golang/prometheus"
15+
"github.com/prometheus/client_golang/prometheus/promhttp"
1516
"golang.org/x/sync/errgroup"
1617

1718
"github.com/davidsbond/dns/internal/cache"
1819
"github.com/davidsbond/dns/internal/handler"
1920
"github.com/davidsbond/dns/internal/list"
2021
)
2122

23+
func init() {
24+
handler.RegisterMetrics(prometheus.DefaultRegisterer)
25+
cache.RegisterMetrics(prometheus.DefaultRegisterer)
26+
list.RegisterMetrics(prometheus.DefaultRegisterer)
27+
}
28+
2229
// Run the DNS server.
2330
func Run(ctx context.Context, config Config) error {
2431
if err := config.Validate(); err != nil {
@@ -112,9 +119,14 @@ func Run(ctx context.Context, config Config) error {
112119
})
113120
}
114121

115-
handler.RegisterMetrics(prometheus.DefaultRegisterer)
116-
cache.RegisterMetrics(prometheus.DefaultRegisterer)
117-
list.RegisterMetrics(prometheus.DefaultRegisterer)
122+
if config.Metrics != nil {
123+
group.Go(func() error {
124+
return runHTTPServer(ctx, logger, &http.Server{
125+
Addr: config.Metrics.Bind,
126+
Handler: promhttp.Handler(),
127+
})
128+
})
129+
}
118130

119131
return group.Wait()
120132
}

internal/server/server_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func TestRun(t *testing.T) {
5555
DeferTLS: true,
5656
},
5757
},
58+
Metrics: &server.MetricsConfig{
59+
Bind: "127.0.0.1:9100",
60+
},
5861
}
5962

6063
group, ctx := errgroup.WithContext(ctx)

internal/server/testdata/full.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ bind = "127.0.0.1:443"
2424
[transport.doh.tls]
2525
cert = "path/to/cert.pem"
2626
key = "path/to/key.pem"
27+
28+
[metrics]
29+
bind = "127.0.0.1:9100"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2013 The Go Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google Inc. nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)