Cloudwatch: Remove core imports from infra/log (#81543)

* Cloudwatch: use logging from plugin-sdk-go instead of infra/log
* Add a link to the TODO issue for moving `instrumentContext`
This commit is contained in:
Nathan Vērzemnieks 2024-02-07 13:53:05 +01:00 committed by GitHub
parent c16cb7ed3c
commit b5f26560c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 211 additions and 172 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -29,7 +30,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}} client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}}
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -61,7 +62,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}} client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}}
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@ -21,9 +21,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "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/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "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/proxy" "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
@ -61,12 +61,16 @@ const (
timeSeriesQuery = "timeSeriesQuery" timeSeriesQuery = "timeSeriesQuery"
) )
var logger = log.New("tsdb.cloudwatch")
func ProvideService(httpClientProvider *httpclient.Provider) *CloudWatchService { func ProvideService(httpClientProvider *httpclient.Provider) *CloudWatchService {
logger := backend.NewLoggerWith("logger", "tsdb.cloudwatch")
logger.Debug("Initializing") logger.Debug("Initializing")
executor := newExecutor(datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)), awsds.NewSessionCache()) executor := newExecutor(
datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider)),
awsds.NewSessionCache(),
logger,
)
return &CloudWatchService{ return &CloudWatchService{
Executor: executor, Executor: executor,
} }
@ -80,10 +84,11 @@ type SessionCache interface {
GetSession(c awsds.SessionConfig) (*session.Session, error) GetSession(c awsds.SessionConfig) (*session.Session, error)
} }
func newExecutor(im instancemgmt.InstanceManager, sessions SessionCache) *cloudWatchExecutor { func newExecutor(im instancemgmt.InstanceManager, sessions SessionCache, logger log.Logger) *cloudWatchExecutor {
e := &cloudWatchExecutor{ e := &cloudWatchExecutor{
im: im, im: im,
sessions: sessions, sessions: sessions,
logger: logger,
} }
e.resourceHandler = httpadapter.New(e.newResourceMux()) e.resourceHandler = httpadapter.New(e.newResourceMux())
@ -122,10 +127,26 @@ type cloudWatchExecutor struct {
im instancemgmt.InstanceManager im instancemgmt.InstanceManager
sessions SessionCache sessions SessionCache
regionCache sync.Map regionCache sync.Map
logger log.Logger
resourceHandler backend.CallResourceHandler resourceHandler backend.CallResourceHandler
} }
// instrumentContext adds plugin key-values to the context; later, logger.FromContext(ctx) will provide a logger
// that adds these values to its output.
// TODO: move this into the sdk (see https://github.com/grafana/grafana/issues/82033)
func instrumentContext(ctx context.Context, endpoint string, pCtx backend.PluginContext) context.Context {
p := []any{"endpoint", endpoint, "pluginId", pCtx.PluginID}
if pCtx.DataSourceInstanceSettings != nil {
p = append(p, "dsName", pCtx.DataSourceInstanceSettings.Name)
p = append(p, "dsUID", pCtx.DataSourceInstanceSettings.UID)
}
if pCtx.User != nil {
p = append(p, "uname", pCtx.User.Login)
}
return log.WithContextualAttributes(ctx, p)
}
func (e *cloudWatchExecutor) getRequestContext(ctx context.Context, pluginCtx backend.PluginContext, region string) (models.RequestContext, error) { func (e *cloudWatchExecutor) getRequestContext(ctx context.Context, pluginCtx backend.PluginContext, region string) (models.RequestContext, error) {
r := region r := region
instance, err := e.getInstance(ctx, pluginCtx) instance, err := e.getInstance(ctx, pluginCtx)
@ -152,16 +173,17 @@ func (e *cloudWatchExecutor) getRequestContext(ctx context.Context, pluginCtx ba
LogsAPIProvider: NewLogsAPI(sess), LogsAPIProvider: NewLogsAPI(sess),
EC2APIProvider: ec2Client, EC2APIProvider: ec2Client,
Settings: instance.Settings, Settings: instance.Settings,
Logger: logger, Logger: e.logger.FromContext(ctx),
}, nil }, nil
} }
func (e *cloudWatchExecutor) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { func (e *cloudWatchExecutor) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
ctx = instrumentContext(ctx, "callResource", req.PluginContext)
return e.resourceHandler.CallResource(ctx, req, sender) return e.resourceHandler.CallResource(ctx, req, sender)
} }
func (e *cloudWatchExecutor) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { func (e *cloudWatchExecutor) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
logger := logger.FromContext(ctx) ctx = instrumentContext(ctx, "queryData", req.PluginContext)
q := req.Queries[0] q := req.Queries[0]
var model DataQueryJson var model DataQueryJson
err := json.Unmarshal(q.JSON, &model) err := json.Unmarshal(q.JSON, &model)
@ -185,17 +207,18 @@ func (e *cloudWatchExecutor) QueryData(ctx context.Context, req *backend.QueryDa
case annotationQuery: case annotationQuery:
result, err = e.executeAnnotationQuery(ctx, req.PluginContext, model, q) result, err = e.executeAnnotationQuery(ctx, req.PluginContext, model, q)
case logAction: case logAction:
result, err = e.executeLogActions(ctx, logger, req) result, err = e.executeLogActions(ctx, req)
case timeSeriesQuery: case timeSeriesQuery:
fallthrough fallthrough
default: default:
result, err = e.executeTimeSeriesQuery(ctx, logger, req) result, err = e.executeTimeSeriesQuery(ctx, req)
} }
return result, err return result, err
} }
func (e *cloudWatchExecutor) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { func (e *cloudWatchExecutor) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
ctx = instrumentContext(ctx, "checkHealth", req.PluginContext)
status := backend.HealthStatusOk status := backend.HealthStatusOk
metricsTest := "Successfully queried the CloudWatch metrics API." metricsTest := "Successfully queried the CloudWatch metrics API."
logsTest := "Successfully queried the CloudWatch logs API." logsTest := "Successfully queried the CloudWatch logs API."

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
@ -67,7 +68,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4"), Value: aws.String("Value1")}}}, {MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4"), Value: aws.String("Value1")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value2")}}}, {MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1"), Value: aws.String("Value2")}}},
}, MetricsPerPage: 100} }, MetricsPerPage: 100}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@ -103,7 +104,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}}, {MetricName: aws.String("Test_MetricName8"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName9"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2} }, MetricsPerPage: 2}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/EC2&metricName=CPUUtilization&dimensionFilters={"NodeID":["Shared"],"stage":["QueryCommit"]}`, Path: `/dimension-keys?region=us-east-2&namespace=AWS/EC2&metricName=CPUUtilization&dimensionFilters={"NodeID":["Shared"],"stage":["QueryCommit"]}`,
@ -127,7 +129,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
t.Run("Should handle standard dimension key query and return hard coded keys", func(t *testing.T) { t.Run("Should handle standard dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{} api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@ -152,7 +154,8 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
t.Run("Should handle custom namespace dimension key query and return hard coded keys", func(t *testing.T) { t.Run("Should handle custom namespace dimension key query and return hard coded keys", func(t *testing.T) {
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
api = mocks.FakeMetricsAPI{} api = mocks.FakeMetricsAPI{}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/dimension-keys?region=us-east-2&namespace=AWS/CloudSearch&metricName=CPUUtilization`, Path: `/dimension-keys?region=us-east-2&namespace=AWS/CloudSearch&metricName=CPUUtilization`,
@ -187,7 +190,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
{MetricName: aws.String("Test_MetricName8"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}}, {MetricName: aws.String("Test_MetricName8"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName4")}}},
{MetricName: aws.String("Test_MetricName9"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}}, {MetricName: aws.String("Test_MetricName9"), Namespace: aws.String("AWS/EC2"), Dimensions: []*cloudwatch.Dimension{{Name: aws.String("Test_DimensionName1")}}},
}, MetricsPerPage: 2} }, MetricsPerPage: 2}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@ -224,7 +227,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}, },
}, },
}, nil) }, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
@ -246,7 +249,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
t.Run("Should handle region requests and return regions from the api", func(t *testing.T) { t.Run("Should handle region requests and return regions from the api", func(t *testing.T) {
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/regions`, Path: `/regions`,
@ -272,7 +275,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(imWithoutDefaultRegion, &fakeSessionCache{}) executor := newExecutor(imWithoutDefaultRegion, &fakeSessionCache{}, log.NewNullLogger())
req := &backend.CallResourceRequest{ req := &backend.CallResourceRequest{
Method: "GET", Method: "GET",
Path: `/regions`, Path: `/regions`,

View File

@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "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/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "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/proxy" "github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
@ -134,7 +135,7 @@ func Test_CheckHealth(t *testing.T) {
t.Run("successfully query metrics and logs", func(t *testing.T) { t.Run("successfully query metrics and logs", func(t *testing.T) {
client = fakeCheckHealthClient{} client = fakeCheckHealthClient{}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -153,7 +154,7 @@ func Test_CheckHealth(t *testing.T) {
return nil, fmt.Errorf("some logs query error") return nil, fmt.Errorf("some logs query error")
}} }}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -172,7 +173,7 @@ func Test_CheckHealth(t *testing.T) {
return fmt.Errorf("some list metrics error") return fmt.Errorf("some list metrics error")
}} }}
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -190,7 +191,7 @@ func Test_CheckHealth(t *testing.T) {
executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) { executor := newExecutor(im, &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
return nil, fmt.Errorf("some sessions error") return nil, fmt.Errorf("some sessions error")
}}) }}, log.NewNullLogger())
resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{ resp, err := executor.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -228,7 +229,7 @@ func TestNewSession_passes_authSettings(t *testing.T) {
return &session.Session{ return &session.Session{
Config: &aws.Config{}, Config: &aws.Config{},
}, nil }, nil
}}) }}, log.NewNullLogger())
_, err := executor.newSession(context.Background(), _, err := executor.newSession(context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, "us-east-1") backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, "us-east-1")
@ -274,7 +275,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
}, },
} }
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
err := executor.CallResource(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), req, sender) err := executor.CallResource(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), req, sender)
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/clients"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
@ -15,7 +14,7 @@ import (
// getDimensionValues gets the actual dimension values for dimensions with a wildcard // getDimensionValues gets the actual dimension values for dimensions with a wildcard
func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context, pluginCtx backend.PluginContext, region string, func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context, pluginCtx backend.PluginContext, region string,
client models.CloudWatchMetricsAPIProvider, origQueries []*models.CloudWatchQuery, tagValueCache *cache.Cache, logger log.Logger) ([]*models.CloudWatchQuery, error) { client models.CloudWatchMetricsAPIProvider, origQueries []*models.CloudWatchQuery, tagValueCache *cache.Cache) ([]*models.CloudWatchQuery, error) {
instance, err := e.getInstance(ctx, pluginCtx) instance, err := e.getInstance(ctx, pluginCtx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -40,12 +39,12 @@ func (e *cloudWatchExecutor) getDimensionValuesForWildcards(ctx context.Context,
cacheKey := fmt.Sprintf("%s-%s-%s-%s-%s", region, accountID, query.Namespace, query.MetricName, dimensionKey) cacheKey := fmt.Sprintf("%s-%s-%s-%s-%s", region, accountID, query.Namespace, query.MetricName, dimensionKey)
cachedDimensions, found := tagValueCache.Get(cacheKey) cachedDimensions, found := tagValueCache.Get(cacheKey)
if found { if found {
logger.Debug("Fetching dimension values from cache") e.logger.FromContext(ctx).Debug("Fetching dimension values from cache")
query.Dimensions[dimensionKey] = cachedDimensions.([]string) query.Dimensions[dimensionKey] = cachedDimensions.([]string)
continue continue
} }
logger.Debug("Cache miss, fetching dimension values from AWS") e.logger.FromContext(ctx).Debug("Cache miss, fetching dimension values from AWS")
request := resources.DimensionValuesRequest{ request := resources.DimensionValuesRequest{
ResourceRequest: &resources.ResourceRequest{ ResourceRequest: &resources.ResourceRequest{
Region: region, Region: region,

View File

@ -7,7 +7,7 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
@ -16,8 +16,7 @@ import (
) )
func TestGetDimensionValuesForWildcards(t *testing.T) { func TestGetDimensionValuesForWildcards(t *testing.T) {
logger := &logtest.Fake{} executor := &cloudWatchExecutor{im: defaultTestInstanceManager(), logger: log.NewNullLogger()}
executor := &cloudWatchExecutor{im: defaultTestInstanceManager()}
ctx := context.Background() ctx := context.Background()
pluginCtx := backend.PluginContext{ pluginCtx := backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ID: 1, Updated: time.Now()}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ID: 1, Updated: time.Now()},
@ -28,7 +27,7 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
query := getBaseQuery() query := getBaseQuery()
query.MetricName = "Test_MetricName1" query.MetricName = "Test_MetricName1"
query.Dimensions = map[string][]string{"Test_DimensionName1": {"Value1"}} query.Dimensions = map[string][]string{"Test_DimensionName1": {"Value1"}}
queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
assert.NotNil(t, queries[0].Dimensions["Test_DimensionName1"], 1) assert.NotNil(t, queries[0].Dimensions["Test_DimensionName1"], 1)
@ -39,7 +38,7 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
query := getBaseQuery() query := getBaseQuery()
query.MetricName = "Test_MetricName1" query.MetricName = "Test_MetricName1"
query.Dimensions = map[string][]string{"Test_DimensionName1": {"*"}} query.Dimensions = map[string][]string{"Test_DimensionName1": {"*"}}
queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
assert.NotNil(t, queries[0].Dimensions["Test_DimensionName1"]) assert.NotNil(t, queries[0].Dimensions["Test_DimensionName1"])
@ -58,7 +57,7 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
{MetricName: utils.Pointer("Test_MetricName4"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName1"), Value: utils.Pointer("Value2")}}}, {MetricName: utils.Pointer("Test_MetricName4"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName1"), Value: utils.Pointer("Value2")}}},
}} }}
api.On("ListMetricsPagesWithContext").Return(nil) api.On("ListMetricsPagesWithContext").Return(nil)
queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
assert.Equal(t, map[string][]string{"Test_DimensionName1": {"Value1", "Value2", "Value3", "Value4"}}, queries[0].Dimensions) assert.Equal(t, map[string][]string{"Test_DimensionName1": {"Value1", "Value2", "Value3", "Value4"}}, queries[0].Dimensions)
@ -74,13 +73,13 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
{MetricName: utils.Pointer("Test_MetricName"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName"), Value: utils.Pointer("Value")}}}, {MetricName: utils.Pointer("Test_MetricName"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName"), Value: utils.Pointer("Value")}}},
}} }}
api.On("ListMetricsPagesWithContext").Return(nil) api.On("ListMetricsPagesWithContext").Return(nil)
_, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache, logger) _, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
// make sure the original query wasn't altered // make sure the original query wasn't altered
assert.Equal(t, map[string][]string{"Test_DimensionName": {"*"}}, query.Dimensions) assert.Equal(t, map[string][]string{"Test_DimensionName": {"*"}}, query.Dimensions)
//setting the api to nil confirms that it's using the cached value //setting the api to nil confirms that it's using the cached value
queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", nil, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
assert.Equal(t, map[string][]string{"Test_DimensionName": {"Value"}}, queries[0].Dimensions) assert.Equal(t, map[string][]string{"Test_DimensionName": {"Value"}}, queries[0].Dimensions)
@ -94,7 +93,7 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
query.MatchExact = false query.MatchExact = false
api := &mocks.MetricsAPI{Metrics: []*cloudwatch.Metric{}} api := &mocks.MetricsAPI{Metrics: []*cloudwatch.Metric{}}
api.On("ListMetricsPagesWithContext").Return(nil) api.On("ListMetricsPagesWithContext").Return(nil)
queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err := executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
// assert that the values was set to an empty array // assert that the values was set to an empty array
@ -105,7 +104,7 @@ func TestGetDimensionValuesForWildcards(t *testing.T) {
{MetricName: utils.Pointer("Test_MetricName"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName2"), Value: utils.Pointer("Value")}}}, {MetricName: utils.Pointer("Test_MetricName"), Dimensions: []*cloudwatch.Dimension{{Name: utils.Pointer("Test_DimensionName2"), Value: utils.Pointer("Value")}}},
} }
api.On("ListMetricsPagesWithContext").Return(nil) api.On("ListMetricsPagesWithContext").Return(nil)
queries, err = executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache, logger) queries, err = executor.getDimensionValuesForWildcards(ctx, pluginCtx, "us-east-1", api, []*models.CloudWatchQuery{query}, tagValueCache)
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, queries, 1) assert.Len(t, queries, 1)
assert.Equal(t, map[string][]string{"Test_DimensionName2": {"Value"}}, queries[0].Dimensions) assert.Equal(t, map[string][]string{"Test_DimensionName2": {"Value"}}, queries[0].Dimensions)

View File

@ -3,7 +3,7 @@ package cloudwatch
import ( import (
"regexp" "regexp"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )

View File

@ -3,13 +3,13 @@ package cloudwatch
import ( import (
"testing" "testing"
"github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestGetMetricQueryBatches(t *testing.T) { func TestGetMetricQueryBatches(t *testing.T) {
logger := &logtest.Fake{} nullLogger := log.NewNullLogger()
insight1 := models.CloudWatchQuery{ insight1 := models.CloudWatchQuery{
MetricQueryType: models.MetricQueryTypeQuery, MetricQueryType: models.MetricQueryTypeQuery,
Id: "i1", Id: "i1",
@ -86,7 +86,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&m88_ref_m98, &m88_ref_m98,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 3) assert.Len(t, result, 3)
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1}, result[0]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1}, result[0])
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[1]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[1])
@ -102,7 +102,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&m4_ref_s1, &m4_ref_s1,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.Equal(t, batch, result[0]) assert.Equal(t, batch, result[0])
}) })
@ -113,7 +113,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&metricStat, &metricStat,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.ElementsMatch(t, batch, result[0]) assert.ElementsMatch(t, batch, result[0])
}) })
@ -125,7 +125,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&insight2, &insight2,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 3) assert.Len(t, result, 3)
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1}, result[0]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1}, result[0])
assert.ElementsMatch(t, []*models.CloudWatchQuery{&metricStat}, result[1]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&metricStat}, result[1])
@ -142,7 +142,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&m4_ref_s1, &m4_ref_s1,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 1) assert.Len(t, result, 1)
assert.ElementsMatch(t, batch, result[0]) assert.ElementsMatch(t, batch, result[0])
}) })
@ -157,7 +157,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&m4_ref_s1, &m4_ref_s1,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 3) assert.Len(t, result, 3)
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[0]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[0])
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1, &m1_ref_i1, &m2_ref_i1, &m3_ref_m1_m2}, result[1]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1, &m1_ref_i1, &m2_ref_i1, &m3_ref_m1_m2}, result[1])
@ -172,7 +172,7 @@ func TestGetMetricQueryBatches(t *testing.T) {
&m4_ref_i1_i3, &m4_ref_i1_i3,
} }
result := getMetricQueryBatches(batch, logger) result := getMetricQueryBatches(batch, nullLogger)
assert.Len(t, result, 3) assert.Len(t, result, 3)
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[0]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight2}, result[0])
assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1, &m1_ref_i1}, result[1]) assert.ElementsMatch(t, []*models.CloudWatchQuery{&insight1, &m1_ref_i1}, result[1])

View File

@ -17,10 +17,9 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"golang.org/x/sync/errgroup"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"golang.org/x/sync/errgroup"
) )
const ( const (
@ -41,7 +40,7 @@ func (e *AWSError) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message) return fmt.Sprintf("%s: %s", e.Code, e.Message)
} }
func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, logger log.Logger, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
resp := backend.NewQueryDataResponse() resp := backend.NewQueryDataResponse()
resultChan := make(chan backend.Responses, len(req.Queries)) resultChan := make(chan backend.Responses, len(req.Queries))
@ -56,7 +55,7 @@ func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, logger log.L
query := query query := query
eg.Go(func() error { eg.Go(func() error {
dataframe, err := e.executeLogAction(ectx, logger, logsQuery, query, req.PluginContext) dataframe, err := e.executeLogAction(ectx, logsQuery, query, req.PluginContext)
if err != nil { if err != nil {
var AWSError *AWSError var AWSError *AWSError
if errors.As(err, &AWSError) { if errors.As(err, &AWSError) {
@ -96,7 +95,7 @@ func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, logger log.L
return resp, nil return resp, nil
} }
func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, logger log.Logger, logsQuery models.LogsQuery, query backend.DataQuery, pluginCtx backend.PluginContext) (*data.Frame, error) { func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, logsQuery models.LogsQuery, query backend.DataQuery, pluginCtx backend.PluginContext) (*data.Frame, error) {
instance, err := e.getInstance(ctx, pluginCtx) instance, err := e.getInstance(ctx, pluginCtx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -115,7 +114,7 @@ func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, logger log.Lo
var data *data.Frame = nil var data *data.Frame = nil
switch logsQuery.Subtype { switch logsQuery.Subtype {
case "StartQuery": case "StartQuery":
data, err = e.handleStartQuery(ctx, logger, logsClient, logsQuery, query.TimeRange, query.RefID) data, err = e.handleStartQuery(ctx, logsClient, logsQuery, query.TimeRange, query.RefID)
case "StopQuery": case "StopQuery":
data, err = e.handleStopQuery(ctx, logsClient, logsQuery) data, err = e.handleStopQuery(ctx, logsClient, logsQuery)
case "GetQueryResults": case "GetQueryResults":
@ -229,17 +228,17 @@ func (e *cloudWatchExecutor) executeStartQuery(ctx context.Context, logsClient c
startQueryInput.Limit = aws.Int64(*logsQuery.Limit) startQueryInput.Limit = aws.Int64(*logsQuery.Limit)
} }
logger.Debug("Calling startquery with context with input", "input", startQueryInput) e.logger.FromContext(ctx).Debug("Calling startquery with context with input", "input", startQueryInput)
return logsClient.StartQueryWithContext(ctx, startQueryInput) return logsClient.StartQueryWithContext(ctx, startQueryInput)
} }
func (e *cloudWatchExecutor) handleStartQuery(ctx context.Context, logger log.Logger, logsClient cloudwatchlogsiface.CloudWatchLogsAPI, func (e *cloudWatchExecutor) handleStartQuery(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI,
logsQuery models.LogsQuery, timeRange backend.TimeRange, refID string) (*data.Frame, error) { logsQuery models.LogsQuery, timeRange backend.TimeRange, refID string) (*data.Frame, error) {
startQueryResponse, err := e.executeStartQuery(ctx, logsClient, logsQuery, timeRange) startQueryResponse, err := e.executeStartQuery(ctx, logsClient, logsQuery, timeRange)
if err != nil { if err != nil {
var awsErr awserr.Error var awsErr awserr.Error
if errors.As(err, &awsErr) && awsErr.Code() == "LimitExceededException" { if errors.As(err, &awsErr) && awsErr.Code() == "LimitExceededException" {
logger.Debug("ExecuteStartQuery limit exceeded", "err", awsErr) e.logger.FromContext(ctx).Debug("ExecuteStartQuery limit exceeded", "err", awsErr)
return nil, &AWSError{Code: limitExceededException, Message: err.Error()} return nil, &AWSError{Code: limitExceededException, Message: err.Error()}
} }
return nil, err return nil, err

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "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/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
@ -90,7 +91,7 @@ func TestQuery_handleGetLogEvents_passes_nil_start_and_end_times_to_GetLogEvents
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -123,7 +124,7 @@ func TestQuery_GetLogEvents_returns_response_from_GetLogEvents_to_data_frame_fie
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
cli = &mocks.MockLogEvents{} cli = &mocks.MockLogEvents{}
cli.On("GetLogEventsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetLogEventsOutput{ cli.On("GetLogEventsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetLogEventsOutput{
@ -208,7 +209,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -265,7 +266,7 @@ func TestQuery_StartQuery(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -322,7 +323,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -358,7 +359,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -384,7 +385,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -420,7 +421,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -456,8 +457,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@ -492,7 +492,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@ -526,7 +526,7 @@ func Test_executeStartQuery(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@ -597,7 +597,7 @@ func TestQuery_StopQuery(t *testing.T) {
To: time.Unix(1584700643, 0), To: time.Unix(1584700643, 0),
} }
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -687,7 +687,7 @@ func TestQuery_GetQueryResults(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "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/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
@ -40,7 +41,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, &sess) executor := newExecutor(im, &sess, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@ -67,7 +68,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, &sess) executor := newExecutor(im, &sess, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -124,7 +125,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, &sess) executor := newExecutor(im, &sess, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: tc.headers, Headers: tc.headers,
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -167,7 +168,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
}) })
sess := fakeSessionCache{} sess := fakeSessionCache{}
executor := newExecutor(im, &sess) executor := newExecutor(im, &sess, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
Queries: []backend.DataQuery{ Queries: []backend.DataQuery{
@ -206,7 +207,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@ -235,7 +236,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@ -304,7 +305,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@ -349,7 +350,8 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{})
executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},
@ -381,7 +383,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ res, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
Headers: map[string]string{headerFromAlert: "some value"}, Headers: map[string]string{headerFromAlert: "some value"},

View File

@ -6,11 +6,10 @@ import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )
func (e *cloudWatchExecutor) buildMetricDataInput(logger log.Logger, startTime time.Time, endTime time.Time, func (e *cloudWatchExecutor) buildMetricDataInput(startTime time.Time, endTime time.Time,
queries []*models.CloudWatchQuery) (*cloudwatch.GetMetricDataInput, error) { queries []*models.CloudWatchQuery) (*cloudwatch.GetMetricDataInput, error) {
metricDataInput := &cloudwatch.GetMetricDataInput{ metricDataInput := &cloudwatch.GetMetricDataInput{
StartTime: aws.Time(startTime), StartTime: aws.Time(startTime),
@ -27,7 +26,7 @@ func (e *cloudWatchExecutor) buildMetricDataInput(logger log.Logger, startTime t
} }
for _, query := range queries { for _, query := range queries {
metricDataQuery, err := e.buildMetricDataQuery(logger, query) metricDataQuery, err := e.buildMetricDataQuery(query)
if err != nil { if err != nil {
return nil, &models.QueryError{Err: err, RefID: query.RefId} return nil, &models.QueryError{Err: err, RefID: query.RefId}
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )
@ -26,13 +27,13 @@ func TestMetricDataInputBuilder(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.TimezoneUTCOffset = tc.timezoneUTCOffset query.TimezoneUTCOffset = tc.timezoneUTCOffset
from := now.Add(time.Hour * -2) from := now.Add(time.Hour * -2)
to := now.Add(time.Hour * -1) to := now.Add(time.Hour * -1)
mdi, err := executor.buildMetricDataInput(logger, from, to, []*models.CloudWatchQuery{query}) mdi, err := executor.buildMetricDataInput(from, to, []*models.CloudWatchQuery{query})
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, mdi) require.NotNil(t, mdi)

View File

@ -9,11 +9,10 @@ import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )
func (e *cloudWatchExecutor) buildMetricDataQuery(logger log.Logger, query *models.CloudWatchQuery) (*cloudwatch.MetricDataQuery, error) { func (e *cloudWatchExecutor) buildMetricDataQuery(query *models.CloudWatchQuery) (*cloudwatch.MetricDataQuery, error) {
mdq := &cloudwatch.MetricDataQuery{ mdq := &cloudwatch.MetricDataQuery{
Id: aws.String(query.Id), Id: aws.String(query.Id),
ReturnData: aws.Bool(query.ReturnData), ReturnData: aws.Bool(query.ReturnData),

View File

@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -12,11 +13,11 @@ import (
func TestMetricDataQueryBuilder(t *testing.T) { func TestMetricDataQueryBuilder(t *testing.T) {
t.Run("buildMetricDataQuery", func(t *testing.T) { t.Run("buildMetricDataQuery", func(t *testing.T) {
t.Run("should use metric stat", func(t *testing.T) { t.Run("should use metric stat", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, mdq.Expression) require.Empty(t, mdq.Expression)
assert.Equal(t, query.MetricName, *mdq.MetricStat.Metric.MetricName) assert.Equal(t, query.MetricName, *mdq.MetricStat.Metric.MetricName)
@ -24,70 +25,70 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should pass AccountId in metric stat query", func(t *testing.T) { t.Run("should pass AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
query.AccountId = aws.String("some account id") query.AccountId = aws.String("some account id")
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "some account id", *mdq.AccountId) assert.Equal(t, "some account id", *mdq.AccountId)
}) })
t.Run("should leave AccountId in metric stat query", func(t *testing.T) { t.Run("should leave AccountId in metric stat query", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, mdq.AccountId) assert.Nil(t, mdq.AccountId)
}) })
t.Run("should use custom built expression", func(t *testing.T) { t.Run("should use custom built expression", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeBuilder query.MetricEditorMode = models.MetricEditorModeBuilder
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
query.MatchExact = false query.MatchExact = false
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)
assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"="lb1"', '', 300))`, *mdq.Expression) assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"="lb1"', '', 300))`, *mdq.Expression)
}) })
t.Run("should use sql expression", func(t *testing.T) { t.Run("should use sql expression", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeQuery query.MetricQueryType = models.MetricQueryTypeQuery
query.SqlExpression = `SELECT SUM(CPUUTilization) FROM "AWS/EC2"` query.SqlExpression = `SELECT SUM(CPUUTilization) FROM "AWS/EC2"`
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)
assert.Equal(t, query.SqlExpression, *mdq.Expression) assert.Equal(t, query.SqlExpression, *mdq.Expression)
}) })
t.Run("should use user defined math expression", func(t *testing.T) { t.Run("should use user defined math expression", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
query.Expression = `SUM(x+y)` query.Expression = `SUM(x+y)`
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)
assert.Equal(t, query.Expression, *mdq.Expression) assert.Equal(t, query.Expression, *mdq.Expression)
}) })
t.Run("should set period in user defined expression", func(t *testing.T) { t.Run("should set period in user defined expression", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.MetricEditorMode = models.MetricEditorModeRaw query.MetricEditorMode = models.MetricEditorModeRaw
query.MetricQueryType = models.MetricQueryTypeSearch query.MetricQueryType = models.MetricQueryTypeSearch
query.MatchExact = false query.MatchExact = false
query.Expression = `SUM([a,b])` query.Expression = `SUM([a,b])`
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)
assert.Equal(t, int64(300), *mdq.Period) assert.Equal(t, int64(300), *mdq.Period)
@ -95,11 +96,11 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should set label", func(t *testing.T) { t.Run("should set label", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.Label = "some label" query.Label = "some label"
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, mdq.Label) require.NotNil(t, mdq.Label)
@ -107,18 +108,18 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should not set label for empty string query label", func(t *testing.T) { t.Run("should not set label for empty string query label", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := getBaseQuery() query := getBaseQuery()
query.Label = "" query.Label = ""
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
assert.NoError(t, err) assert.NoError(t, err)
assert.Nil(t, mdq.Label) assert.Nil(t, mdq.Label)
}) })
t.Run(`should not specify accountId when it is "all"`, func(t *testing.T) { t.Run(`should not specify accountId when it is "all"`, func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := &models.CloudWatchQuery{ query := &models.CloudWatchQuery{
Namespace: "AWS/EC2", Namespace: "AWS/EC2",
MetricName: "CPUUtilization", MetricName: "CPUUtilization",
@ -128,7 +129,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
AccountId: aws.String("all"), AccountId: aws.String("all"),
} }
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
assert.NoError(t, err) assert.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)
@ -136,7 +137,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
}) })
t.Run("should set accountId when it is specified", func(t *testing.T) { t.Run("should set accountId when it is specified", func(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
query := &models.CloudWatchQuery{ query := &models.CloudWatchQuery{
Namespace: "AWS/EC2", Namespace: "AWS/EC2",
MetricName: "CPUUtilization", MetricName: "CPUUtilization",
@ -146,7 +147,7 @@ func TestMetricDataQueryBuilder(t *testing.T) {
AccountId: aws.String("12345"), AccountId: aws.String("12345"),
} }
mdq, err := executor.buildMetricDataQuery(logger, query) mdq, err := executor.buildMetricDataQuery(query)
assert.NoError(t, err) assert.NoError(t, err)
require.Nil(t, mdq.MetricStat) require.Nil(t, mdq.MetricStat)

View File

@ -63,7 +63,7 @@ func (e *cloudWatchExecutor) handleGetRegions(ctx context.Context, pluginCtx bac
ec2Regions, err := client.DescribeRegionsWithContext(ctx, &ec2.DescribeRegionsInput{}) ec2Regions, err := client.DescribeRegionsWithContext(ctx, &ec2.DescribeRegionsInput{})
if err != nil { if err != nil {
// ignore error for backward compatibility // ignore error for backward compatibility
logger.Error("Failed to get regions", "error", err) e.logger.FromContext(ctx).Error("Failed to get regions", "error", err)
} else { } else {
mergeEC2RegionsAndConstantRegions(regions, ec2Regions.Regions) mergeEC2RegionsAndConstantRegions(regions, ec2Regions.Regions)
} }

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "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/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
@ -53,7 +54,7 @@ func TestQuery_Regions(t *testing.T) {
}}, nil }}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.handleGetRegions( resp, err := executor.handleGetRegions(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@ -115,7 +116,7 @@ func Test_handleGetRegions_regionCache(t *testing.T) {
t.Run("AWS only called once for multiple calls to handleGetRegions", func(t *testing.T) { t.Run("AWS only called once for multiple calls to handleGetRegions", func(t *testing.T) {
cli.On("DescribeRegionsWithContext", mock.Anything, mock.Anything).Return(&ec2.DescribeRegionsOutput{}, nil) cli.On("DescribeRegionsWithContext", mock.Anything, mock.Anything).Return(&ec2.DescribeRegionsOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.handleGetRegions( _, err := executor.handleGetRegions(
context.Background(), context.Background(),
backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, nil) backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, nil)
@ -171,7 +172,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
filterJson, err := json.Marshal(filterMap) filterJson, err := json.Marshal(filterMap)
require.NoError(t, err) require.NoError(t, err)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.handleGetEc2InstanceAttribute( resp, err := executor.handleGetEc2InstanceAttribute(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@ -249,7 +250,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
return DataSource{Settings: models.CloudWatchSettings{}}, nil return DataSource{Settings: models.CloudWatchSettings{}}, nil
}) })
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.handleGetEbsVolumeIds( resp, err := executor.handleGetEbsVolumeIds(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{
@ -316,7 +317,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
tagJson, err := json.Marshal(tagMap) tagJson, err := json.Marshal(tagMap)
require.NoError(t, err) require.NoError(t, err)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.handleGetResourceArns( resp, err := executor.handleGetResourceArns(
context.Background(), context.Background(),
backend.PluginContext{ backend.PluginContext{

View File

@ -10,7 +10,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/oam" "github.com/aws/aws-sdk-go/service/oam"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
) )

View File

@ -14,9 +14,9 @@ import (
"github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery"
) )

View File

@ -10,15 +10,15 @@ import (
"github.com/grafana/kindsys" "github.com/grafana/kindsys"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log/logtest"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
) )
var logger = &logtest.Fake{} var logger = log.NewNullLogger()
func TestCloudWatchQuery(t *testing.T) { func TestCloudWatchQuery(t *testing.T) {
t.Run("Deeplink", func(t *testing.T) { t.Run("Deeplink", func(t *testing.T) {

View File

@ -8,62 +8,62 @@ import (
"net/url" "net/url"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/routes" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/routes"
) )
func (e *cloudWatchExecutor) newResourceMux() *http.ServeMux { func (e *cloudWatchExecutor) newResourceMux() *http.ServeMux {
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/ebs-volume-ids", handleResourceReq(e.handleGetEbsVolumeIds)) mux.HandleFunc("/ebs-volume-ids", handleResourceReq(e.handleGetEbsVolumeIds, e.logger))
mux.HandleFunc("/ec2-instance-attribute", handleResourceReq(e.handleGetEc2InstanceAttribute)) mux.HandleFunc("/ec2-instance-attribute", handleResourceReq(e.handleGetEc2InstanceAttribute, e.logger))
mux.HandleFunc("/resource-arns", handleResourceReq(e.handleGetResourceArns)) mux.HandleFunc("/resource-arns", handleResourceReq(e.handleGetResourceArns, e.logger))
mux.HandleFunc("/log-groups", routes.ResourceRequestMiddleware(routes.LogGroupsHandler, logger, e.getRequestContext)) mux.HandleFunc("/log-groups", routes.ResourceRequestMiddleware(routes.LogGroupsHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/metrics", routes.ResourceRequestMiddleware(routes.MetricsHandler, logger, e.getRequestContext)) mux.HandleFunc("/metrics", routes.ResourceRequestMiddleware(routes.MetricsHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/dimension-values", routes.ResourceRequestMiddleware(routes.DimensionValuesHandler, logger, e.getRequestContext)) mux.HandleFunc("/dimension-values", routes.ResourceRequestMiddleware(routes.DimensionValuesHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/dimension-keys", routes.ResourceRequestMiddleware(routes.DimensionKeysHandler, logger, e.getRequestContext)) mux.HandleFunc("/dimension-keys", routes.ResourceRequestMiddleware(routes.DimensionKeysHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/accounts", routes.ResourceRequestMiddleware(routes.AccountsHandler, logger, e.getRequestContext)) mux.HandleFunc("/accounts", routes.ResourceRequestMiddleware(routes.AccountsHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/namespaces", routes.ResourceRequestMiddleware(routes.NamespacesHandler, logger, e.getRequestContext)) mux.HandleFunc("/namespaces", routes.ResourceRequestMiddleware(routes.NamespacesHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/log-group-fields", routes.ResourceRequestMiddleware(routes.LogGroupFieldsHandler, logger, e.getRequestContext)) mux.HandleFunc("/log-group-fields", routes.ResourceRequestMiddleware(routes.LogGroupFieldsHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/external-id", routes.ResourceRequestMiddleware(routes.ExternalIdHandler, logger, e.getRequestContext)) mux.HandleFunc("/external-id", routes.ResourceRequestMiddleware(routes.ExternalIdHandler, e.logger, e.getRequestContext))
mux.HandleFunc("/regions", routes.ResourceRequestMiddleware(routes.RegionsHandler, logger, e.getRequestContext)) mux.HandleFunc("/regions", routes.ResourceRequestMiddleware(routes.RegionsHandler, e.logger, e.getRequestContext))
// remove this once AWS's Cross Account Observability is supported in GovCloud // remove this once AWS's Cross Account Observability is supported in GovCloud
mux.HandleFunc("/legacy-log-groups", handleResourceReq(e.handleGetLogGroups)) mux.HandleFunc("/legacy-log-groups", handleResourceReq(e.handleGetLogGroups, e.logger))
return mux return mux
} }
type handleFn func(ctx context.Context, pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error) type handleFn func(ctx context.Context, pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error)
func handleResourceReq(handleFunc handleFn) func(rw http.ResponseWriter, req *http.Request) { func handleResourceReq(handleFunc handleFn, logger log.Logger) func(rw http.ResponseWriter, req *http.Request) {
return func(rw http.ResponseWriter, req *http.Request) { return func(rw http.ResponseWriter, req *http.Request) {
ctx := req.Context() ctx := req.Context()
pluginContext := httpadapter.PluginConfigFromContext(ctx) pluginContext := httpadapter.PluginConfigFromContext(ctx)
err := req.ParseForm() err := req.ParseForm()
if err != nil { if err != nil {
writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err)) writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err), logger.FromContext(ctx))
return return
} }
data, err := handleFunc(ctx, pluginContext, req.URL.Query()) data, err := handleFunc(ctx, pluginContext, req.URL.Query())
if err != nil { if err != nil {
writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err)) writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err), logger.FromContext(ctx))
return return
} }
body, err := json.Marshal(data) body, err := json.Marshal(data)
if err != nil { if err != nil {
writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err)) writeResponse(rw, http.StatusBadRequest, fmt.Sprintf("unexpected error %v", err), logger.FromContext(ctx))
return return
} }
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
_, err = rw.Write(body) _, err = rw.Write(body)
if err != nil { if err != nil {
logger.Error("Unable to write HTTP response", "error", err) logger.FromContext(ctx).Error("Unable to write HTTP response", "error", err)
return return
} }
} }
} }
func writeResponse(rw http.ResponseWriter, code int, msg string) { func writeResponse(rw http.ResponseWriter, code int, msg string, logger log.Logger) {
rw.WriteHeader(code) rw.WriteHeader(code)
_, err := rw.Write([]byte(msg)) _, err := rw.Write([]byte(msg))
if err != nil { if err != nil {

View File

@ -9,18 +9,18 @@ import (
"testing" "testing"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log/logtest"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/services" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/services"
) )
var logger = &logtest.Fake{} var logger = log.NewNullLogger()
func Test_DimensionKeys_Route(t *testing.T) { func Test_DimensionKeys_Route(t *testing.T) {
t.Run("calls FilterDimensionKeysRequest when a StandardDimensionKeysRequest is passed", func(t *testing.T) { t.Run("calls FilterDimensionKeysRequest when a StandardDimensionKeysRequest is passed", func(t *testing.T) {

View File

@ -3,9 +3,9 @@ package routes
import ( import (
"net/http" "net/http"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
) )
@ -20,7 +20,7 @@ func ResourceRequestMiddleware(handleFunc models.RouteHandlerFunc, logger log.Lo
pluginContext := httpadapter.PluginConfigFromContext(ctx) pluginContext := httpadapter.PluginConfigFromContext(ctx)
json, httpError := handleFunc(ctx, pluginContext, reqCtxFactory, req.URL.Query()) json, httpError := handleFunc(ctx, pluginContext, reqCtxFactory, req.URL.Query())
if httpError != nil { if httpError != nil {
logger.Error("Error handling resource request", "error", httpError.Message) logger.FromContext(ctx).Error("Error handling resource request", "error", httpError.Message)
respondWithError(rw, httpError) respondWithError(rw, httpError)
return return
} }
@ -28,7 +28,7 @@ func ResourceRequestMiddleware(handleFunc models.RouteHandlerFunc, logger log.Lo
rw.Header().Set("Content-Type", "application/json") rw.Header().Set("Content-Type", "application/json")
_, err := rw.Write(json) _, err := rw.Write(json)
if err != nil { if err != nil {
logger.Error("Error handling resource request", "error", err) logger.FromContext(ctx).Error("Error handling resource request", "error", err)
respondWithError(rw, models.NewHttpError("error writing response in resource request middleware", http.StatusInternalServerError, err)) respondWithError(rw, models.NewHttpError("error writing response in resource request middleware", http.StatusInternalServerError, err))
} }
} }

View File

@ -5,7 +5,7 @@ import (
"sort" "sort"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/constants"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"

View File

@ -5,14 +5,14 @@ import (
"testing" "testing"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var testLogger = log.New("test logger") var testLogger = log.New().With("logger", "test.logger")
func TestRegions(t *testing.T) { func TestRegions(t *testing.T) {
t.Run("returns regions from the api and merges them with default regions", func(t *testing.T) { t.Run("returns regions from the api and merges them with default regions", func(t *testing.T) {

View File

@ -5,12 +5,12 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
) )
type responseWrapper struct { type responseWrapper struct {
@ -18,8 +18,8 @@ type responseWrapper struct {
RefId string RefId string
} }
func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger log.Logger, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
logger.Debug("Executing time series query") e.logger.FromContext(ctx).Debug("Executing time series query")
resp := backend.NewQueryDataResponse() resp := backend.NewQueryDataResponse()
if len(req.Queries) == 0 { if len(req.Queries) == 0 {
@ -37,7 +37,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger
return nil, err return nil, err
} }
requestQueries, err := models.ParseMetricDataQueries(req.Queries, startTime, endTime, instance.Settings.Region, logger, requestQueries, err := models.ParseMetricDataQueries(req.Queries, startTime, endTime, instance.Settings.Region, e.logger.FromContext(ctx),
features.IsEnabled(ctx, features.FlagCloudWatchCrossAccountQuerying)) features.IsEnabled(ctx, features.FlagCloudWatchCrossAccountQuerying))
if err != nil { if err != nil {
return nil, err return nil, err
@ -62,7 +62,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger
batches := [][]*models.CloudWatchQuery{regionQueries} batches := [][]*models.CloudWatchQuery{regionQueries}
if features.IsEnabled(ctx, features.FlagCloudWatchBatchQueries) { if features.IsEnabled(ctx, features.FlagCloudWatchBatchQueries) {
batches = getMetricQueryBatches(regionQueries, logger) batches = getMetricQueryBatches(regionQueries, e.logger.FromContext(ctx))
} }
for _, batch := range batches { for _, batch := range batches {
@ -70,7 +70,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger
eg.Go(func() error { eg.Go(func() error {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
logger.Error("Execute Get Metric Data Query Panic", "error", err, "stack", log.Stack(1)) e.logger.FromContext(ctx).Error("Execute Get Metric Data Query Panic", "error", err, "stack", utils.Stack(1))
if theErr, ok := err.(error); ok { if theErr, ok := err.(error); ok {
resultChan <- &responseWrapper{ resultChan <- &responseWrapper{
DataResponse: &backend.DataResponse{ DataResponse: &backend.DataResponse{
@ -86,7 +86,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger
return err return err
} }
metricDataInput, err := e.buildMetricDataInput(logger, startTime, endTime, requestQueries) metricDataInput, err := e.buildMetricDataInput(startTime, endTime, requestQueries)
if err != nil { if err != nil {
return err return err
} }
@ -97,7 +97,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger
} }
if features.IsEnabled(ctx, features.FlagCloudWatchWildCardDimensionValues) { if features.IsEnabled(ctx, features.FlagCloudWatchWildCardDimensionValues) {
requestQueries, err = e.getDimensionValuesForWildcards(ctx, req.PluginContext, region, client, requestQueries, instance.tagValueCache, logger) requestQueries, err = e.getDimensionValuesForWildcards(ctx, req.PluginContext, region, client, requestQueries, instance.tagValueCache)
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
@ -26,7 +27,7 @@ import (
) )
func TestTimeSeriesQuery(t *testing.T) { func TestTimeSeriesQuery(t *testing.T) {
executor := newExecutor(nil, &fakeSessionCache{}) executor := newExecutor(nil, &fakeSessionCache{}, log.NewNullLogger())
now := time.Now() now := time.Now()
origNewCWClient := NewCWClient origNewCWClient := NewCWClient
@ -52,7 +53,7 @@ func TestTimeSeriesQuery(t *testing.T) {
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ resp, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -117,7 +118,7 @@ func TestTimeSeriesQuery(t *testing.T) {
}) })
t.Run("End time before start time should result in error", func(t *testing.T) { t.Run("End time before start time should result in error", func(t *testing.T) {
_, err := executor.executeTimeSeriesQuery(context.Background(), logger, &backend.QueryDataRequest{Queries: []backend.DataQuery{{TimeRange: backend.TimeRange{ _, err := executor.executeTimeSeriesQuery(context.Background(), &backend.QueryDataRequest{Queries: []backend.DataQuery{{TimeRange: backend.TimeRange{
From: now.Add(time.Hour * -1), From: now.Add(time.Hour * -1),
To: now.Add(time.Hour * -2), To: now.Add(time.Hour * -2),
}}}}) }}}})
@ -125,7 +126,7 @@ func TestTimeSeriesQuery(t *testing.T) {
}) })
t.Run("End time equals start time should result in error", func(t *testing.T) { t.Run("End time equals start time should result in error", func(t *testing.T) {
_, err := executor.executeTimeSeriesQuery(context.Background(), logger, &backend.QueryDataRequest{Queries: []backend.DataQuery{{TimeRange: backend.TimeRange{ _, err := executor.executeTimeSeriesQuery(context.Background(), &backend.QueryDataRequest{Queries: []backend.DataQuery{{TimeRange: backend.TimeRange{
From: now.Add(time.Hour * -1), From: now.Add(time.Hour * -1),
To: now.Add(time.Hour * -1), To: now.Add(time.Hour * -1),
}}}}) }}}})
@ -158,7 +159,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{} mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, mockSessionCache) executor := newExecutor(im, mockSessionCache, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -209,7 +210,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
mockMetricClient = mocks.MetricsAPI{} mockMetricClient = mocks.MetricsAPI{}
mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) mockMetricClient.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
executor := newExecutor(im, sessionCache) executor := newExecutor(im, sessionCache, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -342,7 +343,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run("passes query label as GetMetricData label", func(t *testing.T) { t.Run("passes query label as GetMetricData label", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
query := newTestQuery(t, queryParameters{ query := newTestQuery(t, queryParameters{
Label: aws.String("${PROP('Period')} some words ${PROP('Dim.InstanceId')}"), Label: aws.String("${PROP('Period')} some words ${PROP('Dim.InstanceId')}"),
}) })
@ -381,7 +382,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}},
@ -432,7 +433,7 @@ func Test_QueryData_response_data_frame_name_is_always_response_label(t *testing
}}, nil) }}, nil)
im := defaultTestInstanceManager() im := defaultTestInstanceManager()
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
t.Run("where user defines search expression", func(t *testing.T) { t.Run("where user defines search expression", func(t *testing.T) {
query := newTestQuery(t, queryParameters{ query := newTestQuery(t, queryParameters{
@ -589,7 +590,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId nil when no AccountId is provided", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId nil when no AccountId is provided", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
@ -630,7 +631,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId nil when feature flag is false", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId nil when feature flag is false", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{ _, err := executor.QueryData(context.Background(), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -671,7 +672,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should call GetMetricDataInput with AccountId in a MetricStat query", func(t *testing.T) { t.Run("should call GetMetricDataInput with AccountId in a MetricStat query", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},
@ -712,7 +713,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
t.Run("should GetMetricDataInput with AccountId in an inferred search expression query", func(t *testing.T) { t.Run("should GetMetricDataInput with AccountId in an inferred search expression query", func(t *testing.T) {
api = mocks.MetricsAPI{} api = mocks.MetricsAPI{}
api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil) api.On("GetMetricDataWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.GetMetricDataOutput{}, nil)
executor := newExecutor(im, &fakeSessionCache{}) executor := newExecutor(im, &fakeSessionCache{}, log.NewNullLogger())
_, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{ _, err := executor.QueryData(contextWithFeaturesEnabled(features.FlagCloudWatchCrossAccountQuerying), &backend.QueryDataRequest{
PluginContext: backend.PluginContext{ PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{},

View File

@ -1,3 +1,13 @@
package utils package utils
import "github.com/go-stack/stack"
func Pointer[T any](arg T) *T { return &arg } func Pointer[T any](arg T) *T { return &arg }
// Stack is copied from grafana/pkg/infra/log
// TODO: maybe this should live in grafana-plugin-sdk-go?
func Stack(skip int) string {
call := stack.Caller(skip)
s := stack.Trace().TrimBelow(call).TrimRuntime()
return s.String()
}