feat: Added more data to existing analytics events (#15684)

* feat: added more data to existing analytics events

* Added extra audit data points for page and action events

* Corrected minor comment issue

* Review changes

* Removed audit references in variable names

* Review changes related to sending analytics events and DB optimization
This commit is contained in:
Vishnu Gp 2022-08-09 18:35:00 +05:30 committed by GitHub
parent ec29bbfac4
commit 2c03cecbb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 19 deletions

View File

@ -115,7 +115,11 @@ public class FieldName {
public static final String THEME = "theme"; public static final String THEME = "theme";
public static final String EDIT_MODE_THEME = "editModeTheme"; public static final String EDIT_MODE_THEME = "editModeTheme";
public static final String FLOW_NAME = "flowName"; public static final String FLOW_NAME = "flowName";
public static final String AUDIT_DATA = "auditData"; public static final String EVENT_DATA = "eventData";
public static final String MODE_OF_LOGIN = "modeOfLogin"; public static final String MODE_OF_LOGIN = "modeOfLogin";
public static final String FORM_LOGIN = "FormLogin"; public static final String FORM_LOGIN = "FormLogin";
public static final String VIEW_MODE = "viewMode";
public static final String ACTION_EXECUTION_REQUEST = "actionExecutionRequest";
public static final String ACTION_EXECUTION_RESULT = "actionExecutionResult";
public static final String ACTION_EXECUTION_TIME = "actionExecutionTime";
} }

View File

@ -164,7 +164,8 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
return Mono.just(object); return Mono.just(object);
} }
final String eventTag = event.getEventName() + "_" + object.getClass().getSimpleName().toUpperCase(); // In case of action execution, event.getEventName() only is used to support backward compatibility of event name
final String eventTag = AnalyticsEvents.EXECUTE_ACTION.equals(event) ? event.getEventName() : event.getEventName() + "_" + object.getClass().getSimpleName().toUpperCase();
// We will create an anonymous user object for event tracking if no user is present // We will create an anonymous user object for event tracking if no user is present
// Without this, a lot of flows meant for anonymous users will error out // Without this, a lot of flows meant for anonymous users will error out
@ -197,8 +198,8 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
analyticsProperties.put("oid", object.getId()); analyticsProperties.put("oid", object.getId());
if (extraProperties != null) { if (extraProperties != null) {
analyticsProperties.putAll(extraProperties); analyticsProperties.putAll(extraProperties);
// To avoid sending extra audit data to analytics // To avoid sending extra event data to analytics
analyticsProperties.remove(FieldName.AUDIT_DATA); analyticsProperties.remove(FieldName.EVENT_DATA);
} }
sendEvent(eventTag, username, analyticsProperties); sendEvent(eventTag, username, analyticsProperties);

View File

@ -1117,7 +1117,7 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
private Mono<Application> sendCloneApplicationAnalyticsEvent(Application sourceApplication, Application application) { private Mono<Application> sendCloneApplicationAnalyticsEvent(Application sourceApplication, Application application) {
return workspaceService.getById(application.getWorkspaceId()) return workspaceService.getById(application.getWorkspaceId())
.flatMap(workspace -> { .flatMap(workspace -> {
final Map<String, Object> auditData = Map.of( final Map<String, Object> eventData = Map.of(
FieldName.SOURCE_APPLICATION, sourceApplication, FieldName.SOURCE_APPLICATION, sourceApplication,
FieldName.APPLICATION, application, FieldName.APPLICATION, application,
FieldName.WORKSPACE, workspace FieldName.WORKSPACE, workspace
@ -1127,7 +1127,7 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
FieldName.SOURCE_APPLICATION_ID, sourceApplication.getId(), FieldName.SOURCE_APPLICATION_ID, sourceApplication.getId(),
FieldName.APPLICATION_ID, application.getId(), FieldName.APPLICATION_ID, application.getId(),
FieldName.WORKSPACE_ID, workspace.getId(), FieldName.WORKSPACE_ID, workspace.getId(),
FieldName.AUDIT_DATA, auditData FieldName.EVENT_DATA, eventData
); );
return analyticsService.sendObjectEvent(AnalyticsEvents.CLONE, application, data); return analyticsService.sendObjectEvent(AnalyticsEvents.CLONE, application, data);
@ -1145,13 +1145,12 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
return Mono.empty(); return Mono.empty();
} }
//TODO: Add more audit data final Map<String, Object> eventData = Map.of(
final Map<String, Object> auditData = Map.of(
FieldName.PAGE, newPage FieldName.PAGE, newPage
); );
final Map<String, Object> data = Map.of( final Map<String, Object> data = Map.of(
FieldName.AUDIT_DATA, auditData FieldName.EVENT_DATA, eventData
); );
return analyticsService.sendObjectEvent(AnalyticsEvents.VIEW, newPage, data); return analyticsService.sendObjectEvent(AnalyticsEvents.VIEW, newPage, data);

View File

@ -990,13 +990,15 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
ActionExecutionResult actionExecutionResult, ActionExecutionResult actionExecutionResult,
Long timeElapsed Long timeElapsed
) { ) {
// Since we're loading the application from DB *only* for analytics, we check if analytics is // Since we're loading the application from DB *only* for analytics, we check if analytics is
// active before making the call to DB. // active before making the call to DB.
if (!analyticsService.isActive()) { if (!analyticsService.isActive()) {
// This is to have consistency in how the AnalyticsService is being called.
// Even though sendObjectEvent is triggered, AnalyticsService would still reject this and prevent the event
// from being sent to analytics provider if telemetry is disabled.
analyticsService.sendObjectEvent(AnalyticsEvents.EXECUTE_ACTION, action);
return Mono.empty(); return Mono.empty();
} }
ActionExecutionRequest actionExecutionRequest = actionExecutionResult.getRequest(); ActionExecutionRequest actionExecutionRequest = actionExecutionResult.getRequest();
ActionExecutionRequest request; ActionExecutionRequest request;
if (actionExecutionRequest != null) { if (actionExecutionRequest != null) {
@ -1123,8 +1125,18 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
"statusCode", actionExecutionResult.getStatusCode() "statusCode", actionExecutionResult.getStatusCode()
)); ));
} }
final Map<String, Object> eventData = Map.of(
analyticsService.sendEvent(AnalyticsEvents.EXECUTE_ACTION.getEventName(), user.getUsername(), data); FieldName.ACTION, action,
FieldName.DATASOURCE, datasource,
FieldName.VIEW_MODE, viewMode,
FieldName.ACTION_EXECUTION_RESULT, actionExecutionResult,
FieldName.ACTION_EXECUTION_TIME, timeElapsed,
FieldName.ACTION_EXECUTION_REQUEST, request,
FieldName.APPLICATION, application,
FieldName.PLUGIN, plugin
);
data.put(FieldName.EVENT_DATA, eventData);
analyticsService.sendObjectEvent(AnalyticsEvents.EXECUTE_ACTION, action, data);
return request; return request;
}) })
.onErrorResume(error -> { .onErrorResume(error -> {
@ -1860,7 +1872,10 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
if (!StringUtils.hasLength(savedAction.getUnpublishedAction().getPluginName())) { if (!StringUtils.hasLength(savedAction.getUnpublishedAction().getPluginName())) {
savedAction.getUnpublishedAction().setPluginName(datasource.getPluginName()); savedAction.getUnpublishedAction().setPluginName(datasource.getPluginName());
} }
return this.getAnalyticsProperties(savedAction); Map<String, Object> analyticsProperties = this.getAnalyticsProperties(savedAction);
Map<String, Object> eventData = Map.of(FieldName.DATASOURCE, datasource);
analyticsProperties.put(FieldName.EVENT_DATA, eventData);
return analyticsProperties;
} }
@Override @Override

View File

@ -22,6 +22,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -47,11 +48,14 @@ public class ApplicationForkingServiceCEImpl implements ApplicationForkingServic
Mono<User> userMono = sessionUserService.getCurrentUser(); Mono<User> userMono = sessionUserService.getCurrentUser();
// For collecting all the possible event data
Map<String, Object> eventData = new HashMap<>();
Mono<Application> forkApplicationMono = Mono.zip(sourceApplicationMono, targetWorkspaceMono, userMono) Mono<Application> forkApplicationMono = Mono.zip(sourceApplicationMono, targetWorkspaceMono, userMono)
.flatMap(tuple -> { .flatMap(tuple -> {
final Application application = tuple.getT1(); final Application application = tuple.getT1();
final Workspace targetWorkspace = tuple.getT2(); final Workspace targetWorkspace = tuple.getT2();
final User user = tuple.getT3(); final User user = tuple.getT3();
eventData.put(FieldName.WORKSPACE, targetWorkspace);
//If the forking application is connected to git, do not copy those data to the new forked application //If the forking application is connected to git, do not copy those data to the new forked application
application.setGitApplicationMetadata(null); application.setGitApplicationMetadata(null);
@ -76,7 +80,7 @@ public class ApplicationForkingServiceCEImpl implements ApplicationForkingServic
final String newApplicationId = applicationIds.get(0); final String newApplicationId = applicationIds.get(0);
return applicationService.getById(newApplicationId) return applicationService.getById(newApplicationId)
.flatMap(application -> .flatMap(application ->
sendForkApplicationAnalyticsEvent(srcApplicationId, targetWorkspaceId, application)); sendForkApplicationAnalyticsEvent(srcApplicationId, targetWorkspaceId, application, eventData));
}); });
// Fork application is currently a slow API because it needs to create application, clone all the pages, and then // Fork application is currently a slow API because it needs to create application, clone all the pages, and then
@ -116,14 +120,15 @@ public class ApplicationForkingServiceCEImpl implements ApplicationForkingServic
.map(responseUtils::updateApplicationWithDefaultResources); .map(responseUtils::updateApplicationWithDefaultResources);
} }
private Mono<Application> sendForkApplicationAnalyticsEvent(String applicationId, String workspaceId, Application application) { private Mono<Application> sendForkApplicationAnalyticsEvent(String applicationId, String workspaceId, Application application, Map<String, Object> eventData) {
return applicationService.findById(applicationId, AclPermission.READ_APPLICATIONS) return applicationService.findById(applicationId, AclPermission.READ_APPLICATIONS)
.flatMap(sourceApplication -> { .flatMap(sourceApplication -> {
final Map<String, Object> data = Map.of( final Map<String, Object> data = Map.of(
"forkedFromAppId", applicationId, "forkedFromAppId", applicationId,
"forkedToOrgId", workspaceId, "forkedToOrgId", workspaceId,
"forkedFromAppName", sourceApplication.getName() "forkedFromAppName", sourceApplication.getName(),
FieldName.EVENT_DATA, eventData
); );
return analyticsService.sendObjectEvent(AnalyticsEvents.FORK, application, data); return analyticsService.sendObjectEvent(AnalyticsEvents.FORK, application, data);

View File

@ -2116,7 +2116,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
.flatMap(tuple -> { .flatMap(tuple -> {
Application application = tuple.getT1(); Application application = tuple.getT1();
Workspace workspace = tuple.getT2(); Workspace workspace = tuple.getT2();
final Map<String, Object> auditData = Map.of( final Map<String, Object> eventData = Map.of(
FieldName.APPLICATION, application, FieldName.APPLICATION, application,
FieldName.WORKSPACE, workspace FieldName.WORKSPACE, workspace
); );
@ -2124,7 +2124,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
final Map<String, Object> data = Map.of( final Map<String, Object> data = Map.of(
FieldName.APPLICATION_ID, application.getId(), FieldName.APPLICATION_ID, application.getId(),
FieldName.WORKSPACE_ID, workspace.getId(), FieldName.WORKSPACE_ID, workspace.getId(),
FieldName.AUDIT_DATA, auditData FieldName.EVENT_DATA, eventData
); );
return analyticsService.sendObjectEvent(event, application, data); return analyticsService.sendObjectEvent(event, application, data);