Skip to content

Commit

Permalink
Implement http timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
satk0 committed Jan 16, 2024
1 parent 4cd4020 commit 628c6aa
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 17 deletions.
9 changes: 7 additions & 2 deletions cmd/exporter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ func main() {
versionInfo := config.GetVersionInfo()
slog.Info(versionInfo.String())

collectorManager := collectors.NewCollectorManager(exporterConfig.Logstash.Servers)
slog.Debug("http timeout", "timeout", exporterConfig.Logstash.HttpTimeout)

collectorManager := collectors.NewCollectorManager(
exporterConfig.Logstash.Servers,
exporterConfig.Logstash.HttpTimeout,
)
prometheus.MustRegister(collectorManager)

appServer := server.NewAppServer(host, port, exporterConfig)
appServer := server.NewAppServer(host, port, exporterConfig, exporterConfig.Logstash.HttpTimeout)

slog.Info("starting server on", "host", host, "port", port)
if err := appServer.ListenAndServe(); err != nil {
Expand Down
7 changes: 4 additions & 3 deletions collectors/collector_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Collector interface {
type CollectorManager struct {
collectors map[string]Collector
scrapeDurations *prometheus.SummaryVec
httpTimeout time.Duration
}

func getClientsForEndpoints(endpoints []*config.LogstashServer) []logstashclient.Client {
Expand All @@ -34,15 +35,15 @@ func getClientsForEndpoints(endpoints []*config.LogstashServer) []logstashclient
return clients
}

func NewCollectorManager(servers []*config.LogstashServer) *CollectorManager {
func NewCollectorManager(servers []*config.LogstashServer, httpTimeout time.Duration) *CollectorManager {
clients := getClientsForEndpoints(servers)

collectors := getCollectors(clients)

scrapeDurations := getScrapeDurationsCollector()
prometheus.MustRegister(version.NewCollector("logstash_exporter"))

return &CollectorManager{collectors: collectors, scrapeDurations: scrapeDurations}
return &CollectorManager{collectors: collectors, scrapeDurations: scrapeDurations, httpTimeout: httpTimeout}
}

func getCollectors(clients []logstashclient.Client) map[string]Collector {
Expand All @@ -55,7 +56,7 @@ func getCollectors(clients []logstashclient.Client) map[string]Collector {
// Collect executes all collectors and sends the collected metrics to the provided channel.
// It also sends the duration of the collection to the scrapeDurations collector.
func (manager *CollectorManager) Collect(ch chan<- prometheus.Metric) {
ctx, cancel := context.WithTimeout(context.Background(), config.HttpTimeout)
ctx, cancel := context.WithTimeout(context.Background(), manager.httpTimeout)

defer cancel()

Expand Down
5 changes: 4 additions & 1 deletion collectors/collector_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import (
"errors"
"sync"
"testing"
"time"

"github.com/kuskoman/logstash-exporter/config"
"github.com/prometheus/client_golang/prometheus"
)

const httpTimeout = 2 * time.Second

func TestNewCollectorManager(t *testing.T) {
t.Parallel()

Expand All @@ -23,7 +26,7 @@ func TestNewCollectorManager(t *testing.T) {
}

mockEndpoints := []*config.LogstashServer{endpoint1, endpoint2}
cm := NewCollectorManager(mockEndpoints)
cm := NewCollectorManager(mockEndpoints, httpTimeout)

if cm == nil {
t.Error("expected collector manager to be initialized")
Expand Down
5 changes: 3 additions & 2 deletions server/healthcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"sync"
"time"

"github.com/kuskoman/logstash-exporter/config"
)
Expand All @@ -18,7 +19,7 @@ func convertServersToUrls(servers []*config.LogstashServer) []string {
return urls
}

func getHealthCheck(logstashUrls []string) func(http.ResponseWriter, *http.Request) {
func getHealthCheck(logstashUrls []string, httpTimeout time.Duration) func(http.ResponseWriter, *http.Request) {
client := &http.Client{}

return func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -29,7 +30,7 @@ func getHealthCheck(logstashUrls []string) func(http.ResponseWriter, *http.Reque
wg.Add(1)
go func(url string) {
defer wg.Done()
ctx, cancel := context.WithTimeout(r.Context(), config.HttpTimeout)
ctx, cancel := context.WithTimeout(r.Context(), httpTimeout)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
Expand Down
6 changes: 3 additions & 3 deletions server/healthcheck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestHealthCheck(t *testing.T) {
urls = append(urls, server.URL)
}

handler := getHealthCheck(urls)
handler := getHealthCheck(urls, defaultHttpTimeout)
req, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatalf("Error creating request: %v", err)
Expand Down Expand Up @@ -52,7 +52,7 @@ func TestHealthCheck(t *testing.T) {
})

t.Run("no response", func(t *testing.T) {
handler := getHealthCheck([]string{"http://localhost:12345"})
handler := getHealthCheck([]string{"http://localhost:12345"}, defaultHttpTimeout)
req, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatalf("Error creating request: %v", err)
Expand All @@ -67,7 +67,7 @@ func TestHealthCheck(t *testing.T) {
})

t.Run("invalid url", func(t *testing.T) {
handler := getHealthCheck([]string{"http://localhost:96010:invalidurl"})
handler := getHealthCheck([]string{"http://localhost:96010:invalidurl"}, defaultHttpTimeout)
req, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatalf("Error creating request: %v", err)
Expand Down
5 changes: 3 additions & 2 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server
import (
"fmt"
"net/http"
"time"

"github.com/kuskoman/logstash-exporter/config"
"github.com/prometheus/client_golang/prometheus/promhttp"
Expand All @@ -12,15 +13,15 @@ import (
// and registers the prometheus handler and the healthcheck handler
// to the server's mux. The prometheus handler is managed under the
// hood by the prometheus client library.
func NewAppServer(host, port string, cfg *config.Config) *http.Server {
func NewAppServer(host, port string, cfg *config.Config, httpTimeout time.Duration) *http.Server {
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/metrics", http.StatusMovedPermanently)
})

logstashUrls := convertServersToUrls(cfg.Logstash.Servers)
mux.HandleFunc("/healthcheck", getHealthCheck(logstashUrls))
mux.HandleFunc("/healthcheck", getHealthCheck(logstashUrls, httpTimeout))
mux.HandleFunc("/version", getVersionInfoHandler(config.GetVersionInfo()))

listenUrl := fmt.Sprintf("%s:%s", host, port)
Expand Down
11 changes: 7 additions & 4 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/kuskoman/logstash-exporter/config"
)

const defaultHttpTimeout = 2 * time.Second

func TestNewAppServer(t *testing.T) {
t.Run("test handling of /metrics endpoint", func(t *testing.T) {
cfg := &config.Config{}
server := NewAppServer("", "8080", cfg)
server := NewAppServer("", "8080", cfg, defaultHttpTimeout)
req, err := http.NewRequest("GET", "/metrics", nil)
if err != nil {
t.Fatal(fmt.Errorf("error creating request: %v", err))
Expand All @@ -26,7 +29,7 @@ func TestNewAppServer(t *testing.T) {

t.Run("test handling of / endpoint", func(t *testing.T) {
cfg := &config.Config{}
server := NewAppServer("", "8080", cfg)
server := NewAppServer("", "8080", cfg, defaultHttpTimeout)
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(fmt.Errorf("error creating request: %v", err))
Expand All @@ -49,7 +52,7 @@ func TestNewAppServer(t *testing.T) {
},
},
}
server := NewAppServer("", "8080", cfg)
server := NewAppServer("", "8080", cfg, defaultHttpTimeout)
req, err := http.NewRequest("GET", "/healthcheck", nil)
if err != nil {
t.Fatal(fmt.Errorf("error creating request: %v", err))
Expand All @@ -64,7 +67,7 @@ func TestNewAppServer(t *testing.T) {

t.Run("test handling of /version endpoint", func(t *testing.T) {
cfg := &config.Config{}
server := NewAppServer("", "8080", cfg)
server := NewAppServer("", "8080", cfg, defaultHttpTimeout)
req, err := http.NewRequest("GET", "/version", nil)
if err != nil {
t.Fatal(fmt.Errorf("error creating request: %v", err))
Expand Down

0 comments on commit 628c6aa

Please sign in to comment.