Introduction to Rollbar
Rollbar provides real-time error tracking and monitoring for applications. It aggregates errors, provides detailed context, and enables quick debugging and resolution of issues in production environments.
Dependencies and Setup
Maven Configuration
<properties> <rollbar.version>1.9.2</rollbar.version> <jackson.version>2.15.2</jackson.version> </properties> <dependencies> <!-- Rollbar Java SDK --> <dependency> <groupId>com.rollbar</groupId> <artifactId>rollbar-java</artifactId> <version>${rollbar.version}</version> </dependency> <!-- Rollbar Spring Boot Starter --> <dependency> <groupId>com.rollbar</groupId> <artifactId>rollbar-spring-boot-web</artifactId> <version>${rollbar.version}</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- For async logging --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-async</artifactId> </dependency> </dependencies> Core Configuration
Rollbar Config Builder
@Configuration public class RollbarConfig { private static final Logger logger = LoggerFactory.getLogger(RollbarConfig.class); @Value("${rollbar.access-token:}") private String accessToken; @Value("${rollbar.environment:development}") private String environment; @Value("${rollbar.code-version:1.0.0}") private String codeVersion; @Value("${rollbar.enabled:false}") private boolean enabled; @Bean @ConditionalOnProperty(name = "rollbar.enabled", havingValue = "true") public Rollbar rollbar() { if (accessToken == null || accessToken.trim().isEmpty()) { logger.warn("Rollbar access token not configured. Rollbar will not be initialized."); return null; } ConfigBuilder configBuilder = ConfigBuilder.withAccessToken(accessToken) .environment(environment) .codeVersion(codeVersion) .framework("spring-boot") .handleUncaughtErrors(true) .enabled(enabled); // Custom configuration configureRollbar(configBuilder); return new Rollbar(configBuilder.build()); } private void configureRollbar(ConfigBuilder configBuilder) { // Configure person tracking configBuilder.person(new PersonProvider() { @Override public Person provide() { // This will be populated from current context return null; } }); // Configure server information configBuilder.server(new ServerProvider() { @Override public Server provide() { try { return new Server.Builder() .host(InetAddress.getLocalHost().getHostName()) .root("/app") .branch("main") .build(); } catch (UnknownHostException e) { return new Server.Builder() .host("unknown") .build(); } } }); // Configure notifier information configBuilder.notifier(new NotifierProvider() { @Override public Notifier provide() { return new Notifier.Builder() .name("my-spring-boot-app") .version("1.0") .build(); } }); // Add custom data configBuilder.custom(new CustomProvider() { @Override public Object provide() { Map<String, Object> custom = new HashMap<>(); custom.put("app_start_time", Instant.now().toString()); custom.put("jvm_version", System.getProperty("java.version")); custom.put("os_name", System.getProperty("os.name")); return custom; } }); } } Spring Boot Auto-Configuration
@Configuration @EnableConfigurationProperties(RollbarProperties.class) @ConditionalOnProperty(name = "rollbar.enabled", havingValue = "true") public class RollbarAutoConfiguration { @Bean @ConditionalOnMissingBean public RollbarService rollbarService(Rollbar rollbar, RollbarProperties properties) { return new RollbarService(rollbar, properties); } @Bean public RollbarAspect rollbarAspect(RollbarService rollbarService) { return new RollbarAspect(rollbarService); } @Bean public RollbarWebFilter rollbarWebFilter(RollbarService rollbarService) { return new RollbarWebFilter(rollbarService); } @Bean public RollbarAsyncConfigurer rollbarAsyncConfigurer() { return new RollbarAsyncConfigurer(); } } @ConfigurationProperties(prefix = "rollbar") public class RollbarProperties { private boolean enabled = false; private String accessToken; private String environment = "development"; private String codeVersion = "1.0.0"; private boolean logUncaughtExceptions = true; private boolean captureIpAddress = true; private int maxRetries = 3; private List<String> ignoredExceptions = Arrays.asList( "org.springframework.web.servlet.NoHandlerFoundException" ); private List<String> sensitiveFields = Arrays.asList( "password", "token", "secret", "authorization" ); // Getters and setters public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public String getEnvironment() { return environment; } public void setEnvironment(String environment) { this.environment = environment; } public String getCodeVersion() { return codeVersion; } public void setCodeVersion(String codeVersion) { this.codeVersion = codeVersion; } public boolean isLogUncaughtExceptions() { return logUncaughtExceptions; } public void setLogUncaughtExceptions(boolean logUncaughtExceptions) { this.logUncaughtExceptions = logUncaughtExceptions; } public boolean isCaptureIpAddress() { return captureIpAddress; } public void setCaptureIpAddress(boolean captureIpAddress) { this.captureIpAddress = captureIpAddress; } public int getMaxRetries() { return maxRetries; } public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; } public List<String> getIgnoredExceptions() { return ignoredExceptions; } public void setIgnoredExceptions(List<String> ignoredExceptions) { this.ignoredExceptions = ignoredExceptions; } public List<String> getSensitiveFields() { return sensitiveFields; } public void setSensitiveFields(List<String> sensitiveFields) { this.sensitiveFields = sensitiveFields; } } Core Rollbar Service
Rollbar Service Implementation
@Service public class RollbarService { private final Rollbar rollbar; private final RollbarProperties properties; private final ObjectMapper objectMapper; private static final Logger logger = LoggerFactory.getLogger(RollbarService.class); public RollbarService(Rollbar rollbar, RollbarProperties properties) { this.rollbar = rollbar; this.properties = properties; this.objectMapper = new ObjectMapper(); configureObjectMapper(); } public void logError(Throwable throwable) { logError(throwable, null, null); } public void logError(Throwable throwable, String description) { logError(throwable, description, null); } public void logError(Throwable throwable, String description, Map<String, Object> context) { if (!properties.isEnabled() || shouldIgnoreException(throwable)) { return; } try { RollbarContext rollbarContext = buildContext(context); if (description != null) { rollbar.error(throwable, rollbarContext, description); } else { rollbar.error(throwable, rollbarContext); } logger.debug("Error logged to Rollbar: {}", throwable.getMessage()); } catch (Exception e) { logger.warn("Failed to log error to Rollbar", e); } } public void logWarning(String message) { logWarning(message, null); } public void logWarning(String message, Map<String, Object> context) { if (!properties.isEnabled()) { return; } try { RollbarContext rollbarContext = buildContext(context); rollbar.warning(message, rollbarContext); logger.debug("Warning logged to Rollbar: {}", message); } catch (Exception e) { logger.warn("Failed to log warning to Rollbar", e); } } public void logInfo(String message) { logInfo(message, null); } public void logInfo(String message, Map<String, Object> context) { if (!properties.isEnabled()) { return; } try { RollbarContext rollbarContext = buildContext(context); rollbar.info(message, rollbarContext); } catch (Exception e) { logger.warn("Failed to log info to Rollbar", e); } } public void logDebug(String message) { logDebug(message, null); } public void logDebug(String message, Map<String, Object> context) { if (!properties.isEnabled()) { return; } try { RollbarContext rollbarContext = buildContext(context); rollbar.debug(message, rollbarContext); } catch (Exception e) { logger.warn("Failed to log debug to Rollbar", e); } } public void logCritical(Throwable throwable, String description) { logCritical(throwable, description, null); } public void logCritical(Throwable throwable, String description, Map<String, Object> context) { if (!properties.isEnabled() || shouldIgnoreException(throwable)) { return; } try { RollbarContext rollbarContext = buildContext(context); rollbar.critical(throwable, rollbarContext, description); logger.debug("Critical error logged to Rollbar: {}", description); } catch (Exception e) { logger.warn("Failed to log critical error to Rollbar", e); } } public void trackPerson(String userId, String username, String email) { if (!properties.isEnabled()) { return; } try { Person person = new Person.Builder() .id(userId) .username(username) .email(email) .build(); rollbar.setPerson(person); } catch (Exception e) { logger.warn("Failed to track person in Rollbar", e); } } public void clearPerson() { if (!properties.isEnabled()) { return; } try { rollbar.clearPerson(); } catch (Exception e) { logger.warn("Failed to clear person in Rollbar", e); } } private RollbarContext buildContext(Map<String, Object> customContext) { RollbarContext.Builder contextBuilder = new RollbarContext.Builder(); // Add request context if available RequestContext requestContext = getRequestContext(); if (requestContext != null) { contextBuilder.request(requestContext); } // Add custom context if (customContext != null && !customContext.isEmpty()) { Map<String, Object> sanitizedContext = sanitizeContext(customContext); contextBuilder.custom(sanitizedContext); } // Add person context if available Person person = getCurrentPerson(); if (person != null) { contextBuilder.person(person); } return contextBuilder.build(); } private RequestContext getRequestContext() { try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) .getRequest(); return new RequestContext.Builder() .url(getRequestUrl(request)) .method(request.getMethod()) .headers(sanitizeHeaders(getHeaders(request))) .params(sanitizeParams(getParameters(request))) .userIp(properties.isCaptureIpAddress() ? getClientIp(request) : null) .build(); } catch (Exception e) { // Not in request context return null; } } private Person getCurrentPerson() { // Implement based on your authentication system // Example with Spring Security: /* Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.isAuthenticated()) { Object principal = authentication.getPrincipal(); if (principal instanceof UserDetails) { UserDetails userDetails = (UserDetails) principal; return new Person.Builder() .id(userDetails.getUsername()) .username(userDetails.getUsername()) .build(); } } */ return null; } private boolean shouldIgnoreException(Throwable throwable) { if (throwable == null) return false; String exceptionName = throwable.getClass().getName(); return properties.getIgnoredExceptions().stream() .anyMatch(ignored -> exceptionName.equals(ignored)); } private Map<String, Object> sanitizeContext(Map<String, Object> context) { Map<String, Object> sanitized = new HashMap<>(context); properties.getSensitiveFields().forEach(field -> { if (sanitized.containsKey(field)) { sanitized.put(field, "***REDACTED***"); } }); return sanitized; } private Map<String, String> sanitizeHeaders(Map<String, String> headers) { Map<String, String> sanitized = new HashMap<>(headers); properties.getSensitiveFields().forEach(field -> { String headerKey = field.toLowerCase(); if (sanitized.containsKey(headerKey)) { sanitized.put(headerKey, "***REDACTED***"); } }); return sanitized; } private Map<String, String> sanitizeParams(Map<String, String> params) { Map<String, String> sanitized = new HashMap<>(params); properties.getSensitiveFields().forEach(field -> { if (sanitized.containsKey(field)) { sanitized.put(field, "***REDACTED***"); } }); return sanitized; } private void configureObjectMapper() { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } // Helper methods for request context private String getRequestUrl(HttpServletRequest request) { return request.getRequestURL().toString(); } private Map<String, String> getHeaders(HttpServletRequest request) { Map<String, String> headers = new HashMap<>(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); headers.put(headerName, request.getHeader(headerName)); } return headers; } private Map<String, String> getParameters(HttpServletRequest request) { Map<String, String> params = new HashMap<>(); Enumeration<String> paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); params.put(paramName, request.getParameter(paramName)); } return params; } private String getClientIp(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } } Spring Boot Integration
Web Filter for Request Context
@Component public class RollbarWebFilter implements Filter { private final RollbarService rollbarService; private static final Logger logger = LoggerFactory.getLogger(RollbarWebFilter.class); public RollbarWebFilter(RollbarService rollbarService) { this.rollbarService = rollbarService; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { chain.doFilter(request, response); return; } HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // Extract user information for Rollbar person tracking trackUserIfAuthenticated(httpRequest); try { chain.doFilter(request, response); } catch (Exception e) { // Log unhandled exceptions to Rollbar handleException(e, httpRequest); throw e; } finally { // Clear person context after request rollbarService.clearPerson(); } } private void trackUserIfAuthenticated(HttpServletRequest request) { // Implement based on your authentication mechanism // Example: /* String userId = extractUserId(request); String username = extractUsername(request); String email = extractEmail(request); if (userId != null) { rollbarService.trackPerson(userId, username, email); } */ } private void handleException(Exception e, HttpServletRequest request) { Map<String, Object> context = new HashMap<>(); context.put("request_url", request.getRequestURL().toString()); context.put("request_method", request.getMethod()); context.put("user_agent", request.getHeader("User-Agent")); rollbarService.logError(e, "Unhandled exception in web request", context); } } Aspect-Oriented Error Handling
@Aspect @Component public class RollbarAspect { private final RollbarService rollbarService; private static final Logger logger = LoggerFactory.getLogger(RollbarAspect.class); public RollbarAspect(RollbarService rollbarService) { this.rollbarService = rollbarService; } @AfterThrowing(pointcut = "execution(* com.myapp.service.*.*(..))", throwing = "ex") public void logServiceException(JoinPoint joinPoint, Exception ex) { Map<String, Object> context = buildMethodContext(joinPoint); rollbarService.logError(ex, "Service method exception", context); } @AfterThrowing(pointcut = "execution(* com.myapp.repository.*.*(..))", throwing = "ex") public void logRepositoryException(JoinPoint joinPoint, Exception ex) { Map<String, Object> context = buildMethodContext(joinPoint); rollbarService.logError(ex, "Repository method exception", context); } @AfterThrowing(pointcut = "execution(* com.myapp.controller.*.*(..))", throwing = "ex") public void logControllerException(JoinPoint joinPoint, Exception ex) { Map<String, Object> context = buildMethodContext(joinPoint); rollbarService.logError(ex, "Controller method exception", context); } @Around("@annotation(rollbarTracked)") public Object trackMethodExecution(ProceedingJoinPoint joinPoint, RollbarTracked rollbarTracked) throws Throwable { String methodName = joinPoint.getSignature().toShortString(); long startTime = System.currentTimeMillis(); try { Object result = joinPoint.proceed(); long duration = System.currentTimeMillis() - startTime; // Log performance if threshold exceeded if (rollbarTracked.performanceThreshold() > 0 && duration > rollbarTracked.performanceThreshold()) { Map<String, Object> context = buildPerformanceContext(joinPoint, duration); rollbarService.logWarning( String.format("Method %s took %dms (threshold: %dms)", methodName, duration, rollbarTracked.performanceThreshold()), context ); } return result; } catch (Exception e) { long duration = System.currentTimeMillis() - startTime; Map<String, Object> context = buildErrorContext(joinPoint, duration, e); rollbarService.logError(e, String.format("Method %s failed after %dms", methodName, duration), context ); throw e; } } private Map<String, Object> buildMethodContext(JoinPoint joinPoint) { Map<String, Object> context = new HashMap<>(); context.put("class", joinPoint.getTarget().getClass().getSimpleName()); context.put("method", joinPoint.getSignature().getName()); context.put("args", Arrays.toString(joinPoint.getArgs())); return context; } private Map<String, Object> buildPerformanceContext(ProceedingJoinPoint joinPoint, long duration) { Map<String, Object> context = buildMethodContext(joinPoint); context.put("duration_ms", duration); context.put("event_type", "performance_issue"); return context; } private Map<String, Object> buildErrorContext(ProceedingJoinPoint joinPoint, long duration, Exception e) { Map<String, Object> context = buildMethodContext(joinPoint); context.put("duration_ms", duration); context.put("error_type", e.getClass().getSimpleName()); context.put("error_message", e.getMessage()); return context; } } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RollbarTracked { long performanceThreshold() default 0; // in milliseconds boolean captureArguments() default true; String description() default ""; } Custom Exception Handler
Global Exception Handler
@ControllerAdvice @Slf4j public class GlobalExceptionHandler { private final RollbarService rollbarService; public GlobalExceptionHandler(RollbarService rollbarService) { this.rollbarService = rollbarService; } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleGenericException(Exception ex, WebRequest request) { log.error("Unhandled exception", ex); Map<String, Object> context = buildErrorContext(request, ex); rollbarService.logError(ex, "Unhandled global exception", context); ErrorResponse errorResponse = new ErrorResponse( "INTERNAL_SERVER_ERROR", "An unexpected error occurred", Instant.now().toString() ); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex, WebRequest request) { log.warn("Business exception: {}", ex.getMessage()); Map<String, Object> context = buildErrorContext(request, ex); context.put("business_error_code", ex.getErrorCode()); rollbarService.logWarning( String.format("Business exception: %s", ex.getMessage()), context ); ErrorResponse errorResponse = new ErrorResponse( ex.getErrorCode(), ex.getMessage(), Instant.now().toString() ); return ResponseEntity.status(ex.getHttpStatus()).body(errorResponse); } @ExceptionHandler(ValidationException.class) public ResponseEntity<ErrorResponse> handleValidationException(ValidationException ex, WebRequest request) { log.warn("Validation exception: {}", ex.getMessage()); Map<String, Object> context = buildErrorContext(request, ex); context.put("validation_errors", ex.getValidationErrors()); rollbarService.logWarning( String.format("Validation exception: %s", ex.getMessage()), context ); ErrorResponse errorResponse = new ErrorResponse( "VALIDATION_ERROR", ex.getMessage(), Instant.now().toString(), ex.getValidationErrors() ); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); } @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) { log.info("Resource not found: {}", ex.getMessage()); // Don't log 404 errors to Rollbar to reduce noise // rollbarService.logInfo(ex.getMessage(), buildErrorContext(request, ex)); ErrorResponse errorResponse = new ErrorResponse( "RESOURCE_NOT_FOUND", ex.getMessage(), Instant.now().toString() ); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse); } private Map<String, Object> buildErrorContext(WebRequest request, Exception ex) { Map<String, Object> context = new HashMap<>(); if (request instanceof ServletWebRequest) { ServletWebRequest servletRequest = (ServletWebRequest) request; HttpServletRequest httpRequest = servletRequest.getRequest(); context.put("request_url", httpRequest.getRequestURL().toString()); context.put("request_method", httpRequest.getMethod()); context.put("query_string", httpRequest.getQueryString()); context.put("user_agent", httpRequest.getHeader("User-Agent")); context.put("client_ip", getClientIp(httpRequest)); } context.put("exception_class", ex.getClass().getName()); context.put("exception_message", ex.getMessage()); context.put("timestamp", Instant.now().toString()); return context; } private String getClientIp(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty()) { return xForwardedFor.split(",")[0].trim(); } return request.getRemoteAddr(); } } // Error Response DTO public class ErrorResponse { private String code; private String message; private String timestamp; private Map<String, Object> details; public ErrorResponse(String code, String message, String timestamp) { this.code = code; this.message = message; this.timestamp = timestamp; } public ErrorResponse(String code, String message, String timestamp, Map<String, Object> details) { this.code = code; this.message = message; this.timestamp = timestamp; this.details = details; } // Getters and setters public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } public Map<String, Object> getDetails() { return details; } public void setDetails(Map<String, Object> details) { this.details = details; } } Async Error Tracking
Async Configuration
@Configuration @EnableAsync public class RollbarAsyncConfigurer implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(100); executor.setThreadNamePrefix("RollbarAsync-"); executor.setTaskDecorator(new RollbarMdcTaskDecorator()); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new RollbarAsyncExceptionHandler(); } } @Component public class RollbarMdcTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { Map<String, String> context = MDC.getCopyOfContextMap(); return () -> { try { if (context != null) { MDC.setContextMap(context); } runnable.run(); } finally { MDC.clear(); } }; } } @Component public class RollbarAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { private final RollbarService rollbarService; private static final Logger logger = LoggerFactory.getLogger(RollbarAsyncExceptionHandler.class); public RollbarAsyncExceptionHandler() { // Get RollbarService from application context this.rollbarService = ApplicationContextProvider.getApplicationContext() .getBean(RollbarService.class); } @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { logger.error("Uncaught async exception in method: {}", method.getName(), ex); Map<String, Object> context = new HashMap<>(); context.put("method", method.getName()); context.put("class", method.getDeclaringClass().getSimpleName()); context.put("parameters", Arrays.toString(params)); context.put("thread", Thread.currentThread().getName()); rollbarService.logError(ex, "Uncaught async exception", context); } } @Component public class ApplicationContextProvider implements ApplicationContextAware { private static ApplicationContext context; public static ApplicationContext getApplicationContext() { return context; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } } Business Event Tracking
Custom Business Events
@Service public class BusinessEventTracker { private final RollbarService rollbarService; private static final Logger logger = LoggerFactory.getLogger(BusinessEventTracker.class); public BusinessEventTracker(RollbarService rollbarService) { this.rollbarService = rollbarService; } public void trackUserLogin(String userId, boolean success, String failureReason) { Map<String, Object> context = new HashMap<>(); context.put("user_id", userId); context.put("success", success); context.put("event_type", "user_login"); context.put("timestamp", Instant.now().toString()); if (!success) { context.put("failure_reason", failureReason); rollbarService.logWarning("User login failed", context); } else { rollbarService.logInfo("User login successful", context); } } public void trackOrderCreation(String orderId, String customerId, BigDecimal amount) { Map<String, Object> context = new HashMap<>(); context.put("order_id", orderId); context.put("customer_id", customerId); context.put("amount", amount); context.put("event_type", "order_created"); context.put("timestamp", Instant.now().toString()); rollbarService.logInfo("Order created successfully", context); } public void trackPaymentProcessed(String paymentId, String orderId, String status) { Map<String, Object> context = new HashMap<>(); context.put("payment_id", paymentId); context.put("order_id", orderId); context.put("status", status); context.put("event_type", "payment_processed"); context.put("timestamp", Instant.now().toString()); if ("FAILED".equals(status)) { rollbarService.logWarning("Payment processing failed", context); } else { rollbarService.logInfo("Payment processed successfully", context); } } public void trackSystemEvent(String eventName, String component, String status, Map<String, Object> metadata) { Map<String, Object> context = new HashMap<>(); context.put("event_name", eventName); context.put("component", component); context.put("status", status); context.put("event_type", "system_event"); context.put("timestamp", Instant.now().toString()); if (metadata != null) { context.putAll(metadata); } if ("ERROR".equals(status)) { rollbarService.logError( new RuntimeException("System event error: " + eventName), "System event error occurred", context ); } else { rollbarService.logInfo("System event: " + eventName, context); } } } Testing Rollbar Integration
Test Configuration
@SpringBootTest @TestPropertySource(properties = { "rollbar.enabled=true", "rollbar.access-token=test-token", "rollbar.environment=test" }) @Slf4j public class RollbarIntegrationTest { @Autowired private RollbarService rollbarService; @Autowired private BusinessEventTracker businessEventTracker; @Mock private Rollbar rollbarMock; @Test public void testErrorLogging() { RuntimeException testException = new RuntimeException("Test exception"); // This should not throw an exception rollbarService.logError(testException, "Test error message"); } @Test public void testBusinessEventTracking() { // This should not throw an exception businessEventTracker.trackOrderCreation( "order-123", "customer-456", new BigDecimal("99.99") ); } @Test public void testContextBuilding() { Map<String, Object> context = new HashMap<>(); context.put("user_id", "test-user"); context.put("action", "test_action"); // This should not throw an exception rollbarService.logInfo("Test message with context", context); } @Test public void testSensitiveDataFiltering() { Map<String, Object> context = new HashMap<>(); context.put("password", "secret123"); context.put("token", "jwt-token"); context.put("normal_field", "normal_value"); // This should redact sensitive fields rollbarService.logInfo("Test sensitive data filtering", context); } } Application Configuration
application.yml
rollbar: enabled: true access-token: ${ROLLBAR_ACCESS_TOKEN:} environment: ${spring.profiles.active:development} code-version: 1.0.0 log-uncaught-exceptions: true capture-ip-address: true max-retries: 3 ignored-exceptions: - "org.springframework.web.servlet.NoHandlerFoundException" - "org.springframework.security.access.AccessDeniedException" sensitive-fields: - "password" - "token" - "secret" - "authorization" - "credit_card" - "ssn" spring: application: name: my-service profiles: active: development logging: level: com.rollbar: WARN com.myapp: INFO Docker Deployment
FROM openjdk:17-jdk-slim COPY target/my-app.jar /app/my-app.jar # Set Rollbar environment variables ENV ROLLBAR_ACCESS_TOKEN=your-access-token-here ENV SPRING_PROFILES_ACTIVE=production ENTRYPOINT ["java", "-jar", "/app/my-app.jar"]
Conclusion
Rollbar error tracking in Java provides:
- Real-time Error Monitoring - Immediate notification of production errors
- Rich Context - Detailed request, user, and environment information
- Smart Grouping - Automatic grouping of similar errors
- Custom Business Events - Track important business events and metrics
- Performance Monitoring - Track slow methods and performance issues
- Integration Flexibility - Spring Boot integration with minimal configuration
- Security - Automatic sensitive data filtering
This implementation enables comprehensive error tracking and monitoring while providing the flexibility to add custom business context and events for better debugging and analysis.