From 5694a89589304bf8c36616f42c93187ca341d597 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 4 Nov 2020 09:37:24 +0100 Subject: [PATCH] Set span kinds for internal requests --- .../sonia/scm/net/ahc/BaseHttpRequest.java | 2 +- .../sonia/scm/admin/ReleaseFeedParser.java | 9 ++++- .../sonia/scm/plugin/PluginCenterLoader.java | 7 ++-- .../sonia/scm/plugin/PluginInstaller.java | 4 ++- .../main/java/sonia/scm/plugin/Tracing.java | 33 +++++++++++++++++++ .../scm/admin/ReleaseFeedParserTest.java | 12 +++++-- .../scm/plugin/PluginCenterLoaderTest.java | 12 +++++-- .../sonia/scm/plugin/PluginInstallerTest.java | 12 +++++-- 8 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java diff --git a/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java b/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java index bab0b4e0a8..9c36ae3b1c 100644 --- a/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java +++ b/scm-core/src/main/java/sonia/scm/net/ahc/BaseHttpRequest.java @@ -422,5 +422,5 @@ public abstract class BaseHttpRequest private String url; /** kind of span for trace api */ - private String spanKind = "http-request"; + private String spanKind = "HTTP Request"; } diff --git a/scm-webapp/src/main/java/sonia/scm/admin/ReleaseFeedParser.java b/scm-webapp/src/main/java/sonia/scm/admin/ReleaseFeedParser.java index 26c4c63b94..6576cdbceb 100644 --- a/scm-webapp/src/main/java/sonia/scm/admin/ReleaseFeedParser.java +++ b/scm-webapp/src/main/java/sonia/scm/admin/ReleaseFeedParser.java @@ -24,6 +24,7 @@ package sonia.scm.admin; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,6 +47,9 @@ public class ReleaseFeedParser { public static final int DEFAULT_TIMEOUT_IN_MILLIS = 1000; private static final Logger LOG = LoggerFactory.getLogger(ReleaseFeedParser.class); + + @VisibleForTesting + static final String SPAN_KIND = "Release Feed"; private final AdvancedHttpClient client; private final ExecutorService executorService; @@ -103,7 +107,10 @@ public class ReleaseFeedParser { if (Strings.isNullOrEmpty(url)) { return Optional.empty(); } - ReleaseFeedDto releaseFeed = client.get(url).request().contentFromXml(ReleaseFeedDto.class); + ReleaseFeedDto releaseFeed = client.get(url) + .spanKind(SPAN_KIND) + .request() + .contentFromXml(ReleaseFeedDto.class); return filterForLatestRelease(releaseFeed); } catch (Exception e) { LOG.error("Could not parse release feed from {}", url, e); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterLoader.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterLoader.java index efc967df49..0ab33dd6b1 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterLoader.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterLoader.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; import com.google.common.annotations.VisibleForTesting; @@ -34,6 +34,8 @@ import javax.inject.Inject; import java.util.Collections; import java.util.Set; +import static sonia.scm.plugin.Tracing.SPAN_KIND; + class PluginCenterLoader { private static final Logger LOG = LoggerFactory.getLogger(PluginCenterLoader.class); @@ -57,7 +59,8 @@ class PluginCenterLoader { Set load(String url) { try { LOG.info("fetch plugins from {}", url); - PluginCenterDto pluginCenterDto = client.get(url).request().contentFromJson(PluginCenterDto.class); + PluginCenterDto pluginCenterDto = client.get(url).spanKind(SPAN_KIND).request() + .contentFromJson(PluginCenterDto.class); return mapper.map(pluginCenterDto); } catch (Exception ex) { LOG.error("failed to load plugins from plugin center, returning empty list", ex); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginInstaller.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginInstaller.java index 5c371aa323..bea6451028 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PluginInstaller.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginInstaller.java @@ -38,6 +38,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; +import static sonia.scm.plugin.Tracing.SPAN_KIND; + @SuppressWarnings("UnstableApiUsage") // guava hash is marked as unstable class PluginInstaller { @@ -126,7 +128,7 @@ class PluginInstaller { } private InputStream download(AvailablePlugin plugin) throws IOException { - return client.get(plugin.getDescriptor().getUrl()).request().contentAsStream(); + return client.get(plugin.getDescriptor().getUrl()).spanKind(SPAN_KIND).request().contentAsStream(); } private Path createFile(AvailablePlugin plugin) throws IOException { diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java b/scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java new file mode 100644 index 0000000000..41903830f2 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java @@ -0,0 +1,33 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.plugin; + +final class Tracing { + + public static final String SPAN_KIND = "Plugin Center"; + + private Tracing() { + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/admin/ReleaseFeedParserTest.java b/scm-webapp/src/test/java/sonia/scm/admin/ReleaseFeedParserTest.java index f2e9516f1e..1e67b74df9 100644 --- a/scm-webapp/src/test/java/sonia/scm/admin/ReleaseFeedParserTest.java +++ b/scm-webapp/src/test/java/sonia/scm/admin/ReleaseFeedParserTest.java @@ -32,6 +32,7 @@ import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.net.ahc.AdvancedHttpClient; +import sonia.scm.net.ahc.AdvancedHttpResponse; import java.io.IOException; import java.util.Date; @@ -44,6 +45,7 @@ import java.util.concurrent.Semaphore; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import static sonia.scm.admin.ReleaseFeedParser.SPAN_KIND; @ExtendWith(MockitoExtension.class) class ReleaseFeedParserTest { @@ -62,7 +64,7 @@ class ReleaseFeedParserTest { void shouldFindLatestRelease() throws IOException { String url = "https://www.scm-manager.org/download/rss.xml"; - when(client.get(url).request().contentFromXml(ReleaseFeedDto.class)).thenReturn(createReleaseFeedDto()); + when(request(url).contentFromXml(ReleaseFeedDto.class)).thenReturn(createReleaseFeedDto()); Optional update = releaseFeedParser.findLatestRelease(url); @@ -71,13 +73,17 @@ class ReleaseFeedParserTest { assertThat(update.get().getLink()).isEqualTo("download-3"); } + private AdvancedHttpResponse request(String url) throws IOException { + return client.get(url).spanKind(SPAN_KIND).request(); + } + @Test void shouldHandleTimeout() throws IOException { String url = "https://www.scm-manager.org/download/rss.xml"; Semaphore waitWithResultUntilTimeout = new Semaphore(0); - when(client.get(url).request().contentFromXml(ReleaseFeedDto.class)).thenAnswer(invocation -> { + when(request(url).contentFromXml(ReleaseFeedDto.class)).thenAnswer(invocation -> { waitWithResultUntilTimeout.acquire(); return createReleaseFeedDto(); }); @@ -95,7 +101,7 @@ class ReleaseFeedParserTest { Semaphore waitWithResultUntilBothTriggered = new Semaphore(0); - when(client.get(url).request().contentFromXml(ReleaseFeedDto.class)).thenAnswer(invocation -> { + when(request(url).contentFromXml(ReleaseFeedDto.class)).thenAnswer(invocation -> { waitWithResultUntilBothTriggered.acquire(); return createReleaseFeedDto(); }); diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterLoaderTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterLoaderTest.java index cc59e42f62..ebd48a3b24 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterLoaderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterLoaderTest.java @@ -32,6 +32,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.event.ScmEventBus; import sonia.scm.net.ahc.AdvancedHttpClient; +import sonia.scm.net.ahc.AdvancedHttpResponse; import java.io.IOException; import java.util.Collections; @@ -41,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static sonia.scm.plugin.Tracing.SPAN_KIND; @ExtendWith(MockitoExtension.class) class PluginCenterLoaderTest { @@ -63,16 +65,20 @@ class PluginCenterLoaderTest { void shouldFetch() throws IOException { Set plugins = Collections.emptySet(); PluginCenterDto dto = new PluginCenterDto(); - when(client.get(PLUGIN_URL).request().contentFromJson(PluginCenterDto.class)).thenReturn(dto); + when(request().contentFromJson(PluginCenterDto.class)).thenReturn(dto); when(mapper.map(dto)).thenReturn(plugins); Set fetched = loader.load(PLUGIN_URL); assertThat(fetched).isSameAs(plugins); } + private AdvancedHttpResponse request() throws IOException { + return client.get(PLUGIN_URL).spanKind(SPAN_KIND).request(); + } + @Test void shouldReturnEmptySetIfPluginCenterNotBeReached() throws IOException { - when(client.get(PLUGIN_URL).request()).thenThrow(new IOException("failed to fetch")); + when(request()).thenThrow(new IOException("failed to fetch")); Set fetch = loader.load(PLUGIN_URL); assertThat(fetch).isEmpty(); @@ -80,7 +86,7 @@ class PluginCenterLoaderTest { @Test void shouldFirePluginCenterErrorEvent() throws IOException { - when(client.get(PLUGIN_URL).request()).thenThrow(new IOException("failed to fetch")); + when(request()).thenThrow(new IOException("failed to fetch")); loader.load(PLUGIN_URL); diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/PluginInstallerTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PluginInstallerTest.java index a619289094..7d18082833 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/PluginInstallerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PluginInstallerTest.java @@ -34,6 +34,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.SCMContextProvider; import sonia.scm.net.ahc.AdvancedHttpClient; +import sonia.scm.net.ahc.AdvancedHttpResponse; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -50,6 +51,7 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static sonia.scm.plugin.Tracing.SPAN_KIND; @ExtendWith({MockitoExtension.class}) class PluginInstallerTest { @@ -101,10 +103,14 @@ class PluginInstallerTest { } private void mockContent(String content) throws IOException { - when(client.get("https://download.hitchhiker.com").request().contentAsStream()) + when(request("https://download.hitchhiker.com").contentAsStream()) .thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); } + private AdvancedHttpResponse request(String url) throws IOException { + return client.get(url).spanKind(SPAN_KIND).request(); + } + private AvailablePlugin createGitPlugin() { return createPlugin( "scm-git-plugin", @@ -115,7 +121,7 @@ class PluginInstallerTest { @Test void shouldThrowPluginDownloadException() throws IOException { - when(client.get("https://download.hitchhiker.com").request()).thenThrow(new IOException("failed to download")); + when(request("https://download.hitchhiker.com")).thenThrow(new IOException("failed to download")); PluginInstallationContext context = PluginInstallationContext.empty(); AvailablePlugin gitPlugin = createGitPlugin(); @@ -136,7 +142,7 @@ class PluginInstallerTest { void shouldThrowPluginDownloadExceptionAndCleanup() throws IOException { InputStream stream = mock(InputStream.class); when(stream.read(any(), anyInt(), anyInt())).thenThrow(new IOException("failed to read")); - when(client.get("https://download.hitchhiker.com").request().contentAsStream()).thenReturn(stream); + when(request("https://download.hitchhiker.com").contentAsStream()).thenReturn(stream); PluginInstallationContext context = PluginInstallationContext.empty(); AvailablePlugin gitPlugin = createGitPlugin();