Introduction to Honeycomb Beeline
Honeycomb Beeline is a lightweight instrumentation library that makes it easy to collect and send telemetry data to Honeycomb.io. It provides distributed tracing, custom fields, and structured events to help debug complex systems.
System Architecture Overview
Honeycomb Beeline Pipeline ├── Application Instrumentation │ ├ - Span Creation │ ├ - Custom Fields │ ├ - Trace Propagation │ └ - Event Sending ├── Beeline Configuration │ ├ - Honeycomb API Key │ ├ - Dataset Configuration │ └ - Sampling Settings ├── Data Collection │ ├ - HTTP Requests │ ├ - Database Calls │ ├ - Custom Business Logic │ └ - Error Tracking └── Honeycomb Platform ├ - Trace Visualization ├ - Query Builder ├ - Boards & Triggers └ - Service Maps
Core Implementation
1. Maven Dependencies
<properties>
<honeycomb.version>1.6.0</honeycomb.version>
<opentelemetry.version>1.32.0</opentelemetry.version>
<spring.boot.version>2.7.0</spring.boot.version>
</properties>
<dependencies>
<!-- Honeycomb Beeline -->
<dependency>
<groupId>io.honeycomb.beeline</groupId>
<artifactId>beeline-core</artifactId>
<version>${honeycomb.version}</version>
</dependency>
<dependency>
<groupId>io.honeycomb.beeline</groupId>
<artifactId>beeline-spring-boot-starter</artifactId>
<version>${honeycomb.version}</version>
</dependency>
<dependency>
<groupId>io.honeycomb.beeline</groupId>
<artifactId>beeline-spring-common</artifactId>
<version>${honeycomb.version}</version>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<!-- OpenTelemetry (optional, for advanced use cases) -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>${opentelemetry.version}</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
2. Honeycomb Configuration
import io.honeycomb.beeline.autoconfigure.BeelineAutoConfiguration;
import io.honeycomb.beeline.tracing.Span;
import io.honeycomb.beeline.tracing.SpanBuilderFactory;
import io.honeycomb.beeline.tracing.Tracer;
import io.honeycomb.beeline.tracing.propagation.Propagation;
import io.honeycomb.libhoney.HoneyClient;
import io.honeycomb.libhoney.transport.batch.impl.SystemClock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
@Configuration
public class HoneycombConfig {
@Value("${honeycomb.api.key:}")
private String honeycombApiKey;
@Value("${honeycomb.dataset:my-java-service}")
private String dataset;
@Value("${honeycomb.service.name:order-service}")
private String serviceName;
@Bean
public HoneyClient honeyClient() {
return HoneyClient.builder()
.dataSet(dataset)
.writeKey(honeycombApiKey)
.apiHost("https://api.honeycomb.io") // Or your Honeycomb endpoint
.globalFields(Collections.singletonMap("service_name", serviceName))
.build();
}
@Bean
public Tracer tracer(HoneyClient honeyClient) {
return new Tracer(Propagation.honeycombHeaderV1(), honeyClient, new SystemClock());
}
@Bean
public SpanBuilderFactory spanBuilderFactory(Tracer tracer) {
return new SpanBuilderFactory(
tracer,
Collections.singletonList(new io.honeycomb.beeline.tracing.sampling.TraceSampler<>(
(traces) -> 100 // Sample 100% of traces
)),
Collections.emptyList() // No span processors
);
}
}
3. Honeycomb Service Wrapper
import io.honeycomb.beeline.tracing.Span;
import io.honeycomb.beeline.tracing.SpanBuilderFactory;
import io.honeycomb.beeline.tracing.Tracer;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
@Service
public class HoneycombService {
private final Tracer tracer;
private final SpanBuilderFactory spanBuilderFactory;
public HoneycombService(Tracer tracer, SpanBuilderFactory spanBuilderFactory) {
this.tracer = tracer;
this.spanBuilderFactory = spanBuilderFactory;
}
/**
* Start a new root span
*/
public Span startSpan(String spanName) {
return spanBuilderFactory.createBuilder()
.setSpanName(spanName)
.build();
}
/**
* Start a child span
*/
public Span startChildSpan(String spanName, Span parent) {
return spanBuilderFactory.createBuilder()
.setSpanName(spanName)
.setParentSpan(parent)
.build();
}
/**
* Add field to current active span
*/
public void addField(String key, Object value) {
Span currentSpan = tracer.getActiveSpan();
if (currentSpan != null) {
currentSpan.addField(key, value);
}
}
/**
* Add multiple fields to current active span
*/
public void addFields(Map<String, Object> fields) {
Span currentSpan = tracer.getActiveSpan();
if (currentSpan != null) {
fields.forEach(currentSpan::addField);
}
}
/**
* Execute code within a span with automatic cleanup
*/
public <T> T runInSpan(String spanName, Callable<T> operation) {
Span span = startSpan(spanName);
try {
return operation.call();
} catch (Exception e) {
span.addField("error", true);
span.addField("error_message", e.getMessage());
span.addField("error_type", e.getClass().getSimpleName());
throw new RuntimeException("Operation failed in span: " + spanName, e);
} finally {
span.close();
}
}
/**
* Execute code within a span with custom fields
*/
public <T> T runInSpan(String spanName, Map<String, Object> fields, Callable<T> operation) {
Span span = startSpan(spanName);
try {
addFields(fields);
return operation.call();
} catch (Exception e) {
span.addField("error", true);
span.addField("error_message", e.getMessage());
span.addField("error_type", e.getClass().getSimpleName());
throw new RuntimeException("Operation failed in span: " + spanName, e);
} finally {
span.close();
}
}
/**
* Record timing information for an operation
*/
public <T> T timeOperation(String operationName, Callable<T> operation) {
long startTime = System.currentTimeMillis();
Span span = startSpan(operationName);
try {
T result = operation.call();
long duration = System.currentTimeMillis() - startTime;
span.addField("duration_ms", duration);
span.addField("operation", operationName);
span.addField("success", true);
return result;
} catch (Exception e) {
long duration = System.currentTimeMillis() - startTime;
span.addField("duration_ms", duration);
span.addField("success", false);
span.addField("error", e.getMessage());
span.addField("error_type", e.getClass().getSimpleName());
throw new RuntimeException("Timed operation failed: " + operationName, e);
} finally {
span.close();
}
}
/**
* Create a business transaction span
*/
public Span startBusinessTransaction(String transactionType, String transactionId) {
Map<String, Object> fields = new HashMap<>();
fields.put("transaction_type", transactionType);
fields.put("transaction_id", transactionId);
fields.put("business_span", true);
Span span = startSpan("business." + transactionType);
addFields(fields);
return span;
}
/**
* Get current trace ID for logging correlation
*/
public String getCurrentTraceId() {
Span currentSpan = tracer.getActiveSpan();
return currentSpan != null ? currentSpan.getTraceId() : "no-active-trace";
}
/**
* Get current span ID for logging correlation
*/
public String getCurrentSpanId() {
Span currentSpan = tracer.getActiveSpan();
return currentSpan != null ? currentSpan.getSpanId() : "no-active-span";
}
}
4. Spring Web Integration
import io.honeycomb.beeline.tracing.Span;
import io.honeycomb.beeline.tracing.Tracer;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.stereotype.Component;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
public class HoneycombWebFilter extends OncePerRequestFilter {
private final Tracer tracer;
private final HoneycombService honeycombService;
public HoneycombWebFilter(Tracer tracer, HoneycombService honeycombService) {
this.tracer = tracer;
this.honeycombService = honeycombService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String spanName = request.getMethod() + " " + request.getRequestURI();
Span span = tracer.startSpan(spanName);
try {
// Add request details to span
addRequestFields(span, request);
// Continue with request processing
filterChain.doFilter(request, response);
// Add response details to span
addResponseFields(span, response);
} catch (Exception e) {
// Add error details to span
span.addField("error", true);
span.addField("error_message", e.getMessage());
span.addField("error_type", e.getClass().getSimpleName());
throw e;
} finally {
span.close();
}
}
private void addRequestFields(Span span, HttpServletRequest request) {
Map<String, Object> requestFields = new HashMap<>();
requestFields.put("http.method", request.getMethod());
requestFields.put("http.path", request.getRequestURI());
requestFields.put("http.query_string", request.getQueryString());
requestFields.put("http.user_agent", request.getHeader("User-Agent"));
requestFields.put("http.client_ip", getClientIpAddress(request));
requestFields.put("http.content_type", request.getContentType());
requestFields.put("http.content_length", request.getContentLength());
span.addFields(requestFields);
}
private void addResponseFields(Span span, HttpServletResponse response) {
Map<String, Object> responseFields = new HashMap<>();
responseFields.put("http.status_code", response.getStatus());
responseFields.put("http.response_size", response.getBufferSize());
responseFields.put("http.response_content_type", response.getContentType());
span.addFields(responseFields);
}
private String getClientIpAddress(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0].trim();
}
return request.getRemoteAddr();
}
}
5. REST Controller with Honeycomb Instrumentation
import io.honeycomb.beeline.tracing.Span;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
private final HoneycombService honeycombService;
public OrderController(OrderService orderService, HoneycombService honeycombService) {
this.orderService = orderService;
this.honeycombService = honeycombService;
}
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
// Start business transaction span
Span transactionSpan = honeycombService.startBusinessTransaction("create_order",
java.util.UUID.randomUUID().toString());
try {
honeycombService.addField("order.customer_id", request.getCustomerId());
honeycombService.addField("order.amount", request.getAmount());
honeycombService.addField("order.item_count", request.getItems().size());
// Time the order creation operation
Order order = honeycombService.timeOperation("order_creation", () ->
orderService.createOrder(request)
);
honeycombService.addField("order.id", order.getId());
honeycombService.addField("order.status", order.getStatus());
return ResponseEntity.ok(order);
} finally {
transactionSpan.close();
}
}
@GetMapping("/{orderId}")
public ResponseEntity<Order> getOrder(@PathVariable String orderId) {
return honeycombService.runInSpan("get_order", Map.of("order_id", orderId), () -> {
honeycombService.addField("http.operation", "read");
honeycombService.addField("order.id", orderId);
Order order = orderService.getOrder(orderId);
if (order == null) {
honeycombService.addField("order.found", false);
return ResponseEntity.notFound().build();
}
honeycombService.addField("order.found", true);
honeycombService.addField("order.status", order.getStatus());
honeycombService.addField("order.customer_id", order.getCustomerId());
return ResponseEntity.ok(order);
});
}
@PostMapping("/{orderId}/payments")
public ResponseEntity<PaymentResponse> processPayment(@PathVariable String orderId,
@RequestBody PaymentRequest request) {
Span paymentSpan = honeycombService.startBusinessTransaction("process_payment",
java.util.UUID.randomUUID().toString());
try {
honeycombService.addFields(Map.of(
"order.id", orderId,
"payment.amount", request.getAmount(),
"payment.method", request.getPaymentMethod(),
"payment.currency", request.getCurrency()
));
PaymentResponse response = honeycombService.timeOperation("payment_processing", () ->
orderService.processPayment(orderId, request)
);
honeycombService.addFields(Map.of(
"payment.id", response.getPaymentId(),
"payment.status", response.getStatus(),
"payment.processed_at", response.getProcessedAt()
));
return ResponseEntity.ok(response);
} catch (Exception e) {
honeycombService.addField("payment.error", true);
throw e;
} finally {
paymentSpan.close();
}
}
@GetMapping("/{orderId}/status")
public ResponseEntity<OrderStatus> getOrderStatus(@PathVariable String orderId) {
honeycombService.addField("order.id", orderId);
return honeycombService.runInSpan("check_order_status", () -> {
OrderStatus status = orderService.getOrderStatus(orderId);
honeycombService.addFields(Map.of(
"order.status", status.getStatus(),
"order.last_updated", status.getLastUpdated(),
"order.estimated_delivery", status.getEstimatedDelivery()
));
return ResponseEntity.ok(status);
});
}
}
6. Database Instrumentation
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public class OrderRepository {
private final JdbcTemplate jdbcTemplate;
private final HoneycombService honeycombService;
public OrderRepository(JdbcTemplate jdbcTemplate, HoneycombService honeycombService) {
this.jdbcTemplate = jdbcTemplate;
this.honeycombService = honeycombService;
}
public Order findById(String orderId) {
return honeycombService.timeOperation("database.query", () -> {
honeycombService.addFields(Map.of(
"db.operation", "select",
"db.table", "orders",
"db.query_type", "by_id"
));
String sql = "SELECT * FROM orders WHERE id = ?";
List<Order> orders = jdbcTemplate.query(sql, new Object[]{orderId}, (rs, rowNum) ->
new Order(
rs.getString("id"),
rs.getString("customer_id"),
rs.getBigDecimal("amount"),
rs.getString("status")
)
);
honeycombService.addField("db.result_count", orders.size());
return orders.isEmpty() ? null : orders.get(0);
});
}
public Order save(Order order) {
return honeycombService.timeOperation("database.insert", () -> {
honeycombService.addFields(Map.of(
"db.operation", "insert",
"db.table", "orders",
"order.id", order.getId()
));
String sql = "INSERT INTO orders (id, customer_id, amount, status) VALUES (?, ?, ?, ?)";
int affectedRows = jdbcTemplate.update(sql,
order.getId(),
order.getCustomerId(),
order.getAmount(),
order.getStatus()
);
honeycombService.addField("db.affected_rows", affectedRows);
return order;
});
}
public List<Order> findByCustomerId(String customerId) {
return honeycombService.runInSpan("database.query_customer_orders",
Map.of("customer_id", customerId), () -> {
honeycombService.addFields(Map.of(
"db.operation", "select",
"db.table", "orders",
"db.query_type", "by_customer"
));
String sql = "SELECT * FROM orders WHERE customer_id = ? ORDER BY created_at DESC";
List<Order> orders = jdbcTemplate.query(sql, new Object[]{customerId}, (rs, rowNum) ->
new Order(
rs.getString("id"),
rs.getString("customer_id"),
rs.getBigDecimal("amount"),
rs.getString("status")
)
);
honeycombService.addField("db.result_count", orders.size());
return orders;
});
}
}
7. External Service Calls with Propagation
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.Map;
@Service
public class InventoryService {
private final RestTemplate restTemplate;
private final HoneycombService honeycombService;
public InventoryService(RestTemplate restTemplate, HoneycombService honeycombService) {
this.restTemplate = restTemplate;
this.honeycombService = honeycombService;
}
public boolean reserveItems(String orderId, List<OrderItem> items) {
return honeycombService.timeOperation("inventory_reservation", () -> {
honeycombService.addFields(Map.of(
"external.service", "inventory",
"external.operation", "reserve_items",
"order.id", orderId,
"item.count", items.size()
));
String url = "http://inventory-service/api/items/reserve";
Map<String, Object> requestBody = Map.of(
"orderId", orderId,
"items", items
);
try {
// Create request with headers
RequestEntity<Map<String, Object>> request = RequestEntity
.post(URI.create(url))
.header("X-Trace-Id", honeycombService.getCurrentTraceId())
.header("X-Span-Id", honeycombService.getCurrentSpanId())
.body(requestBody);
// Make the external call
Map response = restTemplate.exchange(request, Map.class).getBody();
boolean success = Boolean.TRUE.equals(response.get("success"));
honeycombService.addField("inventory.reservation_success", success);
return success;
} catch (Exception e) {
honeycombService.addField("external.call.error", true);
honeycombService.addField("external.error_message", e.getMessage());
throw new RuntimeException("Inventory service call failed", e);
}
});
}
public Map<String, Integer> checkStockLevels(List<String> productIds) {
return honeycombService.runInSpan("check_stock_levels",
Map.of("product_count", productIds.size()), () -> {
honeycombService.addFields(Map.of(
"external.service", "inventory",
"external.operation", "check_stock"
));
String url = "http://inventory-service/api/items/stock";
try {
RequestEntity<List<String>> request = RequestEntity
.post(URI.create(url))
.header("X-Trace-Id", honeycombService.getCurrentTraceId())
.body(productIds);
Map<String, Integer> stockLevels = restTemplate.exchange(request, Map.class).getBody();
honeycombService.addField("external.response_count", stockLevels.size());
return stockLevels;
} catch (Exception e) {
honeycombService.addField("external.call.error", true);
honeycombService.addField("external.error_message", e.getMessage());
throw new RuntimeException("Stock check failed", e);
}
});
}
}
8. Async Processing Instrumentation
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncOrderProcessor {
private final HoneycombService honeycombService;
private final OrderService orderService;
public AsyncOrderProcessor(HoneycombService honeycombService, OrderService orderService) {
this.honeycombService = honeycombService;
this.orderService = orderService;
}
@Async
public CompletableFuture<Void> processOrderAsync(String orderId) {
// Capture trace context before async execution
String traceId = honeycombService.getCurrentTraceId();
String spanId = honeycombService.getCurrentSpanId();
return CompletableFuture.runAsync(() -> {
// Create new span for async processing
honeycombService.runInSpan("async_order_processing", Map.of(
"order.id", orderId,
"processing.type", "async",
"parent.trace_id", traceId,
"parent.span_id", spanId
), () -> {
try {
honeycombService.addField("async.task.started", true);
// Simulate async processing
orderService.processOrderBackgroundTasks(orderId);
honeycombService.addField("async.task.completed", true);
} catch (Exception e) {
honeycombService.addField("async.task.failed", true);
honeycombService.addField("async.error", e.getMessage());
throw e;
}
});
});
}
}
9. Custom Business Metrics
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class BusinessMetricsService {
private final HoneycombService honeycombService;
private final AtomicLong ordersProcessed = new AtomicLong(0);
private final AtomicLong revenueGenerated = new AtomicLong(0);
public BusinessMetricsService(HoneycombService honeycombService) {
this.honeycombService = honeycombService;
}
public void recordOrderProcessed(String orderId, double amount, String customerTier) {
ordersProcessed.incrementAndGet();
revenueGenerated.addAndGet((long) amount);
honeycombService.runInSpan("business_metric", Map.of(
"metric_type", "order_processed",
"order.id", orderId,
"order.amount", amount,
"customer.tier", customerTier,
"cumulative.orders", ordersProcessed.get(),
"cumulative.revenue", revenueGenerated.get()
), () -> {
// Metric recorded automatically via span fields
});
}
public void recordPaymentProcessed(String paymentId, String status, double fee) {
honeycombService.runInSpan("business_metric", Map.of(
"metric_type", "payment_processed",
"payment.id", paymentId,
"payment.status", status,
"payment.fee", fee,
"success", "success".equals(status)
), () -> {
// Metric recorded
});
}
public void recordUserAction(String userId, String action, Map<String, Object> context) {
Map<String, Object> fields = new HashMap<>();
fields.put("metric_type", "user_action");
fields.put("user.id", userId);
fields.put("user.action", action);
fields.putAll(context);
honeycombService.runInSpan("business_metric", fields, () -> {
// User action recorded
});
}
}
10. Configuration Properties
# application.yml
honeycomb:
api-key: ${HONEYCOMB_API_KEY:your-api-key-here}
dataset: ${HONEYCOMB_DATaset:order-service}
service-name: ${HONEYCOMB_SERVICE_NAME:order-service}
enabled: true
# Beeline specific configuration
beeline:
# Sample rate (1 = 100%, 10 = 10%, 100 = 1%)
sample-rate: 1
# Enable request/response body capture
include-request-body: false
include-response-body: false
# Global fields
global-fields:
environment: ${ENVIRONMENT:development}
version: 1.0.0
region: ${AWS_REGION:us-east-1}
# Spring configuration
spring:
application:
name: order-service
jackson:
date-format: com.fasterxml.jackson.databind.util.StdDateFormat
time-zone: UTC
# Logging correlation with Honeycomb
logging:
pattern:
level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
11. Testing Honeycomb Instrumentation
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import io.honeycomb.beeline.tracing.Tracer;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@SpringBootTest
class HoneycombInstrumentationTest {
@MockBean
private Tracer tracer;
@MockBean
private SpanBuilderFactory spanBuilderFactory;
@Test
void testOrderCreationInstrumentation() {
// Test that spans are created during order processing
// Verify tracer interactions
verify(tracer, atLeastOnce()).startSpan(any(String.class));
}
@Test
void testErrorInstrumentation() {
// Test that errors are properly captured in spans
// Verify error fields are added to spans
}
}
Best Practices
1. Meaningful Span Names
// Good - descriptive and hierarchical
honeycombService.startSpan("http.request.api.orders.create");
honeycombService.startSpan("database.query.orders.by_customer");
honeycombService.startSpan("business.order_processing");
// Avoid - generic names
honeycombService.startSpan("span1");
honeycombService.startSpan("operation");
2. Consistent Field Naming
public class FieldNames {
public static final String ORDER_ID = "order.id";
public static final String CUSTOMER_ID = "customer.id";
public static final String PAYMENT_AMOUNT = "payment.amount";
public static final String HTTP_STATUS = "http.status_code";
public static final String DB_OPERATION = "db.operation";
public static final String ERROR_MESSAGE = "error.message";
}
3. Sampling Strategy
@Configuration
public class SamplingConfig {
@Bean
public Sampler<Trace> customSampler() {
return trace -> {
// Sample all errors
if (trace.getSpans().stream().anyMatch(span ->
span.getFields().containsKey("error"))) {
return true;
}
// Sample 10% of successful requests
return Math.random() < 0.1;
};
}
}
4. Performance Optimization
@Component
public class EfficientInstrumentation {
public void processWithMinimalOverhead() {
// Check if tracing is enabled before expensive operations
if (tracer.getActiveSpan() != null) {
honeycombService.addField("expensive_data", computeExpensiveData());
}
}
}
Conclusion
This comprehensive Honeycomb Beeline implementation provides:
- Automatic HTTP request tracing with Spring integration
- Database operation instrumentation with timing and metadata
- External service call tracking with context propagation
- Async processing support with trace continuity
- Business metrics collection for product analytics
- Custom field enrichment for detailed debugging
- Error tracking with full context
Key benefits:
- Distributed tracing across service boundaries
- Powerful querying in Honeycomb UI
- Performance insights through timing data
- Error analysis with rich context
- Business analytics integrated with operational data
- Low overhead with efficient sampling
The setup enables comprehensive observability of your Java applications, making it easy to debug complex issues and understand system behavior in production.