Deployer uses remoteServiceName; fixes gh-1947

This commit is contained in:
Marcin Grzejszczak
2021-05-13 09:16:11 +02:00
parent 181c789020
commit 4241bca952
6 changed files with 274 additions and 159 deletions

View File

@@ -14,11 +14,12 @@
* limitations under the License.
*/
package org.springframework.cloud.sleuth.instrument.deployer;
package org.springframework.cloud.sleuth.autoconfig.instrument.deployer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.deployer.spi.app.AppDeployer;
import org.springframework.cloud.sleuth.instrument.deployer.TraceAppDeployer;
import org.springframework.core.env.Environment;
/**

View File

@@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.deployer.spi.app.AppDeployer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.deployer.TraceAppDeployerBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.sleuth.instrument.deployer;
import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -67,17 +68,11 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public String deploy(AppDeploymentRequest request) {
Span span = tracer().nextSpan().name("deploy");
// TODO: Is this secure to pass?
// TODO: Does it make sense?
// if (!request.getCommandlineArguments().isEmpty()) {
// span.tag("commandlineArguments", request.getCommandlineArguments().toString());
// }
// if (!request.getDeploymentProperties().isEmpty()) {
// span.tag("deploymentProperties", request.getDeploymentProperties().toString());
// }
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span.start())) {
span.event("start");
Span.Builder spanBuilder = clientSpan("deploy");
Span span = spanBuilder.start();
// Span span = tracer().nextSpan().name("deploy");
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span)) {
span.event("deployer.start");
String id = this.delegate.deploy(request);
span.tag("deployer.app.id", id);
registerListener(span, id);
@@ -85,6 +80,56 @@ public class TraceAppDeployer implements AppDeployer {
}
}
private Span.Builder clientSpan(String name) {
Span.Builder spanBuilder = tracer().spanBuilder();
Span currentSpan = tracer().currentSpan();
if (currentSpan != null) {
spanBuilder.setParent(currentSpan.context());
}
return clientSpanKind(name, spanBuilder);
}
private Span.Builder clientSpanKind(String name, Span.Builder spanBuilder) {
return spanBuilder.kind(Span.Kind.CLIENT).name(name).remoteServiceName(remoteServiceName());
}
private Span.Builder clientSpan(String name, Span parentSpan) {
Span.Builder spanBuilder = tracer().spanBuilder();
Span currentSpan = parentSpan != null ? parentSpan : tracer().currentSpan();
if (currentSpan != null) {
spanBuilder.setParent(currentSpan.context());
}
Map<String, String> platformSpecificInfo = environmentInfo().getPlatformSpecificInfo();
addCfTags(spanBuilder, platformSpecificInfo);
addK8sTags(spanBuilder, platformSpecificInfo);
return clientSpanKind(name, spanBuilder);
}
private void addCfTags(Span.Builder spanBuilder, Map<String, String> platformSpecificInfo) {
if (platformSpecificInfo.containsKey("API Endpoint")) {
spanBuilder.tag("deployer.platform.cf.url", platformSpecificInfo.get("API Endpoint"));
}
if (platformSpecificInfo.containsKey("Organization")) {
spanBuilder.tag("deployer.platform.cf.org", platformSpecificInfo.get("Organization"));
}
if (platformSpecificInfo.containsKey("Space")) {
spanBuilder.tag("deployer.platform.cf.space", platformSpecificInfo.get("Space"));
}
}
private void addK8sTags(Span.Builder spanBuilder, Map<String, String> platformSpecificInfo) {
if (platformSpecificInfo.containsKey("master-url")) {
spanBuilder.tag("deployer.platform.k8s.url", platformSpecificInfo.get("master-url"));
}
if (platformSpecificInfo.containsKey("namespace")) {
spanBuilder.tag("deployer.platform.k8s.namespace", platformSpecificInfo.get("namespace"));
}
}
private String remoteServiceName() {
return environmentInfo().getPlatformType();
}
private void registerListener(Span span, String id) {
PreviousAndCurrentStatus previousAndCurrentStatus = new PreviousAndCurrentStatus(span);
// @formatter:off
@@ -102,10 +147,11 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public void undeploy(String id) {
Span span = tracer().nextSpan().name("undeploy");
Span.Builder spanBuilder = clientSpan("undeploy");
Span span = spanBuilder.start();
span.tag("deployer.app.id", id);
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span.start())) {
span.event("start");
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span)) {
span.event("deployer.start");
this.delegate.undeploy(id);
registerListener(span, id);
}
@@ -116,7 +162,8 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public AppStatus status(String id) {
Span span = tracer().nextSpan().name("status");
Span.Builder spanBuilder = clientSpan("status");
Span span = spanBuilder.start();
span.tag("deployer.app.id", id);
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span.start())) {
return this.delegate.status(id);
@@ -129,14 +176,16 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public Mono<AppStatus> statusReactive(String id) {
return ReactorSleuth.tracedMono(tracer(), currentTraceContext(), "status",
() -> this.delegate.statusReactive(id), (o, span) -> span.tag("deployer.app.id", id));
() -> this.delegate.statusReactive(id), (o, span) -> span.tag("deployer.app.id", id),
span -> clientSpan("status", span).start());
}
@Override
public Flux<AppStatus> statusesReactive(String... ids) {
return ReactorSleuth.tracedFlux(tracer(), currentTraceContext(), "statuses",
() -> this.delegate.statusesReactive(ids),
(o, span) -> span.tag("deployer.app.ids", Arrays.toString(ids)));
(o, span) -> span.tag("deployer.app.ids", Arrays.toString(ids)),
span -> clientSpan("statuses", span).start());
}
@Override
@@ -146,9 +195,10 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public String getLog(String id) {
Span span = tracer().nextSpan().name("getLog");
Span.Builder spanBuilder = clientSpan("getLog");
Span span = spanBuilder.start();
span.tag("deployer.app.id", id);
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span.start())) {
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span)) {
return this.delegate.getLog(id);
}
finally {
@@ -158,15 +208,10 @@ public class TraceAppDeployer implements AppDeployer {
@Override
public void scale(AppScaleRequest appScaleRequest) {
Span span = tracer().nextSpan().name("scale");
Span.Builder spanBuilder = clientSpan("scale");
Span span = spanBuilder.start();
span.tag("deployer.scale.deploymentId", appScaleRequest.getDeploymentId());
span.tag("deployer.scale.count", String.valueOf(appScaleRequest.getCount()));
// TODO: Is this secure to pass?
// TODO: Does it make sense?
// if (appScaleRequest.getProperties().isPresent() &&
// !appScaleRequest.getProperties().get().isEmpty()) {
// span.tag("properties", appScaleRequest.getProperties().get().toString());
// }
try (Tracer.SpanInScope spanInScope = tracer().withSpan(span.start())) {
this.delegate.scale(appScaleRequest);
}

View File

@@ -338,6 +338,25 @@ public abstract class ReactorSleuth {
context -> ReactorSleuth.enhanceContext(tracer, currentTraceContext, context, childSpanName));
}
/**
* Wraps the given Mono in a trace representation. Retrieves the span from context,
* creates a child span with the given name.
* @param tracer - Tracer bean
* @param currentTraceContext - CurrentTraceContext bean
* @param childSpanName - name of the created child span
* @param supplier - supplier of a {@link Mono} to be wrapped in tracing
* @param <T> - type returned by the Mono
* @param spanCustomizer - customizer for the child span
* @param spanFunction - function that creates a new or child span
* @return traced Mono
*/
public static <T> Mono<T> tracedMono(@NonNull Tracer tracer, @NonNull CurrentTraceContext currentTraceContext,
@NonNull String childSpanName, @NonNull Supplier<Mono<T>> supplier,
@NonNull BiConsumer<T, Span> spanCustomizer, @NonNull Function<Span, Span> spanFunction) {
return runMonoSupplierInScope(supplier, spanCustomizer).contextWrite(context -> ReactorSleuth
.enhanceContext(tracer, currentTraceContext, context, childSpanName, spanFunction));
}
private static <T> Mono<T> runMonoSupplierInScope(Supplier<Mono<T>> supplier, BiConsumer<T, Span> spanCustomizer) {
return Mono.deferContextual(contextView -> {
Span span = contextView.get(Span.class);
@@ -407,6 +426,25 @@ public abstract class ReactorSleuth {
context -> ReactorSleuth.enhanceContext(tracer, currentTraceContext, context, childSpanName));
}
/**
* Wraps the given Flux in a trace representation. Retrieves the span from context,
* creates a child span with the given name.
* @param tracer - Tracer bean
* @param currentTraceContext - CurrentTraceContext bean
* @param childSpanName - name of the created child span
* @param supplier - supplier of a {@link Flux} to be wrapped in tracing
* @param <T> - type returned by the Flux
* @param spanCustomizer - customizer for the child span
* @param spanFunction - function that creates a new or child span
* @return traced Flux
*/
public static <T> Flux<T> tracedFlux(@NonNull Tracer tracer, @NonNull CurrentTraceContext currentTraceContext,
@NonNull String childSpanName, @NonNull Supplier<Flux<T>> supplier,
@NonNull BiConsumer<T, Span> spanCustomizer, @NonNull Function<Span, Span> spanFunction) {
return runFluxSupplierInScope(supplier, spanCustomizer).contextWrite(context -> ReactorSleuth
.enhanceContext(tracer, currentTraceContext, context, childSpanName, spanFunction));
}
/**
* Wraps the given Flux in a trace representation. Retrieves the span from context,
* creates a child span with the given name.
@@ -461,10 +499,16 @@ public abstract class ReactorSleuth {
private static Span childSpanFromContext(Tracer tracer, CurrentTraceContext currentTraceContext,
reactor.util.context.Context context, String childSpanName) {
return childSpanFromContext(currentTraceContext, context, childSpanName,
span -> span == null ? tracer.nextSpan() : tracer.nextSpan(span));
}
private static Span childSpanFromContext(CurrentTraceContext currentTraceContext,
reactor.util.context.Context context, String childSpanName, Function<Span, Span> spanSupplier) {
TraceContext traceContext = context.getOrDefault(TraceContext.class, null);
Span span = context.getOrDefault(Span.class, null);
if (traceContext == null && span == null) {
span = tracer.nextSpan();
span = spanSupplier.apply(null);
if (log.isDebugEnabled()) {
log.debug("There was no previous span in reactor context, created a new one [" + span + "]");
}
@@ -475,7 +519,7 @@ public abstract class ReactorSleuth {
if (log.isDebugEnabled()) {
log.debug("Found a trace context in reactor context [" + traceContext + "]");
}
span = tracer.nextSpan();
span = spanSupplier.apply(null);
if (log.isDebugEnabled()) {
log.debug("Created a child span [" + span + "]");
}
@@ -485,7 +529,7 @@ public abstract class ReactorSleuth {
if (log.isDebugEnabled()) {
log.debug("Found a span in reactor context [" + span + "]");
}
span = tracer.nextSpan(span);
span = spanSupplier.apply(span);
if (log.isDebugEnabled()) {
log.debug("Created a child span [" + span + "]");
}
@@ -493,6 +537,22 @@ public abstract class ReactorSleuth {
return span.name(childSpanName).start();
}
/**
* Updates the Reactor context with tracing information. Creates a new span if there
* is no current span. Creates a child span if there was an entry in the context
* already.
* @param currentTraceContext current trace context
* @param context Reactor context
* @param childSpanName child span name when there is no span in context
* @param spanSupplier function that creates a new or child span
* @return updated Reactor context
*/
public static Context enhanceContext(Tracer tracer, CurrentTraceContext currentTraceContext,
reactor.util.context.Context context, String childSpanName, Function<Span, Span> spanSupplier) {
Span span = childSpanFromContext(currentTraceContext, context, childSpanName, spanSupplier);
return putSpanInScope(tracer, context, span);
}
/**
* Updates the Reactor context with tracing information. Creates a new span if there
* is no current span. Creates a child span if there was an entry in the context

View File

@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map;
import org.assertj.core.api.BDDAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import reactor.core.publisher.Flux;
@@ -34,6 +35,7 @@ import org.springframework.cloud.deployer.spi.app.AppScaleRequest;
import org.springframework.cloud.deployer.spi.app.AppStatus;
import org.springframework.cloud.deployer.spi.core.AppDefinition;
import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest;
import org.springframework.cloud.deployer.spi.core.RuntimeEnvironmentInfo;
import org.springframework.cloud.sleuth.tracer.NoOpCurrentTraceContext;
import org.springframework.cloud.sleuth.tracer.SimpleTracer;
import org.springframework.core.env.Environment;
@@ -48,6 +50,14 @@ class TraceAppDeployerTests {
TraceAppDeployer traceAppDeployer = new TraceAppDeployer(this.delegate, beanFactory(), environment());
@BeforeEach
void setup() {
BDDMockito.given(this.delegate.environmentInfo())
.willReturn(new RuntimeEnvironmentInfo.Builder().spiClass(Object.class).implementationName("asd")
.implementationVersion("asd").platformType("asd").platformApiVersion("asd")
.platformClientVersion("asd").platformHostVersion("asd").build());
}
@Test
void should_trace_deploy() {
BDDMockito.given(this.delegate.statusReactive(BDDMockito.any()))

View File

@@ -1,128 +1,128 @@
/*
* Copyright 2013-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.sleuth.tracer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.assertj.core.api.BDDAssertions;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanCustomizer;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;
/**
* A noop implementation. Does nothing.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class SimpleTracer implements Tracer {
public List<SimpleSpan> spans = new ArrayList<>();
@Override
public Span nextSpan(Span parent) {
return new SimpleSpan();
}
public SimpleSpan getOnlySpan() {
BDDAssertions.then(this.spans).hasSize(1);
SimpleSpan span = this.spans.get(0);
BDDAssertions.then(span.started).as("Span must be started").isTrue();
BDDAssertions.then(span.ended).as("Span must be finished").isTrue();
return span;
}
public SimpleSpan getLastSpan() {
BDDAssertions.then(this.spans).isNotEmpty();
SimpleSpan span = this.spans.get(this.spans.size() - 1);
BDDAssertions.then(span.started).as("Span must be started").isTrue();
return span;
}
@Override
public SpanInScope withSpan(Span span) {
return new NoOpSpanInScope();
}
@Override
public SpanCustomizer currentSpanCustomizer() {
return null;
}
@Override
public Span currentSpan() {
if (this.spans.isEmpty()) {
return null;
}
return this.spans.get(spans.size() - 1);
}
@Override
public SimpleSpan nextSpan() {
final SimpleSpan span = new SimpleSpan();
this.spans.add(span);
return span;
}
@Override
public ScopedSpan startScopedSpan(String name) {
return null;
}
@Override
public Span.Builder spanBuilder() {
return new SimpleSpanBuilder();
}
@Override
public TraceContext.Builder traceContextBuilder() {
return null;
}
@Override
public Map<String, String> getAllBaggage() {
return new HashMap<>();
}
@Override
public BaggageInScope getBaggage(String name) {
return null;
}
@Override
public BaggageInScope getBaggage(TraceContext traceContext, String name) {
return null;
}
@Override
public BaggageInScope createBaggage(String name) {
return null;
}
@Override
public BaggageInScope createBaggage(String name, String value) {
return null;
}
}
/*
* Copyright 2013-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.sleuth.tracer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.assertj.core.api.BDDAssertions;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanCustomizer;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;
/**
* A noop implementation. Does nothing.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class SimpleTracer implements Tracer {
public List<SimpleSpan> spans = new ArrayList<>();
@Override
public Span nextSpan(Span parent) {
return new SimpleSpan();
}
public SimpleSpan getOnlySpan() {
BDDAssertions.then(this.spans).hasSize(1);
SimpleSpan span = this.spans.get(0);
BDDAssertions.then(span.started).as("Span must be started").isTrue();
BDDAssertions.then(span.ended).as("Span must be finished").isTrue();
return span;
}
public SimpleSpan getLastSpan() {
BDDAssertions.then(this.spans).isNotEmpty();
SimpleSpan span = this.spans.get(this.spans.size() - 1);
BDDAssertions.then(span.started).as("Span must be started").isTrue();
return span;
}
@Override
public SpanInScope withSpan(Span span) {
return new NoOpSpanInScope();
}
@Override
public SpanCustomizer currentSpanCustomizer() {
return null;
}
@Override
public Span currentSpan() {
if (this.spans.isEmpty()) {
return null;
}
return this.spans.get(spans.size() - 1);
}
@Override
public SimpleSpan nextSpan() {
final SimpleSpan span = new SimpleSpan();
this.spans.add(span);
return span;
}
@Override
public ScopedSpan startScopedSpan(String name) {
return null;
}
@Override
public Span.Builder spanBuilder() {
return new SimpleSpanBuilder();
}
@Override
public TraceContext.Builder traceContextBuilder() {
return null;
}
@Override
public Map<String, String> getAllBaggage() {
return new HashMap<>();
}
@Override
public BaggageInScope getBaggage(String name) {
return null;
}
@Override
public BaggageInScope getBaggage(TraceContext traceContext, String name) {
return null;
}
@Override
public BaggageInScope createBaggage(String name) {
return null;
}
@Override
public BaggageInScope createBaggage(String name, String value) {
return null;
}
}