Added logs and analytics (#3622)

* Added logs and analytics

* Fix in error string

Co-authored-by: Shri <shrikant@appsmith.com>

* Review fixes :)

Co-authored-by: Shri <shrikant@appsmith.com>

Co-authored-by: Shri <shrikant@appsmith.com>
This commit is contained in:
Nidhi 2021-03-18 21:48:13 +05:30 committed by GitHub
parent bb1d0059d3
commit 93d5a061e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 12 deletions

View File

@ -8,6 +8,7 @@ public enum AnalyticsEvents {
DELETE,
FIRST_LOGIN,
EXECUTE_ACTION("execute_ACTION_TRIGGERED"),
UPDATE_LAYOUT,
;
private final String eventName;

View File

@ -37,7 +37,8 @@ public enum AppsmithError {
" \"widgetName\" : \"{1}\"," +
" \"widgetId\" : \"{2}\"," +
" \"pageId\" : \"{4}\"," +
" \"layoutId\" : \"{5}\"",
" \"layoutId\" : \"{5}\"," +
" \"dynamicBinding\" : \"{6}\"",
AppsmithErrorAction.LOG_EXTERNALLY),
USER_ALREADY_EXISTS_IN_ORGANIZATION(400, 4021, "The user {0} has already been added to the organization with role {1}. To change the role, please navigate to `Manage Users` page.", AppsmithErrorAction.DEFAULT),
UNAUTHORIZED_DOMAIN(401, 4019, "Invalid email domain {0} used for sign in/sign up. Please contact the administrator to configure this domain if this is unexpected.", AppsmithErrorAction.DEFAULT),

View File

@ -2,9 +2,12 @@ package com.appsmith.server.services;
import com.appsmith.external.helpers.MustacheHelper;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.server.constants.AnalyticsEvents;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.ActionDependencyEdge;
import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.ActionDTO;
import com.appsmith.server.dtos.ActionMoveDTO;
import com.appsmith.server.dtos.DslActionDTO;
@ -31,6 +34,7 @@ import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -53,6 +57,8 @@ public class LayoutActionServiceImpl implements LayoutActionService {
private final NewPageService newPageService;
private final NewActionService newActionService;
private final PageLoadActionsUtil pageLoadActionsUtil;
private final SessionUserService sessionUserService;
/*
* To replace fetchUsers in `{{JSON.stringify(fetchUsers)}}` with getUsers, the following regex is required :
@ -65,12 +71,15 @@ public class LayoutActionServiceImpl implements LayoutActionService {
public LayoutActionServiceImpl(ObjectMapper objectMapper,
AnalyticsService analyticsService,
NewPageService newPageService,
NewActionService newActionService, PageLoadActionsUtil pageLoadActionsUtil) {
NewActionService newActionService,
PageLoadActionsUtil pageLoadActionsUtil,
SessionUserService sessionUserService) {
this.objectMapper = objectMapper;
this.analyticsService = analyticsService;
this.newPageService = newPageService;
this.newActionService = newActionService;
this.pageLoadActionsUtil = pageLoadActionsUtil;
this.sessionUserService = sessionUserService;
}
@Override
@ -310,7 +319,7 @@ public class LayoutActionServiceImpl implements LayoutActionService {
// For nested fields, the parent dsl to search in would shift by one level every iteration
Object parent = dsl;
Iterator<String> fieldsIterator = Arrays.stream(fields).filter(fieldToken -> !fieldToken.isBlank()).iterator();
Boolean isLeafNode = false;
boolean isLeafNode = false;
// This loop will end at either a leaf node, or the last identified JSON field (by throwing an exception)
// Valid forms of the fieldPath for this search could be:
// root.field.list[index].childField.anotherList.indexWithDotOperator.multidimensionalList[index1][index2]
@ -327,30 +336,30 @@ public class LayoutActionServiceImpl implements LayoutActionService {
} catch (IndexOutOfBoundsException e) {
// The index being referred does not exist. Hence the path would not exist.
throw new AppsmithException(AppsmithError.INVALID_DYNAMIC_BINDING_REFERENCE, widgetType,
widgetName, widgetId, fieldPath, pageId, layoutId);
widgetName, widgetId, fieldPath, pageId, layoutId, null);
}
} else {
throw new AppsmithException(AppsmithError.INVALID_DYNAMIC_BINDING_REFERENCE, widgetType,
widgetName, widgetId, fieldPath, pageId, layoutId);
widgetName, widgetId, fieldPath, pageId, layoutId, null);
}
}
// After updating the parent, check for the types
if (parent == null) {
throw new AppsmithException(AppsmithError.INVALID_DYNAMIC_BINDING_REFERENCE, widgetType,
widgetName, widgetId, fieldPath, pageId, layoutId);
widgetName, widgetId, fieldPath, pageId, layoutId, null);
} else if (parent instanceof String) {
// If we get String value, then this is a leaf node
isLeafNode = true;
}
}
// Only extract mustache keys from leaf nodes
if (parent != null && isLeafNode) {
if (isLeafNode) {
Set<String> mustacheKeysFromFields = MustacheHelper.extractMustacheKeysFromFields(parent);
// We found the path. But if the path does not have any mustache bindings, throw the error
if (mustacheKeysFromFields.isEmpty()) {
throw new AppsmithException(AppsmithError.INVALID_DYNAMIC_BINDING_REFERENCE, widgetType,
widgetName, widgetId, fieldPath, pageId, layoutId);
widgetName, widgetId, fieldPath, pageId, layoutId, parent);
}
dynamicBindings.addAll(mustacheKeysFromFields);
@ -499,9 +508,38 @@ public class LayoutActionServiceImpl implements LayoutActionService {
.then(Mono.just(pageId));
}
private Mono<Boolean> sendUpdateLayoutAnalyticsEvent(String pageId, String layoutId, JSONObject dsl, boolean isSuccess, Throwable error) {
return Mono.zip(
sessionUserService.getCurrentUser(),
newPageService.getById(pageId)
)
.flatMap(tuple -> {
User t1 = tuple.getT1();
NewPage t2 = tuple.getT2();
final Map<String, Object> data = Map.of(
"username", t1.getUsername(),
"appId", t2.getApplicationId(),
"pageId", pageId,
"layoutId", layoutId,
"dsl", dsl.toJSONString(),
"isSuccessfulExecution", isSuccess,
"error", error == null ? "" : error.getMessage()
);
analyticsService.sendEvent(AnalyticsEvents.UPDATE_LAYOUT.getEventName(), t1.getUsername(), data);
return Mono.just(isSuccess);
})
.onErrorResume(e -> {
log.warn("Error sending action execution data point", e);
return Mono.just(isSuccess);
});
}
@Override
public Mono<LayoutDTO> updateLayout(String pageId, String layoutId, Layout layout) {
JSONObject dsl = layout.getDsl();
final JSONObject dsl = layout.getDsl();
if (dsl == null) {
// There is no DSL here. No need to process anything. Return as is.
return Mono.just(generateResponseDTO(layout));
@ -512,7 +550,8 @@ public class LayoutActionServiceImpl implements LayoutActionService {
try {
extractAllWidgetNamesAndDynamicBindingsFromDSL(dsl, widgetNames, jsSnippetsInDynamicBindings, pageId, layoutId);
} catch (Throwable t) {
return Mono.error(t);
return sendUpdateLayoutAnalyticsEvent(pageId, layoutId, dsl, false, t)
.then(Mono.error(t));
}
layout.setWidgetNames(widgetNames);
@ -581,11 +620,13 @@ public class LayoutActionServiceImpl implements LayoutActionService {
}
return Mono.empty();
})
.map(savedLayout -> {
.flatMap(savedLayout -> {
LayoutDTO layoutDTO = generateResponseDTO(savedLayout);
layoutDTO.setActionUpdates(actionUpdates);
layoutDTO.setMessages(messages);
return layoutDTO;
return sendUpdateLayoutAnalyticsEvent(pageId, layoutId, dsl, true, null)
.thenReturn(layoutDTO);
});
}