Skip to content

Commit

Permalink
AxonFramework#46: add configurable span operation name
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam-Kruglov committed Apr 24, 2020
1 parent 80d3633 commit 757bc89
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.axonframework.extensions.tracing.OpenTraceDispatchInterceptor;
import org.axonframework.extensions.tracing.OpenTraceHandlerInterceptor;
import org.axonframework.extensions.tracing.TracingCommandGateway;
import org.axonframework.extensions.tracing.TracingProperties;
import org.axonframework.extensions.tracing.TracingProvider;
import org.axonframework.extensions.tracing.TracingQueryGateway;
import org.axonframework.messaging.correlation.CorrelationDataProvider;
Expand All @@ -32,8 +33,11 @@
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
* Auto configure a tracing capabilities.
Expand All @@ -45,28 +49,42 @@
@Configuration
@AutoConfigureAfter(EventProcessingAutoConfiguration.class)
@ConditionalOnClass(io.opentracing.Tracer.class)
@Import(TracingAutoConfiguration.PropertiesConfiguration.class)
public class TracingAutoConfiguration {

@Configuration
public static class PropertiesConfiguration{

//must be defined in a separate @Configuration to ensure creation order
@Bean
@ConfigurationProperties(prefix = "axon.tracing")
public TracingProperties tracingProperties() {
return new TracingProperties();
}
}

@Bean
public OpenTraceDispatchInterceptor traceDispatchInterceptor(Tracer tracer) {
return new OpenTraceDispatchInterceptor(tracer);
}

@Bean
public OpenTraceHandlerInterceptor traceHandlerInterceptor(Tracer tracer) {
return new OpenTraceHandlerInterceptor(tracer);
public OpenTraceHandlerInterceptor traceHandlerInterceptor(Tracer tracer, TracingProperties properties) {
return new OpenTraceHandlerInterceptor(tracer, properties);
}

@Bean
@ConditionalOnMissingBean
public QueryGateway queryGateway(Tracer tracer,
QueryBus queryBus,
TracingProperties properties,
OpenTraceDispatchInterceptor openTraceDispatchInterceptor,
OpenTraceHandlerInterceptor openTraceHandlerInterceptor) {
queryBus.registerHandlerInterceptor(openTraceHandlerInterceptor);
TracingQueryGateway tracingQueryGateway = TracingQueryGateway.builder()
.delegateQueryBus(queryBus)
.tracer(tracer)
.tracingProperties(properties)
.build();
tracingQueryGateway.registerDispatchInterceptor(openTraceDispatchInterceptor);
return tracingQueryGateway;
Expand All @@ -76,12 +94,14 @@ public QueryGateway queryGateway(Tracer tracer,
@ConditionalOnMissingBean
public CommandGateway commandGateway(Tracer tracer,
CommandBus commandBus,
TracingProperties properties,
OpenTraceDispatchInterceptor openTraceDispatchInterceptor,
OpenTraceHandlerInterceptor openTraceHandlerInterceptor) {
commandBus.registerHandlerInterceptor(openTraceHandlerInterceptor);
TracingCommandGateway tracingCommandGateway = TracingCommandGateway.builder()
.tracer(tracer)
.delegateCommandBus(commandBus)
.tracingProperties(properties)
.build();
tracingCommandGateway.registerDispatchInterceptor(openTraceDispatchInterceptor);
return tracingCommandGateway;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.tag.Tags;
import org.axonframework.commandhandling.CommandMessage;
import org.axonframework.messaging.InterceptorChain;
import org.axonframework.messaging.Message;
import org.axonframework.messaging.MessageHandlerInterceptor;
import org.axonframework.messaging.MetaData;
import org.axonframework.messaging.unitofwork.UnitOfWork;
import org.axonframework.queryhandling.QueryMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -46,21 +48,33 @@ public class OpenTraceHandlerInterceptor implements MessageHandlerInterceptor<Me
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private final Tracer tracer;
private final TracingProperties.OperationNamePrefix spanOperationNamePrefix;

/**
* Initialize a {@link MessageHandlerInterceptor} implementation which uses the provided {@link Tracer} to map span
* information from the {@link Message}'s {@link MetaData} on a {@link SpanContext}.
*
* @param tracer the {@link Tracer} used to set a {@link SpanContext} on from a {@link Message}'s {@link MetaData}
* @param tracingProperties only those applicable to message handling will be used.
*/
public OpenTraceHandlerInterceptor(Tracer tracer) {
public OpenTraceHandlerInterceptor(Tracer tracer, TracingProperties tracingProperties) {
this.tracer = tracer;
this.spanOperationNamePrefix = tracingProperties.getHandle().getOperationNamePrefix();
}

@Override
public Object handle(UnitOfWork unitOfWork, InterceptorChain interceptorChain) throws Exception {
Message<?> message = unitOfWork.getMessage();
String operationName = "handle_" + SpanUtils.messageName(message);
String operationNamePrefix;
if (message instanceof CommandMessage) {
operationNamePrefix = spanOperationNamePrefix.getCommand();
} else if (message instanceof QueryMessage) {
operationNamePrefix = spanOperationNamePrefix.getQuery();
} else {
//fixme what prefix to use here?
operationNamePrefix = spanOperationNamePrefix.getCommand();
}
String operationName = operationNamePrefix + SpanUtils.messageName(message);

Tracer.SpanBuilder spanBuilder = getParentSpan(message)
.map(parentSpan -> tracer.buildSpan(operationName).asChildOf(parentSpan))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class TracingCommandGateway implements CommandGateway {

private final Tracer tracer;
private final CommandGateway delegate;
private final String spanOperationNamePrefix;

/**
* Instantiate a {@link TracingCommandGateway} based on the fields contained in the {@link Builder}.
Expand All @@ -74,6 +75,7 @@ protected TracingCommandGateway(Builder builder) {
builder.validate();
this.tracer = builder.tracer;
this.delegate = builder.buildDelegateCommandGateway();
this.spanOperationNamePrefix = builder.tracingProperties.getDispatch().getOperationNamePrefix().getCommand();
}

/**
Expand All @@ -95,7 +97,7 @@ public static Builder builder() {
@Override
public <C, R> void send(C command, CommandCallback<? super C, ? super R> callback) {
CommandMessage<? super C> cmd = GenericCommandMessage.asCommandMessage(command);
sendWithSpan("send_" + SpanUtils.messageName(cmd), cmd, (childSpan) -> {
sendWithSpan(spanOperationNamePrefix + SpanUtils.messageName(cmd), cmd, (childSpan) -> {
CompletableFuture<?> resultReceived = new CompletableFuture<>();
delegate.send(cmd, (CommandCallback<Object, R>) (commandMessage, commandResultMessage) -> {
try (Scope ignored = tracer.activateSpan(childSpan)) {
Expand Down Expand Up @@ -147,7 +149,7 @@ private <R> R doSendAndExtract(Object command,
FutureCallback<Object, R> futureCallback = new FutureCallback<>();

CommandMessage<?> cmd = GenericCommandMessage.asCommandMessage(command);
sendWithSpan("sendAndWait_" + SpanUtils.messageName(cmd), cmd, (childSpan) -> {
sendWithSpan(spanOperationNamePrefix + SpanUtils.messageName(cmd), cmd, (childSpan) -> {
delegate.send(cmd, futureCallback);
futureCallback.thenRun(() -> childSpan.log("resultReceived"));

Expand Down Expand Up @@ -208,6 +210,7 @@ public static class Builder {
private Tracer tracer;
private CommandBus delegateBus;
private CommandGateway delegateGateway;
private TracingProperties tracingProperties;

/**
* Sets the {@link Tracer} used to set a {@link Span} on dispatched {@link CommandMessage}s.
Expand Down Expand Up @@ -248,6 +251,17 @@ public Builder delegateCommandGateway(CommandGateway delegateGateway) {
return this;
}

/**
* Sets the tracing properties. Only those applicable to command dispatching will be used.
*
* @return the current Builder instance, for fluent interfacing
*/
public Builder tracingProperties(TracingProperties tracingProperties) {
assertNonNull(tracingProperties, "Tracing properties may not be null");
this.tracingProperties = tracingProperties;
return this;
}

/**
* Initializes a {@link TracingCommandGateway} as specified through this Builder.
*
Expand Down Expand Up @@ -279,6 +293,7 @@ private CommandGateway buildDelegateCommandGateway() {
*/
protected void validate() throws AxonConfigurationException {
assertNonNull(tracer, "The Tracer is a hard requirement and should be provided");
assertNonNull(tracingProperties, "The tracing properties is a hard requirement and should be provided");
if (delegateBus == null) {
assertNonNull(
delegateGateway, "The delegate CommandGateway is a hard requirement and should be provided"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2010-2020. Axon Framework
*
* 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
*
* http://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.axonframework.extensions.tracing;

/**
* Properties for tracing customizations.
*/
public class TracingProperties {

//fixme which coordinates are better?
//axon.tracing.{dispatch/handle}.{command/query}
// vs
//axon.tracing.{command/query}.{dispatch/handle}

public TracingProperties() {
setDefaults();
}

private Handle handle = new Handle();

private Dispatch dispatch = new Dispatch();

public Handle getHandle() {
return handle;
}

public void setHandle(Handle handle) {
this.handle = handle;
}

public Dispatch getDispatch() {
return dispatch;
}

public void setDispatch(Dispatch dispatch) {
this.dispatch = dispatch;
}

private void setDefaults() {
dispatch.getOperationNamePrefix().setCommand("fire_");
dispatch.getOperationNamePrefix().setQuery("ask_");
handle.getOperationNamePrefix().setCommand("handle_");
handle.getOperationNamePrefix().setQuery("serve_");
}

private static abstract class HasOperationNamePrefix {

private OperationNamePrefix operationNamePrefix = new OperationNamePrefix();

public OperationNamePrefix getOperationNamePrefix() {
return operationNamePrefix;
}

public void setOperationNamePrefix(OperationNamePrefix operationNamePrefix) {
this.operationNamePrefix = operationNamePrefix;
}
}

/**
* Customizations for message dispatching.
*/
public static class Dispatch extends HasOperationNamePrefix {
}

/**
* Customizations for message dispatching.
*/
public static class Handle extends HasOperationNamePrefix {

}

/**
* Span operation name for messages.
*/
public static class OperationNamePrefix {

/**
* Span operation name prefix for commands.
* <p/>
* E.g. given it's {@code "send_"}, the name would be {@code "send_MyCommand"}
*/
private String command;

/**
* Span operation name prefix for queries.
* <p/>
* E.g. given it's {@code "send_"}, the name would be {@code "send_MyQuery"}
*/
private String query;

public String getCommand() {
return command;
}

public void setCommand(String command) {
this.command = command;
}

public String getQuery() {
return query;
}

public void setQuery(String query) {
this.query = query;
}
}
}
Loading

0 comments on commit 757bc89

Please sign in to comment.