diff --git a/docker/docker-compose-examples/analytics/setup/db/clickhouse/init-scripts/init.sql b/docker/docker-compose-examples/analytics/setup/db/clickhouse/init-scripts/init.sql
index 419a5a60ce07..1802cd6c964d 100644
--- a/docker/docker-compose-examples/analytics/setup/db/clickhouse/init-scripts/init.sql
+++ b/docker/docker-compose-examples/analytics/setup/db/clickhouse/init-scripts/init.sql
@@ -4,6 +4,10 @@ CREATE TABLE IF NOT EXISTS clickhouse_test_db.events
_timestamp DateTime,
api_key String,
cluster_id String,
+ customer_name String,
+ customer_category String,
+ environment_name String,
+ environment_version String,
customer_id String,
doc_encoding String,
doc_host String,
@@ -110,3 +114,9 @@ ALTER TABLE clickhouse_test_db.events DROP COLUMN IF EXISTS object_detail_page_u
ALTER TABLE clickhouse_test_db.events DROP COLUMN IF EXISTS object_url;
ALTER TABLE clickhouse_test_db.events DROP COLUMN IF EXISTS object_forward_to;
ALTER TABLE clickhouse_test_db.events DROP COLUMN IF EXISTS comefromvanityurl;
+
+
+ALTER TABLE clickhouse_test_db.events ADD COLUMN IF NOT EXISTS customer_name String;
+ALTER TABLE clickhouse_test_db.events ADD COLUMN IF NOT EXISTS customer_category String;
+ALTER TABLE clickhouse_test_db.events ADD COLUMN IF NOT EXISTS environment_name String;
+ALTER TABLE clickhouse_test_db.events ADD COLUMN IF NOT EXISTS environment_version String;
\ No newline at end of file
diff --git a/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/BasicProfileCollector.java b/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/BasicProfileCollector.java
index 6057c93b9221..b9d25248479a 100644
--- a/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/BasicProfileCollector.java
+++ b/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/BasicProfileCollector.java
@@ -1,13 +1,15 @@
package com.dotcms.analytics.track.collectors;
import com.dotcms.enterprise.cluster.ClusterFactory;
+import com.dotcms.exception.ExceptionUtil;
+import com.dotcms.telemetry.business.MetricsAPI;
import com.dotcms.util.FunctionUtils;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.web.WebAPILocator;
-import com.dotmarketing.util.PageMode;
+import com.dotmarketing.exception.DotDataException;
+import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.liferay.portal.model.User;
-import com.liferay.util.StringPool;
import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
@@ -15,12 +17,14 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
- * Collects the basic profile information for a collector payload bean.
+ * Collects the basic profile information for a collector payload bean. It's worth noting that
+ * ALLALL data collectors will include the information added by this one.
+ *
* @author jsanca
+ * @since Sep 17th, 2024
*/
public class BasicProfileCollector implements Collector {
@@ -56,6 +60,8 @@ public CollectorPayloadBean collect(final CollectorContextMap collectorContextMa
collectorPayloadBean.put(SESSION_ID, sessionId);
collectorPayloadBean.put(SESSION_NEW, sessionNew);
+ this.setCustomerTelemetryData(collectorPayloadBean);
+
if (UtilMethods.isSet(collectorContextMap.get(CollectorContextMap.REFERER))) {
collectorPayloadBean.put(REFERER, collectorContextMap.get(CollectorContextMap.REFERER).toString());
}
@@ -83,13 +89,34 @@ public CollectorPayloadBean collect(final CollectorContextMap collectorContextMa
return collectorPayloadBean;
}
+ /**
+ * Sets the customer Telemetry data as part of the information that will be persisted to the
+ * Content Analytics database.
+ *
+ * @param collectorPayloadBean The {@link CollectorPayloadBean} that will be persisted to the
+ * Content Analytics database.
+ */
+ private void setCustomerTelemetryData(final CollectorPayloadBean collectorPayloadBean) {
+ final MetricsAPI metricsAPI = APILocator.getMetricsAPI();
+ try {
+ final MetricsAPI.Client client = metricsAPI.getClient();
+ collectorPayloadBean.put(CUSTOMER_NAME, client.getClientName());
+ collectorPayloadBean.put(CUSTOMER_CATEGORY, client.getCategory());
+ collectorPayloadBean.put(ENVIRONMENT_NAME, client.getEnvironment());
+ collectorPayloadBean.put(ENVIRONMENT_VERSION, client.getVersion());
+ } catch (final DotDataException e) {
+ Logger.warnAndDebug(BasicProfileCollector.class, String.format("Failed to retrieve customer Telemetry data: " +
+ "%s", ExceptionUtil.getErrorMessage(e)), e);
+ }
+ }
+
private void setUserInfo(final HttpServletRequest request, final CollectorPayloadBean collectorPayloadBean) {
final User user = WebAPILocator.getUserWebAPI().getUser(request);
if (Objects.nonNull(user)) {
final HashMap userObject = new HashMap<>();
- userObject.put(ID, user.getUserId().toString());
+ userObject.put(ID, user.getUserId());
userObject.put(EMAIL, user.getEmailAddress());
collectorPayloadBean.put(USER_OBJECT, userObject);
}
diff --git a/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/Collector.java b/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/Collector.java
index f77ed70d7aed..0e783e1cf5bf 100644
--- a/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/Collector.java
+++ b/dotCMS/src/main/java/com/dotcms/analytics/track/collectors/Collector.java
@@ -47,11 +47,9 @@ public interface Collector {
String USER_AGENT = "userAgent";
String UTC_TIME = "utc_time";
-
String RESPONSE = "action";
String RESPONSE_CODE = "response_code";
-
String DETAIL_PAGE_URL = "detail_page_url";
String IS_EXPERIMENT_PAGE = "isexperimentpage";
String IS_TARGET_PAGE = "istargetpage";
@@ -61,6 +59,12 @@ public interface Collector {
String EMAIL = "email";
String USER_OBJECT = "user";
+
+ String CUSTOMER_NAME = "customer_name";
+ String CUSTOMER_CATEGORY = "customer_category";
+ String ENVIRONMENT_NAME = "environment_name";
+ String ENVIRONMENT_VERSION = "environment_version";
+
/**
* Test if the collector should run
* @param collectorContextMap
diff --git a/dotcms-integration/src/test/java/com/dotcms/analytics/track/collectors/BasicProfileCollectorTest.java b/dotcms-integration/src/test/java/com/dotcms/analytics/track/collectors/BasicProfileCollectorTest.java
index 16b72e4d2d4d..0149cea7f13b 100644
--- a/dotcms-integration/src/test/java/com/dotcms/analytics/track/collectors/BasicProfileCollectorTest.java
+++ b/dotcms-integration/src/test/java/com/dotcms/analytics/track/collectors/BasicProfileCollectorTest.java
@@ -4,6 +4,7 @@
import com.dotcms.LicenseTestUtil;
import com.dotcms.analytics.track.matchers.PagesAndUrlMapsRequestMatcher;
import com.dotcms.enterprise.cluster.ClusterFactory;
+import com.dotcms.telemetry.business.MetricsAPI;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.exception.DotDataException;
@@ -17,11 +18,18 @@
import java.net.UnknownHostException;
import java.util.Map;
+import static com.dotcms.analytics.track.collectors.Collector.CUSTOMER_CATEGORY;
+import static com.dotcms.analytics.track.collectors.Collector.CUSTOMER_NAME;
+import static com.dotcms.analytics.track.collectors.Collector.ENVIRONMENT_NAME;
+import static com.dotcms.analytics.track.collectors.Collector.ENVIRONMENT_VERSION;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
/**
+ * Verifies that the {@link BasicProfileCollector} is able to collect the basic profile data and
+ * works as expected.
*
* @author Jose Castro
* @since Oct 9th, 2024
@@ -43,9 +51,13 @@ public static void prepare() throws Exception {
/**
*
- * - Method to test: {@link }
- * - Given Scenario:
- * - Expected Result:
+ * - Method to test:
+ * {@link BasicProfileCollector#collect(CollectorContextMap, CollectorPayloadBean)}
+ * - Given Scenario: Simulate the collection of Basic Profile data, which is
+ * data that is ALWAYS collected for any kind of Data Collector, and compare it with an
+ * expected data map.
+ * - Expected Result: Both the collected data map and the expected data must
+ * match.
*
*/
@Test
@@ -54,7 +66,7 @@ public void collectBasicProfileData() throws DotDataException, UnknownHostExcept
final String requestId = UUIDUtil.uuid();
final HttpServletRequest request = Util.mockHttpRequestObj(response, "/", requestId,
APILocator.getUserAPI().getAnonymousUser());
- final Map expectedDataMap = Map.of(
+ final Map expectedDataMap = new java.util.HashMap<>(Map.of(
Collector.CLUSTER, CLUSTER_ID,
Collector.SERVER, SERVER_ID,
Collector.PERSONA, "dot:default",
@@ -63,7 +75,22 @@ public void collectBasicProfileData() throws DotDataException, UnknownHostExcept
Collector.USER_AGENT, Util.USER_AGENT,
Collector.SESSION_ID, "DAA3339CD687D9ABD4101CF9EDDD42DB",
Collector.REQUEST_ID, requestId
- );
+ ));
+ expectedDataMap.putAll(Map.of(
+ Collector.EVENT_SOURCE, EventSource.DOT_CMS.getName(),
+ Collector.IS_TARGET_PAGE, false,
+ Collector.IS_EXPERIMENT_PAGE, false,
+ Collector.USER_OBJECT, Map.of(
+ "identifier", "anonymous",
+ "email", "anonymous@dotcms.anonymoususer")));
+ // The values returned when running the Integration Tests are random. So, in this case,
+ // we'll just verify that the attributes are present, and add any values in here
+ expectedDataMap.putAll(Map.of(
+ CUSTOMER_NAME, "",
+ CUSTOMER_CATEGORY, "",
+ ENVIRONMENT_NAME, "",
+ ENVIRONMENT_VERSION, 0
+ ));
final Collector collector = new BasicProfileCollector();
final CollectorPayloadBean collectedData = Util.getCollectorPayloadBean(request, collector, new PagesAndUrlMapsRequestMatcher(), null);
@@ -74,13 +101,25 @@ public void collectBasicProfileData() throws DotDataException, UnknownHostExcept
if (collectedData.toMap().containsKey(key)) {
final Object expectedValue = expectedDataMap.get(key);
final Object collectedValue = collectedData.toMap().get(key);
- if (!Collector.UTC_TIME.equalsIgnoreCase(key)) {
+ if (CUSTOMER_NAME.equalsIgnoreCase(key) || CUSTOMER_CATEGORY.equalsIgnoreCase(key) ||
+ ENVIRONMENT_NAME.equalsIgnoreCase(key) || ENVIRONMENT_VERSION.equalsIgnoreCase(key)) {
+ assertNotNull(String.format("Collected value '%s' cannot be null", key), collectedValue);
+ } else if (!Collector.UTC_TIME.equalsIgnoreCase(key)) {
assertEquals("Collected value must be equal to expected value for key: " + key, expectedValue, collectedValue);
}
counter++;
}
}
- assertEquals("Number of returned expected properties doesn't match", counter, expectedDataMap.size());
+ final MetricsAPI metricsAPI = APILocator.getMetricsAPI();
+ final MetricsAPI.Client client = metricsAPI.getClient();
+ // In local envs, the 'category_name' attribute maybe null, and is NOT added to the
+ // collected data map, so the assertion below would fail. This hack is just to make this
+ // test run locally without devs having to tweak it
+ final boolean areAllAttrsPresent = client.getVersion() >= 0 && UtilMethods.isSet(client.getEnvironment()) &&
+ UtilMethods.isSet(client.getCategory()) && UtilMethods.isSet(client.getClientName());
+ if (areAllAttrsPresent) {
+ assertEquals("Number of returned expected properties doesn't match", counter, expectedDataMap.size());
+ }
}
}