From d6d6ef3614294cb582a8d6161c552cb82e52a99b Mon Sep 17 00:00:00 2001 From: Dennis Oelkers Date: Thu, 4 Dec 2025 15:13:15 +0100 Subject: [PATCH] Make maximum event age configurable. (#24441) * Make maximum event age configurable. * Adding changelog snippet. * Fixing type of tunable. --- changelog/unreleased/pr-24441.toml | 4 ++++ .../src/main/java/org/graylog2/Configuration.java | 3 +++ .../events/ClusterEventCleanupPeriodical.java | 11 ++++++----- .../events/ClusterEventCleanupPeriodicalTest.java | 12 ++++++------ 4 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 changelog/unreleased/pr-24441.toml diff --git a/changelog/unreleased/pr-24441.toml b/changelog/unreleased/pr-24441.toml new file mode 100644 index 0000000000..d10ff7e7d8 --- /dev/null +++ b/changelog/unreleased/pr-24441.toml @@ -0,0 +1,4 @@ +type = "a" +message = "Make maximum event age of cluster events configurable. " + +pulls = ["24441"] diff --git a/graylog2-server/src/main/java/org/graylog2/Configuration.java b/graylog2-server/src/main/java/org/graylog2/Configuration.java index b30533dfc0..703f28f09c 100644 --- a/graylog2-server/src/main/java/org/graylog2/Configuration.java +++ b/graylog2-server/src/main/java/org/graylog2/Configuration.java @@ -301,6 +301,9 @@ public class Configuration extends CaConfiguration implements CommonNodeConfigur @Parameter(value = "global_inputs_only") private boolean globalInputsOnly = false; + @Parameter(value = "max_event_age", validators = PositiveDurationValidator.class) + private java.time.Duration maxEventAge = java.time.Duration.ofDays(1L); + public boolean maintainsStreamAwareFieldTypes() { return streamAwareFieldTypes; } diff --git a/graylog2-server/src/main/java/org/graylog2/events/ClusterEventCleanupPeriodical.java b/graylog2-server/src/main/java/org/graylog2/events/ClusterEventCleanupPeriodical.java index 44b84ed6ba..b1a6c4926e 100644 --- a/graylog2-server/src/main/java/org/graylog2/events/ClusterEventCleanupPeriodical.java +++ b/graylog2-server/src/main/java/org/graylog2/events/ClusterEventCleanupPeriodical.java @@ -19,6 +19,7 @@ package org.graylog2.events; import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.Ints; import com.mongodb.WriteConcern; +import jakarta.inject.Named; import org.graylog2.database.MongoCollection; import com.mongodb.client.model.Filters; import jakarta.inject.Inject; @@ -29,21 +30,21 @@ import org.joda.time.DateTimeZone; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.Duration; import java.util.concurrent.TimeUnit; public class ClusterEventCleanupPeriodical extends Periodical { private static final Logger LOG = LoggerFactory.getLogger(ClusterEventCleanupPeriodical.class); private static final String COLLECTION_NAME = ClusterEventPeriodical.COLLECTION_NAME; - @VisibleForTesting - static final long DEFAULT_MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(1L); - private final MongoCollection collection; + private final Duration maxEventAge; @Inject - public ClusterEventCleanupPeriodical(MongoCollections mongoCollections) { + public ClusterEventCleanupPeriodical(MongoCollections mongoCollections, @Named("max_event_age") Duration maxEventAge) { this.collection = mongoCollections.collection(COLLECTION_NAME, ClusterEvent.class) .withWriteConcern(WriteConcern.JOURNALED); + this.maxEventAge = maxEventAge; } @Override @@ -91,7 +92,7 @@ public class ClusterEventCleanupPeriodical extends Periodical { try { LOG.debug("Removing stale events from MongoDB collection \"{}\"", COLLECTION_NAME); - final long timestamp = DateTime.now(DateTimeZone.UTC).getMillis() - DEFAULT_MAX_EVENT_AGE; + final long timestamp = DateTime.now(DateTimeZone.UTC).getMillis() - maxEventAge.toMillis(); final var deleted = collection.deleteMany(Filters.lt("timestamp", timestamp)).getDeletedCount(); LOG.debug("Removed {} stale events from \"{}\"", deleted, COLLECTION_NAME); diff --git a/graylog2-server/src/test/java/org/graylog2/events/ClusterEventCleanupPeriodicalTest.java b/graylog2-server/src/test/java/org/graylog2/events/ClusterEventCleanupPeriodicalTest.java index 5f4eaa4d53..178583c8ce 100644 --- a/graylog2-server/src/test/java/org/graylog2/events/ClusterEventCleanupPeriodicalTest.java +++ b/graylog2-server/src/test/java/org/graylog2/events/ClusterEventCleanupPeriodicalTest.java @@ -16,14 +16,12 @@ */ package org.graylog2.events; -import com.fasterxml.jackson.databind.ObjectMapper; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DBCollection; import com.mongodb.DBObject; import org.graylog.testing.mongodb.MongoDBExtension; import org.graylog2.database.MongoCollections; import org.graylog2.database.MongoConnection; -import org.graylog2.shared.bindings.providers.ObjectMapperProvider; import org.joda.time.DateTime; import org.joda.time.DateTimeUtils; import org.joda.time.DateTimeZone; @@ -35,6 +33,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import java.time.Duration; import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; @@ -44,8 +43,8 @@ import static org.assertj.core.api.Assertions.assertThat; @MockitoSettings(strictness = Strictness.WARN) public class ClusterEventCleanupPeriodicalTest { private static final DateTime TIME = new DateTime(2015, 4, 1, 0, 0, DateTimeZone.UTC); + private static final Duration maxEventAge = Duration.ofDays(1); - private final ObjectMapper objectMapper = new ObjectMapperProvider().get(); private MongoConnection mongoConnection; private ClusterEventCleanupPeriodical clusterEventCleanupPeriodical; @@ -55,7 +54,7 @@ public class ClusterEventCleanupPeriodicalTest { this.mongoConnection = mongoCollections.mongoConnection(); - this.clusterEventCleanupPeriodical = new ClusterEventCleanupPeriodical(mongoCollections); + this.clusterEventCleanupPeriodical = new ClusterEventCleanupPeriodical(mongoCollections, maxEventAge); } @AfterEach @@ -66,11 +65,12 @@ public class ClusterEventCleanupPeriodicalTest { @Test public void testDoRun() throws Exception { + final var maxEventAgeMillis = maxEventAge.toMillis(); final DBCollection collection = mongoConnection.getDatabase().getCollection(ClusterEventPeriodical.COLLECTION_NAME); assertThat(insertEvent(collection, 0L)).isTrue(); assertThat(insertEvent(collection, TIME.getMillis())).isTrue(); - assertThat(insertEvent(collection, TIME.minus(ClusterEventCleanupPeriodical.DEFAULT_MAX_EVENT_AGE).getMillis())).isTrue(); - assertThat(insertEvent(collection, TIME.minus(2 * ClusterEventCleanupPeriodical.DEFAULT_MAX_EVENT_AGE).getMillis())).isTrue(); + assertThat(insertEvent(collection, TIME.minus(maxEventAgeMillis).getMillis())).isTrue(); + assertThat(insertEvent(collection, TIME.minus(2 * maxEventAgeMillis).getMillis())).isTrue(); assertThat(collection.count()).isEqualTo(4L); clusterEventCleanupPeriodical.run();