From 2c00b1b1042e5ec0132a6cfd2830f6ef14b1dbc0 Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Thu, 11 Jan 2024 18:23:27 +0530 Subject: [PATCH] chore: consolidated API: add NewRelic OTLP trace (#30241) --- .../server/constants/OtlpSpanNames.java | 28 +++ .../ConsolidatedAPIController.java | 25 ++- .../server/helpers/OtlpTelemetry.java | 30 ++- .../services/ConsolidatedAPIService.java | 3 +- .../services/ConsolidatedAPIServiceImpl.java | 186 ++++++++++++++++-- .../ConsolidatedAPIServiceImplTest.java | 10 +- 6 files changed, 249 insertions(+), 33 deletions(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/constants/OtlpSpanNames.java diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/OtlpSpanNames.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/OtlpSpanNames.java new file mode 100644 index 0000000000..c3c83aad5b --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/OtlpSpanNames.java @@ -0,0 +1,28 @@ +package com.appsmith.server.constants; + +public class OtlpSpanNames { + public static final String CONSOLIDATED_API_PREFIX = "consolidated-api/"; + public static final String VIEW = "view/"; + public static final String EDIT = "edit/"; + public static final String ROOT = "root"; + public static final String CONSOLIDATED_API_ROOT_EDIT = CONSOLIDATED_API_PREFIX + EDIT + ROOT; + public static final String CONSOLIDATED_API_ROOT_VIEW = CONSOLIDATED_API_PREFIX + VIEW + ROOT; + public static final String USER_PROFILE_SPAN = "user_profile"; + public static final String FEATURE_FLAG_SPAN = "feature_flag"; + public static final String TENANT_SPAN = "tenant"; + public static final String PRODUCT_ALERT_SPAN = "product_alert"; + public static final String APPLICATION_ID_SPAN = "application_id"; + public static final String PAGES_SPAN = "pages"; + public static final String PAGES_DSL_SPAN = "pages_dsl_list"; + public static final String CURRENT_THEME_SPAN = "current_theme"; + public static final String THEMES_SPAN = "themes"; + public static final String CUSTOM_JS_LIB_SPAN = "js_libs"; + public static final String CURRENT_PAGE_SPAN = "current_page"; + public static final String ACTIONS_SPAN = "actions"; + public static final String ACTION_COLLECTIONS_SPAN = "action_collections"; + public static final String PLUGINS_SPAN = "plugins"; + public static final String WORKSPACE_SPAN = "workspace"; + public static final String DATASOURCES_SPAN = "datasources"; + public static final String FORM_CONFIG_SPAN = "form_config"; + public static final String MOCK_DATASOURCES_SPAN = "mock_datasources"; +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java index 6a300c8d09..a85524136b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java @@ -6,8 +6,10 @@ import com.appsmith.server.constants.Url; import com.appsmith.server.domains.ApplicationMode; import com.appsmith.server.dtos.ConsolidatedAPIResponseDTO; import com.appsmith.server.dtos.ResponseDTO; +import com.appsmith.server.helpers.OtlpTelemetry; import com.appsmith.server.services.ConsolidatedAPIService; import com.fasterxml.jackson.annotation.JsonView; +import io.opentelemetry.api.trace.Span; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; @@ -17,14 +19,19 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; +import static com.appsmith.server.constants.OtlpSpanNames.CONSOLIDATED_API_ROOT_EDIT; +import static com.appsmith.server.constants.OtlpSpanNames.CONSOLIDATED_API_ROOT_VIEW; + @Slf4j @RestController @RequestMapping(Url.CONSOLIDATED_API_URL) public class ConsolidatedAPIController { private final ConsolidatedAPIService consolidatedAPIService; + private final OtlpTelemetry otlpTelemetry; - public ConsolidatedAPIController(ConsolidatedAPIService consolidatedAPIService) { + public ConsolidatedAPIController(ConsolidatedAPIService consolidatedAPIService, OtlpTelemetry otlpTelemetry) { this.consolidatedAPIService = consolidatedAPIService; + this.otlpTelemetry = otlpTelemetry; } /** @@ -45,10 +52,14 @@ public class ConsolidatedAPIController { defaultPageId, branchName, ApplicationMode.EDIT); + + Span consolidatedApiOtlpSpan = this.otlpTelemetry.startOTLPSpan(CONSOLIDATED_API_ROOT_EDIT, null, null); return consolidatedAPIService - .getConsolidatedInfoForPageLoad(defaultPageId, applicationId, branchName, ApplicationMode.EDIT) + .getConsolidatedInfoForPageLoad( + defaultPageId, applicationId, branchName, ApplicationMode.EDIT, consolidatedApiOtlpSpan) .map(consolidatedAPIResponseDTO -> - new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)); + new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(consolidatedApiOtlpSpan)); } @JsonView(Views.Public.class) @@ -64,9 +75,13 @@ public class ConsolidatedAPIController { defaultPageId, branchName, ApplicationMode.PUBLISHED); + + Span consolidatedApiOtlpSpan = this.otlpTelemetry.startOTLPSpan(CONSOLIDATED_API_ROOT_VIEW, null, null); return consolidatedAPIService - .getConsolidatedInfoForPageLoad(defaultPageId, applicationId, branchName, ApplicationMode.PUBLISHED) + .getConsolidatedInfoForPageLoad( + defaultPageId, applicationId, branchName, ApplicationMode.PUBLISHED, consolidatedApiOtlpSpan) .map(consolidatedAPIResponseDTO -> - new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)); + new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(consolidatedApiOtlpSpan)); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/OtlpTelemetry.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/OtlpTelemetry.java index 116e2fd580..aa69b7c0eb 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/OtlpTelemetry.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/OtlpTelemetry.java @@ -1,7 +1,10 @@ package com.appsmith.server.helpers; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; @@ -72,11 +75,26 @@ public class OtlpTelemetry { return W3CTraceContextPropagator.getInstance().extract(Context.current(), model, getter); } - private Span startOTLPSpan(String spanName, Context context) { - return tracer.spanBuilder(spanName) - .setSpanKind(SpanKind.SERVER) - .setParent(context) - .startSpan(); + public Span startOTLPSpan(String spanName, Context context, Span parentSpan) { + if (tracer == null) { + return null; + } + + if (isBlank(spanName)) { + throw new AppsmithException(AppsmithError.INVALID_PARAMETER, "spanName"); + } + + SpanBuilder spanBuilder = tracer.spanBuilder(spanName).setSpanKind(SpanKind.SERVER); + + if (context != null) { + return spanBuilder.setParent(context).startSpan(); + } + + if (parentSpan != null) { + return spanBuilder.setParent(Context.current().with(parentSpan)).startSpan(); + } + + return spanBuilder.startSpan(); } // we build traces using the client's trace context as the parent context, So that any other spans generated // from the server appear as a subspan of the client @@ -88,7 +106,7 @@ public class OtlpTelemetry { return null; } Context context = generateContextFromTraceHeader(traceparent); - return startOTLPSpan(spanName, context); + return startOTLPSpan(spanName, context, null); } public void endOtlpSpanSafely(Span span) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIService.java index 698725f28d..80038c4541 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIService.java @@ -2,9 +2,10 @@ package com.appsmith.server.services; import com.appsmith.server.domains.ApplicationMode; import com.appsmith.server.dtos.ConsolidatedAPIResponseDTO; +import io.opentelemetry.api.trace.Span; import reactor.core.publisher.Mono; public interface ConsolidatedAPIService { Mono getConsolidatedInfoForPageLoad( - String defaultPageId, String applicationId, String branchName, ApplicationMode mode); + String defaultPageId, String applicationId, String branchName, ApplicationMode mode, Span parentSpan); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIServiceImpl.java index e944fc7957..92e1ae7fd1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConsolidatedAPIServiceImpl.java @@ -25,11 +25,13 @@ import com.appsmith.server.dtos.ResponseDTO; import com.appsmith.server.dtos.UserProfileDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.helpers.OtlpTelemetry; import com.appsmith.server.jslibs.base.CustomJSLibService; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.plugins.base.PluginService; import com.appsmith.server.themes.base.ThemeService; +import io.opentelemetry.api.trace.Span; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; @@ -49,6 +51,27 @@ import java.util.stream.Collectors; import static com.appsmith.external.constants.PluginConstants.PackageName.GRAPHQL_PLUGIN; import static com.appsmith.external.constants.PluginConstants.PackageName.REST_API_PLUGIN; +import static com.appsmith.server.constants.OtlpSpanNames.ACTIONS_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.ACTION_COLLECTIONS_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.APPLICATION_ID_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.CONSOLIDATED_API_PREFIX; +import static com.appsmith.server.constants.OtlpSpanNames.CURRENT_PAGE_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.CURRENT_THEME_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.CUSTOM_JS_LIB_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.DATASOURCES_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.EDIT; +import static com.appsmith.server.constants.OtlpSpanNames.FEATURE_FLAG_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.FORM_CONFIG_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.MOCK_DATASOURCES_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.PAGES_DSL_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.PAGES_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.PLUGINS_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.PRODUCT_ALERT_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.TENANT_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.THEMES_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.USER_PROFILE_SPAN; +import static com.appsmith.server.constants.OtlpSpanNames.VIEW; +import static com.appsmith.server.constants.OtlpSpanNames.WORKSPACE_SPAN; import static com.appsmith.server.constants.ce.FieldNameCE.APPLICATION_ID; import static com.appsmith.server.constants.ce.FieldNameCE.APP_MODE; import static com.appsmith.server.constants.ce.FieldNameCE.WORKSPACE_ID; @@ -78,6 +101,7 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { private final ApplicationService applicationService; private final DatasourceService datasourceService; private final MockDataService mockDataService; + private final OtlpTelemetry otlpTelemetry; public ConsolidatedAPIServiceImpl( SessionUserService sessionUserService, @@ -94,7 +118,8 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { PluginService pluginService, ApplicationService applicationService, DatasourceService datasourceService, - MockDataService mockDataService) { + MockDataService mockDataService, + OtlpTelemetry otlpTelemetry) { this.sessionUserService = sessionUserService; this.userService = userService; this.userDataService = userDataService; @@ -110,6 +135,7 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { this.applicationService = applicationService; this.datasourceService = datasourceService; this.mockDataService = mockDataService; + this.otlpTelemetry = otlpTelemetry; } ResponseDTO getSuccessResponse(T data) { @@ -131,16 +157,24 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { INTERNAL_SERVER_ERROR_STATUS, new ErrorDTO(INTERNAL_SERVER_ERROR_CODE, error.getMessage()))); } + public static String getQualifiedSpanName(String spanName, ApplicationMode mode) { + return ApplicationMode.PUBLISHED.equals(mode) + ? CONSOLIDATED_API_PREFIX + VIEW + spanName + : CONSOLIDATED_API_PREFIX + EDIT + spanName; + } + /** * This method is meant to be used by the client application at the time of 1st page load. Client currently makes * several API calls to fetch all the required data. This method consolidates all that data and returns them as * response hence enabling the client to fetch the required data via a single API call only. + * Please check out this Slack conversation to understand why span objects need be put in a list: + * https://theappsmith.slack.com/archives/C024GUDM0LT/p1704891881312049 * * PLEASE TAKE CARE TO USE .cache() FOR Mono THAT GETS REUSED SO THAT FIRST PAGE LOAD PERFORMANCE DOES NOT DEGRADE. */ @Override public Mono getConsolidatedInfoForPageLoad( - String defaultPageId, String applicationId, String branchName, ApplicationMode mode) { + String defaultPageId, String applicationId, String branchName, ApplicationMode mode, Span parentSpan) { /* if either of pageId or applicationId are provided then application mode must also be provided */ if (mode == null && (!isBlank(defaultPageId) || !isBlank(applicationId))) { @@ -151,27 +185,46 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { ConsolidatedAPIResponseDTO consolidatedAPIResponseDTO = new ConsolidatedAPIResponseDTO(); /* Get user profile data */ + ArrayList userProfileSpanList = new ArrayList<>(); Mono> userProfileDTOResponseDTOMono = sessionUserService .getCurrentUser() .flatMap(userService::buildUserProfileDTO) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, UserProfileDTO.class)); + .onErrorResume(error -> getErrorResponseMono(error, UserProfileDTO.class)) + .doOnSubscribe(subscription -> { + userProfileSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(USER_PROFILE_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(userProfileSpanList.get(0))); /* Get all feature flags data */ + ArrayList featureFlagsSpanList = new ArrayList<>(); Mono> featureFlagsForCurrentUserResponseDTOMonoCache = userDataService .getFeatureFlagsForCurrentUser() .map(res -> (Map) res) .map(this::getSuccessResponse) .onErrorResume(error -> getErrorResponseMono(error, Map.class)) + .doOnSubscribe(subscription -> { + featureFlagsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(FEATURE_FLAG_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(featureFlagsSpanList.get(0))) .cache(); /* Get tenant config data */ + ArrayList tenantSpanList = new ArrayList<>(); Mono> tenantResponseDTOMono = tenantService .getTenantConfiguration() .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, Tenant.class)); + .onErrorResume(error -> getErrorResponseMono(error, Tenant.class)) + .doOnSubscribe(subscription -> { + tenantSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(TENANT_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(tenantSpanList.get(0))); /* Get any product alert info */ + ArrayList productAlertSpanList = new ArrayList<>(); Mono> productAlertResponseDTOMono = productAlertService .getSingleApplicableMessage() .map(messages -> { @@ -182,7 +235,12 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { return new ProductAlertResponseDTO(); }) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, ProductAlertResponseDTO.class)); + .onErrorResume(error -> getErrorResponseMono(error, ProductAlertResponseDTO.class)) + .doOnSubscribe(subscription -> { + productAlertSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(PRODUCT_ALERT_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(productAlertSpanList.get(0))); if (isBlank(defaultPageId) && isBlank(applicationId)) { @@ -208,41 +266,71 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { /* Fetch application id if not provided */ Mono applicationIdMonoCache; if (isBlank(applicationId)) { + ArrayList applicationIdSpanList = new ArrayList<>(); applicationIdMonoCache = newPageService .findRootApplicationIdFromNewPage(branchName, defaultPageId) + .doOnSubscribe(subscription -> { + applicationIdSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(APPLICATION_ID_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(applicationIdSpanList.get(0))) .cache(); } else { applicationIdMonoCache = Mono.just(applicationId).cache(); } /* Get all pages in application */ + ArrayList pagesSpanList = new ArrayList<>(); Mono> applicationPagesDTOResponseDTOMonoCache = applicationIdMonoCache .flatMap(appId -> newPageService.findApplicationPages(appId, null, branchName, mode)) .map(this::getSuccessResponse) .onErrorResume(error -> getErrorResponseMono(error, ApplicationPagesDTO.class)) + .doOnSubscribe(subscription -> { + pagesSpanList.add( + this.otlpTelemetry.startOTLPSpan(getQualifiedSpanName(PAGES_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(pagesSpanList.get(0))) .cache(); /* Get current theme */ + ArrayList currentThemeSpanList = new ArrayList<>(); Mono> applicationThemeResponseDTOMono = applicationIdMonoCache .flatMap(appId -> themeService.getApplicationTheme(appId, mode, branchName)) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, Theme.class)); + .onErrorResume(error -> getErrorResponseMono(error, Theme.class)) + .doOnSubscribe(subscription -> { + currentThemeSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(CURRENT_THEME_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(currentThemeSpanList.get(0))); /* Get all themes */ + ArrayList themesSpanList = new ArrayList<>(); Mono> ThemesListResponseDTOMono = applicationIdMonoCache .flatMap(appId -> themeService.getApplicationThemes(appId, branchName).collectList()) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + themesSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(THEMES_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(themesSpanList.get(0))); /* Get all custom JS libraries installed in the application */ + ArrayList customJSLibSpanList = new ArrayList<>(); Mono> allJSLibsInContextDTOResponseDTOMono = applicationIdMonoCache .flatMap(appId -> customJSLibService.getAllJSLibsInContext( appId, CreatorContextType.APPLICATION, branchName, isViewMode)) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + customJSLibSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(CUSTOM_JS_LIB_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(customJSLibSpanList.get(0))); /* Check if release_server_dsl_migrations_enabled flag is true for the user */ Mono migrateDslMonoCache = featureFlagsForCurrentUserResponseDTOMonoCache @@ -266,32 +354,50 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { Mono> currentPageDTOResponseDTOMono = Mono.empty(); if (!isBlank(defaultPageId)) { /* Get current page */ + ArrayList currentPageSpanList = new ArrayList<>(); currentPageDTOResponseDTOMono = migrateDslMonoCache .flatMap(migrateDsl -> applicationPageService.getPageAndMigrateDslByBranchAndDefaultPageId( defaultPageId, branchName, isViewMode, migrateDsl)) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, PageDTO.class)); + .onErrorResume(error -> getErrorResponseMono(error, PageDTO.class)) + .doOnSubscribe(subscription -> { + currentPageSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(CURRENT_PAGE_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(currentPageSpanList.get(0))); } /* Fetch view specific data */ if (isViewMode) { /* Get list of all actions in view mode */ + ArrayList actionsSpanList = new ArrayList<>(); Mono> listOfActionViewResponseDTOMono = applicationIdMonoCache .flatMap(appId -> newActionService .getActionsForViewMode(appId, branchName) .collectList()) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + actionsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(ACTIONS_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(actionsSpanList.get(0))); /* Get list of all action collections in view mode */ + ArrayList actionCollectionsSpanList = new ArrayList<>(); Mono> listOfActionCollectionViewResponseDTOMono = applicationIdMonoCache .flatMap(appId -> actionCollectionService .getActionCollectionsForViewMode(appId, branchName) .collectList()) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + actionCollectionsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(ACTION_COLLECTIONS_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(actionCollectionsSpanList.get(0))); /* This list contains the Mono objects corresponding to all the data points required for view mode. All * the Mono objects in this list will be evaluated via Mono.zip operator. @@ -333,6 +439,7 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { }); } else { /* Get all actions in edit mode */ + ArrayList actionsSpanList = new ArrayList<>(); Mono> listOfActionResponseDTOMono = applicationIdMonoCache .flatMap(appId -> { MultiValueMap params = new LinkedMultiValueMap<>(); @@ -343,9 +450,15 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { }) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + actionsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(ACTIONS_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(actionsSpanList.get(0))); /* Get all action collections in edit mode */ + ArrayList actionCollectionsSpanList = new ArrayList<>(); Mono> listOfActionCollectionResponseDTOMono = applicationIdMonoCache .flatMap(appId -> { MultiValueMap params = new LinkedMultiValueMap<>(); @@ -356,9 +469,15 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { .map(res -> (List) res) .map(this::getSuccessResponse); }) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + actionCollectionsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(ACTION_COLLECTIONS_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(actionCollectionsSpanList.get(0))); /* Get all pages in edit mode post apply migrate DSL changes */ + ArrayList pagesPostMigrateDslSpanList = new ArrayList<>(); Mono> listOfAllPageResponseDTOMono = migrateDslMonoCache .flatMap(migrateDsl -> applicationPagesDTOResponseDTOMonoCache .map(ResponseDTO::getData) @@ -369,9 +488,15 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { .collect(Collectors.toList())) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + pagesPostMigrateDslSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(PAGES_DSL_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(pagesPostMigrateDslSpanList.get(0))); /* Get all workspace id */ + ArrayList workspaceIdSpanList = new ArrayList<>(); Mono workspaceIdMonoCache = applicationPagesDTOResponseDTOMonoCache .map(responseDTO -> { if (INTERNAL_SERVER_ERROR_STATUS @@ -382,9 +507,15 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { return responseDTO.getData().getWorkspaceId(); }) .onErrorResume(error -> Mono.just(EMPTY_WORKSPACE_ID_ON_ERROR)) + .doOnSubscribe(subscription -> { + workspaceIdSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(WORKSPACE_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(workspaceIdSpanList.get(0))) .cache(); /* Get all plugins in workspace */ + ArrayList pluginsSpanList = new ArrayList<>(); Mono> listOfPluginsResponseDTOMonoCache = workspaceIdMonoCache .flatMap(workspaceId -> { MultiValueMap params = new LinkedMultiValueMap<>(); @@ -396,9 +527,15 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { .map(res -> (List) res) .map(this::getSuccessResponse) .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + pluginsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(PLUGINS_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(pluginsSpanList.get(0))) .cache(); /* Get all datasources in workspace */ + ArrayList datasourcesSpanList = new ArrayList<>(); Mono> listOfDatasourcesResponseDTOMonoCache = workspaceIdMonoCache .flatMap(workspaceId -> { MultiValueMap params = new LinkedMultiValueMap<>(); @@ -410,6 +547,11 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { .map(res -> (List) res) .map(this::getSuccessResponse) .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + datasourcesSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(DATASOURCES_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(datasourcesSpanList.get(0))) .cache(); /* Get form config for all relevant plugins by following this rule: @@ -417,6 +559,7 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { * (b) include REST API and GraphQL API plugin always * (c) ignore any other plugin * */ + ArrayList formConfigsSpanList = new ArrayList<>(); Mono> listOfFormConfigsResponseDTOMono = Mono.zip( listOfPluginsResponseDTOMonoCache, listOfDatasourcesResponseDTOMonoCache) .map(tuple2 -> { @@ -451,15 +594,26 @@ public class ConsolidatedAPIServiceImpl implements ConsolidatedAPIService { }) .map(res -> (Map) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, Map.class)); + .onErrorResume(error -> getErrorResponseMono(error, Map.class)) + .doOnSubscribe(subscription -> { + formConfigsSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(FORM_CONFIG_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(formConfigsSpanList.get(0))); /* List of mock datasources available to the user */ + ArrayList mockDatasourcesSpanList = new ArrayList<>(); Mono> mockDataListResponseDTOMono = mockDataService .getMockDataSet() .map(MockDataDTO::getMockdbs) .map(res -> (List) res) .map(this::getSuccessResponse) - .onErrorResume(error -> getErrorResponseMono(error, List.class)); + .onErrorResume(error -> getErrorResponseMono(error, List.class)) + .doOnSubscribe(subscription -> { + mockDatasourcesSpanList.add(this.otlpTelemetry.startOTLPSpan( + getQualifiedSpanName(MOCK_DATASOURCES_SPAN, mode), null, parentSpan)); + }) + .doFinally(signalType -> this.otlpTelemetry.endOtlpSpanSafely(mockDatasourcesSpanList.get(0))); /* This list contains the Mono objects corresponding to all the data points required for edit mode. All * the Mono objects in this list will be evaluated via Mono.zip operator diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java index 22c4b34f1b..99a4271d6f 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java @@ -118,7 +118,7 @@ public class ConsolidatedAPIServiceImplTest { @Test public void testErrorWhenModeIsNullAndPageIdAvailable() { Mono consolidatedInfoForPageLoad = - consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, null); + consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, null, null); StepVerifier.create(consolidatedInfoForPageLoad).verifyErrorSatisfies(error -> { assertTrue(error instanceof AppsmithException); assertEquals("Please enter a valid parameter appMode.", error.getMessage()); @@ -149,7 +149,7 @@ public class ConsolidatedAPIServiceImplTest { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.PUBLISHED); + "pageId", "appId", "branch", ApplicationMode.PUBLISHED, null); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -243,7 +243,7 @@ public class ConsolidatedAPIServiceImplTest { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.PUBLISHED); + "pageId", "appId", "branch", ApplicationMode.PUBLISHED, null); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getPublishedActions()); @@ -439,7 +439,7 @@ public class ConsolidatedAPIServiceImplTest { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.EDIT); + "pageId", "appId", "branch", ApplicationMode.EDIT, null); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -637,7 +637,7 @@ public class ConsolidatedAPIServiceImplTest { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.PUBLISHED); + "pageId", "appId", "branch", ApplicationMode.PUBLISHED, null); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile());