|
|
|
@ -16,6 +16,7 @@ import ( |
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" |
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" |
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" |
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log" |
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azmoncredentials" |
|
|
|
@ -26,19 +27,23 @@ import ( |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func ProvideService(httpClientProvider *httpclient.Provider) *Service { |
|
|
|
|
proxy := &httpServiceProxy{} |
|
|
|
|
logger := backend.NewLoggerWith("logger", "tsdb.azuremonitor") |
|
|
|
|
proxy := &httpServiceProxy{ |
|
|
|
|
logger: logger, |
|
|
|
|
} |
|
|
|
|
executors := map[string]azDatasourceExecutor{ |
|
|
|
|
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy}, |
|
|
|
|
azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy}, |
|
|
|
|
azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy}, |
|
|
|
|
azureTraces: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy}, |
|
|
|
|
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy, Logger: logger}, |
|
|
|
|
azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy, Logger: logger}, |
|
|
|
|
azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy, Logger: logger}, |
|
|
|
|
azureTraces: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy, Logger: logger}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
im := datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider, executors)) |
|
|
|
|
im := datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider, executors, logger)) |
|
|
|
|
|
|
|
|
|
s := &Service{ |
|
|
|
|
im: im, |
|
|
|
|
executors: executors, |
|
|
|
|
logger: logger, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s.queryMux = s.newQueryMux() |
|
|
|
@ -61,9 +66,10 @@ type Service struct { |
|
|
|
|
|
|
|
|
|
queryMux *datasource.QueryTypeMux |
|
|
|
|
resourceHandler backend.CallResourceHandler |
|
|
|
|
logger log.Logger |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getDatasourceService(ctx context.Context, settings *backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientProvider *httpclient.Provider, dsInfo types.DatasourceInfo, routeName string) (types.DatasourceService, error) { |
|
|
|
|
func getDatasourceService(ctx context.Context, settings *backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientProvider *httpclient.Provider, dsInfo types.DatasourceInfo, routeName string, logger log.Logger) (types.DatasourceService, error) { |
|
|
|
|
route := dsInfo.Routes[routeName] |
|
|
|
|
client, err := newHTTPClient(ctx, route, dsInfo, settings, azureSettings, clientProvider) |
|
|
|
|
if err != nil { |
|
|
|
@ -72,10 +78,11 @@ func getDatasourceService(ctx context.Context, settings *backend.DataSourceInsta |
|
|
|
|
return types.DatasourceService{ |
|
|
|
|
URL: dsInfo.Routes[routeName].URL, |
|
|
|
|
HTTPClient: client, |
|
|
|
|
Logger: logger, |
|
|
|
|
}, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func NewInstanceSettings(clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc { |
|
|
|
|
func NewInstanceSettings(clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor, logger log.Logger) datasource.InstanceFactoryFunc { |
|
|
|
|
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { |
|
|
|
|
jsonData := map[string]any{} |
|
|
|
|
err := json.Unmarshal(settings.JSONData, &jsonData) |
|
|
|
@ -91,7 +98,7 @@ func NewInstanceSettings(clientProvider *httpclient.Provider, executors map[stri |
|
|
|
|
|
|
|
|
|
azureSettings, err := azsettings.ReadSettings(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
backend.Logger.Error("failed to read Azure settings from Grafana", "error", err.Error()) |
|
|
|
|
logger.Error("failed to read Azure settings from Grafana", "error", err.Error()) |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -124,7 +131,7 @@ func NewInstanceSettings(clientProvider *httpclient.Provider, executors map[stri |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for routeName := range executors { |
|
|
|
|
service, err := getDatasourceService(ctx, &settings, azureSettings, clientProvider, model, routeName) |
|
|
|
|
service, err := getDatasourceService(ctx, &settings, azureSettings, clientProvider, model, routeName, logger) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
@ -300,7 +307,7 @@ func checkAzureMonitorResourceGraphHealth(dsInfo types.DatasourceInfo, subscript |
|
|
|
|
return res, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func metricCheckHealth(dsInfo types.DatasourceInfo) (message string, defaultSubscription string, status backend.HealthStatus) { |
|
|
|
|
func metricCheckHealth(dsInfo types.DatasourceInfo, logger log.Logger) (message string, defaultSubscription string, status backend.HealthStatus) { |
|
|
|
|
defaultSubscription = dsInfo.Settings.SubscriptionId |
|
|
|
|
metricsRes, err := queryMetricHealth(dsInfo) |
|
|
|
|
if err != nil { |
|
|
|
@ -323,7 +330,7 @@ func metricCheckHealth(dsInfo types.DatasourceInfo) (message string, defaultSubs |
|
|
|
|
} |
|
|
|
|
return fmt.Sprintf("Error connecting to Azure Monitor endpoint: %s", string(body)), defaultSubscription, backend.HealthStatusError |
|
|
|
|
} |
|
|
|
|
subscriptions, err := parseSubscriptions(metricsRes) |
|
|
|
|
subscriptions, err := parseSubscriptions(metricsRes, logger) |
|
|
|
|
if err != nil { |
|
|
|
|
return err.Error(), defaultSubscription, backend.HealthStatusError |
|
|
|
|
} |
|
|
|
@ -387,7 +394,7 @@ func graphLogHealthCheck(dsInfo types.DatasourceInfo, defaultSubscription string |
|
|
|
|
return "Successfully connected to Azure Resource Graph endpoint.", backend.HealthStatusOk |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func parseSubscriptions(res *http.Response) ([]string, error) { |
|
|
|
|
func parseSubscriptions(res *http.Response, logger log.Logger) ([]string, error) { |
|
|
|
|
var target struct { |
|
|
|
|
Value []struct { |
|
|
|
|
SubscriptionId string `json:"subscriptionId"` |
|
|
|
@ -399,7 +406,7 @@ func parseSubscriptions(res *http.Response) ([]string, error) { |
|
|
|
|
} |
|
|
|
|
defer func() { |
|
|
|
|
if err := res.Body.Close(); err != nil { |
|
|
|
|
backend.Logger.Warn("Failed to close response body", "err", err) |
|
|
|
|
logger.Warn("Failed to close response body", "err", err) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
@ -422,7 +429,7 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque |
|
|
|
|
|
|
|
|
|
status := backend.HealthStatusOk |
|
|
|
|
|
|
|
|
|
metricsLog, defaultSubscription, metricsStatus := metricCheckHealth(dsInfo) |
|
|
|
|
metricsLog, defaultSubscription, metricsStatus := metricCheckHealth(dsInfo, s.logger) |
|
|
|
|
if metricsStatus != backend.HealthStatusOk { |
|
|
|
|
status = metricsStatus |
|
|
|
|
} |
|
|
|
|