From 2bb79e0b2ecafc04e8c24709736b1a617150db44 Mon Sep 17 00:00:00 2001
From: Andre Onuki
Date: Thu, 19 Sep 2024 15:28:28 -0400
Subject: [PATCH 1/4] Cloud API
---
.../newrelic/agent/bridge/AgentBridge.java | 2 +
.../com/newrelic/agent/bridge/CloudApi.java | 31 +++++++
.../com/newrelic/agent/bridge/NoOpAgent.java | 6 ++
.../com/newrelic/agent/bridge/NoOpCloud.java | 37 ++++++++
.../agent/extension/FakeExtensionAgent.java | 6 ++
.../java/com/newrelic/agent/AgentImpl.java | 6 ++
.../java/com/newrelic/agent/MetricNames.java | 5 +
.../agent/cloud/CloudAccountInfoCache.java | 74 +++++++++++++++
.../newrelic/agent/cloud/CloudApiImpl.java | 61 ++++++++++++
.../newrelic/agent/core/CoreServiceImpl.java | 2 +
.../cloud/CloudAccountInfoCacheTest.java | 74 +++++++++++++++
.../agent/cloud/CloudApiImplTest.java | 92 +++++++++++++++++++
.../java/com/newrelic/api/agent/Agent.java | 7 ++
.../java/com/newrelic/api/agent/Cloud.java | 50 ++++++++++
.../newrelic/api/agent/CloudAccountInfo.java | 16 ++++
.../com/newrelic/api/agent/NoOpAgent.java | 13 +++
.../opentelemetry/OpenTelemetryAgent.java | 6 ++
17 files changed, 488 insertions(+)
create mode 100644 agent-bridge/src/main/java/com/newrelic/agent/bridge/CloudApi.java
create mode 100644 agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpCloud.java
create mode 100644 newrelic-agent/src/main/java/com/newrelic/agent/cloud/CloudAccountInfoCache.java
create mode 100644 newrelic-agent/src/main/java/com/newrelic/agent/cloud/CloudApiImpl.java
create mode 100644 newrelic-agent/src/test/java/com/newrelic/agent/cloud/CloudAccountInfoCacheTest.java
create mode 100644 newrelic-agent/src/test/java/com/newrelic/agent/cloud/CloudApiImplTest.java
create mode 100644 newrelic-api/src/main/java/com/newrelic/api/agent/Cloud.java
create mode 100644 newrelic-api/src/main/java/com/newrelic/api/agent/CloudAccountInfo.java
diff --git a/agent-bridge/src/main/java/com/newrelic/agent/bridge/AgentBridge.java b/agent-bridge/src/main/java/com/newrelic/agent/bridge/AgentBridge.java
index a5511e2d7c..18270c8789 100644
--- a/agent-bridge/src/main/java/com/newrelic/agent/bridge/AgentBridge.java
+++ b/agent-bridge/src/main/java/com/newrelic/agent/bridge/AgentBridge.java
@@ -42,6 +42,8 @@ public final class AgentBridge {
public static volatile AsyncApi asyncApi = new NoOpAsyncApi();
+ public static volatile CloudApi cloud = NoOpCloud.INSTANCE;
+
public static volatile CollectionFactory collectionFactory = new DefaultCollectionFactory();
/**
diff --git a/agent-bridge/src/main/java/com/newrelic/agent/bridge/CloudApi.java b/agent-bridge/src/main/java/com/newrelic/agent/bridge/CloudApi.java
new file mode 100644
index 0000000000..529ad91415
--- /dev/null
+++ b/agent-bridge/src/main/java/com/newrelic/agent/bridge/CloudApi.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * * Copyright 2024 New Relic Corporation. All rights reserved.
+ * * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+package com.newrelic.agent.bridge;
+
+import com.newrelic.api.agent.Cloud;
+import com.newrelic.api.agent.CloudAccountInfo;
+
+/**
+ * Internal Cloud API. This extends the public Cloud API and adds methods
+ * for retrieving the data set by the public API methods.
+ */
+public interface CloudApi extends Cloud {
+
+ /**
+ * Return the general account information of the provided type.
+ * This data is either set by {@link Cloud#setAccountInfo(CloudAccountInfo, String)}
+ * or the agent config.
+ */
+ String getAccountInfo(CloudAccountInfo cloudAccountInfo);
+
+ /**
+ * Retrieves the account information for a cloud service SDK client.
+ * If no data was recorded for the SDK client, the general account information will be returned.
+ */
+ String getAccountInfo(Object sdkClient, CloudAccountInfo cloudAccountInfo);
+}
diff --git a/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpAgent.java b/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpAgent.java
index 904f3fdcfb..2d654f1a30 100644
--- a/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpAgent.java
+++ b/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpAgent.java
@@ -8,6 +8,7 @@
package com.newrelic.agent.bridge;
import com.newrelic.api.agent.AiMonitoring;
+import com.newrelic.api.agent.Cloud;
import com.newrelic.api.agent.Config;
import com.newrelic.api.agent.ErrorApi;
import com.newrelic.api.agent.Insights;
@@ -73,6 +74,11 @@ public AiMonitoring getAiMonitoring() {
return NoOpAiMonitoring.INSTANCE;
}
+ @Override
+ public Cloud getCloud() {
+ return NoOpCloud.INSTANCE;
+ }
+
@Override
public ErrorApi getErrorApi() {
return NoOpErrorApi.INSTANCE;
diff --git a/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpCloud.java b/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpCloud.java
new file mode 100644
index 0000000000..1b3ab7889a
--- /dev/null
+++ b/agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpCloud.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * * Copyright 2024 New Relic Corporation. All rights reserved.
+ * * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+package com.newrelic.agent.bridge;
+
+import com.newrelic.api.agent.CloudAccountInfo;
+
+public class NoOpCloud implements CloudApi {
+
+ public static final CloudApi INSTANCE = new NoOpCloud();
+
+ private NoOpCloud() {
+ // only instance should be the INSTANCE
+ }
+
+ @Override
+ public void setAccountInfo(CloudAccountInfo cloudAccountInfo, String value) {
+ }
+
+ @Override
+ public void setAccountInfo(Object sdkClient, CloudAccountInfo cloudAccountInfo, String value) {
+ }
+
+ @Override
+ public String getAccountInfo(CloudAccountInfo cloudAccountInfo) {
+ return null;
+ }
+
+ @Override
+ public String getAccountInfo(Object sdkClient, CloudAccountInfo cloudAccountInfo) {
+ return null;
+ }
+}
diff --git a/functional_test/src/test/java/com/newrelic/agent/extension/FakeExtensionAgent.java b/functional_test/src/test/java/com/newrelic/agent/extension/FakeExtensionAgent.java
index e6bb7559d2..3201fe67d1 100644
--- a/functional_test/src/test/java/com/newrelic/agent/extension/FakeExtensionAgent.java
+++ b/functional_test/src/test/java/com/newrelic/agent/extension/FakeExtensionAgent.java
@@ -11,6 +11,7 @@
import com.newrelic.agent.bridge.TracedMethod;
import com.newrelic.agent.bridge.Transaction;
import com.newrelic.api.agent.AiMonitoring;
+import com.newrelic.api.agent.Cloud;
import com.newrelic.api.agent.Config;
import com.newrelic.api.agent.ErrorApi;
import com.newrelic.api.agent.Insights;
@@ -44,6 +45,11 @@ public AiMonitoring getAiMonitoring() {
return null;
}
+ @Override
+ public Cloud getCloud() {
+ return null;
+ }
+
@Override
public ErrorApi getErrorApi() { throw new RuntimeException(); }
diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/AgentImpl.java b/newrelic-agent/src/main/java/com/newrelic/agent/AgentImpl.java
index 2acd5efd7a..aa20d24c35 100644
--- a/newrelic-agent/src/main/java/com/newrelic/agent/AgentImpl.java
+++ b/newrelic-agent/src/main/java/com/newrelic/agent/AgentImpl.java
@@ -17,6 +17,7 @@
import com.newrelic.agent.service.ServiceFactory;
import com.newrelic.agent.tracers.Tracer;
import com.newrelic.api.agent.AiMonitoring;
+import com.newrelic.api.agent.Cloud;
import com.newrelic.api.agent.ErrorApi;
import com.newrelic.api.agent.Insights;
import com.newrelic.api.agent.Logger;
@@ -144,6 +145,11 @@ public AiMonitoring getAiMonitoring() {
return new AiMonitoringImpl();
}
+ @Override
+ public Cloud getCloud() {
+ return AgentBridge.cloud;
+ }
+
@Override
public Logs getLogSender() {
return ServiceFactory.getServiceManager().getLogSenderService();
diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/MetricNames.java b/newrelic-agent/src/main/java/com/newrelic/agent/MetricNames.java
index 0a426c81b7..3666a607cd 100644
--- a/newrelic-agent/src/main/java/com/newrelic/agent/MetricNames.java
+++ b/newrelic-agent/src/main/java/com/newrelic/agent/MetricNames.java
@@ -361,6 +361,11 @@ public class MetricNames {
public static final String SUPPORTABILITY_API_SET_ACCOUNT_NAME = "SetAccountName";
public static final String SUPPORTABILITY_API_SET_USER_ID = "SetUserId";
+ // Cloud API
+ public static final String SUPPORTABILITY_API_CLOUD_SET_ACCOUNT_INFO_CLIENT = "Cloud/SetAccountInfoClient/";
+ public static final String SUPPORTABILITY_API_CLOUD_SET_ACCOUNT_INFO = "Cloud/SetAccountInfo/";
+ public static final String SUPPORTABILITY_CONFIG_AWS_ACCOUNT_ID = "Supportability/Cloud/ConfigAccountInfo/aws_account_id";
+
//Transaction supportability metrics
public static final String SUPPORTABILITY_TRANSACTION_STARTED = "Supportability/Transaction/StartedCount";
public static final String SUPPORTABILITY_TRANSACTION_FINISHED = "Supportability/Transaction/FinishedCount";
diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/cloud/CloudAccountInfoCache.java b/newrelic-agent/src/main/java/com/newrelic/agent/cloud/CloudAccountInfoCache.java
new file mode 100644
index 0000000000..4cf9f5c0be
--- /dev/null
+++ b/newrelic-agent/src/main/java/com/newrelic/agent/cloud/CloudAccountInfoCache.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * * Copyright 2024 New Relic Corporation. All rights reserved.
+ * * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+package com.newrelic.agent.cloud;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import com.newrelic.agent.MetricNames;
+import com.newrelic.agent.config.AgentConfig;
+import com.newrelic.agent.service.ServiceFactory;
+import com.newrelic.api.agent.CloudAccountInfo;
+import com.newrelic.api.agent.NewRelic;
+
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Map;
+
+/**
+ * This class implements the account info methods from the Cloud API.
+ */
+public class CloudAccountInfoCache {
+ private final LoadingCache
+ *
+ * Passing null as the value will remove the account information previously stored.
+ *
* @param cloudAccountInfo the type of account information being stored
* @param value the value to store
*/
@@ -42,6 +45,9 @@ public interface Cloud {
* The value provided to this method has priority over a value set in
* the agent configuration or a value set using {@link #setAccountInfo(CloudAccountInfo, String)}.
*
+ *
+ * Passing null as the value will remove the account information previously stored.
+ *
* @param sdkClient the SDK client object this account information is associated with
* @param cloudAccountInfo the type of account information being stored
* @param value the value to store