chore: Removed manipulation for custom traceparent header (#37121)

This commit is contained in:
Nidhi 2024-10-30 11:27:25 +05:30 committed by GitHub
parent d6305bad82
commit e7e3d5e002
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 37 additions and 124 deletions

View File

@ -16,7 +16,7 @@ const provider = new NodeTracerProvider({
resource: new Resource({ resource: new Resource({
[ATTR_DEPLOYMENT_NAME]: `${process.env.APPSMITH_DEPLOYMENT_NAME || "self-hosted"}`, [ATTR_DEPLOYMENT_NAME]: `${process.env.APPSMITH_DEPLOYMENT_NAME || "self-hosted"}`,
[ATTR_SERVICE_INSTANCE_ID]: `${process.env.HOSTNAME || "appsmith-0"}`, [ATTR_SERVICE_INSTANCE_ID]: `${process.env.HOSTNAME || "appsmith-0"}`,
[ATTR_SERVICE_NAME]: "rts", [ATTR_SERVICE_NAME]: "appsmith-rts",
}), }),
}); });

View File

@ -283,7 +283,7 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => {
observability: { observability: {
deploymentName: observabilityDeploymentName.value, deploymentName: observabilityDeploymentName.value,
serviceInstanceId: observabilityServiceInstanceId.value, serviceInstanceId: observabilityServiceInstanceId.value,
serviceName: "frontend", serviceName: "appsmith-client",
}, },
fusioncharts: { fusioncharts: {
enabled: fusioncharts.enabled, enabled: fusioncharts.enabled,

View File

@ -7,5 +7,6 @@ public class MDCConstants {
public static final String THREAD = "thread"; public static final String THREAD = "thread";
public static final String OBSERVATION = "micrometer.observation"; public static final String OBSERVATION = "micrometer.observation";
public static final String TRACE_ID = "traceId"; public static final String TRACE_ID = "traceId";
public static final String TRACE_PARENT = "traceparent";
public static final String SPAN_ID = "spanId"; public static final String SPAN_ID = "spanId";
} }

View File

@ -15,5 +15,5 @@ import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD}) @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@ConditionalOnExpression("${appsmith.micrometer.metrics.enabled}") @ConditionalOnExpression("${appsmith.observability.metrics.enabled}")
public @interface ConditionalOnMicrometerMetricsEnabled {} public @interface ConditionalOnMicrometerMetricsEnabled {}

View File

@ -64,13 +64,13 @@ public class CommonConfig {
@Value("${disable.telemetry:true}") @Value("${disable.telemetry:true}")
private boolean isTelemetryDisabled; private boolean isTelemetryDisabled;
@Value("${appsmith.micrometer.tracing.detail.enabled:false}") @Value("${appsmith.observability.tracing.detail.enabled:false}")
private boolean tracingDetail; private boolean tracingDetail;
@Value("${appsmith.micrometer.metrics.detail.enabled:false}") @Value("${appsmith.observability.metrics.detail.enabled:false}")
private boolean metricsDetail; private boolean metricsDetail;
@Value("${appsmith.micrometer.metrics.interval.millis:60000}") @Value("${appsmith.observability.metrics.interval.millis:60000}")
private int metricsIntervalMillis; private int metricsIntervalMillis;
private List<String> allowedDomains; private List<String> allowedDomains;

View File

@ -33,20 +33,21 @@ public class MetricsConfig {
public static final String NEW_RELIC_MICROMETER_METRICS_ENDPOINT = "https://otlp.nr-data.net:4317"; public static final String NEW_RELIC_MICROMETER_METRICS_ENDPOINT = "https://otlp.nr-data.net:4317";
public static final String API_KEY = "api-key"; public static final String API_KEY = "api-key";
public static final String CONTAINER_NAME_KEY = "container.name"; public static final String DEPLOYMENT_NAME_KEY = "deployment.name";
public static final String SERVICE_INSTANCE_ID_KEY = "service.instance.id";
public static final String SERVICE_NAME_KEY = "service.name"; public static final String SERVICE_NAME_KEY = "service.name";
public static final String SERVICE_NAME = "appsmith-server";
public static final String INSTRUMENTATION_PROVIDER_KEY = "instrumentation.provider"; public static final String INSTRUMENTATION_PROVIDER_KEY = "instrumentation.provider";
public static final String MICROMETER = "micrometer"; public static final String MICROMETER = "micrometer";
@Value("${appsmith.newrelic.micrometer.metrics.application.name}")
private String newRelicApplicationName;
@Value("${appsmith.newrelic.licensekey}") @Value("${appsmith.newrelic.licensekey}")
private String newRelicKey; private String newRelicKey;
@Value("${appsmith.newrelic.micrometer.metrics.container.name}") @Value("${appsmith.observability.deployment.name}")
private String newRelicContainerName; private String deploymentName;
@Value("${appsmith.observability.service.instance.id}")
private String serviceInstanceId;
private final CommonConfig commonConfig; private final CommonConfig commonConfig;
@ -68,11 +69,12 @@ public class MetricsConfig {
return OpenTelemetrySdk.builder() return OpenTelemetrySdk.builder()
.setMeterProvider(SdkMeterProvider.builder() .setMeterProvider(SdkMeterProvider.builder()
.setResource(Resource.getDefault().toBuilder() .setResource(Resource.getDefault().toBuilder()
.put(SERVICE_NAME_KEY, newRelicApplicationName) .put(DEPLOYMENT_NAME_KEY, deploymentName)
.put(SERVICE_NAME_KEY, SERVICE_NAME)
// Include instrumentation.provider=micrometer to enable micrometer metrics // Include instrumentation.provider=micrometer to enable micrometer metrics
// experience in New Relic // experience in New Relic
.put(INSTRUMENTATION_PROVIDER_KEY, MICROMETER) .put(INSTRUMENTATION_PROVIDER_KEY, MICROMETER)
.put(CONTAINER_NAME_KEY, newRelicContainerName) .put(SERVICE_INSTANCE_ID_KEY, serviceInstanceId)
.build()) .build())
.registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder() .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder()
.setEndpoint(NEW_RELIC_MICROMETER_METRICS_ENDPOINT) .setEndpoint(NEW_RELIC_MICROMETER_METRICS_ENDPOINT)

View File

@ -1,78 +0,0 @@
package com.appsmith.server.configurations;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import static org.springframework.util.CollectionUtils.isEmpty;
/**
* This webfilter copies the value of traceparent-otlp header into traceparent header. This is required because at
* the moment the client application has two different services that creates traces and sends to the NewRelic server
* - one that gathers web vitals information like LCP, FCP etc. and another one that creates user defined traces. They
* both have different traceparent header and hence to overcome this conflict of headers the client has copied the
* user defined trace header into traceparent-otlp. However, Micrometer expects the traceparent information to be
* present in the traceparent header - hence this method copies the correct header data into traceparent header
* before it gets set into Micrometer context.
* In cases where traceparent-otlp header is not present but the traceparent header is present, this method removes
* the traceparent header because if it is present then the Micrometer trace would use its value for trace id (which
* is incorrect).
* As per measurement on my local setup this webFilter generally takes around 0.5 milliseconds to complete hence should
* not have any practical impact on response times.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class MicrometerTraceHeaderWebFilter implements WebFilter {
public static final String TRACEPARENT_OTLP_HEADER_KEY = "traceparent-otlp";
public static final String TRACEPARENT_HEADER_KEY = "traceparent";
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
HttpHeaders requestHeaders = serverWebExchange.getRequest().getHeaders();
if (isTraceparentOtlpHeaderPresent(requestHeaders)) {
ServerHttpRequest newRequest = serverWebExchange
.getRequest()
.mutate()
.header(
TRACEPARENT_HEADER_KEY,
requestHeaders.get(TRACEPARENT_OTLP_HEADER_KEY).get(0))
.build();
ServerWebExchange newExchange =
serverWebExchange.mutate().request(newRequest).build();
return webFilterChain.filter(newExchange);
} else if (isTraceparentHeaderPresent(requestHeaders)) {
ServerHttpRequest newRequest = serverWebExchange
.getRequest()
.mutate()
.headers((httpHeader) -> {
httpHeader.remove(TRACEPARENT_HEADER_KEY);
})
.build();
ServerWebExchange newExchange =
serverWebExchange.mutate().request(newRequest).build();
return webFilterChain.filter(newExchange);
}
return webFilterChain.filter(serverWebExchange);
}
private boolean isTraceparentHeaderPresent(HttpHeaders requestHeaders) {
return requestHeaders != null
&& requestHeaders.containsKey(TRACEPARENT_HEADER_KEY)
&& !isEmpty(requestHeaders.get(TRACEPARENT_HEADER_KEY));
}
private boolean isTraceparentOtlpHeaderPresent(HttpHeaders requestHeaders) {
return requestHeaders != null && requestHeaders.containsKey(TRACEPARENT_OTLP_HEADER_KEY);
}
}

View File

@ -3,16 +3,10 @@ package com.appsmith.server.configurations;
import io.micrometer.observation.Observation; import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationPredicate;
import io.micrometer.observation.ObservationView; import io.micrometer.observation.ObservationView;
import io.micrometer.tracing.Span;
import io.micrometer.tracing.exporter.SpanExportingPredicate;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext; import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
import static com.appsmith.external.constants.spans.BaseSpan.APPSMITH_SPAN_PREFIX;
import static com.appsmith.external.constants.spans.BaseSpan.AUTHENTICATE;
import static com.appsmith.external.constants.spans.BaseSpan.AUTHORIZE;
/** /**
* This configuration file creates beans that are required to filter just Appsmith specific spans * This configuration file creates beans that are required to filter just Appsmith specific spans
*/ */
@ -42,19 +36,4 @@ public class TracingConfig {
} }
}; };
} }
@Bean
SpanExportingPredicate onlyAppsmithSpans() {
return (finishedSpan) -> {
if ((finishedSpan.getKind() != null && finishedSpan.getKind().equals(Span.Kind.SERVER))
|| finishedSpan.getName().startsWith(APPSMITH_SPAN_PREFIX)
|| finishedSpan.getName().startsWith(AUTHENTICATE)
|| finishedSpan.getName().startsWith(AUTHORIZE)) {
// A span is either an http server request root or Appsmith specific or login related or signup related
return true;
} else {
return false;
}
};
}
} }

View File

@ -1,5 +1,6 @@
package com.appsmith.server.helpers; package com.appsmith.server.helpers;
import io.micrometer.observation.ObservationRegistry;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -24,6 +25,8 @@ import static org.apache.commons.lang3.StringUtils.isEmpty;
@Component @Component
public class RTSCaller { public class RTSCaller {
private final ObservationRegistry observationRegistry;
private WebClient webClient; private WebClient webClient;
@Value("${appsmith.rts.port:}") @Value("${appsmith.rts.port:}")
@ -31,6 +34,10 @@ public class RTSCaller {
private static final int MAX_IN_MEMORY_SIZE_IN_BYTES = 16 * 1024 * 1024; private static final int MAX_IN_MEMORY_SIZE_IN_BYTES = 16 * 1024 * 1024;
public RTSCaller(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
@PostConstruct @PostConstruct
private void makeWebClient() { private void makeWebClient() {
if (isEmpty(rtsPort)) { if (isEmpty(rtsPort)) {
@ -53,6 +60,7 @@ public class RTSCaller {
.build()) .build())
.clientConnector(new ReactorClientHttpConnector(HttpClient.create(connectionProvider))) .clientConnector(new ReactorClientHttpConnector(HttpClient.create(connectionProvider)))
.baseUrl("http://127.0.0.1:" + rtsPort) .baseUrl("http://127.0.0.1:" + rtsPort)
.observationRegistry(observationRegistry)
.build(); .build();
} }

View File

@ -1,3 +1,4 @@
spring.application.name=appsmith-server
server.port=${PORT:8080} server.port=${PORT:8080}
# Allow the Spring context to close all active requests before shutting down the server # Allow the Spring context to close all active requests before shutting down the server
# Please ref: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/spring-boot-features.html#boot-features-graceful-shutdown # Please ref: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/spring-boot-features.html#boot-features-graceful-shutdown
@ -95,6 +96,16 @@ management.tracing.sampling.probability=${APPSMITH_SAMPLING_PROBABILITY:0.1}
management.prometheus.metrics.export.descriptions=true management.prometheus.metrics.export.descriptions=true
management.metrics.distribution.percentiles-histogram.http.server.requests=true management.metrics.distribution.percentiles-histogram.http.server.requests=true
# Observability and Micrometer related configs
# Keeping this license key around, until later
appsmith.newrelic.licensekey=${APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY:}
appsmith.observability.deployment.name=${APPSMITH_DEPLOYMENT_NAME:self-hosted}
appsmith.observability.service.instance.id=${HOSTNAME:appsmith-0}
appsmith.observability.metrics.enabled=${APPSMITH_MICROMETER_METRICS_ENABLED:false}
appsmith.observability.tracing.detail.enabled=${APPSMITH_ENABLE_TRACING_DETAIL:false}
appsmith.observability.metrics.detail.enabled=${APPSMITH_ENABLE_METRICS_DETAIL:false}
appsmith.observability.metrics.interval.millis=${APPSMITH_METRICS_INTERVAL_MILLIS:60000}
# Support disabling signup with an environment variable # Support disabling signup with an environment variable
signup.disabled = ${APPSMITH_SIGNUP_DISABLED:false} signup.disabled = ${APPSMITH_SIGNUP_DISABLED:false}
signup.allowed-domains=${APPSMITH_SIGNUP_ALLOWED_DOMAINS:} signup.allowed-domains=${APPSMITH_SIGNUP_ALLOWED_DOMAINS:}
@ -117,15 +128,5 @@ appsmith.internal.password=${APPSMITH_INTERNAL_PASSWORD:}
# GIT stale index.lock file valid time # GIT stale index.lock file valid time
appsmith.index.lock.file.time=${APPSMITH_INDEX_LOCK_FILE_TIME:300} appsmith.index.lock.file.time=${APPSMITH_INDEX_LOCK_FILE_TIME:300}
# NewRelic and Micrometer related configs
appsmith.newrelic.licensekey=${APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY:}
appsmith.newrelic.micrometer.metrics.container.name=${NEW_RELIC_METADATA_KUBERNETES_POD_NAME:appsmith-0}
appsmith.newrelic.micrometer.metrics.application.name=${APPSMITH_NEWRELIC_MICROMETER_SERVICE_NAME:}
spring.application.name=${OTEL_SERVICE_NAME:appsmith-anonymous}
appsmith.micrometer.metrics.enabled=${APPSMITH_MICROMETER_METRICS_ENABLED:false}
appsmith.micrometer.tracing.detail.enabled=${APPSMITH_ENABLE_TRACING_DETAIL:false}
appsmith.micrometer.metrics.detail.enabled=${APPSMITH_ENABLE_METRICS_DETAIL:false}
appsmith.micrometer.metrics.interval.millis=${APPSMITH_METRICS_INTERVAL_MILLIS:60000}
springdoc.api-docs.path=/v3/docs springdoc.api-docs.path=/v3/docs
springdoc.swagger-ui.path=/v3/swagger springdoc.swagger-ui.path=/v3/swagger