9 Commits

Author SHA1 Message Date
e1f6e0ad60 v1.0.2 : Handle no key expiration with TTL = -1 2024-02-04 11:37:59 +01:00
e77d4d915d typo 2024-02-04 11:35:56 +01:00
0a0748172e Handle TTL to -1 = no key expiration 2024-02-04 11:33:31 +01:00
8febd14eb6 Comment on redis_lookup function: do not use 2024-02-04 11:33:07 +01:00
2cf5dff011 v1.0.1: Handle TTL and clear key 2024-02-04 10:42:12 +01:00
30e1bf70d9 Minor fixes so this compile 2024-02-04 10:40:25 +01:00
yo
f1c53077a4 Handle disconnect at doStop 2024-02-03 22:52:46 +01:00
yo
5a4b3cb38a Add clearKey and assignTtl 2024-02-03 22:38:36 +01:00
yo
5487e2dd71 Support TTL setting in 'lookup_set_value(lookup_table, key, value, ttl)' 2024-02-03 22:19:50 +01:00
6 changed files with 109 additions and 18 deletions

View File

@ -30,8 +30,14 @@ Usage
----- -----
* Create data adapter, cache (or not), lookup table * Create data adapter, cache (or not), lookup table
* Use 'lookup_set_value(lookup_table, key, value)' to create or update key in redis * Use 'lookup_set_value(lookup_table, key, value, [ttl])' to create or update key in redis
* Use 'lookup(lookup_table, key)' to get key * Use 'lookup_value(lookup_table, key)' to get key value
* Use 'lookup_clear_key(lookup_table, key)' to remove key
* Use 'lookup_has_value(lookup_table, key)' to test key existence
* Use 'lookup_assign_ttl(lookup_table, key, ttl)' to change TTL of existing key
By default keys will be created in Redis with the default TTL defined at data adapter creation time
Getting started Getting started
--------------- ---------------

View File

@ -10,7 +10,7 @@
<groupId>in.nosd.redis</groupId> <groupId>in.nosd.redis</groupId>
<artifactId>graylog-plugin-redis-lookup</artifactId> <artifactId>graylog-plugin-redis-lookup</artifactId>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<version>1.0.0</version> <version>1.0.2</version>
<description>Graylog ${project.artifactId} plugin.</description> <description>Graylog ${project.artifactId} plugin.</description>
<url>https://www.graylog.org</url> <url>https://www.graylog.org</url>
<developers> <developers>

View File

@ -31,7 +31,7 @@
<groupId>in.nosd.redis</groupId> <groupId>in.nosd.redis</groupId>
<artifactId>graylog-plugin-redis-lookup</artifactId> <artifactId>graylog-plugin-redis-lookup</artifactId>
<version>1.0.0</version> <version>1.0.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>

View File

@ -68,6 +68,7 @@ public class RedisLookupDataAdapter extends LookupDataAdapter {
private final Config config; private final Config config;
private final RedisClient client; private final RedisClient client;
private RedisCommands<String, String> commands; private RedisCommands<String, String> commands;
private StatefulRedisConnection<String, String> connection;
private final Timer redisGetRequestTimer; private final Timer redisGetRequestTimer;
private final Meter redisGetRequestErrors; private final Meter redisGetRequestErrors;
private final Timer redisSetRequestTimer; private final Timer redisSetRequestTimer;
@ -99,19 +100,19 @@ public class RedisLookupDataAdapter extends LookupDataAdapter {
this.redisSetRequestErrors = metricRegistry.meter(MetricRegistry.name(getClass(), "redisSetRequestErrors")); this.redisSetRequestErrors = metricRegistry.meter(MetricRegistry.name(getClass(), "redisSetRequestErrors"));
} }
// Add code to initialise Redis connection
@Override @Override
protected void doStart() throws Exception { protected void doStart() throws Exception {
StatefulRedisConnection<String, String> connection = this.client.connect(); connection = this.client.connect();
this.commands = connection.sync(); this.commands = connection.sync();
} }
// Add code to close Redis connection
@Override @Override
protected void doStop() throws Exception { protected void doStop() throws Exception {
connection.close();
client.close();
} }
// Returns the refresh interval for this data adapter. Use {@link Duration#ZERO} if refresh should be disabled.
@Override @Override
public Duration refreshInterval() { public Duration refreshInterval() {
return REFRESH_INTERVAL_DURATION; return REFRESH_INTERVAL_DURATION;
@ -134,7 +135,7 @@ public class RedisLookupDataAdapter extends LookupDataAdapter {
try { try {
final String value = this.commands.get(trimmedKey); final String value = this.commands.get(trimmedKey);
if (value == null) { if (value == null) {
LOG.warn("Redis GET request for key <{}> returned null, key do not exists.", trimmedKey); LOG.debug("Redis GET request for key <{}> returned null, key do not exists.", trimmedKey);
redisGetRequestErrors.mark(); redisGetRequestErrors.mark();
return LookupResult.empty(); return LookupResult.empty();
} }
@ -149,31 +150,115 @@ public class RedisLookupDataAdapter extends LookupDataAdapter {
} }
// This is deprecated, see setValue // This is deprecated, see setValue
@Override @Deprecated
public void set(Object key, Object value) { public void set(Object key, Object value) {
return; return;
} }
@Override @Override
public LookupResult setValue(Object key, Object value) { public LookupResult setValue(Object key, Object value) {
return setValueWithTtl(key, value, this.config.redisKeyTTL());
}
public LookupResult setValueWithTtl(Object key, Object value, Long ttlSec) {
final Timer.Context time = redisSetRequestTimer.time(); final Timer.Context time = redisSetRequestTimer.time();
final String trimmedKey = StringUtils.trimToNull(key.toString());
try { try {
final String result = this.commands.setex(key.toString(), this.config.redisKeyTTL(), value.toString()); final String result;
if (ttlSec > 0 ) {
result = this.commands.setex(trimmedKey, ttlSec, value.toString());
} else {
result = this.commands.set(trimmedKey, value.toString());
}
if (!result.equals("OK")) { if (!result.equals("OK")) {
LOG.warn("Redis SET key <{}> to value <{}> returned {}", key, value, result); LOG.warn("Redis SET(EX) key <{}> to value <{}> with TTL <{}> returned {}", key, value, ttlSec, result);
redisSetRequestErrors.mark(); redisSetRequestErrors.mark();
return LookupResult.empty(); return LookupResult.empty();
} }
return LookupResult.single(value.toString()); return LookupResult.single(value.toString());
} catch (Exception e) { } catch (Exception e) {
LOG.error("Redis SET key <{}> to value <{}> returned an exception: {}", key, value, e); LOG.error("Redis SET(EX) key <{}> to value <{}> with TTL <{}> returned an exception: {}", key, value, ttlSec, e);
redisSetRequestErrors.mark(); redisSetRequestErrors.mark();
return LookupResult.empty(); return LookupResult.withError();
} finally { } finally {
time.stop(); time.stop();
} }
} }
@Override
public void clearKey(Object key) {
final Timer.Context time = redisSetRequestTimer.time();
final String trimmedKey = StringUtils.trimToNull(key.toString());
try {
final Long result = this.commands.del(key.toString());
if (result != 1) {
LOG.debug("Redis DEL key <{}> returned {}", key, result);
redisSetRequestErrors.mark();
}
return;
} catch (Exception e) {
LOG.error("Redis DEL key <{}> returned {}", key, e);
redisSetRequestErrors.mark();
return;
} finally {
time.stop();
}
}
private LookupResult setExpire(String key, Long ttl) {
try {
final Boolean result = this.commands.expire(key, ttl);
if (!result) {
LOG.warn("Redis EXPIRE key <{}> to <{}> returned {}", key, ttl, result);
return LookupResult.withError();
}
final String value = this.commands.get(key);
return LookupResult.single(value.toString());
} catch (Exception e) {
LOG.error("Redis EXPIRE key <{}> to <{}> returned {}", key, ttl, e);
return LookupResult.withError(e.toString());
}
}
private LookupResult setPersist(String key) {
try {
final Boolean result = this.commands.persist(key);
if (!result) {
LOG.warn("Redis PERSIST key <{}> returned {}", key, result);
return LookupResult.withError();
}
final String value = this.commands.get(key);
return LookupResult.single(value.toString());
} catch (Exception e) {
LOG.error("Redis PERSIST key <{}> returned {}", key, e);
return LookupResult.withError(e.toString());
}
}
// TTL -1 = never expire
public LookupResult assignTtl(Object key, Long ttlSec) {
final Timer.Context time = redisSetRequestTimer.time();
final String trimmedKey = StringUtils.trimToNull(key.toString());
try {
if (ttlSec > 0) {
return setExpire(trimmedKey, ttlSec);
} else {
return setPersist(trimmedKey);
}
} catch (Exception e) {
LOG.error("assignTtl <{}> to key <{}> returned {}", ttlSec, trimmedKey, e);
redisSetRequestErrors.mark();
return LookupResult.withError();
} finally {
time.stop();
}
}
@Override
public LookupResult setStringList(Object key, List<String> listValue) {
return LookupResult.empty();
}
public interface Factory extends LookupDataAdapter.Factory2<RedisLookupDataAdapter> { public interface Factory extends LookupDataAdapter.Factory2<RedisLookupDataAdapter> {
@Override @Override
RedisLookupDataAdapter create(@Assisted("dto") DataAdapterDto dto); RedisLookupDataAdapter create(@Assisted("dto") DataAdapterDto dto);
@ -194,7 +279,7 @@ public class RedisLookupDataAdapter extends LookupDataAdapter {
.redisHost("127.0.0.1") .redisHost("127.0.0.1")
.redisPort(6379) .redisPort(6379)
.redisDB(0) .redisDB(0)
.redisKeyTTL(86400) .redisKeyTTL(-1)
.redisUsername("") .redisUsername("")
.redisPassword("") .redisPassword("")
.build(); .build();

View File

@ -76,7 +76,7 @@ public class RedisLookupPluginFunction extends LookupTableFunction<GenericLookup
public FunctionDescriptor<GenericLookupResult> descriptor() { public FunctionDescriptor<GenericLookupResult> descriptor() {
return FunctionDescriptor.<GenericLookupResult>builder() return FunctionDescriptor.<GenericLookupResult>builder()
.name(NAME) .name(NAME)
.description("Match a key into Redis instance and return value") .description("Match a key into Redis instance and return value. Do not use, prefer standard 'lookup_*' functions")
.params(keyParam) .params(keyParam)
.returnType(GenericLookupResult.class) .returnType(GenericLookupResult.class)
.build(); .build();

View File

@ -82,7 +82,7 @@ class RedisLookupAdapterFieldSet extends React.Component {
label="Redis key TTL" label="Redis key TTL"
required required
onChange={this.props.handleFormEvent} onChange={this.props.handleFormEvent}
help={this.props.validationMessage('redis_ttl', 'Redis key TTL in seconds')} help={this.props.validationMessage('redis_ttl', 'Redis key TTL in seconds. Set -1 to not expire keys')}
bsStyle={this.props.validationState('redis_ttl')} bsStyle={this.props.validationState('redis_ttl')}
value={config.redis_ttl} value={config.redis_ttl}
labelClassName="col-sm-3" labelClassName="col-sm-3"