diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 824a61f83d4..756debda002 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -330,6 +330,15 @@ Switching Request Logger routes native query's request logs to one request logge |`druid.request.logging.nativeQueryLogger`|request logger for emitting native query's request logs.|none| |`druid.request.logging.sqlQueryLogger`|request logger for emitting SQL query's request logs.|none| +### Audit Logging + +Coordinator and Overlord log changes to lookups, segment load/drop rules, dynamic configuration changes for auditing + +|Property|Description|Default| +|--------|-----------|-------| +|`druid.audit.manager.auditHistoryMillis`|Default duration for querying audit history.|1 week| +|`druid.audit.manager.includePayloadAsDimensionInMetric`|Boolean flag on whether to add `payload` column in service metric.|false| + ### Enabling Metrics Druid processes periodically emit metrics and different metrics monitors can be included. Each process can overwrite the default list of monitors. diff --git a/server/src/main/java/org/apache/druid/server/audit/SQLAuditManager.java b/server/src/main/java/org/apache/druid/server/audit/SQLAuditManager.java index fc68c84727c..9ea53c670e1 100644 --- a/server/src/main/java/org/apache/druid/server/audit/SQLAuditManager.java +++ b/server/src/main/java/org/apache/druid/server/audit/SQLAuditManager.java @@ -20,6 +20,7 @@ package org.apache.druid.server.audit; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Supplier; import com.google.inject.Inject; import org.apache.druid.audit.AuditEntry; @@ -90,16 +91,28 @@ public class SQLAuditManager implements AuditManager ); } - @Override - public void doAudit(AuditEntry auditEntry, Handle handle) throws IOException + @VisibleForTesting + ServiceMetricEvent.Builder getAuditMetricEventBuilder(AuditEntry auditEntry) { - emitter.emit( - new ServiceMetricEvent.Builder() + ServiceMetricEvent.Builder builder = new ServiceMetricEvent.Builder() .setDimension("key", auditEntry.getKey()) .setDimension("type", auditEntry.getType()) .setDimension("author", auditEntry.getAuditInfo().getAuthor()) - .build("config/audit", 1) - ); + .setDimension("comment", auditEntry.getAuditInfo().getComment()) + .setDimension("remote_address", auditEntry.getAuditInfo().getIp()) + .setDimension("created_date", auditEntry.getAuditTime().toString()); + + if (config.getIncludePayloadAsDimensionInMetric()) { + builder.setDimension("payload", auditEntry.getPayload()); + } + + return builder; + } + + @Override + public void doAudit(AuditEntry auditEntry, Handle handle) throws IOException + { + emitter.emit(getAuditMetricEventBuilder(auditEntry).build("config/audit", 1)); handle.createStatement( StringUtils.format( diff --git a/server/src/main/java/org/apache/druid/server/audit/SQLAuditManagerConfig.java b/server/src/main/java/org/apache/druid/server/audit/SQLAuditManagerConfig.java index c57b2d700b8..4ef45d1ee92 100644 --- a/server/src/main/java/org/apache/druid/server/audit/SQLAuditManagerConfig.java +++ b/server/src/main/java/org/apache/druid/server/audit/SQLAuditManagerConfig.java @@ -28,8 +28,16 @@ public class SQLAuditManagerConfig @JsonProperty private long auditHistoryMillis = 7 * 24 * 60 * 60 * 1000L; // 1 WEEK + @JsonProperty + private boolean includePayloadAsDimensionInMetric = false; + public long getAuditHistoryMillis() { return auditHistoryMillis; } + + public boolean getIncludePayloadAsDimensionInMetric() + { + return includePayloadAsDimensionInMetric; + } } diff --git a/server/src/test/java/org/apache/druid/server/audit/SQLAuditManagerTest.java b/server/src/test/java/org/apache/druid/server/audit/SQLAuditManagerTest.java index 8677f42a0c5..13dc10ab316 100644 --- a/server/src/test/java/org/apache/druid/server/audit/SQLAuditManagerTest.java +++ b/server/src/test/java/org/apache/druid/server/audit/SQLAuditManagerTest.java @@ -27,6 +27,7 @@ import org.apache.druid.jackson.DefaultObjectMapper; import org.apache.druid.java.util.common.DateTimes; import org.apache.druid.java.util.common.Intervals; import org.apache.druid.java.util.common.StringUtils; +import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; import org.apache.druid.metadata.TestDerbyConnector; import org.apache.druid.server.metrics.NoopServiceEmitter; import org.junit.After; @@ -47,6 +48,7 @@ public class SQLAuditManagerTest private TestDerbyConnector connector; private AuditManager auditManager; + private final String PAYLOAD_DIMENSION_KEY = "payload"; private final ObjectMapper mapper = new DefaultObjectMapper(); @@ -83,6 +85,43 @@ public class SQLAuditManagerTest Assert.assertEquals(entry, serde); } + @Test + public void testAuditMetricEventBuilderConfig() + { + AuditEntry entry = new AuditEntry( + "testKey", + "testType", + new AuditInfo( + "testAuthor", + "testComment", + "127.0.0.1" + ), + "testPayload", + DateTimes.of("2013-01-01T00:00:00Z") + ); + + SQLAuditManager auditManagerWithPayloadAsDimension = new SQLAuditManager( + connector, + derbyConnectorRule.metadataTablesConfigSupplier(), + new NoopServiceEmitter(), + mapper, + new SQLAuditManagerConfig() + { + @Override + public boolean getIncludePayloadAsDimensionInMetric() + { + return true; + } + } + ); + + ServiceMetricEvent.Builder auditEntryBuilder = ((SQLAuditManager) auditManager).getAuditMetricEventBuilder(entry); + Assert.assertEquals(null, auditEntryBuilder.getDimension(PAYLOAD_DIMENSION_KEY)); + + ServiceMetricEvent.Builder auditEntryBuilderWithPayload = auditManagerWithPayloadAsDimension.getAuditMetricEventBuilder(entry); + Assert.assertEquals("testPayload", auditEntryBuilderWithPayload.getDimension(PAYLOAD_DIMENSION_KEY)); + } + @Test(timeout = 60_000L) public void testCreateAuditEntry() throws IOException {