diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad006d8..aa76a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,8 @@ name: ci on: push: + branches: + - main pull_request: jobs: @@ -14,6 +16,7 @@ jobs: with: go-version: '1.20' check-latest: true + cache: true - name: Tests run: make test @@ -30,6 +33,7 @@ jobs: with: go-version: '1.20' check-latest: true + cache: true - name: golangci-lint uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0 timeout-minutes: 5 diff --git a/internal/server/server.go b/internal/server/server.go index 2f94f38..d5d543a 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -16,9 +16,10 @@ import ( ) type Opts struct { - MetricsPath string - ListenAddress string - WebhookPath string + MetricsPath string + ListenAddressMetrics string + ListenAddressIngress string + WebhookPath string // GitHub webhook token. GitHubToken string // GitHub API token. @@ -30,17 +31,17 @@ type Opts struct { type Server struct { logger log.Logger - server *http.Server + serverMetrics *http.Server + serverIngress *http.Server workflowMetricsExporter *WorkflowMetricsExporter billingExporter *BillingMetricsExporter opts Opts } func NewServer(logger log.Logger, opts Opts) *Server { - mux := http.NewServeMux() - - httpServer := &http.Server{ - Handler: mux, + muxMetrics := http.NewServeMux() + httpServerMetrics := &http.Server{ + Handler: muxMetrics, ReadHeaderTimeout: 10 * time.Second, } @@ -54,39 +55,67 @@ func NewServer(logger log.Logger, opts Opts) *Server { _ = level.Info(logger).Log("msg", fmt.Sprintf("not exporting user billing: %v", err)) } + muxIngress := http.NewServeMux() + httpServerIngress := &http.Server{ + Handler: muxIngress, + ReadHeaderTimeout: 10 * time.Second, + } + workflowExporter := NewWorkflowMetricsExporter(logger, opts) server := &Server{ logger: logger, - server: httpServer, + serverMetrics: httpServerMetrics, + serverIngress: httpServerIngress, workflowMetricsExporter: workflowExporter, billingExporter: billingExporter, opts: opts, } - mux.Handle(opts.MetricsPath, promhttp.Handler()) - mux.HandleFunc(opts.WebhookPath, workflowExporter.HandleGHWebHook) - mux.HandleFunc("/", server.handleRoot) + muxMetrics.Handle(opts.MetricsPath, promhttp.Handler()) + muxMetrics.HandleFunc(opts.WebhookPath, workflowExporter.HandleGHWebHook) + + muxIngress.HandleFunc("/", server.handleRoot) return server } func (s *Server) Serve(ctx context.Context) error { - listener, err := getListener(s.opts.ListenAddress, s.logger) + listenerMetrics, err := getListener(s.opts.ListenAddressMetrics, s.logger) + if err != nil { + return fmt.Errorf("get listener: %w", err) + } + + listenerIgress, err := getListener(s.opts.ListenAddressIngress, s.logger) if err != nil { return fmt.Errorf("get listener: %w", err) } - _ = level.Info(s.logger).Log("msg", "GitHub Actions Prometheus Exporter has successfully started") - err = s.server.Serve(listener) + _ = level.Info(s.logger).Log("msg", "GitHub Actions Prometheus Exporter Metrics has successfully started") + go func() { + _ = s.serverMetrics.Serve(listenerMetrics) + }() + _ = level.Info(s.logger).Log("msg", "GitHub Actions Prometheus Exporter Ingress has successfully started") + err = s.serverIngress.Serve(listenerIgress) if err != nil && !errors.Is(err, http.ErrServerClosed) { - return fmt.Errorf("server closed: %w", err) + return fmt.Errorf("server ingress closed: %w", err) } + return nil } func (s *Server) Shutdown(ctx context.Context) error { - return s.server.Shutdown(ctx) + err := s.serverMetrics.Shutdown(ctx) + if err != nil { + return err + } + + err = s.serverIngress.Shutdown(ctx) + if err != nil { + return err + } + + return nil } func (s *Server) handleRoot(w http.ResponseWriter, _ *http.Request) { @@ -95,7 +124,6 @@ func (s *Server) handleRoot(w http.ResponseWriter, _ *http.Request) {

GitHub Actions Exporter

` + version.Print("ghactions_exporter") + `

-

Metrics

`)) diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 51450d1..1ff81fc 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -18,10 +18,11 @@ import ( func Test_Server_MetricsRouteWithNoMetrics(t *testing.T) { logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) srv := server.NewServer(logger, server.Opts{ - MetricsPath: "/metrics", - ListenAddress: ":8000", - WebhookPath: "/webhook", - GitHubToken: "webhook_token", + MetricsPath: "/metrics", + ListenAddressMetrics: ":8000", + ListenAddressIngress: ":8001", + WebhookPath: "/webhook", + GitHubToken: "webhook_token", }) t.Cleanup(func() { @@ -45,15 +46,32 @@ func Test_Server_MetricsRouteWithNoMetrics(t *testing.T) { payload, err := io.ReadAll(res.Body) require.NoError(t, err) assert.NotNil(t, payload) + + res, err = http.Get("http://localhost:8000") + require.NoError(t, err) + defer res.Body.Close() + + assert.Equal(t, 404, res.StatusCode) + + res, err = http.Get("http://localhost:8001") + require.NoError(t, err) + defer res.Body.Close() + + assert.Equal(t, 200, res.StatusCode) + + payload, err = io.ReadAll(res.Body) + require.NoError(t, err) + assert.NotNil(t, payload) } func Test_Server_MetricsRouteAfterWorkflowJob(t *testing.T) { logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) srv := server.NewServer(logger, server.Opts{ - MetricsPath: "/metrics", - ListenAddress: ":8000", - WebhookPath: "/webhook", - GitHubToken: webhookSecret, + MetricsPath: "/metrics", + ListenAddressMetrics: ":8000", + ListenAddressIngress: ":8001", + WebhookPath: "/webhook", + GitHubToken: webhookSecret, }) t.Cleanup(func() { diff --git a/main.go b/main.go index de1d718..6723537 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,8 @@ import ( ) var ( - listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9101").String() + listenAddressMetrics = kingpin.Flag("web.listen-address", "Address to listen on for metrics.").Default(":9101").String() + listenAddressIngress = kingpin.Flag("web.listen-address-ingress", "Address to listen on for web interface and receive webhook.").Default(":8065").String() metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() ghWebHookPath = kingpin.Flag("web.gh-webhook-path", "Path that will be called by the GitHub webhook.").Default("/gh_event").String() githubWebhookToken = kingpin.Flag("gh.github-webhook-token", "GitHub Webhook Token.").Envar("GITHUB_WEBHOOK_TOKEN").Default("").String() @@ -53,7 +54,8 @@ func main() { srv := server.NewServer(logger, server.Opts{ WebhookPath: *ghWebHookPath, - ListenAddress: *listenAddress, + ListenAddressMetrics: *listenAddressMetrics, + ListenAddressIngress: *listenAddressIngress, MetricsPath: *metricsPath, GitHubToken: *githubWebhookToken, GitHubAPIToken: *gitHubAPIToken,