38 Commits

Author SHA1 Message Date
9934dc8e36 Update Go, slog-otel, prometheus client 2024-04-06 09:42:41 -07:00
a458dcb226 tracing: add EndpointURL option 2024-03-16 10:40:43 -07:00
4ed44c72a4 Update dependencies 2024-03-09 21:57:46 -08:00
8a8ff93996 scripts: goreleaser 1.24.0 2024-02-10 19:10:01 -08:00
1e8785bd32 version: fix metric name for services with dash in the name 2024-02-03 00:21:31 -08:00
5aeaa97c6f Add BSD license
(for pkg.go.dev)
2024-01-20 11:48:32 -07:00
df2285d355 tracing: update semconv, better error checking 2024-01-19 22:59:29 -08:00
232a6f98df tracing: add minimal test 2024-01-19 22:48:14 -08:00
4f6b09200f Update dependencies 2024-01-12 23:12:15 -08:00
7085202154 Update goreleaser 2024-01-12 22:17:07 -08:00
5c7ae6ab8a Basic config package to parse NTP Pool system config 2023-12-10 20:43:38 -08:00
608f05d395 types: shared data types 2023-12-10 19:16:13 -08:00
b5420f9dbd build: private repository support for drone / goreleaser 2023-12-10 19:15:49 -08:00
537ee53384 Minor dependency updates 2023-11-26 01:15:04 -08:00
0a92ad768e tracing: option to set endpoint without environment variables 2023-11-15 22:29:20 +08:00
61d73f7be3 Update dependencies 2023-11-15 22:28:41 +08:00
2bff6d8ef3 X-Forwarded-For handler for labstack echo and Fastly 2023-11-12 15:51:21 -08:00
62e28b71f1 tracing: option to use a GetClientCertificates function 2023-10-29 18:18:41 -07:00
5b033a1f0b logging: use remychantenay/slog-otel 2023-10-21 22:09:48 -07:00
a4447c97f6 tracing: support for shutting down the trace provider 2023-10-21 21:59:10 -07:00
9d136b2502 logger: Add experimental support for adding trace_id from context 2023-10-21 21:51:29 -07:00
7420ad12f4 Update dependencies 2023-10-21 21:49:51 -07:00
cf33a99566 tracing: tweak API 2023-10-14 04:20:29 -07:00
c2b303bec9 goreleaser: --skip-publish is now --skip=publish 2023-10-14 04:10:33 -07:00
6fd0728668 Update kafka-go 2023-10-14 03:31:30 -07:00
09f963b267 tracing: wip / test 2023-10-14 03:30:19 -07:00
ad63071f60 Update dependencies and goreleaser; require Go 1.21.3 for h2 fix 2023-10-11 22:03:38 -07:00
020966a4b3 Go 1.21; use log/slog instead of version from x/exp 2023-09-17 23:03:55 -07:00
053de4fd16 scripts: manage goreleaser version in script 2023-09-17 23:02:48 -07:00
3f1f4436df metrics: have Registry() return a Registry instead of Registerer
(so it can also be used as a Gatherer)
2023-08-06 12:34:56 -07:00
be9b63f382 health: support custom health check functions 2023-07-22 23:48:04 -07:00
e9d0f7419a kafka: CheckPartitions() method for health checks 2023-07-22 23:47:37 -07:00
2a021b453d timeutil: time.Duration json helper 2023-07-22 00:10:55 -07:00
03bde25c6d health: make health listener semantics match metrics one 2023-07-08 21:18:38 -07:00
6b6b22092e metrics: allow server to return errors 2023-07-08 21:13:31 -07:00
facd2f4f57 Common release scripts 2023-07-08 17:39:36 -07:00
5c067e3752 version: Prefix build_info metric name 2023-07-08 15:56:57 -07:00
7550d1597c version: add more data to prometheus metric 2023-07-08 15:04:43 -07:00
24 changed files with 923 additions and 109 deletions

10
LICENSE Normal file
View File

@@ -0,0 +1,10 @@
Copyright (c) 2012-2024 Develooper LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Develooper LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

90
config/config.go Normal file
View File

@@ -0,0 +1,90 @@
// Package config provides NTP Pool specific
// configuration tools.
package config
import (
"net/url"
"os"
"strconv"
"strings"
"go.ntppool.org/common/logger"
)
//go:generate accessory -type Config
type Config struct {
deploymentMode string `accessor:"getter"`
manageHostname string `accessor:"getter"`
manageTLS bool
webHostname string `accessor:"getter"`
webHostnames []string
webTLS bool
valid bool `accessor:"getter"`
}
func New() *Config {
c := Config{}
c.deploymentMode = os.Getenv("deployment_mode")
c.manageHostname = os.Getenv("manage_hostname")
c.webHostnames = strings.Split(os.Getenv("web_hostname"), ",")
for i, h := range c.webHostnames {
c.webHostnames[i] = strings.TrimSpace(h)
}
if len(c.webHostnames) > 0 {
c.webHostname = c.webHostnames[0]
c.valid = true
}
c.manageTLS = parseBool(os.Getenv("manage_tls"))
c.webTLS = parseBool(os.Getenv("web_tls"))
return &c
}
func (c *Config) WebURL(path string, query *url.Values) string {
return baseURL(c.webHostname, c.webTLS, path, query)
}
func baseURL(host string, tls bool, path string, query *url.Values) string {
uri := url.URL{}
uri.Host = host
if tls {
uri.Scheme = "https"
} else {
uri.Scheme = "http"
}
uri.Path = path
if query != nil {
uri.RawQuery = query.Encode()
}
return uri.String()
}
func parseBool(s string) bool {
switch strings.ToLower(s) {
case "yes":
return true
case "y":
return true
case "no":
return false
case "n":
return false
case "":
return false
}
t, err := strconv.ParseBool(s)
if err != nil {
logger.Setup().Error("could not parse bool", "string", s, "err", err)
return false
}
return t
}

31
config/config_accessor.go Normal file
View File

@@ -0,0 +1,31 @@
// Code generated by accessory; DO NOT EDIT.
package config
func (c *Config) DeploymentMode() string {
if c == nil {
return ""
}
return c.deploymentMode
}
func (c *Config) ManageHostname() string {
if c == nil {
return ""
}
return c.manageHostname
}
func (c *Config) WebHostname() string {
if c == nil {
return ""
}
return c.webHostname
}
func (c *Config) Valid() bool {
if c == nil {
return false
}
return c.valid
}

26
config/config_test.go Normal file
View File

@@ -0,0 +1,26 @@
package config
import (
"net/url"
"os"
"testing"
)
func TestBaseURL(t *testing.T) {
os.Setenv("web_hostname", "www.ntp.dev, web.ntppool.dev")
os.Setenv("web_tls", "yes")
c := New()
if !c.Valid() {
t.Fatalf("config not valid")
}
q := url.Values{}
q.Set("foo", "bar")
u := c.WebURL("/foo", &q)
if u != "https://www.ntp.dev/foo?foo=bar" {
t.Fatalf("unexpected WebURL: %s", u)
}
}

60
go.mod
View File

@@ -1,28 +1,54 @@
module go.ntppool.org/common
go 1.20
go 1.22.2
require (
github.com/abh/certman v0.4.0
github.com/prometheus/client_golang v1.16.0
github.com/segmentio/kafka-go v0.4.42
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
github.com/labstack/echo/v4 v4.11.4
github.com/oklog/ulid/v2 v2.1.0
github.com/prometheus/client_golang v1.19.0
github.com/remychantenay/slog-otel v1.3.0
github.com/segmentio/kafka-go v0.4.47
github.com/spf13/cobra v1.8.0
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
golang.org/x/mod v0.17.0
golang.org/x/sync v0.7.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/sys v0.10.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.52.2 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)

188
go.sum
View File

@@ -2,63 +2,88 @@ github.com/abh/certman v0.4.0 h1:XHoDtb0YyRQPclaHMrBDlKTVZpNjTK6vhB0S3Bd/Sbs=
github.com/abh/certman v0.4.0/go.mod h1:x8QhpKVZifmV1Hdiwdg9gLo2GMPAxezz1s3zrVnPs+I=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk=
github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/segmentio/kafka-go v0.4.41 h1:IXPP1q1VbDcrsQ0WhKVjB6bZFZmzARvMTRgeFI5M3hE=
github.com/segmentio/kafka-go v0.4.41/go.mod h1:d0g15xPMqoUookug0OU75DhGZxXwCFxSLeJ4uphwJzg=
github.com/segmentio/kafka-go v0.4.42 h1:qffhBZCz4WcWyNuHEclHjIMLs2slp6mZO8px+5W5tfU=
github.com/segmentio/kafka-go v0.4.42/go.mod h1:d0g15xPMqoUookug0OU75DhGZxXwCFxSLeJ4uphwJzg=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck=
github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/remychantenay/slog-otel v1.2.4 h1:Z/IwIgFPzzGqLTI460KbTuJZPm5U830dgu0gPiEpufA=
github.com/remychantenay/slog-otel v1.2.4/go.mod h1:Ar2ZBcRfIPyoKV/3Xq4oHmNgKc69juGB0QMUzo1vJOc=
github.com/remychantenay/slog-otel v1.3.0 h1:mppL97agkmwR416lKzltRQ9QRhrPdxwVidt0AnI3Ts4=
github.com/remychantenay/slog-otel v1.3.0/go.mod h1:L2VAe6WOMAk/kRzzuv2B/rWe/IDXAhUNae0919b4kHU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
@@ -66,51 +91,98 @@ github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3k
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc=
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s=
google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda h1:b6F6WIV4xHHD0FA4oIyzU6mHWg2WI2X1RBehwa5QN38=
google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda/go.mod h1:AHcE/gZH76Bk/ROZhQphlRoWo5xKDEtz3eVEO1LfA8c=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -2,23 +2,43 @@ package health
import (
"context"
"log/slog"
"net/http"
"strconv"
"time"
"golang.org/x/exp/slog"
"go.ntppool.org/common/logger"
"golang.org/x/sync/errgroup"
)
// HealthCheckListener runs simple http server on the specified port for
// health check probes
func HealthCheckListener(ctx context.Context, port int, log *slog.Logger) {
log.Info("Starting health listener", "port", port)
type Server struct {
log *slog.Logger
healthFn http.HandlerFunc
}
func NewServer(healthFn http.HandlerFunc) *Server {
if healthFn == nil {
healthFn = basicHealth
}
srv := &Server{
log: logger.Setup(),
healthFn: healthFn,
}
return srv
}
func (srv *Server) SetLogger(log *slog.Logger) {
srv.log = log
}
func (srv *Server) Listen(ctx context.Context, port int) error {
srv.log.Info("Starting health listener", "port", port)
serveMux := http.NewServeMux()
serveMux.HandleFunc("/__health", basicHealth)
serveMux.HandleFunc("/__health", srv.healthFn)
srv := &http.Server{
hsrv := &http.Server{
Addr: ":" + strconv.Itoa(port),
ReadTimeout: 10 * time.Second,
WriteTimeout: 20 * time.Second,
@@ -26,19 +46,39 @@ func HealthCheckListener(ctx context.Context, port int, log *slog.Logger) {
Handler: serveMux,
}
go func() {
err := srv.ListenAndServe()
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
err := hsrv.ListenAndServe()
if err != http.ErrServerClosed {
log.Warn("health check server done listening", "err", err)
srv.log.Warn("health check server done listening", "err", err)
return err
}
}()
return nil
})
<-ctx.Done()
if err := srv.Shutdown(ctx); err != nil {
log.Error("health check server shutdown failed", "err", err)
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
g.Go(func() error {
if err := hsrv.Shutdown(ctx); err != nil {
srv.log.Error("health check server shutdown failed", "err", err)
return err
}
return nil
})
return g.Wait()
}
// HealthCheckListener runs simple http server on the specified port for
// health check probes
func HealthCheckListener(ctx context.Context, port int, log *slog.Logger) error {
srv := NewServer(nil)
srv.SetLogger(log)
return srv.Listen(ctx, port)
}
func basicHealth(w http.ResponseWriter, r *http.Request) {

View File

@@ -12,6 +12,7 @@ import (
"github.com/abh/certman"
"github.com/segmentio/kafka-go"
"go.ntppool.org/common/logger"
)
const (
@@ -203,3 +204,17 @@ func (k *Kafka) NewWriter(topic string) (*kafka.Writer, error) {
return w, nil
}
func (k *Kafka) CheckPartitions() error {
partitions, err := k.conn.ReadPartitions()
if err != nil {
return err
}
// should this result in an error?
if len(partitions) == 0 {
log := logger.Setup()
log.Info("kafka connection has no partitions")
}
return nil
}

View File

@@ -3,11 +3,12 @@ package logger
import (
"context"
"log"
"log/slog"
"os"
"strconv"
"sync"
"golang.org/x/exp/slog"
slogotel "github.com/remychantenay/slog-otel"
)
var ConfigPrefix = ""
@@ -41,8 +42,7 @@ func Setup() *slog.Logger {
logReplace := func(groups []string, a slog.Attr) slog.Attr {
// Remove time
if a.Key == slog.TimeKey && len(groups) == 0 {
a.Key = ""
a.Value = slog.AnyValue(nil)
return slog.Attr{}
}
return a
}
@@ -50,7 +50,9 @@ func Setup() *slog.Logger {
logOptions.ReplaceAttr = logReplace
}
logHandler := slog.NewTextHandler(os.Stderr, logOptions)
logHandler := slogotel.OtelHandler{
Next: slog.NewTextHandler(os.Stderr, logOptions),
}
// https://github.com/cyrusaf/ctxlog/pull/1
// log := slog.New(ctxlog.NewHandler(logHandler))

View File

@@ -2,8 +2,7 @@ package logger
import (
"fmt"
"golang.org/x/exp/slog"
"log/slog"
)
type stdLoggerish struct {

View File

@@ -8,6 +8,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/sync/errgroup"
"go.ntppool.org/common/logger"
)
@@ -26,7 +27,7 @@ func New() *Metrics {
return m
}
func (m *Metrics) Registry() prometheus.Registerer {
func (m *Metrics) Registry() *prometheus.Registry {
return m.r
}
@@ -41,7 +42,10 @@ func (m *Metrics) Handler() http.Handler {
})
}
func (m *Metrics) ListenAndServe(ctx context.Context, port int) {
// ListenAndServe starts a goroutine with a server running on
// the specified port. The server will shutdown and return when
// the provided context is done
func (m *Metrics) ListenAndServe(ctx context.Context, port int) error {
log := logger.Setup()
@@ -53,16 +57,23 @@ func (m *Metrics) ListenAndServe(ctx context.Context, port int) {
Handler: m.Handler(),
}
go func() {
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
err := srv.ListenAndServe()
if err != http.ErrServerClosed {
if err != nil && err != http.ErrServerClosed {
log.Warn("metrics server done listening", "err", err)
return err
}
}()
return nil
})
<-ctx.Done()
if err := srv.Shutdown(ctx); err != nil {
log.Error("metrics server shutdown failed", "err", err)
return err
}
return g.Wait()
}

12
scripts/Makefile Normal file
View File

@@ -0,0 +1,12 @@
all: Makefile scripts
Makefile: .PHONY
cp ~/src/go/ntp/common/scripts/Makefile .
scripts: .PHONY
cp ~/src/go/ntp/common/scripts/{fury-publish,run-goreleaser,download-release} .
.PHONY:

32
scripts/download-release Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
BASE=$1
BUILD=$2
DIR=$3
set -euo pipefail
if [ -z "$DIR" ]; then
echo run with $0 NAME BUILD_NUMBER DIR
exit 2
fi
mkdir -p $DIR
BASE=https://geodns.bitnames.com/${BASE}/builds/${BUILD}
files=`curl -sSf ${BASE}/checksums.txt | awk '{print $2}'`
metafiles="checksums.txt metadata.json CHANGELOG.md artifacts.json"
for f in $metafiles; do
url=$BASE/$f
echo downloading $url
curl --remove-on-error -sSfRo $DIR/$f $url || true
done
for f in $files; do
url=$BASE/$f
echo downloading $url
curl --remove-on-error -sSfRo $DIR/$f $url
done

15
scripts/fury-publish Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
account=$1
set -euo pipefail
if [ -z "$account" ]; then
echo specify account as the first parameter
exit 2
fi
for f in dist/*.rpm dist/*.deb; do
echo Uploading $f
curl -sf -F package=@$f https://${FURY_TOKEN}@push.fury.io/${account}/
done

24
scripts/run-goreleaser Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
set -euo pipefail
go install github.com/goreleaser/goreleaser@v1.24.0
if [ ! -z "${harbor_username:-}" ]; then
DOCKER_FILE=~/.docker/config.json
if [ ! -e $DOCKER_FILE ]; then
mkdir -p ~/.docker/
export harbor_auth=`cat /dev/null | jq -s -r '[ env.harbor_username, env.harbor_password ] | join(":") | @base64'`
echo '{"auths":{"harbor.ntppool.org":{"auth":""}}}' | jq '.auths["harbor.ntppool.org"].auth=env.harbor_auth' > $DOCKER_FILE
fi
fi
DRONE_TAG=${DRONE_TAG-""}
is_snapshot=""
if [ -z "$DRONE_TAG" ]; then
is_snapshot="--snapshot"
fi
goreleaser release $is_snapshot -p 6 --skip=publish

36
timeutil/duration.go Normal file
View File

@@ -0,0 +1,36 @@
package timeutil
import (
"encoding/json"
"errors"
"time"
)
type Duration struct {
time.Duration
}
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d.Duration).String())
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch value := v.(type) {
case float64:
*d = Duration{time.Duration(value)}
return nil
case string:
tmp, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = Duration{tmp}
return nil
default:
return errors.New("invalid duration")
}
}

22
timeutil/duration_test.go Normal file
View File

@@ -0,0 +1,22 @@
package timeutil
import (
"encoding/json"
"testing"
)
func TestDuration(t *testing.T) {
js := []byte(`{"foo": "30s"}`)
foo := struct{ Foo Duration }{}
err := json.Unmarshal(js, &foo)
if err != nil {
t.Fatalf("could not unmarshal %q: %s", js, err)
}
if foo.Foo.Seconds() != 30 {
t.Fatalf("parsed time.Duration wasn't 30 seconds: %s", foo.Foo)
}
}

172
tracing/tracing.go Normal file
View File

@@ -0,0 +1,172 @@
package tracing
// todo, review:
// https://github.com/ttys3/tracing-go/blob/main/tracing.go#L136
import (
"context"
"crypto/tls"
"crypto/x509"
"os"
"go.ntppool.org/common/logger"
"go.ntppool.org/common/version"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
otelsdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
"go.opentelemetry.io/otel/trace"
)
// https://github.com/open-telemetry/opentelemetry-go/blob/main/exporters/otlp/otlptrace/otlptracehttp/example_test.go
type TpShutdownFunc func(ctx context.Context) error
func Tracer() trace.Tracer {
traceProvider := otel.GetTracerProvider()
return traceProvider.Tracer("ntppool-tracer")
}
func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
return Tracer().Start(ctx, spanName, opts...)
}
type GetClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
type TracerConfig struct {
ServiceName string
Environment string
Endpoint string
EndpointURL string
CertificateProvider GetClientCertificate
RootCAs *x509.CertPool
}
var emptyTpShutdownFunc = func(_ context.Context) error {
return nil
}
func InitTracer(ctx context.Context, cfg *TracerConfig) (TpShutdownFunc, error) {
log := logger.Setup()
// exporter, err := srv.newStdoutExporter(os.Stdout)
var err error
var exporter otelsdktrace.SpanExporter
if otlpEndPoint := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"); len(otlpEndPoint) > 0 || len(cfg.Endpoint) > 0 {
exporter, err = newOLTPExporter(ctx, cfg)
}
if err != nil {
return emptyTpShutdownFunc, err
}
if exporter == nil {
log.Warn("tracing not configured")
return emptyTpShutdownFunc, nil
}
resource, err := newResource(cfg)
if err != nil {
return nil, err
}
tp := otelsdktrace.NewTracerProvider(
otelsdktrace.WithSampler(otelsdktrace.AlwaysSample()),
otelsdktrace.WithBatcher(exporter),
otelsdktrace.WithResource(resource),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, // W3C Trace Context format; https://www.w3.org/TR/trace-context/
propagation.Baggage{},
),
)
return tp.Shutdown, nil
}
func newOLTPExporter(ctx context.Context, cfg *TracerConfig) (otelsdktrace.SpanExporter, error) {
log := logger.Setup()
opts := []otlptracehttp.Option{
otlptracehttp.WithCompression(otlptracehttp.GzipCompression),
}
if cfg.CertificateProvider != nil {
log.InfoContext(ctx, "setting up cert provider")
opts = append(opts, otlptracehttp.WithTLSClientConfig(&tls.Config{
GetClientCertificate: cfg.CertificateProvider,
RootCAs: cfg.RootCAs,
}))
}
if len(cfg.Endpoint) > 0 {
opts = append(opts, otlptracehttp.WithEndpoint(cfg.Endpoint))
}
if len(cfg.EndpointURL) > 0 {
opts = append(opts, otlptracehttp.WithEndpointURL(cfg.EndpointURL))
}
client := otlptracehttp.NewClient(opts...)
exporter, err := otlptrace.New(ctx, client)
if err != nil {
log.ErrorContext(ctx, "creating OTLP trace exporter", "err", err)
}
return exporter, err
}
// func (srv *Server) newStdoutExporter(w io.Writer) (sdktrace.SpanExporter, error) {
// return stdouttrace.New(
// stdouttrace.WithWriter(w),
// // Use human-readable output.
// stdouttrace.WithPrettyPrint(),
// // Do not print timestamps for the demo.
// stdouttrace.WithoutTimestamps(),
// )
// }
// newResource returns a resource describing this application.
func newResource(cfg *TracerConfig) (*resource.Resource, error) {
log := logger.Setup()
defaultResource := resource.Default()
log.Debug("default semconv", "url", defaultResource.SchemaURL())
newResource := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(cfg.ServiceName),
semconv.ServiceVersionKey.String(version.Version()),
attribute.String("environment", cfg.Environment),
)
log.Debug("new resource semconv", "url", newResource.SchemaURL())
r, err := resource.Merge(
defaultResource,
newResource,
)
if err != nil {
log.Error("could not setup otel resource",
"err", err,
"default", defaultResource.SchemaURL(),
"local", newResource.SchemaURL(),
)
}
return r, nil
}

22
tracing/tracing_test.go Normal file
View File

@@ -0,0 +1,22 @@
package tracing
import (
"context"
"os"
"testing"
)
func TestInit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "localhost")
shutdownFn, err := InitTracer(ctx, &TracerConfig{})
if err != nil {
t.FailNow()
}
defer shutdownFn(ctx)
}

52
types/log_scores.go Normal file
View File

@@ -0,0 +1,52 @@
package types
import (
"database/sql/driver"
"encoding/json"
"errors"
)
type LogScoreAttributes struct {
Leap int8 `json:"leap,omitempty"`
Stratum int8 `json:"stratum,omitempty"`
NoResponse bool `json:"no_response,omitempty"`
Error string `json:"error,omitempty"`
Warning string `json:"warning,omitempty"`
FromLSID int `json:"from_ls_id,omitempty"`
FromSSID int `json:"from_ss_id,omitempty"`
}
func (lsa *LogScoreAttributes) String() string {
b, err := json.Marshal(lsa)
if err != nil {
return ""
}
return string(b)
}
func (lsa *LogScoreAttributes) Value() (driver.Value, error) {
return json.Marshal(lsa)
}
func (lsa *LogScoreAttributes) Scan(value interface{}) error {
var source []byte
_t := LogScoreAttributes{}
switch v := value.(type) {
case []uint8:
source = v
case string:
source = []byte(v)
case nil:
return nil
default:
return errors.New("incompatible type for StringInterfaceMap")
}
err := json.Unmarshal(source, &_t)
if err != nil {
return err
}
*lsa = _t
return nil
}

View File

@@ -23,6 +23,7 @@ var info Info
type Info struct {
Version string `json:",omitempty"`
GitRev string `json:",omitempty"`
GitRevShort string `json:",omitempty"`
BuildTime string `json:",omitempty"`
}
@@ -46,13 +47,18 @@ func init() {
// logger.Setup().Info("build info", "k", h.Key, "v", h.Value)
switch h.Key {
case "vcs.time":
if len(buildTime) == 0 {
buildTime = h.Value
}
info.BuildTime = h.Value
case "vcs.revision":
// https://blog.carlmjohnson.net/post/2023/golang-git-hash-how-to/
// todo: use BuildInfo.Main.Version if revision is empty
gitVersion = h.Value
info.GitRev = h.Value
// if gitVersion != h.Value {
// logger.Setup().Warn("gitVersion and info.GitRev differs", "gitVersion", gitVersion, "gitRev", info.GitRev)
// }
gitVersion = h.Value
case "vcs.modified":
if h.Value == "true" {
gitModified = true
@@ -61,6 +67,12 @@ func init() {
}
}
info.GitRevShort = info.GitRev
if len(info.GitRevShort) > 7 {
info.GitRevShort = info.GitRevShort[:7]
}
info.Version = VERSION
Version()
@@ -78,17 +90,35 @@ func VersionCmd(name string) *cobra.Command {
return versionCmd
}
func RegisterMetric(registry prometheus.Registerer) {
func RegisterMetric(name string, registry prometheus.Registerer) {
if len(name) > 0 {
name = strings.ReplaceAll(name, "-", "_")
name = name + "_build_info"
} else {
name = "build_info"
}
buildInfo := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "build_info",
Name: name,
Help: "Build information",
},
[]string{"version", "build"},
[]string{
"version",
"buildtime",
"gittime",
"git",
},
)
registry.MustRegister(buildInfo)
info := VersionInfo()
buildInfo.WithLabelValues(fmt.Sprintf("%s/%s", info.Version, info.GitRev), info.BuildTime).Set(1)
buildInfo.WithLabelValues(
fmt.Sprintf("%s/%s",
info.Version, info.GitRevShort,
),
buildTime,
info.BuildTime,
info.GitRev,
).Set(1)
}
var v string

View File

@@ -0,0 +1 @@
{"addresses":["23.235.32.0/20","43.249.72.0/22","103.244.50.0/24","103.245.222.0/23","103.245.224.0/24","104.156.80.0/20","140.248.64.0/18","140.248.128.0/17","146.75.0.0/17","151.101.0.0/16","157.52.64.0/18","167.82.0.0/17","167.82.128.0/20","167.82.160.0/20","167.82.224.0/20","172.111.64.0/18","185.31.16.0/22","199.27.72.0/21","199.232.0.0/16"],"ipv6_addresses":["2a04:4e40::/32","2a04:4e42::/32"]}

51
xff/fastlyxff/xff.go Normal file
View File

@@ -0,0 +1,51 @@
package fastlyxff
import (
"encoding/json"
"net"
"net/netip"
"os"
"github.com/labstack/echo/v4"
)
type FastlyXFF struct {
IPv4 []string `json:"addresses"`
IPv6 []string `json:"ipv6_addresses"`
}
type TrustedNets struct {
prefixes []netip.Prefix
}
func New(fileName string) (*FastlyXFF, error) {
b, err := os.ReadFile(fileName)
if err != nil {
return nil, err
}
d := FastlyXFF{}
err = json.Unmarshal(b, &d)
if err != nil {
return nil, err
}
return &d, nil
}
func (xff *FastlyXFF) EchoTrustOption() ([]echo.TrustOption, error) {
ranges := []echo.TrustOption{}
for _, s := range append(xff.IPv4, xff.IPv6...) {
_, cidr, err := net.ParseCIDR(s)
if err != nil {
return nil, err
}
trust := echo.TrustIPRange(cidr)
ranges = append(ranges, trust)
}
return ranges, nil
}

23
xff/fastlyxff/xff_test.go Normal file
View File

@@ -0,0 +1,23 @@
package fastlyxff
import "testing"
func TestFastlyIPRanges(t *testing.T) {
fastlyxff, err := New("fastly.json")
if err != nil {
t.Fatalf("could not load test data: %s", err)
}
data, err := fastlyxff.EchoTrustOption()
if err != nil {
t.Fatalf("could not parse test data: %s", err)
}
if len(data) < 10 {
t.Logf("only got %d prefixes, expected more", len(data))
t.Fail()
}
}