From 6addb1d35056c25c80d0bc416c4419c75ddacad9 Mon Sep 17 00:00:00 2001 From: Matt Sills Date: Mon, 1 Oct 2018 14:53:23 +0100 Subject: [PATCH] Tracing-aware functions, bifunctions, suppliers, consumers, biconsumers --- .../java/com/palantir/tracing/Tracers.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/tracing/src/main/java/com/palantir/tracing/Tracers.java b/tracing/src/main/java/com/palantir/tracing/Tracers.java index b51140c20..ec517d3d4 100644 --- a/tracing/src/main/java/com/palantir/tracing/Tracers.java +++ b/tracing/src/main/java/com/palantir/tracing/Tracers.java @@ -21,6 +21,11 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; /** Utility methods for making {@link ExecutorService} and {@link Runnable} instances tracing-aware. */ public final class Tracers { @@ -103,6 +108,31 @@ public static Runnable wrap(Runnable delegate) { return new TracingAwareRunnable(delegate); } + /** Like {@link #wrap(Callable)}, but for Functions. */ + public static Function wrap(Function delegate) { + return new TracingAwareFunction<>(delegate); + } + + /** Like {@link #wrap(Callable)}, but for BiFunctions. */ + public static BiFunction wrap(BiFunction delegate) { + return new TracingAwareBiFunction<>(delegate); + } + + /** Like {@link #wrap(Callable)}, but for Consumers. */ + public static Consumer wrap(Consumer delegate) { + return new TracingAwareConsumer<>(delegate); + } + + /** Like {@link #wrap(Callable)}, but for BiConsumers. */ + public static BiConsumer wrap(BiConsumer delegate) { + return new TracingAwareBiConsumer<>(delegate); + } + + /** Like {@link #wrap(Callable)}, but for Suppliers. */ + public static Supplier wrap(Supplier delegate) { + return new TracingAwareSupplier<>(delegate); + } + /** * Wraps the provided executor service to make submitted tasks traceable with a fresh {@link Trace trace} * for each execution, see {@link #wrapWithNewTrace(ExecutorService)}. This method should not be used to @@ -242,6 +272,111 @@ public void run() { } } + /** + * Wraps a given Function such that its execution operates with the {@link Trace thread-local Trace} of the thread + * that constructs the {@link TracingAwareFunction} instance rather than the thread that executes the function. + */ + private static final class TracingAwareFunction implements Function { + private final Function delegate; + private final DeferredTracer deferredTracer; + + private TracingAwareFunction(Function delegate) { + this.delegate = delegate; + this.deferredTracer = new DeferredTracer(); + } + + @Override + public R apply(T input) { + return deferredTracer.withTrace(() -> delegate.apply(input)); + } + } + + /** + * Wraps a given bi-function such that its execution operates with the {@link Trace thread-local Trace} of the + * thread that constructs the {@link TracingAwareBiFunction} instance rather than the thread that executes the + * bi-function. + */ + private static final class TracingAwareBiFunction implements BiFunction { + private final BiFunction delegate; + private final DeferredTracer deferredTracer; + + private TracingAwareBiFunction(BiFunction delegate) { + this.delegate = delegate; + this.deferredTracer = new DeferredTracer(); + } + + @Override + public R apply(T inputT, U inputU) { + return deferredTracer.withTrace(() -> delegate.apply(inputT, inputU)); + } + } + + /** + * Wraps a given consumer such that its execution operates with the {@link Trace thread-local Trace} of the + * thread that constructs the {@link TracingAwareConsumer} instance rather than the thread that executes the + * consumer. + */ + private static final class TracingAwareConsumer implements Consumer { + private final Consumer delegate; + private final DeferredTracer deferredTracer; + + private TracingAwareConsumer(Consumer delegate) { + this.delegate = delegate; + this.deferredTracer = new DeferredTracer(); + } + + @Override + public void accept(T input) { + deferredTracer.withTrace(() -> { + delegate.accept(input); + return null; + }); + } + } + + /** + * Wraps a given bi-consumer such that its execution operates with the {@link Trace thread-local Trace} of the + * thread that constructs the {@link TracingAwareBiConsumer} instance rather than the thread that executes the + * bi-consumer. + */ + private static final class TracingAwareBiConsumer implements BiConsumer { + private final BiConsumer delegate; + private final DeferredTracer deferredTracer; + + private TracingAwareBiConsumer(BiConsumer delegate) { + this.delegate = delegate; + this.deferredTracer = new DeferredTracer(); + } + + @Override + public void accept(T inputT, U inputU) { + deferredTracer.withTrace(() -> { + delegate.accept(inputT, inputU); + return null; + }); + } + } + + /** + * Wraps a given supplier such that its execution operates with the {@link Trace thread-local Trace} of the + * thread that constructs the {@link TracingAwareSupplier} instance rather than the thread that executes the + * supplier. + */ + private static final class TracingAwareSupplier implements Supplier { + private final Supplier delegate; + private final DeferredTracer deferredTracer; + + private TracingAwareSupplier(Supplier delegate) { + this.delegate = delegate; + this.deferredTracer = new DeferredTracer(); + } + + @Override + public T get() { + return deferredTracer.withTrace(delegate::get); + } + } + public interface ThrowingCallable { T call() throws E; }