You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Spring Cloud Sleuth对Spring-WS编写的SOAP服务进行埋点?

Spring Cloud Sleuth for Spring-WS SOAP Services: Implementation Guide

Absolutely! You can implement distributed tracing with Spring Cloud Sleuth for SOAP web services built with Spring-WS—you just need to extend a few key components since it’s not out-of-the-box like REST services. Here’s a practical, step-by-step approach to make it work:

1. Create a Server-Side SOAP Interceptor for Span Management

Spring-WS uses EndpointInterceptor to hook into the request lifecycle. We’ll build an interceptor to initialize, manage, and close Sleuth spans as SOAP requests flow through your service.

Example Server Interceptor

@Component
public class SleuthSoapServerInterceptor implements EndpointInterceptor {

    private final Tracer tracer;

    // Inject Sleuth's core Tracer component via constructor
    public SleuthSoapServerInterceptor(Tracer tracer) {
        this.tracer = tracer;
    }

    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        // Extract trace context from incoming SOAP headers (if passed from upstream services)
        SoapMessage soapRequest = (SoapMessage) messageContext.getRequest();
        SoapHeader soapHeader = soapRequest.getSoapHeader();
        
        String incomingTraceId = null;
        String incomingSpanId = null;

        if (soapHeader != null) {
            Iterator<SoapHeaderElement> headerElements = soapHeader.examineAllHeaderElements();
            while (headerElements.hasNext()) {
                SoapHeaderElement element = headerElements.next();
                String headerName = element.getName().getLocalPart();
                if ("X-B3-TraceId".equals(headerName)) {
                    incomingTraceId = element.getText();
                } else if ("X-B3-SpanId".equals(headerName)) {
                    incomingSpanId = element.getText();
                }
            }
        }

        // Create or continue a span
        Span span;
        if (incomingTraceId != null && incomingSpanId != null) {
            // Continue the trace from upstream
            span = tracer.nextSpan(Span.contextBuilder()
                    .traceId(incomingTraceId)
                    .spanId(incomingSpanId)
                    .build());
        } else {
            // Start a new trace
            span = tracer.nextSpan().name("soap-server-request");
        }

        // Activate the span for the current request context
        tracer.withSpan(span.start());
        return true;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        // Close the span when the response is sent
        finishCurrentSpan(null);
        return true;
    }

    @Override
    public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
        // Mark the span as errored if a SOAP fault occurs
        finishCurrentSpan(new RuntimeException("SOAP Fault encountered"));
        return true;
    }

    @Override
    public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
        // Fallback to ensure the span is always closed, even if an unhandled exception occurs
        finishCurrentSpan(ex);
    }

    private void finishCurrentSpan(Exception ex) {
        Span currentSpan = tracer.currentSpan();
        if (currentSpan != null) {
            if (ex != null) {
                currentSpan.error(ex);
            }
            currentSpan.end();
        }
    }
}

Register the Server Interceptor

Add the interceptor to your Spring-WS configuration to activate it:

@Configuration
public class SoapWebServiceConfig implements WsConfigurer {

    private final SleuthSoapServerInterceptor sleuthInterceptor;

    public SoapWebServiceConfig(SleuthSoapServerInterceptor sleuthInterceptor) {
        this.sleuthInterceptor = sleuthInterceptor;
    }

    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(sleuthInterceptor);
    }

    // Add other Spring-WS configs (e.g., MessageDispatcherServlet, DefaultWsdl11Definition) here
}

2. Propagate Trace Context to Downstream Services (If Needed)

If your SOAP service calls other services (SOAP or REST), you need to pass the Sleuth trace context downstream. For SOAP calls, we’ll use a client-side interceptor to inject trace headers into outgoing SOAP requests.

Example Client Interceptor

@Component
public class SleuthSoapClientInterceptor implements ClientInterceptor {

    private final Tracer tracer;

    public SleuthSoapClientInterceptor(Tracer tracer) {
        this.tracer = tracer;
    }

    @Override
    public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
        SoapMessage soapRequest = (SoapMessage) messageContext.getRequest();
        SoapHeader soapHeader = soapRequest.getSoapHeader();
        
        if (soapHeader != null) {
            Span currentSpan = tracer.currentSpan();
            if (currentSpan != null) {
                // Add B3 protocol headers to the SOAP request
                QName traceIdQName = new QName("https://your-service-namespace.com", "X-B3-TraceId");
                soapHeader.addHeaderElement(traceIdQName).setText(currentSpan.context().traceId());
                
                QName spanIdQName = new QName("https://your-service-namespace.com", "X-B3-SpanId");
                soapHeader.addHeaderElement(spanIdQName).setText(currentSpan.context().spanId());
                
                QName sampledQName = new QName("https://your-service-namespace.com", "X-B3-Sampled");
                soapHeader.addHeaderElement(sampledQName).setText("1");
            }
        }
        return true;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
        return true;
    }

    @Override
    public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
        // Mark the current span as errored if a fault is received
        if (tracer.currentSpan() != null) {
            tracer.currentSpan().error(new RuntimeException("Downstream SOAP Fault received"));
        }
        return true;
    }

    @Override
    public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException {
        if (ex != null && tracer.currentSpan() != null) {
            tracer.currentSpan().error(ex);
        }
    }
}

Attach the Client Interceptor to WebServiceTemplate

@Bean
public WebServiceTemplate webServiceTemplate(SleuthSoapClientInterceptor clientInterceptor) {
    WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
    // Set your default URI, message factories, etc.
    webServiceTemplate.setInterceptors(new ClientInterceptor[]{clientInterceptor});
    return webServiceTemplate;
}

3. Update Logging to Include Trace IDs

Make sure your logging configuration includes Sleuth’s MDC variables so you can correlate logs across the trace. For Logback, update your logback.xml:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg | traceId: %X{traceId:-} | spanId: %X{spanId:-}%n</pattern>
    </encoder>
</appender>

Key Notes

  • B3 Protocol: We’re using the standard B3 trace headers (X-B3-TraceId, X-B3-SpanId) for compatibility with other tracing systems (like Zipkin). You can adjust the header names if needed, but sticking to B3 is recommended.
  • Error Handling: The interceptors ensure spans are marked as errored when exceptions or SOAP faults occur, which helps with debugging in tracing UIs.
  • Customization: You can extend the interceptors to add additional span tags (e.g., SOAP operation name, request payload metadata) for richer trace data.

内容的提问来源于stack exchange,提问作者Ian Cccc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:01:53