From 3264fa21628642a969a3ca8c0b848d1509268f9d Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Sun, 1 Jun 2025 06:21:35 +0300 Subject: [PATCH 1/2] feat: update MonitorService with error handling and OpenTelemetry validation --- .../petclinic/errors/MonitorService.java | 139 +++++++++++------- 1 file changed, 86 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/springframework/samples/petclinic/errors/MonitorService.java b/src/main/java/org/springframework/samples/petclinic/errors/MonitorService.java index af0ad68a219..bd4b4395c32 100644 --- a/src/main/java/org/springframework/samples/petclinic/errors/MonitorService.java +++ b/src/main/java/org/springframework/samples/petclinic/errors/MonitorService.java @@ -1,77 +1,110 @@ package org.springframework.samples.petclinic.errors; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; import java.util.InvalidPropertiesFormatException; +import java.util.Objects; @Component public class MonitorService implements SmartLifecycle { - private boolean running = false; - private Thread backgroundThread; - @Autowired - private OpenTelemetry openTelemetry; + private static final Logger logger = LoggerFactory.getLogger(MonitorService.class); + private static final String MONITOR_NAME = "MonitorService"; + private static final long MONITORING_INTERVAL = 5000; - @Override - public void start() { - var otelTracer = openTelemetry.getTracer("MonitorService"); + private boolean running = false; + private Thread backgroundThread; - running = true; - backgroundThread = new Thread(() -> { - while (running) { + @Autowired + private OpenTelemetry openTelemetry; - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - Span span = otelTracer.spanBuilder("monitor").startSpan(); + @Override + public void start() { + if (openTelemetry == null) { + logger.error("OpenTelemetry instance not initialized"); + throw new IllegalStateException("OpenTelemetry instance not initialized"); + } - try { + var otelTracer = openTelemetry.getTracer(MONITOR_NAME); + running = true; + backgroundThread = new Thread(() -> { + while (running) { + try { + Thread.sleep(MONITORING_INTERVAL); + } catch (InterruptedException e) { + logger.warn("Monitoring thread interrupted", e); + Thread.currentThread().interrupt(); + break; + } - System.out.println("Background service is running..."); - monitor(); - } catch (Exception e) { - span.recordException(e); - span.setStatus(StatusCode.ERROR); - } finally { - span.end(); - } - } - }); + Span span = otelTracer.spanBuilder("monitor") + .setAttribute("service.name", MONITOR_NAME) + .setAttribute("monitoring.interval", MONITORING_INTERVAL) + .startSpan(); - // Start the background thread - backgroundThread.start(); - System.out.println("Background service started."); - } + try { + validateMonitoringState(); + logger.debug("Background service is running..."); + monitor(); + span.setStatus(StatusCode.OK); + } catch (InvalidPropertiesFormatException e) { + logger.error("Invalid properties in monitoring", e); + span.recordException(e); + span.setStatus(StatusCode.ERROR, "Invalid properties format"); + } catch (IllegalStateException e) { + logger.error("Monitoring state error", e); + span.recordException(e); + span.setStatus(StatusCode.ERROR, "Monitor failure"); + } catch (Exception e) { + logger.error("Unexpected error during monitoring", e); + span.recordException(e); + span.setStatus(StatusCode.ERROR, "Unexpected monitoring error"); + } finally { + span.end(); + } + } + }); - private void monitor() throws InvalidPropertiesFormatException { - Utils.throwException(IllegalStateException.class,"monitor failure"); - } + backgroundThread.setName("MonitorService-Thread"); + backgroundThread.start(); + logger.info("Background service started"); + } + private void validateMonitoringState() { + Objects.requireNonNull(openTelemetry, "OpenTelemetry must not be null"); + if (!running) { + throw new IllegalStateException("Monitor service is not running"); + } + } + private void monitor() throws InvalidPropertiesFormatException { + Span span = Span.current(); + span.setAttributes( + Attributes.of( + AttributeKey.stringKey("monitor.status"), "active", + AttributeKey.longKey("monitor.timestamp"), System.currentTimeMillis() + ) + ); + Utils.throwException(IllegalStateException.class, "monitor failure"); + } - @Override - public void stop() { - // Stop the background task - running = false; - if (backgroundThread != null) { - try { - backgroundThread.join(); // Wait for the thread to finish - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - System.out.println("Background service stopped."); - } - - @Override - public boolean isRunning() { - return false; - } -} + @Override + public void stop() { + running = false; + if (backgroundThread != null) { + try { + backgroundThread.interrupt(); + backgroundThread.join(MONITORING_INTERVAL); + logger.info("Background service stopped gracefully"); + } catch (InterruptedException e) { + logger.warn("Interrupted while stopping background service", e); + Thread. \ No newline at end of file From 809311bba3881aebb8a728482365f4400c088314 Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Sun, 1 Jun 2025 06:21:49 +0300 Subject: [PATCH 2/2] feat: add OpenTelemetry config for service tracing and exports --- src/main/resources/application.properties | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f7aef094b4f..15c649f5525 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -29,3 +29,14 @@ logging.level.org.springframework=INFO # Maximum time static resources should be cached spring.web.resources.cache.cachecontrol.max-age=12h + +# OpenTelemetry Configuration +otel.service.name=petclinic-service +otel.traces.exporter=otlp +otel.metrics.exporter=otlp +otel.logs.exporter=otlp +otel.exporter.otlp.endpoint=http://localhost:4317 +otel.resource.attributes.environment=production +otel.resource.attributes.deployment.region=us-west +otel.resource.attributes.service.version=1.0.0 +otel.resource.attributes.service.instance.id=${random.uuid} \ No newline at end of file