- VFLInitializer
- VFLStarter
- Log
- VFLFutures
- @SubBlock Annotation
- Buffer Configuration
- Flush Handlers
- Placeholder Patterns
- Error Handling
- Thread Safety
Entry point for setting up VFL instrumentation. Must be called before any application classes containing @SubBlock methods are loaded.
Initializes VFL annotation-based instrumentation with bytecode modification.
Parameters:
config- Configuration object with buffer and enable/disable flag
Example:
VFLBuffer buffer = new AsyncBuffer(100, 3000, 1000, flushHandler, executor, scheduler);
VFLAnnotationConfig config = new VFLAnnotationConfig(false, buffer);
VFLInitializer.initialize(config);Checks if VFL is currently disabled.
Returns: boolean - true if disabled or not initialized
Thread Safety: Thread-safe
Main entry point for creating VFL trace contexts. Provides different ways to start and continue traces.
Start a new root-level trace block.
Parameters:
blockName- Logical name for the operationrunnable- Code to execute within trace context
Example:
VFLStarter.StartRootBlock("Process Order", () -> {
orderService.processOrder();
});Start a root block with return value.
Parameters:
blockName- Logical name for the operationsupplier- Code to execute that returns a value
Returns: R - Result from the supplier
Example:
String result = VFLStarter.StartRootBlock("Calculate Total", () -> {
return orderService.calculateTotal();
});Continue tracing from a block received from another service.
Parameters:
continuationBlock- Block object from upstream servicerunnable- Code to execute in continued trace
Example:
Block traceBlock = deserialize(request.getHeader("vfl-block"));
VFLStarter.ContinueFromBlock(traceBlock, () -> {
handleRequest();
});Continue tracing with return value.
Parameters:
continuationBlock- Block object from upstream servicesupplier- Code to execute that returns a value
Returns: R - Result from the supplier
Start tracing for an event listener/consumer.
Parameters:
publisherBlock- Event publisher block linking to original traceeventListenerName- Logical name for this event listenerrunnable- Code to execute for event handling
Example:
VFLStarter.StartEventListener(publisherBlock, "OrderEventListener", () -> {
processOrderEvent();
});StartEventListener(EventPublisherBlock publisherBlock, String eventListenerName, String message, Runnable runnable)
Start event listener with initial log message.
Parameters:
publisherBlock- Event publisher blockeventListenerName- Logical name for listenermessage- Optional log message for listener startrunnable- Code to execute
Thread Safety: All methods are thread-safe
Error Handling: Exceptions are caught, logged, and re-thrown as RuntimeException
Static logging API for VFL with support for different log levels and functional logging.
Log informational message.
Parameters:
message- Message template with{}placeholdersargs- Arguments for placeholder replacement
Example:
Log.Info("Processing user {} with status {}", userId, status);Log warning message.
Example:
Log.Warn("Memory usage at {}% for user {}", memoryPercent, userId);Log error message.
Example:
Log.Error("Database connection failed for operation {}", operationId);Execute supplier and log result using message template.
Parameters:
fn- Supplier to executemessage- Template with{r}for return valueargs- Additional arguments
Returns: R - Result from supplier
Example:
String result = Log.InfoFn(() -> fetchData(), "Fetched data: {r}");Execute runnable and log completion message.
Example:
Log.InfoFn(() -> saveData(), "Data saved successfully");Execute supplier and create warning message based on result.
Parameters:
fn- Supplier to executemessageSerializer- Function to convert result to log message
Example:
int count = Log.WarnFn(() -> getItemCount(),
count -> "Item count is low: " + count);Create and log an event publisher block for linking async processing.
Parameters:
publisherName- Name of the publisher/event sourcemessage- Message templateargs- Arguments for formatting
Returns: EventPublisherBlock - Block representing the publish action
Example:
EventPublisherBlock event = Log.Publish("Order Created",
"Order {} created with total ${}", orderId, total);Create detached continuation block for cross-service tracing.
Parameters:
blockName- Logical name for the continuation blockfn- Function that receives the block and returns a result
Returns: R - Result from the function
Example:
String response = Log.CreateContinuationBlock("Call External API", block -> {
return httpClient.call("/api/data", serialize(block));
});Create continuation block with start message (void version).
Parameters:
blockName- Logical name for the blockstartMessage- Message logged when block startsconsumer- Consumer that receives the block
Example:
Log.CreateContinuationBlock("Send Message", "Sending to queue", block -> {
messageQueue.send(createMessage(block));
});Thread Safety: All methods are thread-safe when called within VFL context
Error Handling: Returns without logging if VFL is not initialized
VFL-enabled CompletableFuture helpers that preserve trace context in asynchronous operations.
Run supplier asynchronously with custom executor, creating JOIN sub-block.
Parameters:
supplier- Code to execute asynchronouslyexecutor- Custom executor for task execution
Returns: CompletableFuture<R> - Future with VFL context preserved
Example:
CompletableFuture<String> future = VFLFutures.supplyAsync(() -> {
return performCalculation();
}, customExecutor);
String result = future.join();Run supplier asynchronously using common ForkJoin pool.
Example:
CompletableFuture<Data> dataFuture = VFLFutures.supplyAsync(() -> {
return fetchFromDatabase();
});Run task asynchronously creating NO_JOIN sub-block.
Parameters:
runnable- Code to execute asynchronouslyexecutor- Custom executor for task execution
Returns: CompletableFuture<Void>
Example:
CompletableFuture<Void> task = VFLFutures.runAsync(() -> {
sendNotification();
}, notificationExecutor);Run task asynchronously using common pool.
Thread Safety: Thread-safe, but must be called within active VFL block context
Error Handling: Logs warning if no parent context exists; task still executes without VFL tracing
Marks methods for automatic VFL sub-block creation with bytecode instrumentation.
- Type:
String - Default: Method name with arguments
- Supports: Placeholder patterns
{0},{1}, etc.
- Type:
String - Default: No start message
- Supports: Argument placeholders
- Type:
String - Default: No end message
- Supports: Argument and return value placeholders
@SubBlock(blockName = "Process Payment {0}")
public void processPayment(String orderId) {
// Method implementation
}@SubBlock(
blockName = "Calculate Tax for {0}",
startMessage = "Starting tax calculation for order {0}",
endMessage = "Tax calculated: ${r} for order {0}"
)
public BigDecimal calculateTax(String orderId) {
return taxService.calculate(orderId);
}Thread Safety: Methods are thread-safe; instrumentation handles concurrent execution
Error Handling: Logs warning if called outside VFL root block context
Base interface for all buffer implementations.
pushLogToBuffer(Log log)- Buffer a log entrypushBlockToBuffer(Block block)- Buffer block creationpushLogStartToBuffer(String blockId, long timestamp)- Buffer block startpushLogEndToBuffer(String blockId, BlockEndData endData)- Buffer block endflush()- Flush all pending data
Flushes data immediately in calling thread.
VFLBuffer buffer = new SynchronousBuffer(100, flushHandler);Parameters:
bufferSize- Max items before auto-flushflushHandler- Handler for processing flushed data
Thread Safety: Thread-safe
Flushes data asynchronously with periodic flushing.
VFLBuffer buffer = new AsyncBuffer(
100, // buffer size
3000, // flush timeout ms
1000, // periodic flush interval ms
flushHandler, // flush handler
executor, // flush executor
scheduler // periodic scheduler
);Thread Safety: Thread-safe with concurrent flush operations
Discards all data (testing/disabled mode).
VFLBuffer buffer = new NoOpsBuffer();Sends data to VFL Hub server via HTTP.
VFLFlushHandler handler = new VFLHubFlushHandler(
URI.create("http://localhost:8080")
);Thread Safety: Thread-safe for concurrent requests
Error Handling: Returns false on network failures; logs detailed error information
Writes hierarchical JSON to file (development only).
VFLFlushHandler handler = new NestedJsonFlushHandler("output.json");Thread Safety: Thread-safe
Error Handling: Throws RuntimeException on file I/O errors
VFL supports dynamic placeholder replacement in block names and messages.
{0}- First method argument (0-indexed){1}- Second method argument{2}- Third method argument- etc.
Example:
@SubBlock(blockName = "Process order {0} for user {1}")
public void processOrder(String orderId, String userId) {
// Results in: "Process order ORD-123 for user USER-456"
}{r}- Return value (endMessage only){return}- Return value (case-insensitive)
Example:
@SubBlock(endMessage = "Calculation result: {r}")
public BigDecimal calculate() {
return new BigDecimal("123.45");
// Results in: "Calculation result: 123.45"
}nullarguments become"null"in outputnullreturn values become"null"in output- Invalid indices (e.g.,
{5}when only 2 arguments) remain unchanged
Log methods use SLF4J-style {} placeholders:
Log.Info("Processing {} items for user {}", itemCount, userId);Thread Safety: Placeholder replacement is thread-safe
Thrown by: VFLStarter methods
Cause: Wrapped exceptions from user code
Example:
VFLStarter.StartRootBlock("Operation", () -> {
throw new IllegalArgumentException("Invalid data");
// Becomes: RuntimeException wrapping IllegalArgumentException
});Thrown by: Log.CreateContinuationBlock()
Cause: No active VFL context
Example:
// Outside VFL context
Log.CreateContinuationBlock("Invalid", block -> {
// Throws IllegalStateException
});When VFL is disabled or not initialized:
VFLStartermethods execute code without tracingLogmethods return immediately without loggingVFLFuturesmethods behave like standard CompletableFuture@SubBlockmethods execute normally without instrumentation
When @SubBlock methods are called without parent context:
- Warning is logged:
"Could not create block for @SubBlock-{name}: no parent block" - Method executes normally without VFL tracing
- No exception is thrown
- Flush handlers return
falseon failure - Errors are logged but don't interrupt application flow
- Async buffers may retry or fall back to synchronous flush
- Always use try-catch for VFLStarter operations:
try {
VFLStarter.StartRootBlock("Operation", () -> riskyOperation());
} catch (RuntimeException e) {
// Handle wrapped exceptions
}- Check VFL status in critical paths:
if (!VFLInitializer.isDisabled()) {
// VFL operations
}Thread Safety: Error handling is thread-safe across all components
- Thread-safe: All methods can be called concurrently
- Context: Each thread maintains independent block stack
- Isolation: Thread-local storage prevents context bleeding
- Thread-safe: All logging methods are thread-safe
- Context: Operates on calling thread's VFL context
- Buffering: Thread-safe buffer operations
- Thread-safe: Safe for concurrent usage
- Context Transfer: Automatically transfers VFL context to async threads
- Isolation: Each async task gets independent context copy
- Thread-safe: Instrumented methods handle concurrent execution
- Context: Uses calling thread's context
- Stack Management: Thread-local block stack management
- SynchronousBuffer: Thread-safe with concurrent flush operations
- AsyncBuffer: Thread-safe with async flush execution
- NoOpsBuffer: Thread-safe (no-op implementation)
- VFLHubFlushHandler: Thread-safe HTTP operations
- NestedJsonFlushHandler: Thread-safe file operations
VFL maintains execution context using ThreadLocal storage:
// Main thread context
VFLStarter.StartRootBlock("Main", () -> {
// Context propagates to @SubBlock methods
service.processData();
// Context must be explicitly transferred to async operations
VFLFutures.supplyAsync(() -> {
// New thread gets copy of main thread's context
return service.asyncOperation();
});
// Standard CompletableFuture loses context
CompletableFuture.supplyAsync(() -> {
// No VFL context here - logs will be ignored
return service.asyncOperation();
});
});// Multiple threads with separate contexts
executor.submit(() -> {
VFLStarter.StartRootBlock("Task 1", () -> work1());
});
executor.submit(() -> {
VFLStarter.StartRootBlock("Task 2", () -> work2());
});
// Shared service methods with @SubBlock
@SubBlock
public synchronized void sharedMethod() {
// Safe: synchronization handled by application
}// DON'T: Share Block objects between threads
Block block = getCurrentBlock();
executor.submit(() -> {
VFLStarter.ContinueFromBlock(block, () -> work()); // Potentially unsafe
});
// DON'T: Manual context manipulation
ThreadContextManager.PushBlockToThreadLogStack(block); // Internal API- Thread-Local Storage: Each thread has independent VFL context
- No Shared State: Block contexts are not shared between threads
- Atomic Operations: Buffer operations use appropriate synchronization
- Context Cleanup: Automatic cleanup when threads complete VFL operations
Best Practice: Always use VFL-provided methods for context management and async operations.