diff --git a/README.md b/README.md
index 3b694ee..5383d04 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,7 @@ logdispatch.exclude-paths=/health,/actuator/**,/metrics/**
| `logdispatch.masked-headers` | ❌ No | Comma-separated list of headers to mask. Defaults to none |
| `logdispatch.exclude-paths` | ❌ No | Comma-separated list of URI paths to exclude. Supports wildcards such as `/actuator/**` |
| `logdispatch.timeout-ms` | ❌ No | Connection and read timeout in milliseconds. Defaults to `3000`. |
+̉| `logdispatch.health.enabled` | ❌ No | Enables or disables the `/logdispatch/health` endpoint. Defaults to `true` |
Disable LogDispatch in local or test profiles when you want the dependency on the classpath but do not want any APM activity:
@@ -186,6 +187,52 @@ GET /logdispatch/health
}
```
+### Disabling the Health Endpoint
+
+If your application uses a security layer (e.g. Spring Security, an API gateway) that requires all unauthenticated endpoints to be explicitly opted in, or you simply don't want the endpoint exposed, disable it entirely:
+
+```yaml
+logdispatch:
+ health:
+ enabled: false
+```
+
+```properties
+logdispatch.health.enabled=false
+```
+
+When disabled, the `/logdispatch/health` endpoint is not registered at all — requests to that path receive a `404 Not Found`, the same as any other undefined route.
+
+### Rate Limiting
+
+To prevent abuse, the endpoint is limited to:
+
+```text
+60 requests per minute per IP
+```
+
+Requests exceeding the limit receive:
+
+```http
+429 Too Many Requests
+```
+
+### Endpoint
+
+```http
+GET /logdispatch/health
+```
+
+### Response
+
+```json
+{
+ "status": "UP",
+ "startupTime": "2026-05-31T02:00:00.000Z",
+ "uptimeSeconds": 120
+}
+```
+
### Rate Limiting
To prevent abuse, the endpoint is limited to:
diff --git a/mvnw b/mvnw
old mode 100644
new mode 100755
diff --git a/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfiguration.java b/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfiguration.java
index c543bd8..47c8b0a 100644
--- a/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfiguration.java
+++ b/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfiguration.java
@@ -4,6 +4,7 @@
import in.maheshlangote.logdispatch.LogDispatchFilter;
import in.maheshlangote.logdispatch.LogDispatchHealthController;
import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@@ -14,7 +15,7 @@
*
* This configuration automatically registers LogDispatch beans and passes the
* {@code logdispatch.enabled} flag to each component so disabled mode can no-op.
- *
+ *
* @author Mahesh Langote
* @version 1.0.0
*/
@@ -66,12 +67,20 @@ public FilterRegistrationBean logDispatchFilterRegistration(L
/**
* Creates and exposes the {@link in.maheshlangote.logdispatch.LogDispatchHealthController} bean.
* This controller provides a lightweight health endpoint for the APM server to poll.
+ * Registration is skipped entirely when {@code logdispatch.health.enabled=false},
+ * so the endpoint does not exist rather than responding with a "disabled" status.
*
* @param properties LogDispatch configuration properties
* @return a fully configured {@link in.maheshlangote.logdispatch.LogDispatchHealthController}.
*/
@Bean
+ @ConditionalOnProperty(
+ prefix = "logdispatch.health",
+ name = "enabled",
+ havingValue = "true",
+ matchIfMissing = true
+ )
public LogDispatchHealthController logDispatchHealthController(LogDispatchProperties properties) {
return new LogDispatchHealthController(properties.isEnabled());
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchProperties.java b/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchProperties.java
index e8f4276..6d17fac 100644
--- a/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchProperties.java
+++ b/src/main/java/in/maheshlangote/logdispatch/config/LogDispatchProperties.java
@@ -11,6 +11,7 @@
public class LogDispatchProperties {
private boolean enabled = true;
+ private Health health = new Health();
private String serverUrl = "http://localhost:8081/api/v1/ingest/logs";
private String apiKey = "default-key";
private List maskedHeaders = List.of();
@@ -22,6 +23,36 @@ public class LogDispatchProperties {
*
* @return {@code true} when LogDispatch should inspect and dispatch errors
*/
+
+ public Health getHealth(){
+ return health;
+ }
+
+ public void setHealth(Health health){
+ this.health = health;
+ }
+
+ /**
+ * Configuration for the LogDispatch health endpoint.
+ * */
+ public static class Health {
+ private boolean enabled = true;
+ /**
+ * Returns whether the LogDispatch health endpoint is enabled.
+ *
+ * @return {@code true} when the /logdispatch/health endpoint should be registered
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled){
+ this.enabled = enabled;
+ }
+ }
+
+
+
public boolean isEnabled() {
return enabled;
}
diff --git a/src/test/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfigurationTest.java b/src/test/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfigurationTest.java
index 20c65d7..729583a 100644
--- a/src/test/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfigurationTest.java
+++ b/src/test/java/in/maheshlangote/logdispatch/config/LogDispatchAutoConfigurationTest.java
@@ -32,4 +32,20 @@ void shouldRegisterBeansWithDisabledProperties() {
assertThat(context.getBean(LogDispatchProperties.class).isEnabled()).isFalse();
});
}
+ @Test
+ void shouldNotRegisterHealthControllerWhenHealthDisabled() {
+ contextRunner
+ .withPropertyValues("logdispatch.health.enabled=false")
+ .run(context -> {
+ assertThat(context).doesNotHaveBean(LogDispatchHealthController.class);
+ });
+}
+
+@Test
+void shouldRegisterHealthControllerByDefaultWhenHealthPropertyMissing() {
+ contextRunner
+ .run(context -> {
+ assertThat(context).hasSingleBean(LogDispatchHealthController.class);
+ });
+}
}