From cee3caf4f4c2fd7f445f4ea96cbbfb391a5ab9d3 Mon Sep 17 00:00:00 2001
From: Patrick Doyle
Date: Fri, 21 Jun 2024 08:38:59 -0400
Subject: [PATCH] More fiddling with OTel
---
.../src/main/java/io/vena/bosk/Bosk.java | 9 ++-
.../bosk/drivers/OtelSpanContextDriver.java | 59 ++++++++++++++++---
.../vena/bosk/drivers/mongo/MainDriver.java | 2 +-
.../drivers/mongo/MongoDriverHanoiTest.java | 3 +-
.../vena/bosk/drivers/AbstractDriverTest.java | 1 +
.../bosk/drivers/DriverConformanceTest.java | 8 ++-
6 files changed, 69 insertions(+), 13 deletions(-)
diff --git a/bosk-core/src/main/java/io/vena/bosk/Bosk.java b/bosk-core/src/main/java/io/vena/bosk/Bosk.java
index 4d80d2ac..2b2e6b8a 100644
--- a/bosk-core/src/main/java/io/vena/bosk/Bosk.java
+++ b/bosk-core/src/main/java/io/vena/bosk/Bosk.java
@@ -1,5 +1,7 @@
package io.vena.bosk;
+import io.opentelemetry.instrumentation.annotations.SpanAttribute;
+import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.vena.bosk.BoskDiagnosticContext.DiagnosticScope;
import io.vena.bosk.ReferenceUtils.CatalogRef;
import io.vena.bosk.ReferenceUtils.ListingRef;
@@ -399,7 +401,7 @@ private void triggerQueueingOfHooks(Reference target, @Nullable R prior
) {
try (@SuppressWarnings("unused") ReadContext executionContext = new ReadContext(rootForHook)) {
LOGGER.debug("Hook: RUN {}({})", reg.name, changedRef);
- reg.hook.onChanged(changedRef);
+ callHook(reg, changedRef, reg.name());
} catch (Exception e) {
LOGGER.error("Bosk hook \"" + reg.name() + "\" terminated with an exception, which usually indicates a bug. State updates may have been lost", e);
@@ -415,6 +417,11 @@ private void triggerQueueingOfHooks(Reference target, @Nullable R prior
});
}
+ @WithSpan
+ private static void callHook(Bosk.HookRegistration reg, @SpanAttribute("hook.reference") Reference changedRef, @SpanAttribute("hook.name") String hookName) {
+ reg.hook.onChanged(changedRef);
+ }
+
/**
* Runs queued hooks in a "breadth-first" fashion: all hooks "H" triggered by
* any single hook "G" will run before any consequent hooks triggered by "H".
diff --git a/bosk-core/src/main/java/io/vena/bosk/drivers/OtelSpanContextDriver.java b/bosk-core/src/main/java/io/vena/bosk/drivers/OtelSpanContextDriver.java
index f3f6c03f..79597a5d 100644
--- a/bosk-core/src/main/java/io/vena/bosk/drivers/OtelSpanContextDriver.java
+++ b/bosk-core/src/main/java/io/vena/bosk/drivers/OtelSpanContextDriver.java
@@ -1,6 +1,9 @@
package io.vena.bosk.drivers;
+import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.instrumentation.annotations.SpanAttribute;
+import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.vena.bosk.BoskDiagnosticContext;
import io.vena.bosk.BoskDriver;
import io.vena.bosk.DriverFactory;
@@ -18,60 +21,100 @@
public class OtelSpanContextDriver implements BoskDriver {
private final BoskDiagnosticContext context;
private final BoskDriver downstream;
+ private final String caller;
- OtelSpanContextDriver(BoskDiagnosticContext context, BoskDriver downstream) {
+ OtelSpanContextDriver(BoskDiagnosticContext context, BoskDriver downstream, String caller) {
this.context = context;
this.downstream = downstream;
+ this.caller = caller;
}
public static DriverFactory factory() {
- return (b,d) -> new OtelSpanContextDriver<>(b.rootReference().diagnosticContext(), d);
+ StackTraceElement caller = new RuntimeException().getStackTrace()[1];
+ return (b,d) -> new OtelSpanContextDriver<>(
+ b.rootReference().diagnosticContext(),
+ d,
+ caller.toString()
+ );
}
@Override
- public R initialRoot(Type rootType) throws InvalidTypeException, IOException, InterruptedException {
+ @WithSpan("initialRoot")
+ public R initialRoot(
+ @SpanAttribute("bosk.rootType") Type rootType
+ ) throws InvalidTypeException, IOException, InterruptedException {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
return downstream.initialRoot(rootType);
}
}
@Override
- public void submitReplacement(Reference target, T newValue) {
+ @WithSpan("submitReplacement")
+ public void submitReplacement(
+ @SpanAttribute("bosk.target") Reference target,
+ T newValue
+ ) {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.submitReplacement(target, newValue);
}
}
@Override
- public void submitConditionalReplacement(Reference target, T newValue, Reference precondition, Identifier requiredValue) {
+ @WithSpan("submitConditionalReplacement")
+ public void submitConditionalReplacement(
+ @SpanAttribute("bosk.target") Reference target,
+ T newValue,
+ @SpanAttribute("bosk.precondition") Reference precondition,
+ @SpanAttribute("bosk.requiredValue") Identifier requiredValue
+ ) {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.submitConditionalReplacement(target, newValue, precondition, requiredValue);
}
}
@Override
- public void submitInitialization(Reference target, T newValue) {
+ @WithSpan("submitInitialization")
+ public void submitInitialization(
+ @SpanAttribute("bosk.target") Reference target,
+ T newValue
+ ) {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.submitInitialization(target, newValue);
}
}
@Override
- public void submitDeletion(Reference target) {
+ @WithSpan("submitDeletion")
+ public void submitDeletion(
+ @SpanAttribute("bosk.target") Reference target
+ ) {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.submitDeletion(target);
}
}
@Override
- public void submitConditionalDeletion(Reference target, Reference precondition, Identifier requiredValue) {
+ @WithSpan("submitConditionalDeletion")
+ public void submitConditionalDeletion(
+ @SpanAttribute("bosk.target") Reference target,
+ @SpanAttribute("bosk.precondition") Reference precondition,
+ @SpanAttribute("bosk.requiredValue") Identifier requiredValue
+ ) {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.submitConditionalDeletion(target, precondition, requiredValue);
}
}
@Override
+ @WithSpan("InterruptedException")
public void flush() throws IOException, InterruptedException {
+ Span.current().setAttribute("bosk.createdAt", caller);
try (var __ = context.withCurrentOtelContext()) {
downstream.flush();
}
diff --git a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/MainDriver.java b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/MainDriver.java
index 5dbd29e7..0f6cdaf5 100644
--- a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/MainDriver.java
+++ b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/MainDriver.java
@@ -375,6 +375,7 @@ private Listener(FutureTask initialRootAction) {
}
@Override
+ @WithSpan("onConnectionSucceeded")
public void onConnectionSucceeded() throws
UnrecognizedFormatException,
UninitializedCollectionException,
@@ -582,7 +583,6 @@ private MDCScope beginDriverOperation(String description, Object... args) {
return ex;
}
- @WithSpan
private void doRetryableDriverOperation(RetryableOperation operation, String description, Object... args) throws X,Y {
RetryableOperation operationInSession = () -> {
int immediateRetriesLeft = 2;
diff --git a/bosk-mongo/src/test/java/io/vena/bosk/drivers/mongo/MongoDriverHanoiTest.java b/bosk-mongo/src/test/java/io/vena/bosk/drivers/mongo/MongoDriverHanoiTest.java
index 9736fd56..ae7d5349 100644
--- a/bosk-mongo/src/test/java/io/vena/bosk/drivers/mongo/MongoDriverHanoiTest.java
+++ b/bosk-mongo/src/test/java/io/vena/bosk/drivers/mongo/MongoDriverHanoiTest.java
@@ -27,7 +27,8 @@ public MongoDriverHanoiTest(ParameterSet parameters) {
mongoService.clientSettings(),
settings,
new BsonPlugin()
- )
+ ),
+ OtelSpanContextDriver.factory()
);
mongoService.client()
.getDatabase(settings.database())
diff --git a/bosk-testing/src/main/java/io/vena/bosk/drivers/AbstractDriverTest.java b/bosk-testing/src/main/java/io/vena/bosk/drivers/AbstractDriverTest.java
index 2385efcb..3493d34d 100644
--- a/bosk-testing/src/main/java/io/vena/bosk/drivers/AbstractDriverTest.java
+++ b/bosk-testing/src/main/java/io/vena/bosk/drivers/AbstractDriverTest.java
@@ -53,6 +53,7 @@ protected void setupBosksAndReferences(DriverFactory driverFactory)
// This is the bosk we're testing
bosk = new Bosk("Test bosk", TestEntity.class, AbstractDriverTest::initialRoot, DriverStack.of(
MirroringDriver.targeting(canonicalBosk),
+ OtelSpanContextDriver.factory(),
DriverStateVerifier.wrap(driverFactory, TestEntity.class, AbstractDriverTest::initialRoot)
));
driver = bosk.driver();
diff --git a/bosk-testing/src/main/java/io/vena/bosk/drivers/DriverConformanceTest.java b/bosk-testing/src/main/java/io/vena/bosk/drivers/DriverConformanceTest.java
index f4eed1f5..299afc45 100644
--- a/bosk-testing/src/main/java/io/vena/bosk/drivers/DriverConformanceTest.java
+++ b/bosk-testing/src/main/java/io/vena/bosk/drivers/DriverConformanceTest.java
@@ -1,5 +1,7 @@
package io.vena.bosk.drivers;
+import io.opentelemetry.instrumentation.annotations.SpanAttribute;
+import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.vena.bosk.Bosk;
import io.vena.bosk.Catalog;
import io.vena.bosk.CatalogReference;
@@ -62,7 +64,8 @@ void initialState(Path enclosingCatalogPath) {
}
@ParametersByName
- void replaceIdentical(Path enclosingCatalogPath, Identifier childID) throws InvalidTypeException {
+ @WithSpan("replaceIdentical")
+ void replaceIdentical(@SpanAttribute("enclosingPath") Path enclosingCatalogPath, @SpanAttribute("childID") Identifier childID) throws InvalidTypeException {
CatalogReference ref = initializeBoskWithCatalog(enclosingCatalogPath);
driver.submitReplacement(ref.then(childID), newEntity(childID, ref));
assertCorrectBoskContents();
@@ -455,7 +458,8 @@ private Reference initializeBoskWithBlankValues(Path enclosingCatalo
return ref;
}
- private CatalogReference initializeBoskWithCatalog(Path enclosingCatalogPath) {
+ @WithSpan
+ private CatalogReference initializeBoskWithCatalog(@SpanAttribute("enclosingCatalogPath") Path enclosingCatalogPath) {
LOGGER.debug("initializeBoskWithCatalog({})", enclosingCatalogPath);
setupBosksAndReferences(driverFactory);
try {