[1] Create spring-core project in instrumentation-core/spring
ADD
instrumentation-core/spring/spring-web-3.1/spring-web-3.1.gradle
+group = 'io.opentelemetry.instrumentation.spring'
+
+apply plugin: 'java'
+apply from: "$rootDir/gradle/java.gradle"
+
+dependencies {
+
+ // copy-paste from instrumentation-core-aws-sdk:aws-sdk-2.2-core:
+ // TODO(anuraaga): We currently include common instrumentation logic like decorators in the
+ // bootstrap, but we need to move it out so manual instrumentation does not depend on code from
+ // the agent, like Agent.
+ api project(':auto-bootstrap')
+
+ api "org.springframework:spring-web:3.1.0.RELEASE"
+ api deps.opentelemetryApi
+
+ testImplementation "org.springframework:spring-test:3.1.0.RELEASE"
+}
+
+testSets {
+ latestDepTest {
+ dirName = 'test'
+ }
+}

RENAME
instrumentation-core/spring/src/main/java/io/opentelemetry/instrumentation/spring/Application.java
instrumentation-core/spring/spring-web-3.1/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/HttpHeadersInjectAdapter.java
* limitations under the License.
*/
-package io.opentelemetry.instrumentation.spring;
+package io.opentelemetry.instrumentation.spring.httpclients;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
+import io.opentelemetry.context.propagation.HttpTextFormat;
+import org.springframework.http.HttpRequest;
-@SpringBootApplication
-public class Application {
+class HttpHeadersInjectAdapter implements HttpTextFormat.Setter<HttpRequest> {
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
+ public static final HttpHeadersInjectAdapter SETTER = new HttpHeadersInjectAdapter();
+
+ @Override
+ public void set(HttpRequest carrier, String key, String value) {
+ carrier.getHeaders().set(key, value);
}
}

ADD
instrumentation-core/spring/spring-web-3.1/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateDecorator.java
+/*
+ * Copyright The OpenTelemetry 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
+ *
+ * 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 io.opentelemetry.instrumentation.spring.httpclients;
+
+import static io.opentelemetry.OpenTelemetry.getPropagators;
+import static io.opentelemetry.instrumentation.spring.httpclients.HttpHeadersInjectAdapter.SETTER;
+
+import io.grpc.Context;
+import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.ClientHttpResponse;
+
+class RestTemplateDecorator extends HttpClientDecorator<HttpRequest, ClientHttpResponse> {
+
+ public static final RestTemplateDecorator DECORATE = new RestTemplateDecorator();
+
+ public void inject(Context context, HttpRequest request) {
+ getPropagators().getHttpTextFormat().inject(context, request, SETTER);
+ }
+
+ @Override
+ protected String method(final HttpRequest httpRequest) {
+ return httpRequest.getMethod().name();
+ }
+
+ @Override
+ protected URI url(HttpRequest request) throws URISyntaxException {
+ return request.getURI();
+ }
+
+ @Override
+ protected Integer status(ClientHttpResponse response) {
+ try {
+ return response.getStatusCode().value();
+ } catch (IOException e) {
+ return HttpStatus.INTERNAL_SERVER_ERROR.value();
+ }
+ }
+
+ @Override
+ protected String requestHeader(HttpRequest request, String name) {
+ return request.getHeaders().getFirst(name);
+ }
+
+ @Override
+ protected String responseHeader(ClientHttpResponse response, String name) {
+ return response.getHeaders().getFirst(name);
+ }
+}

ADD
instrumentation-core/spring/spring-web-3.1/src/main/java/io/opentelemetry/instrumentation/spring/httpclients/RestTemplateInterceptor.java
+/*
+ * Copyright The OpenTelemetry 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
+ *
+ * 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 io.opentelemetry.instrumentation.spring.httpclients;
+
+import static io.opentelemetry.instrumentation.spring.httpclients.RestTemplateDecorator.DECORATE;
+
+import io.grpc.Context;
+import io.opentelemetry.context.Scope;
+import io.opentelemetry.trace.Span;
+import io.opentelemetry.trace.Tracer;
+import java.io.IOException;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+/** Wraps RestTemplate requests in a span. Adds the current span context to request headers. */
+public final class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
+
+ private final Tracer tracer;
+
+ public RestTemplateInterceptor(Tracer tracer) {
+ this.tracer = tracer;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(
+ HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ Span clientSpan = DECORATE.getOrCreateSpan(request, tracer);
+
+ try (Scope scope = tracer.withSpan(clientSpan)) {
+ DECORATE.onRequest(clientSpan, request);
+ DECORATE.inject(Context.current(), request);
+
+ ClientHttpResponse response = execution.execute(request, body);
+ DECORATE.onResponse(clientSpan, response);
+
+ return response;
+ } finally {
+ clientSpan.end();
+ }
+ }
+}

DELETE
instrumentation-core/spring/spring.gradle
-plugins {
- id 'org.springframework.boot' version '2.3.0.RELEASE'
- id 'io.spring.dependency-management' version '1.0.9.RELEASE'
- id 'java'
-}
-
-ext {
- minJavaVersionForTests = JavaVersion.VERSION_1_8
-}
-
-group = 'io.opentelemetry.instrumentation'
-version = '0.0.1-SNAPSHOT'
-
-apply from: "$rootDir/gradle/java.gradle"
-
-sourceCompatibility = '8'
-
-dependencies {
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- implementation 'org.springframework.boot:spring-boot-starter-web'
- testImplementation('org.springframework.boot:spring-boot-starter-test') {
- exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
- }
-
- compileOnly deps.opentelemetryApi
- compileOnly deps.opentelemetrySdk
- compileOnly "io.opentelemetry:opentelemetry-exporters-logging:0.5.0"
-}
-
-test {
- useJUnitPlatform()
-}

DELETE
instrumentation-core/spring/src/main/resources/application.properties
-

DELETE
instrumentation-core/spring/src/test/java/io/opentelemetry/instrumentation/spring/ApplicationTests.java
-/*
- * Copyright The OpenTelemetry 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
- *
- * 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 io.opentelemetry.instrumentation.spring;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-@EnableAutoConfiguration(
- exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
-class ApplicationTests {
-
- @Test
- void contextLoads() {}
-}

MODIFY
settings.gradle
settings.gradle
@@ -151,7 +151,7 @@ include ':instrumentation:vertx-reactive-3.5'
include ':instrumentation-core:aws-sdk:aws-sdk-2.2'
include ':instrumentation-core:servlet'
-include ':instrumentation-core:spring'
+include ':instrumentation-core:spring:spring-web-3.1'
// exporter adapters
include ":auto-exporters"

[1] Create spring-core project in instrumentation-core/spring (#640)