Migrating from OpenTracing to OpenTelemetry - spring-boot

So I was using Open Tracing to trace calls to the microservice. I used to do it the following way:
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-api</artifactId>
<version>0.31.0</version>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-starter</artifactId>
<version>0.1.13</version>
</dependency>
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-client</artifactId>
<version>0.31.0</version>
</dependency>
Then add following bean:
#Bean
public Tracer initTracer() {
Configuration.SamplerConfiguration samplerConfig = new Configuration.SamplerConfiguration().withType("const").withParam(1);
Configuration.ReporterConfiguration reporterConfig = Configuration.ReporterConfiguration.fromEnv().withLogSpans(true);
return Configuration.fromEnv("my-service").withSampler(samplerConfig).withReporter(reporterConfig).getTracer();
}
When running I usually get these span reported logs whenever an external request is given to the application.
But with open telemetry I cannot simply do this anymore. What is the correct way to simulate the behaviour?

Related

Resource leak detected when using spring-data-redis on cloud foundry

We develop a spring-boot service, which offers a rest api (spring-webflux) and sends data via RabbitMQ (spring-rabbit). The service is deployed on cloud foundry and we use spring-boot in version 2.1.4. We added spring-boot-starter-data-redis to use redis to cache some data and we got the following error:
[io.netty.util.ResourceLeakDetector] [] LEAK: HashedWheelTimer.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:284)
io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:217)
io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:196)
io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:178)
io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:162)
io.lettuce.core.resource.DefaultClientResources.<init>(DefaultClientResources.java:169)
io.lettuce.core.resource.DefaultClientResources$Builder.build(DefaultClientResources.java:532)
io.lettuce.core.resource.DefaultClientResources.create(DefaultClientResources.java:233)
io.lettuce.core.AbstractRedisClient.<init>(AbstractRedisClient.java:98)
io.lettuce.core.RedisClient.<init>(RedisClient.java:87)
io.lettuce.core.RedisClient.create(RedisClient.java:124)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.lambda$createClient$7(LettuceConnectionFactory.java:971)
java.base/java.util.Optional.orElseGet(Unknown Source)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:971)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:273)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:88)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:31)
org.springframework.cloud.Cloud.getServiceConnector(Cloud.java:288)
org.springframework.cloud.Cloud.getSingletonServiceConnector(Cloud.java:202)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:260)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:242)
...
This error only happens when we run the service on cloud foundry, if we run it locally, we don't get any error.
We don't do any configuration of the connection factory or the stringRedisTemplate on our side and only use stringRedisTemplate, which is configured by the spring-autoconfiguration.
We use following configuration for redis on cloud foundry:
#Configuration
#Profile( "cloud" )
public class CloudSpecificConfig extends AbstractCloudConfig {
#Bean
public RedisConnectionFactory redisConnectionFactory() {
return connectionFactory().redisConnectionFactory();
}
}
And this is how we use the template
#Component
#RequiredArgsConstructor
public final class RequestUtil {
private final StringRedisTemplate myRedisTemplate;
public String cacheId(String id, String value) {
myRedisTemplate.opsForValue().set( id, value );
}
}
These are our spring dependencies:
<properties>
<spring-boot-version>2.1.4.RELEASE</spring-boot-version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot-version}</version>
</dependency>
We are quite confused on our side, since we didn't do any specific configuration on our side. It looks for us like there is something wrong with the spring configuration on the cloud. Are we doing something wrong? Do we need to configure something differently? Is this a bug?
This is what I had to do
I will see if I can find a more elegant way
#Bean(destroyMethod = "shutdown")
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
#SuppressWarnings("unused")
#Bean
public RedisConnectionFactory redisConnectionFactory(DefaultClientResources dependency) {
return connectionFactory().redisConnectionFactory("redis-pcf-service");
}
In the end the issue disappeared on our side, because we changed the redis client from lettuce to jedis.
We had the problem with lettuce that we would lose the connection to our redis service on our cloud infrastructure. But since there was an update to the redis service at same time as we changed the client, we don't really know if it was related to lettuce.
Maybe there also just something wrong in the auto-configuration in conjunction with the redis service on our cloud instructure, which is based on cloudfoundry

Parse JSON using Spring SPEL

Can someone tell me why this does not work:
#Test
public void should_parse_json() {
Expression expression = new SpelExpressionParser().parseExpression("#jsonPath(get('JsonData'), '$.someData')");
Map<String, Object> data = new HashMap<>();
data.put("JsonData", "{\"someData\": 100}");
StandardEvaluationContext context = new StandardEvaluationContext(data);
context.addPropertyAccessor(new JsonPropertyAccessor());
assertThat(expression.getValue(context, Object.class)).isEqualTo(100);
}
I get error "org.springframework.expression.spel.SpelEvaluationException: EL1006E: Function 'jsonPath' could not be found"
And I have following jar in classpath:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
The SPEL documentation did not help me.
Such a #jsonPath() SpEL function is a part of Spring Integration infrastructure: https://docs.spring.io/spring-integration/docs/current/reference/html/spel.html#spel-functions.
It's not going to work with the plain Spring and only SpEL.
However I see that you use a JsonPropertyAccessor. This one indeed a part of Spring Integration and you definitely have that in your classpath.
From here I think you just miss to register a SpEL function into the StandardEvaluationContext: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#expressions-ref-functions
context.registerFunction("jsonPath", BeanUtils.resolveSignature("evaluate", JsonPathUtils.class));
Add dependencies.
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
Register SpEL function
evaluationContext.registerFunction("jsonPath", BeanUtils.resolveSignature("evaluate", JsonPathUtils.class));

How to get http_ metrics from Spring-Boot Api

I have list of metrics from Spring Boot Api but it doesn't contains http_* metrics
my pom.xml contains
<prometheus.version>0.1.0</prometheus.version>
....
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_hotspot</artifactId>
<version>${prometheus.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_servlet</artifactId>
<version>${prometheus.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>${prometheus.version}</version>
</dependency>
I made DefaultExports.initialize() and set bean
#Bean
SpringBootMetricsCollector springBootMetricsCollector(Collection<PublicMetrics> publicMetrics) {
SpringBootMetricsCollector springBootMetricsCollector = new SpringBootMetricsCollector(publicMetrics);
springBootMetricsCollector.register();
return springBootMetricsCollector;
}
then i get list of metrics from spring boot api but it does not contain htpp_ * metrics
like http_request_duration_microseconds
how can i get it?

Camel CXF Junit Testing failing with 404

I am trying to Unit test my camel route and i am getting a 404 from test code after a successful invocation of route, meaning am not able to read response from test, always throws 404 not found
Here is my test code
final Exchange send = template.send("cxfrs://http://localhost:9001/v1/core/handshake", new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.OutOnly);
Message inMessage = exchange.getIn();
// setupDestinationURL(inMessage);
final String uuid = UUID.randomUUID().toString().replace("-", "");
System.out.println("uuid = " + uuid);
final GenerateTestHeaders headerGenerator = new GenerateTestHeaders();
final Map<String, Object> outboundHeaderMap = headerGenerator.getOutboundHeaderMap(API_KEY, ACCESS_ID, PRIVATE_ACCESS_KEY, "utf-8", "POST", "2016-08-31T10:40:55.979-0400", uuid);
// set a customer header
inMessage.setHeaders(outboundHeaderMap);
// using the http central client API
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.TRUE);
inMessage.setHeader("HOST", "localhost:9001");
// set the Http method
inMessage.setHeader(Exchange.HTTP_METHOD, "POST");
// set the operation name
inMessage.setHeader(CxfConstants.OPERATION_NAME, "handshake");
inMessage.setHeader(Exchange.ACCEPT_CONTENT_TYPE, "application/json");
// set the relative path
// inMessage.setHeader(Exchange.HTTP_PATH, "/IMP/v1/core/handshake");
// Specify the response class , cxfrs will use InputStream as the response object type
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, HandshakeResponse.class);
// since we use the Get method, so we don't need to set the message body
inMessage.setBody(null);
}
});
My Route is defines as below
<cxf:rsServer id="coreEndPoint" address="http://localhost:9001/v1/core" staticSubresourceResolution="true"
serviceClass="com.incomm.imp.neo.core.incoming.Framework"
loggingFeatureEnabled="true" loggingSizeLimit="20">
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
</bean>
</cxf:providers>
<cxf:inInterceptors>
<ref bean="loggingInInterceptor"></ref>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="loggingOutInterceptor"></ref>
</cxf:outInterceptors>
<cxf:features >
<ref bean="swagger2Feature"></ref>
</cxf:features>
</cxf:rsServer>
So my route gets invoked, The logging inteceptor logs a 200 Success with payload however when producer template is returned it has 404 Exception.
Any idea what i am doing wrong?.
On further debuggin realised that it has to be something with the way the Jetty Server is handled internally.So did a cross comparison with the Camel Apache Samples. Modified it and played around a little bit, long story short main difference is in POM
The reason for failure was the Dependencies in POM i suppose.
<!-- http client tests -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<scope>test</scope>
<version>${camel-version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>${camel-version}</version>
<!-- use the same version as your Camel core version-->
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core-xml</artifactId>
<scope>test</scope>
<version>${camel-version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test</artifactId>
<version>${camel-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring</artifactId>
<version>${camel-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-rm</artifactId>
<version>${cxf-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>test</scope>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<scope>test</scope>
<version>3.2</version>
</dependency>
I added these and it started working. I have to see which one does
that magic, For now am good.

Netbeans jUnit 4 - Java EE API is missing on project classpath

I have clear maven web app project.
I add jUnit to pom.
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<!-- jsoup HTML parser library # http://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
</dependency>
</dependencies>
I have one very simple Servlet in my app.
I want to generate jUnit 4 test for this servlet.
So I click on the Servlet package > Tools > Create Test.
After this I get test class with method.
public void testProcessRequest() throws Exception {
System.out.println("processRequest");
HttpServletRequest request = null;
HttpServletResponse response = null;
MyServlet instance = new MyServlet(); // This is the problem
instance.processRequest(request, response);
// TODO review the generated test code and remove the default call to fail.
//fail("The test case is a prototype.");
}
MyServlet is underline and the error is : "Java EE API is missing on the project classpath".
I tried modify the scopes of dependencies in pom but problem still exist.

Resources