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.