chore: Removed manipulation for custom traceparent header (#37121)
This commit is contained in:
parent
d6305bad82
commit
e7e3d5e002
|
|
@ -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",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user