Skip to content

Commit

Permalink
#72 First of all: Yes, this is pretty ugly. Sure, point taken and ple…
Browse files Browse the repository at this point in the history
…ase keep in mind that this commit is a WIP one ;)

I would like to discuss the idea behind logging and the current implementation to find a sweet spot for this starter. My way is to move some implicit couplings to the ELK Stack out of this codebase.
The CXF Logging Feature (https://cxf.apache.org/docs/message-logging.html) can handle some of our needs.

This change would cause us to talk about the configuration properties.
E.g.
* I can control logging of WebService endpoints using the standard spring boot mechanisms.
* (Re)move explicit creation of ELK Tags and use the one created by the Feature?
  • Loading branch information
marcopaga committed Oct 23, 2020
1 parent ee1109c commit b69024e
Show file tree
Hide file tree
Showing 14 changed files with 52 additions and 372 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>cxf-spring-boot-starter</artifactId>
<version>2.3.0.RELEASE</version>
<version>2.3.1-jaxb-jaxws-3.0.0-M4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package de.codecentric.soap.configuration;

import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingInInterceptor;
import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingOutInterceptor;
import de.codecentric.namespace.weatherservice.WeatherService;
import org.apache.cxf.interceptor.AbstractLoggingInterceptor;
import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.http.MediaType;

@Configuration
@PropertySource("classpath:application.properties")
Expand All @@ -32,25 +31,6 @@ public WeatherService weatherServiceClient() {
JaxWsProxyFactoryBean jaxWsFactory = new JaxWsProxyFactoryBean();
jaxWsFactory.setServiceClass(WeatherService.class);
jaxWsFactory.setAddress(clientUrl);
jaxWsFactory.getInInterceptors().add(logInInterceptorClientSoapMsgLogger());
jaxWsFactory.getOutInterceptors().add(logOutInterceptorClientSoapMsgLogger());
return (WeatherService) jaxWsFactory.create();
}

@Bean
public AbstractLoggingInterceptor logInInterceptorClientSoapMsgLogger() {
SoapMessageLoggingInInterceptor logInInterceptor = new SoapMessageLoggingInInterceptor();
logInInterceptor.logSoapMessage(true);
logInInterceptor.setPrettyLogging(true);
return logInInterceptor;
}

@Bean
public AbstractLoggingInterceptor logOutInterceptorClientSoapMsgLogger() {
SoapMessageLoggingOutInterceptor logOutInterceptor = new SoapMessageLoggingOutInterceptor();
logOutInterceptor.logSoapMessage(true);
logOutInterceptor.setPrettyLogging(true);
return logOutInterceptor;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
server.port=8095

# SOAP client configuration (which SOAP server we want to access)
webservice.client.url = https://cxf-boot-simple.herokuapp.com/my-foo-api/Weather
webservice.client.url = http://localhost:8080/my-foo-api/Weather

# cxf-spring-boot-starter configuration in client-only mode
soap.messages.logging=true
Expand Down
2 changes: 1 addition & 1 deletion cxf-spring-boot-starter-samples/cxf-boot-simple/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>cxf-spring-boot-starter</artifactId>
<version>2.3.0.RELEASE</version>
<version>2.3.1-jaxb-jaxws-3.0.0-M4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ soap.messages.extract=true

# endpoint.autoinit=false

logging.level.org.apache.cxf: INFO

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.codecentric.soap.configuration;

import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingInInterceptor;
import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingOutInterceptor;
import org.apache.cxf.ext.logging.LoggingFeature;
import org.apache.cxf.interceptor.AbstractLoggingInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -15,6 +14,7 @@
import de.codecentric.cxf.configuration.CxfAutoConfiguration;
import de.codecentric.cxf.soaprawclient.SoapRawClient;
import de.codecentric.namespace.weatherservice.WeatherService;
import org.springframework.http.MediaType;

@Configuration
@PropertySource("classpath:dev-test.properties")
Expand All @@ -40,27 +40,18 @@ public WeatherService weatherServiceClient() {
JaxWsProxyFactoryBean jaxWsFactory = new JaxWsProxyFactoryBean();
jaxWsFactory.setServiceClass(WeatherService.class);
jaxWsFactory.setAddress(buildUrl());
jaxWsFactory.getInInterceptors().add(logInInterceptorClientSoapMsgLogger());
jaxWsFactory.getOutInterceptors().add(logOutInterceptorClientSoapMsgLogger());
jaxWsFactory.getFeatures().add(loggingFeature());
return (WeatherService) jaxWsFactory.create();
}

@Bean
public AbstractLoggingInterceptor logInInterceptorClientSoapMsgLogger() {
SoapMessageLoggingInInterceptor logInInterceptor = new SoapMessageLoggingInInterceptor();
logInInterceptor.logSoapMessage(true);
logInInterceptor.setPrettyLogging(true);
return logInInterceptor;
public LoggingFeature loggingFeature() {
LoggingFeature loggingFeature = new LoggingFeature();
loggingFeature.setPrettyLogging(true);
loggingFeature.addBinaryContentMediaTypes(MediaType.APPLICATION_PDF_VALUE);
return loggingFeature;
}

@Bean
public AbstractLoggingInterceptor logOutInterceptorClientSoapMsgLogger() {
SoapMessageLoggingOutInterceptor logOutInterceptor = new SoapMessageLoggingOutInterceptor();
logOutInterceptor.logSoapMessage(true);
logOutInterceptor.setPrettyLogging(true);
return logOutInterceptor;
}

/*
* SoapRawClient for XmlErrorTests
*/
Expand Down
7 changes: 6 additions & 1 deletion cxf-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-features-logging</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- Apache CXF from Java 11 on - see https://stackoverflow.com/questions/55476331/tomcat8-5-and-openjdk11-noclassdeffounderror-could-not-initialize-class-org-apa -->
<dependency>
<groupId>com.sun.activation</groupId>
Expand Down Expand Up @@ -197,4 +202,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import de.codecentric.cxf.common.BootStarterCxfException;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.feature.Feature;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
Expand Down Expand Up @@ -52,6 +54,12 @@ public class CxfAutoConfiguration {
@Value("${cxf.servicelist.title:CXF SpringBoot Starter - service list}")
private String serviceListTitle;

@Autowired(required = false)
private Feature loggingFeature;

@Value("${soap.messages.logging:false}")
private boolean soapMessagesLogging;

private String serviceUrlEnding = "";
private Object seiImplementation;
private Service webServiceClient;
Expand Down Expand Up @@ -111,13 +119,20 @@ public Object seiImplementation() throws BootStarterCxfException {
return seiImplementation;
}

private void activateEndpointFeatures(EndpointImpl endpoint) {
if(soapMessagesLogging && loggingFeature != null){
endpoint.getFeatures().add(loggingFeature);
}
}

@Bean
@ConditionalOnProperty(name = "endpoint.autoinit", matchIfMissing = true)
public Endpoint endpoint() throws BootStarterCxfException {

LOG.info("Autodetection successful. Initializing javax.xml.ws.Endpoint based on " + seiImplementation().getClass().getName());

EndpointImpl endpoint = new EndpointImpl(springBus(), seiImplementation());
activateEndpointFeatures(endpoint);
// CXF JAX-WS implementation relies on the correct ServiceName as QName-Object with
// the name-Attribute´s text <wsdl:service name="Weather"> and the targetNamespace
// "http://www.codecentric.de/namespace/weatherservice/"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package de.codecentric.cxf.configuration;

import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingInInterceptor;
import de.codecentric.cxf.logging.soapmsg.SoapMessageLoggingOutInterceptor;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.interceptor.AbstractLoggingInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.cxf.ext.logging.LoggingFeature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import org.springframework.http.MediaType;

/**
* Logging of SoapMessages to e.g. Console. To activate, set property soap.messages.logging=true.
Expand All @@ -23,71 +19,16 @@
* @author Jonas Hecht
*/
@Configuration
@Conditional(SoapMessageLoggerConfiguration.SoapMessageLoggerPropertyCondition.class)
@ConditionalOnProperty(name = "endpoint.autoinit", matchIfMissing = true)
public class SoapMessageLoggerConfiguration {

@Autowired
private SpringBus springBus;

@Bean
@ConditionalOnProperty("soap.messages.logging")
public String loggingActivatedLogger() {
((SoapMessageLoggingInInterceptor) logInInterceptorSoapMsgLogger()).logSoapMessage(true);
((SoapMessageLoggingOutInterceptor) logOutInterceptorSoapMsgLogger()).logSoapMessage(true);
return "unused - this is just to activate Logging of SoapMessages via SpringBoot";
}

@Bean
@ConditionalOnProperty("soap.messages.extract")
@ConditionalOnResource(resources = "classpath:logback-spring.xml")
public String extractionActivatedLogger() {
((SoapMessageLoggingInInterceptor) logInInterceptorSoapMsgLogger()).extractSoapMessage(true);
((SoapMessageLoggingOutInterceptor) logOutInterceptorSoapMsgLogger()).extractSoapMessage(true);
return "unused - this is just to activate Extraction of SoapMessages via SpringBoot";
}


@PostConstruct
public void activateLoggingFeature() {
// Log SoapMessages to Logfile
springBus.getInInterceptors().add(logInInterceptorSoapMsgLogger());
springBus.getInFaultInterceptors().add(logInInterceptorSoapMsgLogger());
springBus.getOutInterceptors().add(logOutInterceptorSoapMsgLogger());
springBus.getOutFaultInterceptors().add(logOutInterceptorSoapMsgLogger());
}

@Bean
public AbstractLoggingInterceptor logInInterceptorSoapMsgLogger() {
SoapMessageLoggingInInterceptor logInInterceptor = new SoapMessageLoggingInInterceptor();
logInInterceptor.setPrettyLogging(true);
return logInInterceptor;
}

@Bean
public AbstractLoggingInterceptor logOutInterceptorSoapMsgLogger() {
SoapMessageLoggingOutInterceptor logOutInterceptor = new SoapMessageLoggingOutInterceptor();
logOutInterceptor.setPrettyLogging(true);
return logOutInterceptor;
}

/*
* This way we can provide the behavior to autoconfigure this Logger, if one of the properties
* soap.message.logging and/or soap.message.extract are provided in application.properties of the
* using project
* It´s a kind of workaround, till Spring Boot supports the Repeatable @ConditionalOnProperty
* (https://github.com/spring-projects/spring-boot/issues/2541)
*/
static class SoapMessageLoggerPropertyCondition extends AnyNestedCondition {

SoapMessageLoggerPropertyCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}

@ConditionalOnProperty("soap.messages.logging")
static class LoggingEnabled {}
@Bean
public LoggingFeature loggingFeature() {
LoggingFeature loggingFeature = new LoggingFeature();
loggingFeature.setPrettyLogging(true);
loggingFeature.setVerbose(true);
loggingFeature.addBinaryContentMediaTypes(MediaType.APPLICATION_PDF_VALUE);
return loggingFeature;
}

@ConditionalOnProperty("soap.messages.extract")
static class ElasticSearchExtractionEnabled {}
}
}
Loading

0 comments on commit b69024e

Please sign in to comment.