Skip to content

Commit 78e2514

Browse files
committed
Update to 0.4.0
### Added - Support for Redis data types: `string`, `hash`, `list`, `set`, and `zset`. - `fallback` configuration to set a default value when Redis lookup fails or key is missing. - `timeout` option for Redis connection handling. - Improved error logging on Redis failures. - Enhanced documentation, gemspec metadata, and plugin comments for clarity. ### Changed - Connection handling is now lazy and resilient to failures. - Internal structure aligned with Logstash plugin best practices for maintainability.
1 parent 62fca7a commit 78e2514

5 files changed

Lines changed: 146 additions & 106 deletions

File tree

CHANGELOG.md

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
1-
# 0.3.0
2-
- Added support for logstash 5.0.0
1+
# Changelog
32

4-
# 0.2.0
5-
- Removed data store feature
6-
- Renamed configuration option "key" into "field" to match configuration of translate plugin
7-
- Changed main functionality and configuration similar to translate filter (logstash-plugins/logstash-filter-translate)
8-
- Added field, destination and override configuration options and their handling from logstash-plugins/logstash-filter-translate/blob/master/lib/logstash/filters/translate.rb
3+
All notable changes to this project will be documented in this file.
94

10-
# 0.1.0
11-
- forked from meulop/logstash-filter-redis
5+
## [0.4.0]
6+
### Added
7+
- Support for Redis data types: `string`, `hash`, `list`, `set`, and `zset`.
8+
- `fallback` configuration to set a default value when Redis lookup fails or key is missing.
9+
- `timeout` option for Redis connection handling.
10+
- Improved error logging on Redis failures.
11+
- Enhanced documentation, gemspec metadata, and plugin comments for clarity.
12+
13+
### Changed
14+
- Connection handling is now lazy and resilient to failures.
15+
- Internal structure aligned with Logstash plugin best practices for maintainability.
16+
17+
---
18+
19+
## [0.3.0]
20+
### Added
21+
- Initial support for Logstash 5.0.0.
22+
23+
---
24+
25+
## [0.2.0]
26+
### Changed
27+
- Removed the data store feature.
28+
- Renamed configuration option `key` to `field` to match the `translate` plugin convention.
29+
- Aligned plugin behavior with [logstash-filter-translate](https://github.com/logstash-plugins/logstash-filter-translate):
30+
- Introduced `field`, `destination`, and `override` settings.
31+
- Updated logic to reflect `translate`-style mappings.
32+
33+
---
34+
35+
## [0.1.0]
36+
### Added
37+
- Initial fork from [meulop/logstash-filter-redis](https://github.com/meulop/logstash-filter-redis).

CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Contributors:
55
* Aaron Mildenstein (untergeek)
66
* Pier-Hugues Pellerin (ph)
77
* Markus Paaso (make)
8+
* David Rosada (Psych0meter)
89

910
Note: If you've sent us patches, bug reports, or otherwise contributed to
1011
Logstash, and you aren't on the list above and want to be, please let us know

README.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
1-
# Logstash Plugin
1+
# Logstash Filter Plugin: Redis Lookup
22

3-
This is a plugin for [Logstash](https://github.com/elastic/logstash).
3+
This is a custom [Logstash](https://github.com/elastic/logstash) filter plugin that enriches event data by querying a Redis datastore. The plugin retrieves values from Redis using a field in the event as the lookup key and supports various Redis data types (`string`, `hash`, `list`, `set`, `zset`).
44

5-
It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
5+
It is fully free and open source under the Apache 2.0 License.
6+
7+
## 🔧 Features
8+
9+
- Look up values from Redis based on a specified event field.
10+
- Supports Redis types: `string`, `hash`, `list`, `set`, and `zset`.
11+
- Optional fallback value if the key is not found or Redis is unreachable.
12+
- Configurable key source field, destination field, and override behavior.
13+
14+
## 📄 Configuration Example
15+
16+
```logstash
17+
filter {
18+
redis {
19+
host => "localhost"
20+
port => 6379
21+
db => 0
22+
field => "user_id"
23+
destination => "user_data"
24+
override => true
25+
fallback => "unknown"
26+
}
27+
}
28+
````
29+
30+
## 🧠 How It Works
31+
32+
Given an event field (e.g., `user_id`), the plugin queries Redis for a key matching the field’s value. Based on the key type, the plugin updates the event with the corresponding value(s):
33+
34+
* For a `string`, the value is set directly at the destination field.
35+
* For a `hash`, each field in the hash becomes a nested field under the destination.
36+
* For a `list`, `set`, or `zset`, the destination field is set to an array of values.
37+
38+
If the Redis key does not exist or an error occurs, the plugin can optionally populate the destination field with a fallback value.
639
740
## Documentation
841

lib/logstash/filters/redis.rb

Lines changed: 58 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,84 @@
1-
# encoding: utf-8
2-
require "logstash/filters/base"
3-
require "logstash/namespace"
4-
5-
# A general search and replace tool which queries replacement values from a redis instance.
6-
#
7-
# This is actually a redis version of a translate plugin. <https://www.elastic.co/guide/en/logstash/current/plugins-filters-translate.html>
8-
#
9-
# Operationally, if the event field specified in the "field" configuration
10-
# matches the EXACT contents of a redis key, the field's value will be substituted
11-
# with the matched key's value from the redis GET <key> command.
12-
#
13-
# By default, the redis filter will replace the contents of the
14-
# matching event field (in-place). However, by using the "destination"
15-
# configuration item, you may also specify a target event field to
16-
# populate with the new translated value.
17-
#
18-
# Alternatively, for simple string search and replacements for just a few values
19-
# you might consider using the gsub function of the mutate filter.
20-
1+
# A custom Logstash filter plugin to enrich events using data fetched from Redis.
212
class LogStash::Filters::Redis < LogStash::Filters::Base
22-
233
config_name "redis"
244

25-
# The hostname of your Redis server.
5+
# Redis connection settings
266
config :host, :validate => :string, :default => "127.0.0.1"
27-
28-
# The port to connect on.
297
config :port, :validate => :number, :default => 6379
30-
31-
# Password to authenticate with. There is no authentication by default.
328
config :password, :validate => :password
33-
34-
# The Redis database number.
359
config :db, :validate => :number, :default => 0
36-
37-
# The name of the logstash event field containing the value to be compared for a
38-
# match by the translate filter (e.g. "message", "host", "response_code").
39-
#
40-
# If this field is an array, only the first value will be used.
41-
config :field, :validate => :string, :required => true
42-
43-
# If the destination (or target) field already exists, this configuration item specifies
44-
# whether the filter should skip translation (default) or overwrite the target field
45-
# value with the new translation value.
46-
config :override, :validate => :boolean, :default => false
47-
48-
# The destination field you wish to populate with the translated code. The default
49-
# is a field named "redis". Set this to the same value as source if you want
50-
# to do a substitution, in this case filter will allways succeed. This will clobber
51-
# the old value of the source field!
52-
config :destination, :validate => :string, :default => "redis"
53-
54-
# In case no translation occurs in the event (no matches), this will add a default
55-
# translation string, which will always populate "field", if the match failed.
56-
#
57-
# For example, if we have configured `fallback => "no match"`, using this dictionary:
58-
#
59-
# foo: bar
60-
#
61-
# Then, if logstash received an event with the field `foo` set to "bar", the destination
62-
# field would be set to "bar". However, if logstash received an event with `foo` set to "nope",
63-
# then the destination field would still be populated, but with the value of "no match".
64-
config :fallback, :validate => :string
6510

66-
# Connection timeout
67-
config :timeout, :validate => :number, :required => false, :default => 5
11+
# Event processing options
12+
config :field, :validate => :string, :required => true # Field whose value will be used as the Redis key
13+
config :override, :validate => :boolean, :default => false # Whether to overwrite the destination field if it already exists
14+
config :destination, :validate => :string, :default => "redis" # Where to store the retrieved value in the event
15+
config :fallback, :validate => :string # Value to set if lookup fails or key doesn't exist
16+
config :timeout, :validate => :number, :required => false, :default => 5 # Redis connection timeout
6817

6918
public
7019
def register
7120
require 'redis'
7221
require 'json'
7322
@redis = nil
74-
end # def register
23+
end
7524

7625
public
7726
def filter(event)
27+
# Skip processing if the target field is missing or if destination exists and override is false
7828
return unless event.include?(@field)
79-
return if event.include?(@destination) and not @override
29+
return if event.include?(@destination) && !@override
8030

31+
# Resolve source key from event (handle both string and array values)
8132
source = event.get(@field).is_a?(Array) ? event.get(@field).first.to_s : event.get(@field).to_s
82-
@redis ||= connect
83-
val = @redis.get(source)
84-
if val
85-
begin
86-
event.set(@destination, JSON.parse(val))
87-
rescue JSON::ParserError => e
88-
event.set(@destination, val)
33+
34+
begin
35+
@redis ||= connect
36+
type = @redis.type(source)
37+
38+
case type
39+
when "string"
40+
value = @redis.get(source)
41+
event.set(@destination, value) if value
42+
43+
when "hash"
44+
hash = @redis.hgetall(source)
45+
hash.each { |k, v| event.set("#{@destination}[#{k}]", v) } unless hash.empty?
46+
47+
when "list"
48+
list = @redis.lrange(source, 0, -1)
49+
event.set(@destination, list) unless list.empty?
50+
51+
when "set"
52+
set = @redis.smembers(source)
53+
event.set(@destination, set) unless set.empty?
54+
55+
when "zset"
56+
zset = @redis.zrange(source, 0, -1, with_scores: true)
57+
event.set(@destination, zset) unless zset.empty?
58+
59+
else
60+
# Unsupported or nonexistent key type, use fallback if available
61+
event.set(@destination, @fallback) if @fallback
8962
end
90-
elsif @fallback
91-
event.set(@destination, @fallback)
63+
64+
rescue => e
65+
# On error (connection, lookup, etc.), log and optionally set fallback
66+
@logger.warn("Redis lookup failed", :error => e.message)
67+
event.set(@destination, @fallback) if @fallback
9268
end
93-
94-
# filter_matched should go in the last line of our successful code
69+
9570
filter_matched(event)
96-
end # def filter
71+
end
9772

9873
private
74+
# Establish a new Redis connection using configured options
9975
def connect
100-
Redis.new(
101-
:host => @host,
102-
:port => @port,
103-
:timeout => @timeout,
104-
:db => @db,
105-
:password => @password.nil? ? nil : @password.value
106-
)
107-
end #def connect
108-
end # class LogStash::Filters::Redis
76+
Redis.new(
77+
host: @host,
78+
port: @port,
79+
timeout: @timeout,
80+
db: @db,
81+
password: @password.nil? ? nil : @password.value
82+
)
83+
end
84+
end

logstash-filter-redis.gemspec

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
Gem::Specification.new do |s|
22

33
s.name = 'logstash-filter-redis'
4-
s.version = '0.3.0'
5-
s.licenses = ['Apache License (2.0)']
6-
s.summary = "This filter allows the storage of event fields in a redis key to be retrieved by a later event"
7-
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
8-
s.authors = ["meulop","make"]
9-
s.email = 'markus.paaso@gmail.com'
10-
s.homepage = "https://github.com/make/logstash-redis-filter"
4+
s.version = '0.4.0'
5+
s.licenses = ['Apache-2.0']
6+
s.summary = "Logstash filter plugin for enriching events with values from Redis."
7+
s.description = "This plugin allows Logstash to enrich event data by looking up values from Redis using a specified field as a key. It supports Redis types including string, hash, list, set, and zset. Install using: $LS_HOME/bin/logstash-plugin install logstash-filter-redis."
8+
9+
s.authors = ["meulop", "make", "Psych0meter"]
10+
s.email = 'psychometer@chpavaldon.com'
11+
s.homepage = "https://github.com/Psych0meter/logstash-filter-redis"
1112
s.require_paths = ["lib"]
1213

1314
# Files
@@ -16,13 +17,16 @@ Gem::Specification.new do |s|
1617
# Tests
1718
s.test_files = s.files.grep(%r{^(test|spec|features)/})
1819

19-
# Special flag to let us know this is actually a logstash plugin
20+
# Metadata to identify this as a Logstash plugin
2021
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
2122

22-
# Gem dependencies
23+
# Runtime dependencies
2324
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24-
s.add_runtime_dependency "redis", '>= 3.0.0', '< 4.0.0'
25+
s.add_runtime_dependency "redis", ">= 4.0.1", "< 5"
2526

26-
s.add_development_dependency 'logstash-devutils', "= 1.1.0"
27-
end
27+
# Development dependencies
28+
s.add_development_dependency 'logstash-devutils', ">= 2.6", "< 2.7"
2829

30+
# Ruby version constraint
31+
s.required_ruby_version = '>= 3.0'
32+
end

0 commit comments

Comments
 (0)