Monitoring và Profiling Tools

Tổng quan về Monitoring

Monitoring và profiling là essential practices để đảm bảo Java applications chạy efficiently và identify performance bottlenecks trong production environment.

Spring Boot Actuator

Basic Configuration

@Configuration
public class ActuatorConfig {

    @Bean
    public HealthIndicator customHealthIndicator() {
        return new HealthIndicator() {
            @Override
            public Health health() {
                boolean isHealthy = checkDatabaseConnection() && 
                                  checkMemoryUsage();

                if (isHealthy) {
                    return Health.up()
                            .withDetail("status", "All systems operational")
                            .build();
                } else {
                    return Health.down()
                            .withDetail("status", "System issues detected")
                            .build();
                }
            }

            private boolean checkDatabaseConnection() {
                return true;
            }

            private boolean checkMemoryUsage() {
                Runtime runtime = Runtime.getRuntime();
                long maxMemory = runtime.maxMemory();
                long totalMemory = runtime.totalMemory();
                long freeMemory = runtime.freeMemory();
                long usedMemory = totalMemory - freeMemory;

                double memoryUsagePercentage = (double) usedMemory / maxMemory * 100;
                return memoryUsagePercentage < 90;
            }
        };
    }
}

Micrometer Metrics

Custom Metrics

@Service
public class UserService {

    private final Counter userCreationCounter;
    private final Timer userFetchTimer;

    public UserService(MeterRegistry meterRegistry) {
        this.userCreationCounter = Counter.builder("users.created")
                .description("Number of users created")
                .register(meterRegistry);

        this.userFetchTimer = Timer.builder("users.fetch.duration")
                .description("Time taken to fetch user")
                .register(meterRegistry);
    }

    @Timed(value = "users.create", description = "Time taken to create user")
    public User createUser(CreateUserRequest request) {
        try {
            User user = new User();
            user.setName(request.getName());
            user.setEmail(request.getEmail());

            User savedUser = userRepository.save(user);
            userCreationCounter.increment(Tags.of("status", "success"));

            return savedUser;
        } catch (Exception e) {
            userCreationCounter.increment(Tags.of("status", "error"));
            throw e;
        }
    }
}

JProfiler và VisualVM

Performance Monitoring

@Component
public class PerformanceService {

    public void expensiveOperation() {
        List<String> largeList = new ArrayList<>();

        for (int i = 0; i < 1000000; i++) {
            largeList.add("Item " + i);
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Distributed Tracing

OpenTelemetry Configuration

@Configuration
public class TracingConfig {

    @Bean
    public OpenTelemetry openTelemetry() {
        return OpenTelemetrySDK.builder()
                .setTracerProvider(
                        SdkTracerProvider.builder()
                                .setResource(Resource.getDefault()
                                        .merge(Resource.builder()
                                                .put(ResourceAttributes.SERVICE_NAME, "myapp")
                                                .build()))
                                .build())
                .build();
    }

    @Bean
    public Tracer tracer(OpenTelemetry openTelemetry) {
        return openTelemetry.getTracer("myapp");
    }
}

Structured Logging

@Service
@Slf4j
public class UserService {

    public User createUser(CreateUserRequest request) {
        String correlationId = UUID.randomUUID().toString();

        MDC.put("correlation.id", correlationId);
        MDC.put("operation", "user.create");

        try {
            log.info("Starting user creation for email: {}", request.getEmail());

            User user = new User();
            user.setEmail(request.getEmail());

            User savedUser = userRepository.save(user);
            log.info("User created successfully with ID: {}", savedUser.getId());

            return savedUser;
        } finally {
            MDC.clear();
        }
    }
}

Best Practices

  1. Baseline Metrics: Establish performance baselines
  2. Memory Monitoring: Monitor heap usage và GC metrics
  3. Error Tracking: Track và analyze exceptions
  4. Alerting: Set up alerts for critical metrics