Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@
private String grafanaBaseUrl;

private String grafanaMetricsDashboard;
private String tempoDataSourceIdentifier = DEFAULT_TEMPO_DATA_SOURCE_IDENTIFIER;

@Deprecated
private String tempoDataSourceIdentifier;

private String tempoDataSourceUid = DEFAULT_TEMPO_DATA_SOURCE_IDENTIFIER;

private String grafanaOrgId = DEFAULT_GRAFANA_ORG_ID;

Expand All @@ -68,17 +72,27 @@
@DataBoundConstructor
public GrafanaBackend() {}

protected void readResolve() {
if (tempoDataSourceIdentifier != null) {

Check warning on line 76 in src/main/java/io/jenkins/plugins/opentelemetry/backend/GrafanaBackend.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 76 is only partially covered, one branch is missing
if (tempoDataSourceUid == null || tempoDataSourceUid.equals(DEFAULT_TEMPO_DATA_SOURCE_IDENTIFIER)) {

Check warning on line 77 in src/main/java/io/jenkins/plugins/opentelemetry/backend/GrafanaBackend.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 77 is only partially covered, one branch is missing
this.tempoDataSourceUid = tempoDataSourceIdentifier;
}
this.tempoDataSourceIdentifier = null;
}
}

@Nullable
@Override
public String getTraceVisualisationUrlTemplate() {
return "${" + TemplateBindings.GRAFANA_BASE_URL + "}" + "/explore?orgId="
return "${" + TemplateBindings.GRAFANA_BASE_URL + "}" + "/explore?schemaVersion=1&orgId="
+ "${"
+ TemplateBindings.GRAFANA_ORG_ID + "}" + "&left=%7B%22datasource%22:%22"
+ TemplateBindings.GRAFANA_ORG_ID + "}" + "&panes=%7B%22pane1%22:%7B%22datasource%22:%22"
+ "${"
+ TemplateBindings.GRAFANA_TEMPO_DATASOURCE_IDENTIFIER + "}"
+ TemplateBindings.GRAFANA_TEMPO_DATASOURCE_UID + "}"
+ "%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22"
+ "${"
+ TemplateBindings.GRAFANA_TEMPO_DATASOURCE_IDENTIFIER + "}" + "%22%7D,%22queryType%22:%22${"
+ TemplateBindings.GRAFANA_TEMPO_DATASOURCE_UID + "}"
+ "%22%7D,%22queryType%22:%22${"
+ TemplateBindings.GRAFANA_TEMPO_QUERY_TYPE + "}%22,%22query%22:%22" + "${traceId}"
+ "%22%7D%5D,%22range%22:%7B%22from%22:%22"
+ "${"
Expand All @@ -88,7 +102,7 @@
+ "${"
+ TemplateBindings.START_TIME
+ ".plusSeconds(600).atZone(java.util.TimeZone.getDefault().toZoneId()).toInstant().toEpochMilli()}"
+ "%22%7D%7D";
+ "%22%7D%7D%7D";
}

/**
Expand Down Expand Up @@ -125,13 +139,13 @@
GrafanaBackend that = (GrafanaBackend) o;
return Objects.equals(grafanaOrgId, that.grafanaOrgId)
&& Objects.equals(grafanaBaseUrl, that.grafanaBaseUrl)
&& Objects.equals(tempoDataSourceIdentifier, that.tempoDataSourceIdentifier)
&& Objects.equals(tempoDataSourceUid, that.tempoDataSourceUid)

Check warning on line 142 in src/main/java/io/jenkins/plugins/opentelemetry/backend/GrafanaBackend.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 142 is only partially covered, one branch is missing
&& Objects.equals(tempoQueryType, that.tempoQueryType);
}

@Override
public int hashCode() {
return Objects.hash(grafanaBaseUrl, tempoDataSourceIdentifier, grafanaOrgId, tempoQueryType);
return Objects.hash(grafanaBaseUrl, tempoDataSourceUid, grafanaOrgId, tempoQueryType);
}

@Override
Expand All @@ -144,12 +158,20 @@
@Override
public Map<String, Object> getBindings() {
Map<String, Object> bindings = Map.of(
TemplateBindings.BACKEND_NAME, getName(),
TemplateBindings.BACKEND_24_24_ICON_URL, "/plugin/opentelemetry/images/24x24/grafana.png",
TemplateBindings.GRAFANA_BASE_URL, this.getGrafanaBaseUrl(),
TemplateBindings.GRAFANA_ORG_ID, String.valueOf(this.getGrafanaOrgId()),
TemplateBindings.GRAFANA_TEMPO_DATASOURCE_IDENTIFIER, this.getTempoDataSourceIdentifier(),
TemplateBindings.GRAFANA_TEMPO_QUERY_TYPE, this.getTempoQueryType());
TemplateBindings.BACKEND_NAME,
getName(),
TemplateBindings.BACKEND_24_24_ICON_URL,
"/plugin/opentelemetry/images/24x24/grafana.png",
TemplateBindings.GRAFANA_BASE_URL,
this.getGrafanaBaseUrl(),
TemplateBindings.GRAFANA_ORG_ID,
String.valueOf(this.getGrafanaOrgId()),
TemplateBindings.GRAFANA_TEMPO_DATASOURCE_IDENTIFIER,
this.getTempoDataSourceUid(),
TemplateBindings.GRAFANA_TEMPO_DATASOURCE_UID,
this.getTempoDataSourceUid(),
TemplateBindings.GRAFANA_TEMPO_QUERY_TYPE,
this.getTempoQueryType());

if (grafanaLogsBackend instanceof TemplateBindingsProvider) {
Map<String, Object> logsBackendBindings = ((TemplateBindingsProvider) grafanaLogsBackend).getBindings();
Expand Down Expand Up @@ -178,16 +200,25 @@
this.grafanaBaseUrl = grafanaBaseUrl;
}

@DataBoundSetter
@Deprecated
public String getTempoDataSourceIdentifier() {
return tempoDataSourceIdentifier;
}

@DataBoundSetter
@Deprecated
public void setTempoDataSourceIdentifier(String tempoDataSourceIdentifier) {
this.tempoDataSourceIdentifier = tempoDataSourceIdentifier;
}

public String getTempoDataSourceUid() {
return tempoDataSourceUid;
}

@DataBoundSetter
public void setTempoDataSourceUid(String tempoDataSourceUid) {
this.tempoDataSourceUid = tempoDataSourceUid;
}

@DataBoundSetter
public void setGrafanaMetricsDashboard(String grafanaMetricsDashboard) {
this.grafanaMetricsDashboard = grafanaMetricsDashboard;
Expand Down Expand Up @@ -250,6 +281,10 @@
return DEFAULT_TEMPO_DATA_SOURCE_IDENTIFIER;
}

public String getDefaultTempoDataSourceUid() {
return DEFAULT_TEMPO_DATA_SOURCE_IDENTIFIER;
}

public String getDefaultTempoQueryType() {
return DEFAULT_TEMPO_QUERY_TYPE;
}
Expand Down Expand Up @@ -280,6 +315,7 @@
public interface TemplateBindings extends ObservabilityBackend.TemplateBindings {
String GRAFANA_BASE_URL = "grafanaBaseUrl";
String GRAFANA_TEMPO_DATASOURCE_IDENTIFIER = "grafanaTempoDatasourceIdentifier";
String GRAFANA_TEMPO_DATASOURCE_UID = "grafanaTempoDatasourceUid";
String GRAFANA_LOKI_DATASOURCE_IDENTIFIER = "grafanaLokiDatasourceIdentifier";
String GRAFANA_ORG_ID = "grafanaOrgId";
String GRAFANA_TEMPO_QUERY_TYPE = "grafanaTempoQueryType";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
<p>
<strong>Grafana</strong>
</p>
<f:entry title="Tempo data source identifier" field="tempoDataSourceIdentifier"
description="Identifier of the Tempo datasource in which the Jenkins pipeline build traces are stored.">
<f:textbox default="${descriptor.defaultTempoDataSourceIdentifier}"/>
<f:entry title="Tempo data source UID" field="tempoDataSourceUid"
description="The unique identifier (UUID) of the Tempo datasource in Grafana.">
<f:textbox default="${descriptor.defaultTempoDataSourceUid}"/>
</f:entry>
<f:entry title="Tempo Query Type" field="tempoQueryType"
description="Query type passed to Tempo, used when searching for the specific trace.">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,48 @@

package io.jenkins.plugins.opentelemetry.backend;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.junit.jupiter.api.Test;

public class GrafanaBackendTest {

@Test
public void testTraceUrl() {
GrafanaBackend grafanaBackend = new GrafanaBackend();
grafanaBackend.setGrafanaBaseUrl("https://cleclerc.grafana.net");
grafanaBackend.setGrafanaOrgId("1");
grafanaBackend.setTempoDataSourceUid("my-awesome-custom-uid");
grafanaBackend.setTempoQueryType("traceql");

LocalDateTime buildTime =
LocalDateTime.parse("2023-02-05 23:31:52.610", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));

Map<String, Object> bindings = new HashMap<>();
bindings.put("serviceName", "jenkins");
bindings.put("rootSpanName", "BUILD my-app");
bindings.put("traceId", "f464e1f32444443d3fc00fdb19e5c124");
bindings.put("spanId", "00799ea60984f33f");
bindings.put("startTime", buildTime);

String actualUrl = grafanaBackend.getTraceVisualisationUrl(bindings);
System.out.println(actualUrl);

assertTrue(Objects.requireNonNull(actualUrl).contains("schemaVersion=1"), "URL must contain schemaVersion=1");
assertTrue(actualUrl.contains("panes="), "URL must use 'panes' instead of 'left'");
assertTrue(actualUrl.contains("my-awesome-custom-uid"), "URL must contain the new Tempo UID");
assertTrue(actualUrl.contains("f464e1f32444443d3fc00fdb19e5c124"), "URL must contain the exact traceId");
}

@Test
@SuppressWarnings("deprecation")
public void testTraceUrlFallbackToIdentifier() {
GrafanaBackend grafanaBackend = new GrafanaBackend();
grafanaBackend.setGrafanaBaseUrl("https://cleclerc.grafana.net");
grafanaBackend.setGrafanaOrgId("1");
Expand All @@ -31,7 +63,70 @@ public void testTraceUrl() {
bindings.put("spanId", "00799ea60984f33f");
bindings.put("startTime", buildTime);

String actualTraceVisualisationUrl = grafanaBackend.getTraceVisualisationUrl(bindings);
System.out.println(actualTraceVisualisationUrl);
String actualUrl = grafanaBackend.getTraceVisualisationUrl(bindings);

assertTrue(Objects.requireNonNull(actualUrl).contains("schemaVersion=1"), "URL must contain schemaVersion=1");
assertTrue(actualUrl.contains("panes="), "URL must use 'panes' instead of 'left'");
assertTrue(
actualUrl.contains("grafanacloud-traces"),
"URL must fall back to the tempoDataSourceIdentifier when UID is missing");
assertTrue(actualUrl.contains("f464e1f32444443d3fc00fdb19e5c124"), "URL must contain the exact traceId");
}

@Test
public void testEqualsAndHashCode() {
GrafanaBackend backend1 = new GrafanaBackend();
backend1.setGrafanaBaseUrl("http://grafana");
backend1.setGrafanaOrgId("1");
backend1.setTempoDataSourceUid("tempo-uid");
backend1.setTempoQueryType("traceql");

GrafanaBackend backend2 = new GrafanaBackend();
backend2.setGrafanaBaseUrl("http://grafana");
backend2.setGrafanaOrgId("1");
backend2.setTempoDataSourceUid("tempo-uid");
backend2.setTempoQueryType("traceql");

assertEquals(backend1, backend2);
assertEquals(backend1.hashCode(), backend2.hashCode());
}

@Test
@SuppressWarnings("deprecation")
public void testReadResolveMigratesIdentifierToUid() {
GrafanaBackend backend = new GrafanaBackend();

backend.setTempoDataSourceIdentifier("old-datasource-id");
backend.readResolve();

assertEquals("old-datasource-id", backend.getTempoDataSourceUid());
}

@Test
@SuppressWarnings("deprecation")
public void testReadResolveDoesNotOverrideExistingUid() {
GrafanaBackend backend = new GrafanaBackend();

backend.setTempoDataSourceIdentifier("old-id");
backend.setTempoDataSourceUid("new-uid");
backend.readResolve();

assertEquals("new-uid", backend.getTempoDataSourceUid());
}

@Test
public void testDescriptorDefaultTempoDataSourceUid() {
GrafanaBackend.DescriptorImpl descriptor = new GrafanaBackend.DescriptorImpl();

assertEquals("grafanacloud-traces", descriptor.getDefaultTempoDataSourceUid());
}

@Test
public void testDescriptorDefaults() {
GrafanaBackend.DescriptorImpl descriptor = new GrafanaBackend.DescriptorImpl();

assertEquals("grafanacloud-traces", descriptor.getDefaultTempoDataSourceUid());
assertEquals("1", descriptor.getDefaultGrafanaOrgId());
assertEquals("traceql", descriptor.getDefaultTempoQueryType());
}
}