Skip to content
Draft
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
f051562
Rework CollectorApi to accept OTLP data.
FrancesTwisk Mar 17, 2026
a72eb5f
Process OTel spans not ladbug spans.
FrancesTwisk Mar 24, 2026
c2fbf1e
Sort spans in traces and then order traces in tree.
FrancesTwisk Mar 30, 2026
e979479
Add caching.
FrancesTwisk Mar 30, 2026
db5f31c
Add class for correct DFS processing.
FrancesTwisk Apr 2, 2026
20aa659
Remove sorting before expiration from cache.
FrancesTwisk Apr 2, 2026
e5a868a
New class for DFS creation of checkpoints.
FrancesTwisk Apr 2, 2026
d56ed61
Orphan span handling + refactoring.
FrancesTwisk Apr 10, 2026
4bb7c67
Only actual value in infopoint.
FrancesTwisk Apr 10, 2026
6c7a611
Added unit tests for TraceTree.java.
FrancesTwisk Apr 10, 2026
e3d7ae8
Fix.
FrancesTwisk Apr 14, 2026
49836c6
Quick fix for OTel export.
FrancesTwisk May 4, 2026
8b2767b
Update reports.
FrancesTwisk May 5, 2026
cef18da
Refactor API's and the impl.
FrancesTwisk May 18, 2026
c359e2f
Delete unnecessary classes.
FrancesTwisk May 18, 2026
834c462
Delete unnecessary classes.
FrancesTwisk May 18, 2026
8173af9
Dependencies.
FrancesTwisk May 18, 2026
9685edc
Logic for updating instead of storing.
FrancesTwisk May 18, 2026
9396cba
Copyrights.
FrancesTwisk May 19, 2026
9436816
Fix.
FrancesTwisk May 19, 2026
956e0dd
Fix.
FrancesTwisk May 19, 2026
6b3325e
Fix.
FrancesTwisk May 20, 2026
dd7b9d9
Fix.
FrancesTwisk May 20, 2026
68facee
Orphan spans handling.
FrancesTwisk May 20, 2026
6f1e0ac
Fix.
FrancesTwisk May 25, 2026
86d90be
Complete refactor of logic.
FrancesTwisk May 25, 2026
b22986a
Fix.
FrancesTwisk May 25, 2026
05eb209
Add cache back in.
FrancesTwisk May 25, 2026
89b87d3
Add cache back in.
FrancesTwisk May 25, 2026
f4b195d
Rename.
FrancesTwisk May 26, 2026
de42b3e
Process OTel spans instead of Ladybug spans.
FrancesTwisk May 26, 2026
c1fe4de
Delete old Ladybug Span class.
FrancesTwisk May 26, 2026
4dc8667
Fix.
FrancesTwisk May 26, 2026
1f6f9e5
Fix for export.
FrancesTwisk May 26, 2026
e075f4b
Fix.
FrancesTwisk May 26, 2026
eac5efd
Merge branch 'refs/heads/refactor-for-otel' into rework-otel-crud-sto…
FrancesTwisk May 26, 2026
1a8d066
Fix.
FrancesTwisk May 26, 2026
521fcec
Tests.
FrancesTwisk May 26, 2026
533528b
Tests.
FrancesTwisk May 26, 2026
52538e7
Fix.
FrancesTwisk May 26, 2026
f1202b9
Add info points.
FrancesTwisk May 27, 2026
557bc09
Fix.
FrancesTwisk May 27, 2026
0648b10
Fix.
FrancesTwisk May 27, 2026
584721b
Fix.
FrancesTwisk May 27, 2026
af958bc
Fix.
FrancesTwisk May 27, 2026
dea73d4
Fixes.
FrancesTwisk Jun 2, 2026
17b4ca0
Merge branch 'refs/heads/refactor-for-otel' into rework-otel-crud-sto…
FrancesTwisk Jun 2, 2026
87162a0
Fix.
FrancesTwisk Jun 2, 2026
6a86046
Simplify logic on TestTool.
FrancesTwisk Jun 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ To work with Jaeger, you can run the following command:

`docker run --rm -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 9411:9411 jaegertracing/all-in-one:latest`

You'll need to uncomment or add:

```
<property name="openTelemetryEndpoint" ref="openTelemetryEndpoint"/>
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to have an end-to-end test some time with Cypress. I also would like to have end-to-end tests with openTelemetryEndpoint enabled and test environments with openTelemetryEndpoint disabled. Would be nice if that could be added to this PR, but in my opinion it can also be done in a later PR.


In the testTool bean.

To choose between one of the collectors in the Ladybug application, there is a bean available to make your choice. You have to add the following and change the string value of this bean to the collector you want to use. For Zipkin, enter the endpoint in the string value. For Jaeger (which doesn't use a endpoint), you can just enter "jaeger":
```
<bean name="openTelemetryEndpoint" class="java.lang.String">
Expand Down
18 changes: 18 additions & 0 deletions ladybug-backend-jaxrs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,23 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>4.34.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>4.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.proto</groupId>
<artifactId>opentelemetry-proto</artifactId>
<version>1.9.0-alpha</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void setTesterRoles(List<String> testerRoles) {

public void setWebServiceRoles(List<String> webServiceRoles) {
if (constructorDone) log.info("Set web service roles");
addConfigurationPart("POST/" + Constants.LADYBUG_API_PATH + "/collector/.*$", webServiceRoles);
addConfigurationPart("POST/" + Constants.LADYBUG_API_PATH + "/traces/.*$", webServiceRoles);
}

public void setLadybugApiRoles(Map<String, List<String>> ladybugApiRoles) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright 2021-2026 WeAreFrank!

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 org.wearefrank.ladybug.web.jaxrs.api;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.proto.trace.v1.ScopeSpans;
import io.opentelemetry.proto.trace.v1.Span;
import jakarta.annotation.PostConstruct;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.wearefrank.ladybug.SpanBuffer;
import org.wearefrank.ladybug.web.common.TracingApiImpl;
import org.wearefrank.ladybug.web.common.Constants;

@Path("/" + Constants.LADYBUG_API_PATH + "/traces")
public class TracingApi extends ApiBase {
private SpanBuffer spanBuffer;

@Autowired
private @Setter TracingApiImpl delegate;

@PostConstruct
public void init() {
spanBuffer = new SpanBuffer(delegate);
}

@POST
@Consumes({"application/x-protobuf", "application/json"})
public Response receiveSpans(@HeaderParam("Content-Type") String contentType, byte[] data) throws InvalidProtocolBufferException {
ExportTraceServiceRequest request;

Comment thread
FrancesTwisk marked this conversation as resolved.
Outdated
if (contentType != null && contentType.startsWith("application/x-protobuf")) {
request = ExportTraceServiceRequest.parseFrom(data);
} else if (contentType != null && contentType.startsWith("application/json")) {
String json = new String(data);
ExportTraceServiceRequest.Builder builder = ExportTraceServiceRequest.newBuilder();
JsonFormat.parser().merge(json, builder);
request = builder.build();
} else {
ExportTraceServiceResponse response = ExportTraceServiceResponse.newBuilder().build();
return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE)
.type(MediaType.APPLICATION_JSON)
.entity(JsonFormat.printer().print(response))
.build();
}

for (ResourceSpans resourceSpans : request.getResourceSpansList()) {
for (ScopeSpans scopeSpans : resourceSpans.getScopeSpansList()) {
for (Span span : scopeSpans.getSpansList()) {
spanBuffer.addSpan(span);
}
}
}

ExportTraceServiceResponse response = ExportTraceServiceResponse.newBuilder().build();
if (contentType.startsWith("application/x-protobuf")) {
return Response.ok(response.toByteArray())
.type("application/x-protobuf")
.build();
} else {
return Response.ok(JsonFormat.printer().print(response))
.type(MediaType.APPLICATION_JSON)
.build();
}
}
}
19 changes: 18 additions & 1 deletion ladybug-backend-springmvc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<groupId>org.wearefrank</groupId>
<artifactId>ladybug-common</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
Expand Down Expand Up @@ -50,5 +49,23 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>4.34.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>4.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.proto</groupId>
<artifactId>opentelemetry-proto</artifactId>
<version>1.9.0-alpha</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2025, 2026 WeAreFrank!

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 org.wearefrank.ladybug.web.springmvc.api;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.proto.trace.v1.ScopeSpans;
import jakarta.annotation.security.RolesAllowed;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.wearefrank.ladybug.web.common.TracingApiImpl;

@RestController
@RequestMapping("/traces")
@RolesAllowed("IbisWebService")
public class TracingApi {
@Autowired
private @Setter TracingApiImpl delegate;

@PostMapping(consumes = {"application/x-protobuf", MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> receiveSpans(@RequestHeader("Content-Type") String contentType, @RequestBody byte[] data) throws InvalidProtocolBufferException {
Comment thread
FrancesTwisk marked this conversation as resolved.
Outdated
ExportTraceServiceRequest request;

if (contentType != null && contentType.startsWith("application/x-protobuf")) {
request = ExportTraceServiceRequest.parseFrom(data);
} else if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
String json = new String(data);
ExportTraceServiceRequest.Builder builder = ExportTraceServiceRequest.newBuilder();
JsonFormat.parser().merge(json, builder);
request = builder.build();
} else {
ExportTraceServiceResponse response = ExportTraceServiceResponse.newBuilder().build();
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
.contentType(MediaType.APPLICATION_JSON)
.body(JsonFormat.printer().print(response));
}

for (ResourceSpans resourceSpans : request.getResourceSpansList()) {
for (ScopeSpans scopeSpans : resourceSpans.getScopeSpansList()) {
delegate.processSpans(scopeSpans.getSpansList());
}
}

ExportTraceServiceResponse response = ExportTraceServiceResponse.newBuilder().build();
if (contentType.startsWith("application/x-protobuf")) {
return ResponseEntity.ok()
.contentType(org.springframework.http.MediaType.parseMediaType("application/x-protobuf"))
.body(response.toByteArray());
} else {
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(JsonFormat.printer().print(response));
}
}
}
28 changes: 28 additions & 0 deletions ladybug-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,34 @@
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.proto</groupId>
<artifactId>opentelemetry-proto</artifactId>
<version>1.9.0-alpha</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.0</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.18.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Loading
Loading