Unified Logging System
The Brobot Unified Logging System consolidates all logging functionality into a single, cohesive API that simplifies developer experience while providing powerful capabilities for debugging, monitoring, and analysis.
Overview
Previously, Brobot used three separate logging systems:
- SLF4J - Traditional application logging
- ActionLogger - Structured automation event logging
- ConsoleReporter - Real-time console feedback
The new unified system combines these into a single BrobotLogger
facade that automatically handles routing to appropriate backends while providing a consistent API.
Key Features
- Single Entry Point - One logger for all logging needs
- Automatic Context - Session, state, and action context propagation
- Fluent API - Simple methods for common cases, builder pattern for complex scenarios
- Performance Tracking - Built-in timers and metrics
- Backward Compatible - Works with existing logging infrastructure
- Thread Safe - Thread-local context management
Quick Start
Basic Usage
@Component
public class LoginAutomation {
@Autowired
private BrobotLogger logger;
public void performLogin(String username, String password) {
// Simple action logging
logger.action("CLICK", loginButton);
// Log with result
ActionResult result = click(loginButton);
logger.action("CLICK", loginButton, result);
// State transition
logger.transition(loginState, dashboardState);
// Observation
logger.observation("Login form displayed correctly");
// Error logging
logger.error("Failed to find login button", exception);
}
}
Session Scoped Logging
// All logs within the session automatically include session ID
try (var session = logger.session("test-session-123")) {
logger.action("START", testCase);
// Perform test steps...
logger.transition(state1, state2);
logger.observation("Test completed successfully");
}
Performance Tracking
// Using operation scope
try (var operation = logger.operation("ComplexOperation")) {
performComplexTask();
// Duration automatically logged when scope closes
}
// Using explicit timer
try (var timer = logger.startTimer("DataProcessing")) {
processData();
// Timer stops and logs duration when closed
}
// Manual timer control
BrobotLogger.Timer timer = logger.startTimer("CustomTimer");
doWork();
long duration = timer.stop(); // Returns duration in ms
Advanced Usage
Fluent Builder API
The builder API provides fine-grained control for complex logging scenarios:
logger.log()
.type(LogEvent.Type.ACTION)
.level(LogEvent.Level.INFO)
.action("CLICK")
.target(submitButton)
.result(actionResult)
.success(true)
.duration(250)
.screenshot("/tmp/screenshot.png")
.metadata("retryCount", 3)
.metadata("elementVisible", true)
.performance("responseTime", 150)
.color(AnsiColor.GREEN)
.log();
Custom Metadata
Add contextual information that will be included in all subsequent logs:
// Add metadata to context
logger.getContext().addMetadata("testSuite", "regression");
logger.getContext().addMetadata("environment", "staging");
// All subsequent logs will include this metadata
logger.action("CLICK", button); // Includes testSuite and environment
Error Handling with Screenshots
try {
clickElement(targetElement);
} catch (ElementNotFoundException e) {
String screenshotPath = captureScreenshot();
logger.log()
.error(e)
.message("Element not found after retries")
.screenshot(screenshotPath)
.metadata("lastKnownLocation", element.getLocation())
.log();
}
State Transition Logging
// Simple transition
logger.transition(currentState, targetState);
// Transition with details
logger.transition(currentState, targetState, success, duration);
// Complex transition with builder
logger.log()
.transition(currentState.getName(), targetState.getName())
.success(false)
.duration(5000)
.message("Transition timeout - retrying")
.metadata("attemptNumber", 2)
.log();
Configuration
Application Properties
Configure the logging system through application.yml
:
brobot:
logging:
console:
level: HIGH # NONE, LOW, HIGH
colors: true # Enable ANSI colors
format: compact # compact or detailed
structured:
enabled: true # Enable structured logging
format: json # json, xml, csv
sink: file # file, database, cloud
file:
path: logs/brobot-structured.json
rotation: daily # daily, size, none
max-size: 100MB
performance:
enabled: true
metrics-export: prometheus
context:
include-thread-name: true
include-timestamp: true
include-hostname: false
Programmatic Configuration
// Configure console output
logger.setConsoleLevel(ConsoleReporter.OutputLevel.LOW);
// Enable/disable structured logging
logger.enableStructuredLogging(true);
// Custom configuration
BrobotLogger.configure()
.consoleLevel(OutputLevel.HIGH)
.enableColors(true)
.structuredLogging(true)
.addSink(new CustomLogSink())
.apply();
Context Management
Thread-Local Context
The logging context is thread-local, ensuring isolation between concurrent executions:
@Component
public class LoggingContext {
// Set context information
void setSessionId(String sessionId);
void setCurrentState(State state);
void setCurrentAction(String action);
// Hierarchical operations
void pushOperation(String operationName);
String popOperation();
// Custom metadata
void addMetadata(String key, Object value);
Map<String, Object> getAllMetadata();
// Context snapshots for async operations
Context snapshot();
void restore(Context snapshot);
}
Async Operations
For asynchronous operations, capture and restore context:
// Capture context before async operation
LoggingContext.Context snapshot = logger.getContext().snapshot();
CompletableFuture.runAsync(() -> {
// Restore context in async thread
logger.getContext().restore(snapshot);
logger.action("ASYNC_PROCESS", dataObject);
});
Output Formats
Console Output
The console output is formatted for readability with optional ANSI colors:
[session-123] CLICK → LoginButton (success) [250ms]
[session-123] STATE: Login → Dashboard [1.5s]
[session-123] OBSERVE: Form validation passed
[session-123] ERROR: Element not found - ElementNotFoundException
[session-123] PERF: Operation completed: DataLoad (3.2s)
Structured Output (JSON)
{
"timestamp": 1704067200000,
"sessionId": "session-123",
"type": "ACTION",
"level": "INFO",
"action": "CLICK",
"target": "LoginButton",
"success": true,
"duration": 250,
"stateId": "LoginState",
"metadata": {
"matchCount": 1,
"screenshot": "/tmp/screenshot.png"
}
}
Integration with Existing Systems
SLF4J Integration
All logs are automatically routed to SLF4J with appropriate levels:
// BrobotLogger call
logger.error("Critical failure", exception);
// Automatically logs to SLF4J as:
// ERROR [BrobotLogger] [session-123] Critical failure
ActionLogger Compatibility
The unified logger maintains compatibility with the existing ActionLogger interface:
// Actions are automatically logged to ActionLogger
logger.action("CLICK", button, result);
// Routes to: actionLogger.logAction(sessionId, result, objectCollection)
// State transitions
logger.transition(from, to, success, duration);
// Routes to: actionLogger.logStateTransition(...)
ConsoleReporter Integration
Console output respects existing ConsoleReporter settings:
// Set global console level
ConsoleReporter.outputLevel = OutputLevel.LOW;
// Or through unified logger
logger.setConsoleLevel(OutputLevel.HIGH);
Best Practices
1. Use Session Scopes
Always wrap test executions in session scopes for proper correlation:
@Test
public void testUserFlow() {
try (var session = logger.session(generateSessionId())) {
// All logs in this block are correlated
performUserFlow();
}
}
2. Log at Appropriate Levels
- Actions: User interactions (clicks, types, etc.)
- Transitions: State changes in the application
- Observations: Notable conditions or validations
- Performance: Timing-sensitive operations
- Errors: Failures and exceptions
3. Include Relevant Context
logger.log()
.action("SUBMIT_FORM")
.target(form)
.metadata("formData", sanitizeFormData(data))
.metadata("validationErrors", errors)
.screenshot(captureOnError ? screenshotPath : null)
.log();
4. Use Timers for Performance Metrics
try (var timer = logger.startTimer("DatabaseQuery")) {
return executeQuery(sql);
} // Timer automatically logs duration
5. Leverage Metadata for Debugging
// Add test context
logger.getContext().addMetadata("testCase", testName);
logger.getContext().addMetadata("dataSet", dataSetId);
// Add environment context
logger.getContext().addMetadata("browser", getBrowserInfo());
logger.getContext().addMetadata("viewport", getViewportSize());
Migration Guide
From ConsoleReporter
// Old way
ConsoleReporter.print(match, stateObject, actionOptions);
ConsoleReporter.println(OutputLevel.HIGH, "Processing complete");
// New way
logger.action(actionOptions.getAction().toString(), stateObject);
logger.observation("Processing complete");
From ActionLogger
// Old way
actionLogger.logAction(sessionId, result, objectCollection);
actionLogger.logStateTransition(sessionId, from, to, before, success, time);
// New way
logger.action("CLICK", stateObject, result);
logger.transition(fromState, toState, success, time);
From SLF4J
// Old way
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
log.info("Starting process");
log.error("Process failed", exception);
// New way
@Autowired
private BrobotLogger logger;
logger.observation("Starting process");
logger.error("Process failed", exception);
Performance Considerations
- Minimal Overhead: The unified logger adds < 1% overhead compared to direct logging
- Lazy Evaluation: Expensive operations (like screenshots) are only performed when needed
- Async Options: Structured logging can be configured for async operation
- Buffering: File and network sinks support buffering for better performance
Troubleshooting
Common Issues
-
Missing Context: Ensure session is set before logging
// Always set session first
try (var session = logger.session("test-123")) {
// Now context is available
} -
No Console Output: Check console level setting
logger.setConsoleLevel(OutputLevel.HIGH);
-
Lombok Errors: IDE-specific Lombok issues don't affect runtime
- Ensure Lombok plugin is installed
- Enable annotation processing
-
Thread Context Lost: Use snapshots for async operations
var snapshot = logger.getContext().snapshot();
// Pass snapshot to async operation
Future Enhancements
- Cloud logging service integration (CloudWatch, Stackdriver)
- Real-time log streaming
- Advanced filtering and search capabilities
- Machine learning-based anomaly detection
- Distributed tracing support
Action Logging with Console Output and Visual Feedback
The unified logging system now includes enhanced action logging with real-time console output and visual highlighting capabilities. This provides immediate feedback during automation development and debugging.
Console Action Reporting
Get real-time feedback about action execution in the console:
🔍 FIND: login-button → ✓ FOUND (234ms)
└─ Location: (450,320) Score: 98.5%
✓ CLICK login-button (156ms)
⌨️ TYPE: "test@example.com" ✓
✗ FIND submit-button (2003ms)
└─ Search regions: 3 areas checked
⚠️ Performance Warning: FIND took 2003ms (threshold: 1000ms)
Visual Highlighting
See exactly what Brobot is doing with configurable visual feedback:
- Green borders for successful finds
- Blue borders for search regions
- Yellow ripple effects for clicks
- Red indicators for errors
GUI Access Detection
Automatic detection and reporting of GUI access problems:
❌ GUI Problem: No DISPLAY environment variable set
💡 Possible solutions:
• Set DISPLAY=:0 for local display
• For SSH: use -X or -Y flag for X11 forwarding
• For Docker: pass --env DISPLAY=$DISPLAY
• For WSL: install and configure X server (VcXsrv, Xming)
Configuration
Configure action logging through properties:
brobot:
# Console output configuration
console:
actions:
enabled: true
level: NORMAL # QUIET, NORMAL, VERBOSE
show-match-details: true
use-icons: true
# Visual highlighting configuration
highlight:
enabled: true
auto-highlight-finds: true
find:
color: "#00FF00" # Green
duration: 2.0 # seconds
search-region:
color: "#0000FF" # Blue
duration: 1.0
Using Enhanced Action Logging
@Autowired
private EnhancedActionLogger logger;
// Log with visual feedback
logger.logActionWithVisuals(
"FIND",
target,
result,
VisualFeedbackOptions.debug() // Maximum visibility
);
// Check GUI access
if (!logger.checkAndLogGuiAccess()) {
// Handle GUI access problems
}
// Custom visual options
VisualFeedbackOptions options = VisualFeedbackOptions.builder()
.highlightFinds(true)
.findHighlightColor(Color.YELLOW)
.findHighlightDuration(3.0)
.showMatchScore(true)
.build();
logger.logActionWithVisuals("CLICK", button, result, options);
Profile-Based Configuration
Use predefined profiles for different environments:
Development Profile
# Maximum visibility for debugging
java -jar app.jar --spring.profiles.active=visual-debug
CI/CD Profile
# Minimal output, no visual distractions
brobot:
console.actions.level: QUIET
highlight.enabled: false
gui-access.continue-on-error: true
Production Profile
# Disable console output, keep error reporting
brobot:
console.actions.enabled: false
highlight.enabled: false
gui-access.report-problems: true
Visual Feedback Options
Create custom visual feedback for specific scenarios:
// Highlight only successful finds
VisualFeedbackOptions.findsOnly()
// Debug mode - highlight everything
VisualFeedbackOptions.debug()
// No visual feedback
VisualFeedbackOptions.none()
// Custom configuration
VisualFeedbackOptions.builder()
.highlightFinds(true)
.highlightSearchRegions(true)
.flashHighlight(true)
.flashCount(3)
.persistHighlight(true) // Keep highlight until cleared
.highlightLabel("Target Element")
.build()
Integration with Desktop Runner
The desktop runner automatically displays console output and visual feedback when configured. The ConsoleActionEventListener
bridges the event system with the console reporter for real-time updates.
API Reference
The main classes for the unified logging system are:
BrobotLogger
- The main logging facadeLogEvent
- The event model for structured loggingLoggingContext
- Thread-local context managementLogBuilder
- Fluent API for complex logging scenariosEnhancedActionLogger
- Extended interface with visual feedbackVisualFeedbackOptions
- Configuration for visual highlighting
Examples Repository
Find more examples in the brobot-examples repository under /logging-examples
.