From b99931affe17a6e0eceb677fc142c60357065c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9lian=20Garcia?= Date: Wed, 20 Nov 2024 11:32:11 +0100 Subject: [PATCH] [receiver/azuremonitorreceiver] feat: multi subscriptions support and automatic discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: CĂ©lian Garcia --- .chloggen/feat_discovery.yaml | 27 ++ receiver/azuremonitorreceiver/README.md | 4 +- receiver/azuremonitorreceiver/config.go | 18 +- receiver/azuremonitorreceiver/go.mod | 1 + receiver/azuremonitorreceiver/go.sum | 2 + .../internal/metadata/metrics.go | 23 +- .../internal/metadata/metrics_test.go | 27 +- receiver/azuremonitorreceiver/scraper.go | 284 +++++++++++------- receiver/azuremonitorreceiver/scraper_test.go | 235 ++++++++------- .../expected_metrics/metrics_golden.yaml | 158 +++++++--- .../expected_metrics/metrics_tags_golden.yaml | 158 +++++++--- 11 files changed, 603 insertions(+), 334 deletions(-) create mode 100644 .chloggen/feat_discovery.yaml diff --git a/.chloggen/feat_discovery.yaml b/.chloggen/feat_discovery.yaml new file mode 100644 index 000000000000..31916acf4453 --- /dev/null +++ b/.chloggen/feat_discovery.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: receiver/azuremonitorreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "multi subscriptions support and automatic discovery" + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [36467] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/receiver/azuremonitorreceiver/README.md b/receiver/azuremonitorreceiver/README.md index ab18a2cc4b0c..7c8b885b4e28 100644 --- a/receiver/azuremonitorreceiver/README.md +++ b/receiver/azuremonitorreceiver/README.md @@ -18,7 +18,9 @@ This receiver scrapes Azure Monitor API for resources metrics. The following settings are required: -- `subscription_id` +- `subscription_ids`: list of subscriptions on which the resource's metrics are collected +- or `subscriptions_id`: same as `subscription_ids` but not a list +- or `discover_subscriptions`: (default = `false`) If set to true, will collect metrics from all subscriptions in the tenant. The following settings are optional: diff --git a/receiver/azuremonitorreceiver/config.go b/receiver/azuremonitorreceiver/config.go index 6e835003e781..6c31107601d1 100644 --- a/receiver/azuremonitorreceiver/config.go +++ b/receiver/azuremonitorreceiver/config.go @@ -21,12 +21,12 @@ const ( var ( // Predefined error responses for configuration validation failures - errMissingTenantID = errors.New(`TenantID" is not specified in config`) - errMissingSubscriptionID = errors.New(`SubscriptionID" is not specified in config`) - errMissingClientID = errors.New(`ClientID" is not specified in config`) - errMissingClientSecret = errors.New(`ClientSecret" is not specified in config`) - errMissingFedTokenFile = errors.New(`FederatedTokenFile is not specified in config`) - errInvalidCloud = errors.New(`Cloud" is invalid`) + errMissingTenantID = errors.New(`"TenantID" is not specified in config`) + errMissingSubscriptionIDs = errors.New(`neither "SubscriptionID" nor "SubscriptionIDs" nor "DiscoverSubscription" is specified in the config`) + errMissingClientID = errors.New(`"ClientID" is not specified in config`) + errMissingClientSecret = errors.New(`"ClientSecret" is not specified in config`) + errMissingFedTokenFile = errors.New(`"FederatedTokenFile"" is not specified in config`) + errInvalidCloud = errors.New(`"Cloud" is invalid`) monitorServices = []string{ "Microsoft.EventGrid/eventSubscriptions", @@ -234,6 +234,8 @@ type Config struct { MetricsBuilderConfig metadata.MetricsBuilderConfig `mapstructure:",squash"` Cloud string `mapstructure:"cloud"` SubscriptionID string `mapstructure:"subscription_id"` + SubscriptionIDs []string `mapstructure:"subscription_ids"` + DiscoverSubscriptions bool `mapstructure:"discover_subscriptions"` Authentication string `mapstructure:"auth"` TenantID string `mapstructure:"tenant_id"` ClientID string `mapstructure:"client_id"` @@ -257,8 +259,8 @@ const ( // Validate validates the configuration by checking for missing or invalid fields func (c Config) Validate() (err error) { - if c.SubscriptionID == "" { - err = multierr.Append(err, errMissingSubscriptionID) + if c.SubscriptionID == "" && len(c.SubscriptionIDs) == 0 && !c.DiscoverSubscriptions { + err = multierr.Append(err, errMissingSubscriptionIDs) } switch c.Authentication { diff --git a/receiver/azuremonitorreceiver/go.mod b/receiver/azuremonitorreceiver/go.mod index 50b61808ae63..b29f9a1f2b76 100644 --- a/receiver/azuremonitorreceiver/go.mod +++ b/receiver/azuremonitorreceiver/go.mod @@ -7,6 +7,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0 github.com/google/go-cmp v0.6.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.114.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.114.0 diff --git a/receiver/azuremonitorreceiver/go.sum b/receiver/azuremonitorreceiver/go.sum index 58bfdf4df0f5..405e6a8ff791 100644 --- a/receiver/azuremonitorreceiver/go.sum +++ b/receiver/azuremonitorreceiver/go.sum @@ -14,6 +14,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0/go.mod h1:jj6P8ybImR+5topJ+eH6fgcemSFBmU6/6bFF8KkwuDI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0 h1:wxQx2Bt4xzPIKvW59WQf1tJNx/ZZKPfN+EhPX3Z6CYY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0/go.mod h1:TpiwjwnW/khS0LKs4vW5UmmT9OWcxaveS8U7+tlknzo= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= diff --git a/receiver/azuremonitorreceiver/internal/metadata/metrics.go b/receiver/azuremonitorreceiver/internal/metadata/metrics.go index 75af602be1c2..d632d2fd04a2 100644 --- a/receiver/azuremonitorreceiver/internal/metadata/metrics.go +++ b/receiver/azuremonitorreceiver/internal/metadata/metrics.go @@ -108,16 +108,7 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption func(ResourceAttributesSettings, pmetric.ResourceMetrics) -// WithAzureMonitorSubscriptionID sets provided value as "azuremonitor.subscription_id" attribute for current resource. -func WithAzureMonitorSubscriptionID(val string) ResourceMetricsOption { - return func(ras ResourceAttributesSettings, rm pmetric.ResourceMetrics) { - if ras.AzureMonitorSubscriptionID.Enabled { - rm.Resource().Attributes().PutStr("azuremonitor.subscription_id", val) - } - } -} - -// WithAzuremonitorTenantID sets provided value as "azuremonitor.tenant_id" attribute for current resource. +// WithAzureMonitorTenantID sets provided value as "azuremonitor.tenant_id" attribute for current resource. func WithAzureMonitorTenantID(val string) ResourceMetricsOption { return func(ras ResourceAttributesSettings, rm pmetric.ResourceMetrics) { if ras.AzureMonitorTenantID.Enabled { @@ -209,6 +200,7 @@ func (mb *MetricsBuilder) addMetric(resourceMetricID, logicalMetricID, unit stri } func (mb *MetricsBuilder) AddDataPoint( + subscriptionID, resourceID, metric, aggregation, @@ -218,7 +210,7 @@ func (mb *MetricsBuilder) AddDataPoint( val float64, ) { logicalMetricID := getLogicalMetricID(metric, aggregation) - resourceMetricID := getLogicalResourceMetricID(resourceID, logicalMetricID) + resourceMetricID := getLogicalResourceMetricID(subscriptionID, resourceID, logicalMetricID) m, exists := mb.getMetric(resourceMetricID) if !exists { @@ -232,6 +224,11 @@ func (mb *MetricsBuilder) AddDataPoint( dp.SetStartTimestamp(mb.startTime) dp.SetTimestamp(ts) dp.SetDoubleValue(val) + + if mb.resourceAttributesSettings.AzureMonitorSubscriptionID.Enabled { + dp.Attributes().PutStr("azuremonitor.subscription_id", subscriptionID) + } + dp.Attributes().PutStr("azuremonitor.resource_id", resourceID) for key, value := range attributes { dp.Attributes().PutStr(key, *value) @@ -242,8 +239,8 @@ func getLogicalMetricID(metric, aggregation string) string { return strings.ToLower(fmt.Sprintf("%s%s_%s", metricsPrefix, strings.ReplaceAll(metric, " ", "_"), aggregation)) } -func getLogicalResourceMetricID(resourceID, logicalMetricID string) string { - return fmt.Sprintf("%s/%s", strings.ToLower(resourceID), logicalMetricID) +func getLogicalResourceMetricID(subscriptionID, resourceID, logicalMetricID string) string { + return fmt.Sprintf("%s/%s/%s", strings.ToLower(subscriptionID), strings.ToLower(resourceID), logicalMetricID) } func (mb *MetricsBuilder) EmitAllMetrics(ils pmetric.ScopeMetrics) { diff --git a/receiver/azuremonitorreceiver/internal/metadata/metrics_test.go b/receiver/azuremonitorreceiver/internal/metadata/metrics_test.go index 8b09ba23407f..1d98b33481d3 100644 --- a/receiver/azuremonitorreceiver/internal/metadata/metrics_test.go +++ b/receiver/azuremonitorreceiver/internal/metadata/metrics_test.go @@ -56,9 +56,9 @@ func TestMetricsBuilder(t *testing.T) { var val1 float64 = 1 attributes := map[string]*string{} - mb.AddDataPoint("resId1", "metric1", "count", "unit", attributes, ts, val1) + mb.AddDataPoint("subId1", "resId1", "metric1", "count", "unit", attributes, ts, val1) - metrics := mb.Emit(WithAzureMonitorSubscriptionID("attr-val"), WithAzureMonitorTenantID("attr-val")) + metrics := mb.Emit(WithAzureMonitorTenantID("attr-val")) if test.configSet == testSetNone { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) @@ -67,27 +67,22 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) - attrCount := 0 - enabledAttrCount := 0 - attrVal, ok := rm.Resource().Attributes().Get("azuremonitor.subscription_id") - attrCount++ - assert.Equal(t, mb.resourceAttributesSettings.AzureMonitorSubscriptionID.Enabled, ok) - if mb.resourceAttributesSettings.AzureMonitorSubscriptionID.Enabled { - enabledAttrCount++ - assert.EqualValues(t, "attr-val", attrVal.Str()) - } - attrVal, ok = rm.Resource().Attributes().Get("azuremonitor.tenant_id") - attrCount++ + attrVal, ok := rm.Resource().Attributes().Get("azuremonitor.tenant_id") assert.Equal(t, mb.resourceAttributesSettings.AzureMonitorTenantID.Enabled, ok) if mb.resourceAttributesSettings.AzureMonitorTenantID.Enabled { - enabledAttrCount++ assert.EqualValues(t, "attr-val", attrVal.Str()) } - assert.Equal(t, enabledAttrCount, rm.Resource().Attributes().Len()) - assert.Equal(t, 2, attrCount) + attrCount := rm.Resource().Attributes().Len() + assert.Equal(t, 1, attrCount) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() + + attrVal, ok = ms.At(0).Gauge().DataPoints().At(0).Attributes().Get("azuremonitor.subscription_id") + assert.Equal(t, mb.resourceAttributesSettings.AzureMonitorSubscriptionID.Enabled, ok) + if mb.resourceAttributesSettings.AzureMonitorSubscriptionID.Enabled { + assert.EqualValues(t, "subId1", attrVal.Str()) + } if test.configSet == testSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } diff --git a/receiver/azuremonitorreceiver/scraper.go b/receiver/azuremonitorreceiver/scraper.go index 99d24600faa5..bf28b8a093c7 100644 --- a/receiver/azuremonitorreceiver/scraper.go +++ b/receiver/azuremonitorreceiver/scraper.go @@ -16,11 +16,11 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" @@ -59,6 +59,15 @@ const ( tagPrefix = "tags_" ) +// azureSubscription is an extract of armsubscriptions.Subscription. +// It designates a common structure between complex structures retrieved from the AP +// and simple subscriptions ids that you can find in config. +type azureSubscription struct { + SubscriptionID string + DisplayName *string + resourcesUpdated time.Time +} + type azureResource struct { attributes map[string]*string metricsByCompositeKey map[metricsCompositeKey]*azureResourceMetrics @@ -80,45 +89,36 @@ type void struct{} func newScraper(conf *Config, settings receiver.Settings) *azureScraper { return &azureScraper{ - cfg: conf, - settings: settings.TelemetrySettings, - mb: metadata.NewMetricsBuilder(conf.MetricsBuilderConfig, settings), - azDefaultCredentialsFunc: azidentity.NewDefaultAzureCredential, - azIDCredentialsFunc: azidentity.NewClientSecretCredential, - azIDWorkloadFunc: azidentity.NewWorkloadIdentityCredential, - azManagedIdentityFunc: azidentity.NewManagedIdentityCredential, - armClientFunc: armresources.NewClient, - armMonitorDefinitionsClientFunc: armmonitor.NewMetricDefinitionsClient, - armMonitorMetricsClientFunc: armmonitor.NewMetricsClient, - mutex: &sync.Mutex{}, + cfg: conf, + settings: settings.TelemetrySettings, + mb: metadata.NewMetricsBuilder(conf.MetricsBuilderConfig, settings), + azDefaultCredentialsFunc: azidentity.NewDefaultAzureCredential, + azIDCredentialsFunc: azidentity.NewClientSecretCredential, + azIDWorkloadFunc: azidentity.NewWorkloadIdentityCredential, + azManagedIdentityFunc: azidentity.NewManagedIdentityCredential, + mutex: &sync.Mutex{}, } } type azureScraper struct { cred azcore.TokenCredential - - clientResources armClient - clientMetricsDefinitions metricsDefinitionsClientInterface - clientMetricsValues metricsValuesClient - - cfg *Config - settings component.TelemetrySettings - resources map[string]*azureResource - resourcesUpdated time.Time - mb *metadata.MetricsBuilder - azDefaultCredentialsFunc func(options *azidentity.DefaultAzureCredentialOptions) (*azidentity.DefaultAzureCredential, error) - azIDCredentialsFunc func(string, string, string, *azidentity.ClientSecretCredentialOptions) (*azidentity.ClientSecretCredential, error) - azIDWorkloadFunc func(options *azidentity.WorkloadIdentityCredentialOptions) (*azidentity.WorkloadIdentityCredential, error) - azManagedIdentityFunc func(options *azidentity.ManagedIdentityCredentialOptions) (*azidentity.ManagedIdentityCredential, error) - armClientOptions *arm.ClientOptions - armClientFunc func(string, azcore.TokenCredential, *arm.ClientOptions) (*armresources.Client, error) - armMonitorDefinitionsClientFunc func(string, azcore.TokenCredential, *arm.ClientOptions) (*armmonitor.MetricDefinitionsClient, error) - armMonitorMetricsClientFunc func(string, azcore.TokenCredential, *arm.ClientOptions) (*armmonitor.MetricsClient, error) - mutex *sync.Mutex -} - -type armClient interface { - NewListPager(options *armresources.ClientListOptions) *runtime.Pager[armresources.ClientListResponse] + + cfg *Config + settings component.TelemetrySettings + // resources on which we'll collect metrics. Stored by resource id and subscription id. + resources map[string]map[string]*azureResource + // subscriptions on which we'll look up resources. Stored by subscription id. + subscriptions map[string]*azureSubscription + subscriptionsUpdated time.Time + mb *metadata.MetricsBuilder + azDefaultCredentialsFunc func(options *azidentity.DefaultAzureCredentialOptions) (*azidentity.DefaultAzureCredential, error) + azIDCredentialsFunc func(string, string, string, *azidentity.ClientSecretCredentialOptions) (*azidentity.ClientSecretCredential, error) + azIDWorkloadFunc func(options *azidentity.WorkloadIdentityCredentialOptions) (*azidentity.WorkloadIdentityCredential, error) + azManagedIdentityFunc func(options *azidentity.ManagedIdentityCredentialOptions) (*azidentity.ManagedIdentityCredential, error) + armSubscriptionsClientOptions *arm.ClientOptions + armResourcesClientOptions *arm.ClientOptions + armMonitorClientOptions *arm.ClientOptions + mutex *sync.Mutex } func (s *azureScraper) getArmClientOptions() *arm.ClientOptions { @@ -140,52 +140,32 @@ func (s *azureScraper) getArmClientOptions() *arm.ClientOptions { return &options } -func (s *azureScraper) getArmClient() (armClient, error) { - client, err := s.armClientFunc(s.cfg.SubscriptionID, s.cred, s.armClientOptions) - return client, err -} - -type metricsDefinitionsClientInterface interface { - NewListPager(resourceURI string, options *armmonitor.MetricDefinitionsClientListOptions) *runtime.Pager[armmonitor.MetricDefinitionsClientListResponse] -} - -func (s *azureScraper) getMetricsDefinitionsClient() (metricsDefinitionsClientInterface, error) { - client, err := s.armMonitorDefinitionsClientFunc(s.cfg.SubscriptionID, s.cred, s.armClientOptions) - return client, err -} - -type metricsValuesClient interface { - List(ctx context.Context, resourceURI string, options *armmonitor.MetricsClientListOptions) ( - armmonitor.MetricsClientListResponse, error, - ) -} - -func (s *azureScraper) GetMetricsValuesClient() (metricsValuesClient, error) { - client, err := s.armMonitorMetricsClientFunc(s.cfg.SubscriptionID, s.cred, s.armClientOptions) - return client, err -} - func (s *azureScraper) start(_ context.Context, _ component.Host) (err error) { if err = s.loadCredentials(); err != nil { return err } - s.armClientOptions = s.getArmClientOptions() - s.clientResources, err = s.getArmClient() - if err != nil { - return err - } - s.clientMetricsDefinitions, err = s.getMetricsDefinitionsClient() - if err != nil { - return err - } - s.clientMetricsValues, err = s.GetMetricsValuesClient() - if err != nil { - return err + // Init the client options for each azure API + armClientOptions := s.getArmClientOptions() + s.armSubscriptionsClientOptions = armClientOptions + s.armResourcesClientOptions = armClientOptions + s.armMonitorClientOptions = armClientOptions + + s.subscriptions = map[string]*azureSubscription{} + s.resources = map[string]map[string]*azureResource{} + + // Initialize subscription ids from the config. Will be overridden if discovery is enabled anyway. + ids := []string{s.cfg.SubscriptionID} + ids = append(ids, s.cfg.SubscriptionIDs...) + for _, id := range ids { + if id != "" { + s.resources[id] = make(map[string]*azureResource) + s.subscriptions[id] = &azureSubscription{ + SubscriptionID: id, + } + } } - s.resources = map[string]*azureResource{} - return } @@ -220,37 +200,103 @@ func (s *azureScraper) loadCredentials() (err error) { } func (s *azureScraper) scrape(ctx context.Context) (pmetric.Metrics, error) { - s.getResources(ctx) - resourcesIDsWithDefinitions := make(chan string) - - go func() { - defer close(resourcesIDsWithDefinitions) - for resourceID := range s.resources { - s.getResourceMetricsDefinitions(ctx, resourceID) - resourcesIDsWithDefinitions <- resourceID - } - }() + s.getSubscriptions(ctx) var wg sync.WaitGroup - for resourceID := range resourcesIDsWithDefinitions { + for subscriptionID := range s.subscriptions { wg.Add(1) - go func(resourceID string) { + go func(subscriptionID string) { defer wg.Done() - s.getResourceMetricsValues(ctx, resourceID) - }(resourceID) + + s.getResources(ctx, subscriptionID) + + resourcesIDsWithDefinitions := make(chan string) + go func(subscriptionID string) { + defer close(resourcesIDsWithDefinitions) + for resourceID := range s.resources[subscriptionID] { + s.getResourceMetricsDefinitions(ctx, subscriptionID, resourceID) + resourcesIDsWithDefinitions <- resourceID + } + }(subscriptionID) + + var wg2 sync.WaitGroup + for resourceID := range resourcesIDsWithDefinitions { + wg2.Add(1) + go func(subscriptionID, resourceID string) { + defer wg2.Done() + s.getResourceMetricsValues(ctx, subscriptionID, resourceID) + }(subscriptionID, resourceID) + } + + wg2.Wait() + }(subscriptionID) + } + wg.Wait() return s.mb.Emit( - metadata.WithAzureMonitorSubscriptionID(s.cfg.SubscriptionID), metadata.WithAzureMonitorTenantID(s.cfg.TenantID), ), nil } -func (s *azureScraper) getResources(ctx context.Context) { - if time.Since(s.resourcesUpdated).Seconds() < s.cfg.CacheResources { +func (s *azureScraper) getSubscriptions(ctx context.Context) { + if !s.cfg.DiscoverSubscriptions || !(time.Since(s.subscriptionsUpdated).Seconds() < s.cfg.CacheResources) { + return + } + + // if subscriptions discovery is enabled, we'll need a client + armSubscriptionClient, clientErr := armsubscriptions.NewClient(s.cred, s.armSubscriptionsClientOptions) + if clientErr != nil { + s.settings.Logger.Error("failed to initialize the client to get Azure Subscriptions", zap.Error(clientErr)) return } + + opts := &armsubscriptions.ClientListOptions{} + pager := armSubscriptionClient.NewListPager(opts) + + existingSubscriptions := map[string]void{} + for id := range s.subscriptions { + existingSubscriptions[id] = void{} + } + + for pager.More() { + nextResult, err := pager.NextPage(ctx) + if err != nil { + s.settings.Logger.Error("failed to get Azure Subscriptions", zap.Error(err)) + return + } + + for _, subscription := range nextResult.Value { + s.resources[*subscription.SubscriptionID] = make(map[string]*azureResource) + s.subscriptions[*subscription.SubscriptionID] = &azureSubscription{ + SubscriptionID: *subscription.SubscriptionID, + DisplayName: subscription.DisplayName, + } + delete(existingSubscriptions, *subscription.SubscriptionID) + } + } + if len(existingSubscriptions) > 0 { + for idToDelete := range existingSubscriptions { + delete(s.resources, idToDelete) + delete(s.subscriptions, idToDelete) + } + } + + s.subscriptionsUpdated = time.Now() + return +} + +func (s *azureScraper) getResources(ctx context.Context, subscriptionID string) { + if time.Since(s.subscriptions[subscriptionID].resourcesUpdated).Seconds() < s.cfg.CacheResources { + return + } + clientResources, clientErr := armresources.NewClient(subscriptionID, s.cred, s.armResourcesClientOptions) + if clientErr != nil { + s.settings.Logger.Error("failed to initialize the client to get Azure Resources", zap.Error(clientErr)) + return + } + existingResources := map[string]void{} for id := range s.resources { existingResources[id] = void{} @@ -261,7 +307,7 @@ func (s *azureScraper) getResources(ctx context.Context) { Filter: &filter, } - pager := s.clientResources.NewListPager(opts) + pager := clientResources.NewListPager(opts) for pager.More() { nextResult, err := pager.NextPage(ctx) @@ -270,7 +316,7 @@ func (s *azureScraper) getResources(ctx context.Context) { return } for _, resource := range nextResult.Value { - if _, ok := s.resources[*resource.ID]; !ok { + if _, ok := s.resources[subscriptionID][*resource.ID]; !ok { resourceGroup := getResourceGroupFromID(*resource.ID) attributes := map[string]*string{ attributeName: resource.Name, @@ -280,7 +326,7 @@ func (s *azureScraper) getResources(ctx context.Context) { if resource.Location != nil { attributes[attributeLocation] = resource.Location } - s.resources[*resource.ID] = &azureResource{ + s.resources[subscriptionID][*resource.ID] = &azureResource{ attributes: attributes, tags: resource.Tags, } @@ -290,11 +336,12 @@ func (s *azureScraper) getResources(ctx context.Context) { } if len(existingResources) > 0 { for idToDelete := range existingResources { - delete(s.resources, idToDelete) + delete(s.resources[subscriptionID], idToDelete) } } - s.resourcesUpdated = time.Now() + s.subscriptions[subscriptionID].resourcesUpdated = time.Now() + return } func getResourceGroupFromID(id string) string { @@ -321,14 +368,20 @@ func (s *azureScraper) getResourcesFilter() string { return fmt.Sprintf("(resourceType eq '%s')%s", resourcesTypeFilter, resourcesGroupFilterString) } -func (s *azureScraper) getResourceMetricsDefinitions(ctx context.Context, resourceID string) { - if time.Since(s.resources[resourceID].metricsDefinitionsUpdated).Seconds() < s.cfg.CacheResourcesDefinitions { +func (s *azureScraper) getResourceMetricsDefinitions(ctx context.Context, subscriptionID, resourceID string) { + if time.Since(s.resources[subscriptionID][resourceID].metricsDefinitionsUpdated).Seconds() < s.cfg.CacheResourcesDefinitions { + return + } + + clientMetricsDefinitions, clientErr := armmonitor.NewMetricDefinitionsClient(subscriptionID, s.cred, s.armMonitorClientOptions) + if clientErr != nil { + s.settings.Logger.Error("failed to initialize the client to get Azure Metrics definitions", zap.Error(clientErr)) return } - s.resources[resourceID].metricsByCompositeKey = map[metricsCompositeKey]*azureResourceMetrics{} + s.resources[subscriptionID][resourceID].metricsByCompositeKey = map[metricsCompositeKey]*azureResourceMetrics{} - pager := s.clientMetricsDefinitions.NewListPager(resourceID, nil) + pager := clientMetricsDefinitions.NewListPager(resourceID, nil) for pager.More() { nextResult, err := pager.NextPage(ctx) if err != nil { @@ -351,24 +404,30 @@ func (s *azureScraper) getResourceMetricsDefinitions(ctx context.Context, resour sort.Strings(dimensionsSlice) compositeKey.dimensions = strings.Join(dimensionsSlice, ",") } - s.storeMetricsDefinition(resourceID, name, compositeKey) + s.storeMetricsDefinition(subscriptionID, resourceID, name, compositeKey) } } - s.resources[resourceID].metricsDefinitionsUpdated = time.Now() + s.resources[subscriptionID][resourceID].metricsDefinitionsUpdated = time.Now() } -func (s *azureScraper) storeMetricsDefinition(resourceID, name string, compositeKey metricsCompositeKey) { - if _, ok := s.resources[resourceID].metricsByCompositeKey[compositeKey]; ok { - s.resources[resourceID].metricsByCompositeKey[compositeKey].metrics = append( - s.resources[resourceID].metricsByCompositeKey[compositeKey].metrics, name, +func (s *azureScraper) storeMetricsDefinition(subscriptionID, resourceID, name string, compositeKey metricsCompositeKey) { + if _, ok := s.resources[subscriptionID][resourceID].metricsByCompositeKey[compositeKey]; ok { + s.resources[subscriptionID][resourceID].metricsByCompositeKey[compositeKey].metrics = append( + s.resources[subscriptionID][resourceID].metricsByCompositeKey[compositeKey].metrics, name, ) } else { - s.resources[resourceID].metricsByCompositeKey[compositeKey] = &azureResourceMetrics{metrics: []string{name}} + s.resources[subscriptionID][resourceID].metricsByCompositeKey[compositeKey] = &azureResourceMetrics{metrics: []string{name}} } } -func (s *azureScraper) getResourceMetricsValues(ctx context.Context, resourceID string) { - res := *s.resources[resourceID] +func (s *azureScraper) getResourceMetricsValues(ctx context.Context, subscriptionID, resourceID string) { + res := *s.resources[subscriptionID][resourceID] + + clientMetricsValues, clientErr := armmonitor.NewMetricsClient(subscriptionID, s.cred, s.armMonitorClientOptions) + if clientErr != nil { + s.settings.Logger.Error("failed to initialize the client to get Azure Metrics values", zap.Error(clientErr)) + return + } for compositeKey, metricsByGrain := range res.metricsByCompositeKey { if time.Since(metricsByGrain.metricsValuesUpdated).Seconds() < float64(timeGrains[compositeKey.timeGrain]) { @@ -394,7 +453,7 @@ func (s *azureScraper) getResourceMetricsValues(ctx context.Context, resourceID ) start = end - result, err := s.clientMetricsValues.List( + result, err := clientMetricsValues.List( ctx, resourceID, &opts, @@ -422,7 +481,7 @@ func (s *azureScraper) getResourceMetricsValues(ctx context.Context, resourceID } } for _, metricValue := range timeseriesElement.Data { - s.processTimeseriesData(resourceID, metric, metricValue, attributes) + s.processTimeseriesData(subscriptionID, resourceID, metric, metricValue, attributes) } } } @@ -466,7 +525,7 @@ func getResourceMetricsValuesRequestOptions( } func (s *azureScraper) processTimeseriesData( - resourceID string, + subscriptionID, resourceID string, metric *armmonitor.Metric, metricValue *armmonitor.MetricValue, attributes map[string]*string, @@ -489,6 +548,7 @@ func (s *azureScraper) processTimeseriesData( for _, aggregation := range aggregationsData { if aggregation.value != nil { s.mb.AddDataPoint( + subscriptionID, resourceID, *metric.Name.Value, aggregation.name, diff --git a/receiver/azuremonitorreceiver/scraper_test.go b/receiver/azuremonitorreceiver/scraper_test.go index cd53f3abf940..f06200a86991 100644 --- a/receiver/azuremonitorreceiver/scraper_test.go +++ b/receiver/azuremonitorreceiver/scraper_test.go @@ -5,6 +5,10 @@ package azuremonitorreceiver // import "github.com/open-telemetry/opentelemetry- import ( "context" + "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions" + "net/http" "path/filepath" "reflect" "strings" @@ -14,10 +18,13 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" + armmonitorfake "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor/fake" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" + armresourcesfake "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources/fake" + armsubscriptionsfake "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions/fake" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/receiver/receivertest" @@ -51,18 +58,6 @@ func azDefaultCredentialsFuncMock(*azidentity.DefaultAzureCredentialOptions) (*a return &azidentity.DefaultAzureCredential{}, nil } -func armClientFuncMock(string, azcore.TokenCredential, *arm.ClientOptions) (*armresources.Client, error) { - return &armresources.Client{}, nil -} - -func armMonitorDefinitionsClientFuncMock(string, azcore.TokenCredential, *arm.ClientOptions) (*armmonitor.MetricDefinitionsClient, error) { - return &armmonitor.MetricDefinitionsClient{}, nil -} - -func armMonitorMetricsClientFuncMock(string, azcore.TokenCredential, *arm.ClientOptions) (*armmonitor.MetricsClient, error) { - return &armmonitor.MetricsClient{}, nil -} - func TestAzureScraperStart(t *testing.T) { cfg := createDefaultConfig().(*Config) @@ -75,12 +70,9 @@ func TestAzureScraperStart(t *testing.T) { name: "default", testFunc: func(t *testing.T) { s := &azureScraper{ - cfg: cfg, - azIDCredentialsFunc: azIDCredentialsFuncMock, - azIDWorkloadFunc: azIDWorkloadFuncMock, - armClientFunc: armClientFuncMock, - armMonitorDefinitionsClientFunc: armMonitorDefinitionsClientFuncMock, - armMonitorMetricsClientFunc: armMonitorMetricsClientFuncMock, + cfg: cfg, + azIDCredentialsFunc: azIDCredentialsFuncMock, + azIDWorkloadFunc: azIDWorkloadFuncMock, } if err := s.start(context.Background(), componenttest.NewNopHost()); err != nil { @@ -103,12 +95,9 @@ func TestAzureScraperStart(t *testing.T) { Authentication: servicePrincipal, } s := &azureScraper{ - cfg: customCfg, - azIDCredentialsFunc: azIDCredentialsFuncMock, - azIDWorkloadFunc: azIDWorkloadFuncMock, - armClientFunc: armClientFuncMock, - armMonitorDefinitionsClientFunc: armMonitorDefinitionsClientFuncMock, - armMonitorMetricsClientFunc: armMonitorMetricsClientFuncMock, + cfg: customCfg, + azIDCredentialsFunc: azIDCredentialsFuncMock, + azIDWorkloadFunc: azIDWorkloadFuncMock, } if err := s.start(context.Background(), componenttest.NewNopHost()); err != nil { @@ -131,12 +120,9 @@ func TestAzureScraperStart(t *testing.T) { Authentication: workloadIdentity, } s := &azureScraper{ - cfg: customCfg, - azIDCredentialsFunc: azIDCredentialsFuncMock, - azIDWorkloadFunc: azIDWorkloadFuncMock, - armClientFunc: armClientFuncMock, - armMonitorDefinitionsClientFunc: armMonitorDefinitionsClientFuncMock, - armMonitorMetricsClientFunc: armMonitorMetricsClientFuncMock, + cfg: customCfg, + azIDCredentialsFunc: azIDCredentialsFuncMock, + azIDWorkloadFunc: azIDWorkloadFuncMock, } if err := s.start(context.Background(), componenttest.NewNopHost()); err != nil { @@ -159,12 +145,9 @@ func TestAzureScraperStart(t *testing.T) { Authentication: managedIdentity, } s := &azureScraper{ - cfg: customCfg, - azIDCredentialsFunc: azIDCredentialsFuncMock, - azManagedIdentityFunc: azManagedIdentityFuncMock, - armClientFunc: armClientFuncMock, - armMonitorDefinitionsClientFunc: armMonitorDefinitionsClientFuncMock, - armMonitorMetricsClientFunc: armMonitorMetricsClientFuncMock, + cfg: customCfg, + azIDCredentialsFunc: azIDCredentialsFuncMock, + azManagedIdentityFunc: azManagedIdentityFuncMock, } if err := s.start(context.Background(), componenttest.NewNopHost()); err != nil { @@ -187,12 +170,9 @@ func TestAzureScraperStart(t *testing.T) { Authentication: defaultCredentials, } s := &azureScraper{ - cfg: customCfg, - azIDCredentialsFunc: azIDCredentialsFuncMock, - azDefaultCredentialsFunc: azDefaultCredentialsFuncMock, - armClientFunc: armClientFuncMock, - armMonitorDefinitionsClientFunc: armMonitorDefinitionsClientFuncMock, - armMonitorMetricsClientFunc: armMonitorMetricsClientFuncMock, + cfg: customCfg, + azIDCredentialsFunc: azIDCredentialsFuncMock, + azDefaultCredentialsFunc: azDefaultCredentialsFuncMock, } if err := s.start(context.Background(), componenttest.NewNopHost()); err != nil { @@ -208,48 +188,39 @@ func TestAzureScraperStart(t *testing.T) { } } -type armClientMock struct { - current int - pages []armresources.ClientListResponse -} - -func (acm *armClientMock) NewListPager(_ *armresources.ClientListOptions) *runtime.Pager[armresources.ClientListResponse] { - return runtime.NewPager(runtime.PagingHandler[armresources.ClientListResponse]{ - More: func(armresources.ClientListResponse) bool { - return acm.current < len(acm.pages) - }, - Fetcher: func(context.Context, *armresources.ClientListResponse) (armresources.ClientListResponse, error) { - currentPage := acm.pages[acm.current] - acm.current++ - return currentPage, nil - }, - }) -} - -type metricsDefinitionsClientMock struct { - current map[string]int - pages map[string][]armmonitor.MetricDefinitionsClientListResponse +func newMockSubscriptionsListPager(pages []armsubscriptions.ClientListResponse) func(options *armsubscriptions.ClientListOptions) (resp azfake.PagerResponder[armsubscriptions.ClientListResponse]) { + return func(options *armsubscriptions.ClientListOptions) (resp azfake.PagerResponder[armsubscriptions.ClientListResponse]) { + for _, page := range pages { + resp.AddPage(http.StatusOK, page, nil) + } + return + } } -func (mdcm *metricsDefinitionsClientMock) NewListPager(resourceURI string, _ *armmonitor.MetricDefinitionsClientListOptions) *runtime.Pager[armmonitor.MetricDefinitionsClientListResponse] { - return runtime.NewPager(runtime.PagingHandler[armmonitor.MetricDefinitionsClientListResponse]{ - More: func(armmonitor.MetricDefinitionsClientListResponse) bool { - return mdcm.current[resourceURI] < len(mdcm.pages[resourceURI]) - }, - Fetcher: func(context.Context, *armmonitor.MetricDefinitionsClientListResponse) (armmonitor.MetricDefinitionsClientListResponse, error) { - currentPage := mdcm.pages[resourceURI][mdcm.current[resourceURI]] - mdcm.current[resourceURI]++ - return currentPage, nil - }, - }) +func newMockResourcesListPager(pages []armresources.ClientListResponse) func(options *armresources.ClientListOptions) (resp azfake.PagerResponder[armresources.ClientListResponse]) { + return func(options *armresources.ClientListOptions) (resp azfake.PagerResponder[armresources.ClientListResponse]) { + for _, page := range pages { + resp.AddPage(http.StatusOK, page, nil) + } + return + } } -type metricsValuesClientMock struct { - lists map[string]map[string]armmonitor.MetricsClientListResponse +func newMockMetricsDefinitionListPager(pagesByResourceURI map[string][]armmonitor.MetricDefinitionsClientListResponse) func(resourceURI string, options *armmonitor.MetricDefinitionsClientListOptions) (resp azfake.PagerResponder[armmonitor.MetricDefinitionsClientListResponse]) { + return func(resourceURI string, options *armmonitor.MetricDefinitionsClientListOptions) (resp azfake.PagerResponder[armmonitor.MetricDefinitionsClientListResponse]) { + resourceURI = fmt.Sprintf("/%s", resourceURI) // Hack the fake API as it's not taking starting slash from called request + for _, page := range pagesByResourceURI[resourceURI] { + resp.AddPage(http.StatusOK, page, nil) + } + return + } } - -func (mvcm metricsValuesClientMock) List(_ context.Context, resourceURI string, options *armmonitor.MetricsClientListOptions) (armmonitor.MetricsClientListResponse, error) { - return mvcm.lists[resourceURI][*options.Metricnames], nil +func newMockMetricList(listsByResourceURIAndMetricName map[string]map[string]armmonitor.MetricsClientListResponse) func(ctx context.Context, resourceURI string, options *armmonitor.MetricsClientListOptions) (resp azfake.Responder[armmonitor.MetricsClientListResponse], errResp azfake.ErrorResponder) { + return func(ctx context.Context, resourceURI string, options *armmonitor.MetricsClientListOptions) (resp azfake.Responder[armmonitor.MetricsClientListResponse], errResp azfake.ErrorResponder) { + resourceURI = fmt.Sprintf("/%s", resourceURI) // Hack the fake API as it's not taking starting slash from called request + resp.SetResponse(http.StatusOK, listsByResourceURIAndMetricName[resourceURI][*options.Metricnames], nil) + return + } } func TestAzureScraperScrape(t *testing.T) { @@ -261,6 +232,7 @@ func TestAzureScraperScrape(t *testing.T) { } cfg := createDefaultConfig().(*Config) cfg.MaximumNumberOfMetricsInACall = 2 + cfg.SubscriptionIDs = []string{"subscriptionId1"} cfgTagsEnabled := createDefaultConfig().(*Config) cfgTagsEnabled.AppendTagsAsAttributes = true @@ -296,31 +268,48 @@ func TestAzureScraperScrape(t *testing.T) { t.Run(tt.name, func(t *testing.T) { settings := receivertest.NewNopSettings() - armClientMock := &armClientMock{ - current: 0, - pages: getResourcesMockData(tt.fields.cfg.AppendTagsAsAttributes), + resourceServer := armresourcesfake.Server{ + NewListPager: newMockResourcesListPager(getResourcesMockData(tt.fields.cfg.AppendTagsAsAttributes)), } - - counters, pages := getMetricsDefinitionsMockData() - - metricsDefinitionsClientMock := &metricsDefinitionsClientMock{ - current: counters, - pages: pages, + subscriptionsServer := armsubscriptionsfake.Server{ + NewListPager: newMockSubscriptionsListPager(getSubscriptionsMockData()), } - - metricsValuesClientMock := &metricsValuesClientMock{ - lists: getMetricsValuesMockData(), + monitorServerFactory := armmonitorfake.ServerFactory{ + MetricDefinitionsServer: armmonitorfake.MetricDefinitionsServer{ + NewListPager: newMockMetricsDefinitionListPager(getMetricsDefinitionsMockData()), + }, + MetricsServer: armmonitorfake.MetricsServer{ + List: newMockMetricList(getMetricsValuesMockData()), + }, } s := &azureScraper{ - cfg: tt.fields.cfg, - clientResources: armClientMock, - clientMetricsDefinitions: metricsDefinitionsClientMock, - clientMetricsValues: metricsValuesClientMock, - mb: metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), settings), - mutex: &sync.Mutex{}, + cfg: tt.fields.cfg, + mb: metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), settings), + mutex: &sync.Mutex{}, + // From there, initialize everything that is normally initialized in start() func + armResourcesClientOptions: &arm.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: armresourcesfake.NewServerTransport(&resourceServer), + }, + }, + armSubscriptionsClientOptions: &arm.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: armsubscriptionsfake.NewServerTransport(&subscriptionsServer), + }, + }, + armMonitorClientOptions: &arm.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: armmonitorfake.NewServerFactoryTransport(&monitorServerFactory), + }, + }, + subscriptions: map[string]*azureSubscription{ + "subscriptionId1": {SubscriptionID: "subscriptionId1"}, + }, + resources: map[string]map[string]*azureResource{ + "subscriptionId1": {}, + }, } - s.resources = map[string]*azureResource{} metrics, err := s.scrape(tt.args.ctx) if (err != nil) != tt.wantErr { @@ -339,12 +328,33 @@ func TestAzureScraperScrape(t *testing.T) { pmetrictest.IgnoreMetricsOrder(), )) }) + + } +} + +func getSubscriptionsMockData() []armsubscriptions.ClientListResponse { + return []armsubscriptions.ClientListResponse{ + { + SubscriptionListResult: armsubscriptions.SubscriptionListResult{ + Value: []*armsubscriptions.Subscription{ + {ID: to.Ptr("subscriptionId1")}, + {ID: to.Ptr("subscriptionId2")}, + }, + }, + }, + { + SubscriptionListResult: armsubscriptions.SubscriptionListResult{ + Value: []*armsubscriptions.Subscription{ + {ID: to.Ptr("subscriptionId3")}, + }, + }, + }, } } func getResourcesMockData(tags bool) []armresources.ClientListResponse { - id1, id2, id3, location1, name1, type1 := "/resourceGroups/group1/resourceId1", - "/resourceGroups/group1/resourceId2", "/resourceGroups/group1/resourceId3", "location1", "name1", "type1" + id1, id2, id3, location1, name1, type1 := "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId1", + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId2", "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId3", "location1", "name1", "type1" resourceID1 := armresources.GenericResourceExpanded{ ID: &id1, @@ -385,18 +395,12 @@ func getResourcesMockData(tags bool) []armresources.ClientListResponse { } } -func getMetricsDefinitionsMockData() (map[string]int, map[string][]armmonitor.MetricDefinitionsClientListResponse) { +func getMetricsDefinitionsMockData() map[string][]armmonitor.MetricDefinitionsClientListResponse { name1, name2, name3, name4, name5, name6, name7, timeGrain1, timeGrain2, dimension1, dimension2 := "metric1", "metric2", "metric3", "metric4", "metric5", "metric6", "metric7", "PT1M", "PT1H", "dimension1", "dimension2" - counters := map[string]int{ - "/resourceGroups/group1/resourceId1": 0, - "/resourceGroups/group1/resourceId2": 0, - "/resourceGroups/group1/resourceId3": 0, - } - - pages := map[string][]armmonitor.MetricDefinitionsClientListResponse{ - "/resourceGroups/group1/resourceId1": { + return map[string][]armmonitor.MetricDefinitionsClientListResponse{ + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId1": { { MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: []*armmonitor.MetricDefinition{ @@ -434,7 +438,7 @@ func getMetricsDefinitionsMockData() (map[string]int, map[string][]armmonitor.Me }, }, }, - "/resourceGroups/group1/resourceId2": { + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId2": { { MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: []*armmonitor.MetricDefinition{ @@ -485,7 +489,7 @@ func getMetricsDefinitionsMockData() (map[string]int, map[string][]armmonitor.Me }, }, }, - "/resourceGroups/group1/resourceId3": { + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId3": { { MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: []*armmonitor.MetricDefinition{ @@ -509,7 +513,6 @@ func getMetricsDefinitionsMockData() (map[string]int, map[string][]armmonitor.Me }, }, } - return counters, pages } func getMetricsValuesMockData() map[string]map[string]armmonitor.MetricsClientListResponse { @@ -519,7 +522,7 @@ func getMetricsValuesMockData() map[string]map[string]armmonitor.MetricsClientLi var value1 float64 = 1 return map[string]map[string]armmonitor.MetricsClientListResponse{ - "/resourceGroups/group1/resourceId1": { + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId1": { strings.Join([]string{name1, name2}, ","): { Response: armmonitor.Response{ Value: []*armmonitor.Metric{ @@ -590,7 +593,7 @@ func getMetricsValuesMockData() map[string]map[string]armmonitor.MetricsClientLi }, }, }, - "/resourceGroups/group1/resourceId2": { + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId2": { name4: { Response: armmonitor.Response{ Value: []*armmonitor.Metric{ @@ -689,7 +692,7 @@ func getMetricsValuesMockData() map[string]map[string]armmonitor.MetricsClientLi }, }, }, - "/resourceGroups/group1/resourceId3": { + "/subscriptions/subscriptionId1/resourceGroups/group1/resourceId3": { name7: { Response: armmonitor.Response{ Value: []*armmonitor.Metric{ diff --git a/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_golden.yaml b/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_golden.yaml index 9aebbdd5a49e..445775e517a3 100644 --- a/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_golden.yaml +++ b/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_golden.yaml @@ -1,9 +1,6 @@ resourceMetrics: - resource: attributes: - - key: azuremonitor.subscription_id - value: - stringValue: "" - key: azuremonitor.tenant_id value: stringValue: "" @@ -15,7 +12,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -38,7 +38,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -61,7 +64,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -84,7 +90,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -107,7 +116,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -136,7 +148,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -165,7 +180,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -194,7 +212,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -217,7 +238,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -240,7 +264,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -266,7 +293,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -289,7 +319,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -312,7 +345,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -335,7 +371,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -358,7 +397,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId3 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId3 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -384,7 +426,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -413,7 +458,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -439,7 +487,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -462,7 +513,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -485,7 +539,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -508,7 +565,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -531,7 +591,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -554,7 +617,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -577,7 +643,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -606,7 +675,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -629,7 +701,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -652,7 +727,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -675,7 +753,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -701,7 +782,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -727,7 +811,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -750,7 +837,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 diff --git a/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_tags_golden.yaml b/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_tags_golden.yaml index a00a60aa3c09..0f19d3af4d36 100644 --- a/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_tags_golden.yaml +++ b/receiver/azuremonitorreceiver/testdata/expected_metrics/metrics_tags_golden.yaml @@ -1,9 +1,6 @@ resourceMetrics: - resource: attributes: - - key: azuremonitor.subscription_id - value: - stringValue: "" - key: azuremonitor.tenant_id value: stringValue: "" @@ -15,7 +12,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -44,7 +44,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -70,7 +73,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -96,7 +102,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -122,7 +131,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -148,7 +160,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -174,7 +189,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -200,7 +218,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -223,7 +244,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId3 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId3 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -249,7 +273,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -275,7 +302,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -301,7 +331,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -327,7 +360,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -356,7 +392,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -382,7 +421,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -408,7 +450,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -437,7 +482,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -463,7 +511,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -489,7 +540,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -515,7 +569,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -544,7 +601,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -570,7 +630,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -596,7 +659,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -619,7 +685,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -648,7 +717,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -671,7 +743,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -697,7 +772,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -723,7 +801,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId1 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId1 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -749,7 +830,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -772,7 +856,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1 @@ -798,7 +885,10 @@ resourceMetrics: attributes: - key: azuremonitor.resource_id value: - stringValue: /resourceGroups/group1/resourceId2 + stringValue: /subscriptions/subscriptionId1/resourceGroups/group1/resourceId2 + - key: azuremonitor.subscription_id + value: + stringValue: subscriptionId1 - key: location value: stringValue: location1