mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Add client configuration for remote Loki historian backend and test connection (#61114)
* Create loki client type and ping method * Expose TestConnection on client * Configure and ping Loki URL * Close response body reader if present * Add 30 second timeout * Remove duplicate close
This commit is contained in:
parent
f6e3252c00
commit
1ac89ea040
@ -387,7 +387,15 @@ func configureHistorianBackend(cfg setting.UnifiedAlertingStateHistorySettings,
|
|||||||
return historian.NewAnnotationBackend(ar, ds), nil
|
return historian.NewAnnotationBackend(ar, ds), nil
|
||||||
}
|
}
|
||||||
if cfg.Backend == "loki" {
|
if cfg.Backend == "loki" {
|
||||||
return historian.NewRemoteLokiBackend(), nil
|
baseURL, err := url.Parse(cfg.LokiRemoteURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse remote loki URL: %w", err)
|
||||||
|
}
|
||||||
|
backend := historian.NewRemoteLokiBackend(baseURL)
|
||||||
|
if err := backend.TestConnection(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to ping the remote loki historian: %w", err)
|
||||||
|
}
|
||||||
|
return backend, nil
|
||||||
}
|
}
|
||||||
if cfg.Backend == "sql" {
|
if cfg.Backend == "sql" {
|
||||||
return historian.NewSqlBackend(), nil
|
return historian.NewSqlBackend(), nil
|
||||||
|
@ -2,21 +2,35 @@ package historian
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type remoteLokiClient interface {
|
||||||
|
ping() error
|
||||||
|
}
|
||||||
|
|
||||||
type RemoteLokiBackend struct {
|
type RemoteLokiBackend struct {
|
||||||
|
client remoteLokiClient
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoteLokiBackend() *RemoteLokiBackend {
|
func NewRemoteLokiBackend(url *url.URL) *RemoteLokiBackend {
|
||||||
|
logger := log.New("ngalert.state.historian", "backend", "loki")
|
||||||
return &RemoteLokiBackend{
|
return &RemoteLokiBackend{
|
||||||
log: log.New("ngalert.state.historian"),
|
client: newLokiClient(url, logger),
|
||||||
|
log: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RemoteLokiBackend) RecordStatesAsync(ctx context.Context, _ *models.AlertRule, _ []state.StateTransition) {
|
func (h *RemoteLokiBackend) TestConnection() error {
|
||||||
|
return h.client.ping()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RemoteLokiBackend) RecordStatesAsync(ctx context.Context, _ *models.AlertRule, _ []state.StateTransition) {
|
||||||
|
logger := h.log.FromContext(ctx)
|
||||||
|
logger.Debug("Remote Loki state history backend was called with states")
|
||||||
}
|
}
|
||||||
|
54
pkg/services/ngalert/state/historian/loki_http.go
Normal file
54
pkg/services/ngalert/state/historian/loki_http.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package historian
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultClientTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
type httpLokiClient struct {
|
||||||
|
client http.Client
|
||||||
|
url *url.URL
|
||||||
|
log log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLokiClient(u *url.URL, logger log.Logger) *httpLokiClient {
|
||||||
|
return &httpLokiClient{
|
||||||
|
client: http.Client{
|
||||||
|
Timeout: defaultClientTimeout,
|
||||||
|
},
|
||||||
|
url: u,
|
||||||
|
log: logger.New("protocol", "http"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpLokiClient) ping() error {
|
||||||
|
uri := c.url.JoinPath("/loki/api/v1/status/buildinfo")
|
||||||
|
req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if res != nil {
|
||||||
|
defer func() {
|
||||||
|
if err := res.Body.Close(); err != nil {
|
||||||
|
c.log.Warn("Failed to close response body", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error sending request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode < 200 || res.StatusCode >= 300 {
|
||||||
|
return fmt.Errorf("request to the loki buildinfo endpoint returned a non-200 status code: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
c.log.Debug("Request to Loki buildinfo endpoint succeeded", "status", res.StatusCode)
|
||||||
|
return nil
|
||||||
|
}
|
@ -103,6 +103,7 @@ type UnifiedAlertingReservedLabelSettings struct {
|
|||||||
type UnifiedAlertingStateHistorySettings struct {
|
type UnifiedAlertingStateHistorySettings struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Backend string
|
Backend string
|
||||||
|
LokiRemoteURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEnabled returns true if UnifiedAlertingSettings.Enabled is either nil or true.
|
// IsEnabled returns true if UnifiedAlertingSettings.Enabled is either nil or true.
|
||||||
@ -315,6 +316,7 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
|
|||||||
uaCfgStateHistory := UnifiedAlertingStateHistorySettings{
|
uaCfgStateHistory := UnifiedAlertingStateHistorySettings{
|
||||||
Enabled: stateHistory.Key("enabled").MustBool(stateHistoryDefaultEnabled),
|
Enabled: stateHistory.Key("enabled").MustBool(stateHistoryDefaultEnabled),
|
||||||
Backend: stateHistory.Key("backend").MustString("annotations"),
|
Backend: stateHistory.Key("backend").MustString("annotations"),
|
||||||
|
LokiRemoteURL: stateHistory.Key("loki_remote_url").MustString(""),
|
||||||
}
|
}
|
||||||
uaCfg.StateHistory = uaCfgStateHistory
|
uaCfg.StateHistory = uaCfgStateHistory
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user