logstash-input-journald 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: df132fdfd9561d73df5f49ac4c7408a15df597d3
4
+ data.tar.gz: 3c34d90fecb45efee4fa6eadad7e37233539be51
5
+ SHA512:
6
+ metadata.gz: 355034993d7381aa58acead667a6e5a3fa79cae74387c1acb118e9c02f3ec321409467a5b2655a9d7673c068b2b0280779a28ecb3e87d8924f85d6931355f413
7
+ data.tar.gz: 7350329c4f27f81c495fcd498f89fa5443110a10b50280f04c05463cd5ece4ebf85fbfb5fb6b5eae46991532489c45508ca83733aac24700d47d46405b5034fd
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ .bundle
4
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem "logstash", :github => "elasticsearch/logstash", :branch => "1.5"
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2014 Elasticsearch <http://www.elasticsearch.org>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ logstash-input-journald
2
+ =======================
3
+
4
+ POC systemd journal Logstash input
5
+
6
+ Example config
7
+ --------------
8
+ ```
9
+ input {
10
+ journald {
11
+ lowercase => true
12
+ seekto => "head"
13
+ thisboot => true
14
+ type => "systemd"
15
+ tags => [ "coreos" ]
16
+ }
17
+ }
18
+
19
+ output {
20
+ stdout {codec => rubydebug}
21
+ }
22
+ ```
23
+
24
+ Install with
25
+ ------------
26
+ ```
27
+ git clone https://github.com/stuart-warren/logstash-input-journald.git
28
+ cd logstash-input-journald
29
+ gem build logstash-input-journald.gemspec
30
+ sudo /path/to/logstash/bin/plugin install /path/to/git/logstash-input-journald/logstash-input-journald-0.0.1.gem
31
+ ```
32
+ Sincedb
33
+ ----
34
+
35
+ This plugin creates a sincedb in your home, called .sincedb\_journal.
36
+ It automatically stores the cursor to the journal there, so when you restart logstash, only new messages are read.
37
+ When executing the plugin the second time (which means the sincedb exists), ``seekto``, and ``thisboot`` are ignored.
38
+ If you don't want the sincedb, configure it's path to /dev/null.
39
+ Tips
40
+ ----
41
+
42
+ Ensure the user you are running logstash as has read access to the journal files ``/var/log/journal/*/*``
43
+
44
+ Issues
45
+ ------
46
+
47
+ Killing the logstash process takes a long time...
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ @files=[]
2
+
3
+ task :default do
4
+ system("rake -T")
5
+ end
6
+
7
+ require "logstash/devutils/rake"
@@ -0,0 +1,163 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/threadable"
3
+ require "logstash/namespace"
4
+ require "socket"
5
+ require "systemd/journal"
6
+ require "fileutils" # For touch
7
+
8
+ # Pull events from a local systemd journal.
9
+ #
10
+ # See requirements https://github.com/ledbettj/systemd-journal
11
+ class LogStash::Inputs::Journald < LogStash::Inputs::Threadable
12
+
13
+ config_name "journald"
14
+
15
+ # Where in the journal to start capturing logs
16
+ # Options: head, tail
17
+ config :seekto, :validate => [ "head", "tail" ], :default => "tail"
18
+
19
+ # System journal flags
20
+ # 0 = all avalable
21
+ # 1 = local only
22
+ # 2 = runtime only
23
+ # 4 = system only
24
+ #
25
+ config :flags, :validate => [0, 1, 2, 4], :default => 0
26
+
27
+ # Path to read journal files from
28
+ #
29
+ config :path, :validate => :string, :default => "/var/log/journal"
30
+
31
+ # Filter on events. Not heavily tested.
32
+ #
33
+ config :filter, :validate => :hash, :required => false, :default => {}
34
+
35
+ # Filter logs since the system booted (only relevant with seekto => "head")
36
+ #
37
+ config :thisboot, :validate => :boolean, :default => true
38
+
39
+ # Lowercase annoying UPPERCASE fieldnames. (May clobber existing fields)
40
+ #
41
+ config :lowercase, :validate => :boolean, :default => false
42
+
43
+ # Where to write the sincedb database (keeps track of the current
44
+ # position of the journal). The default will write
45
+ # the sincedb file to matching `$HOME/.sincedb_journal`
46
+ #
47
+ config :sincedb_path, :validate => :string
48
+
49
+ # How often (in seconds) to write a since database with the current position of
50
+ # the journal.
51
+ #
52
+ config :sincedb_write_interval, :validate => :number, :default => 15
53
+
54
+ public
55
+ def register
56
+ opts = {
57
+ flags: @flags,
58
+ path: @path,
59
+ }
60
+ @hostname = Socket.gethostname
61
+ @journal = Systemd::Journal.new(opts)
62
+ @cursor = ""
63
+ @written_cursor = ""
64
+ @cursor_lock = Mutex.new
65
+ if @thisboot
66
+ @filter[:_boot_id] = Systemd::Id128.boot_id
67
+ end
68
+ if @sincedb_path.nil?
69
+ if ENV["SINCEDB_DIR"].nil? && ENV["HOME"].nil?
70
+ @logger.error("No SINCEDB_DIR or HOME environment variable set, I don't know where " \
71
+ "to keep track of the files I'm watching. Either set " \
72
+ "HOME or SINCEDB_DIR in your environment, or set sincedb_path in " \
73
+ "in your Logstash config for the file input with " \
74
+ "path '#{@path.inspect}'")
75
+ raise(LogStash::ConfigurationError, "Sincedb can not be created.")
76
+ end
77
+ sincedb_dir = ENV["SINCEDB_DIR"] || ENV["HOME"]
78
+ @sincedb_path = File.join(sincedb_dir, ".sincedb_journal")
79
+ @logger.info("No sincedb_path set, generating one for the journal",
80
+ :sincedb_path => @sincedb_path)
81
+ end
82
+ # (Create and) read sincedb
83
+ FileUtils.touch(@sincedb_path)
84
+ @cursor = IO.read(@sincedb_path)
85
+ # Write sincedb in thread
86
+ @sincedb_writer = Thread.new do
87
+ loop do
88
+ sleep @sincedb_write_interval
89
+ if @cursor != @written_cursor
90
+ file = File.open(@sincedb_path, 'w+')
91
+ file.puts @cursor
92
+ file.close
93
+ @cursor_lock.synchronize {
94
+ @written_cursor = @cursor
95
+ }
96
+ end
97
+ end
98
+ end
99
+ end # def register
100
+
101
+ def run(queue)
102
+ if @cursor.strip.length == 0
103
+ @journal.seek(@seekto.to_sym)
104
+
105
+ # We must make one movement in order for the journal C api or else
106
+ # the @journal.watch call will start from the beginning of the
107
+ # journal. see:
108
+ # https://github.com/ledbettj/systemd-journal/issues/55
109
+ if @seekto == 'tail'
110
+ @journal.move_previous
111
+ end
112
+
113
+ @journal.filter(@filter)
114
+ else
115
+ @journal.seek(@cursor)
116
+ @journal.move_next # Without this, the last event will be read again
117
+ end
118
+ @journal.watch do |entry|
119
+ timestamp = entry.realtime_timestamp
120
+ event = LogStash::Event.new(
121
+ entry.to_h_lower(@lowercase).merge(
122
+ "@timestamp" => timestamp,
123
+ "host" => entry._hostname || @hostname,
124
+ "cursor" => @journal.cursor
125
+ )
126
+ )
127
+ decorate(event)
128
+ queue << event
129
+ @cursor_lock.synchronize {
130
+ @cursor = @journal.cursor
131
+ }
132
+ end
133
+ end # def run
134
+
135
+ public
136
+ def teardown # FIXME: doesn't really seem to work...
137
+ return finished unless @journal # Ignore multiple calls
138
+
139
+ @logger.debug("journald shutting down.")
140
+ @journal = nil
141
+ Thread.kill(@sincedb_writer)
142
+ # Write current cursor
143
+ file = File.open(@sincedb_path, 'w+')
144
+ file.puts @cursor
145
+ file.close
146
+ @cursor = nil
147
+ finished
148
+ end # def teardown
149
+
150
+ end # class LogStash::Inputs::Journald
151
+
152
+ # Monkey patch Systemd::JournalEntry
153
+ module Systemd
154
+ class JournalEntry
155
+ def to_h_lower(is_lowercase)
156
+ if is_lowercase
157
+ @entry.each_with_object({}) { |(k, v), h| h[k.downcase] = v.dup.force_encoding('iso-8859-1').encode('utf-8') }
158
+ else
159
+ @entry.each_with_object({}) { |(k, v), h| h[k] = v.dup.force_encoding('iso-8859-1').encode('utf-8') }
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,32 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-input-journald'
4
+ s.version = '0.0.4'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "Read events from local systemd journal"
7
+ s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
8
+ s.authors = ["stuart-warren"]
9
+ s.email = 'stuart.warren@ocado.com'
10
+ s.homepage = "http://www.elasticsearch.org/guide/en/logstash/current/index.html"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)+::Dir.glob('vendor/*')
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash-core', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_runtime_dependency 'logstash-codec-plain'
26
+ s.add_runtime_dependency 'logstash-codec-line'
27
+ s.add_runtime_dependency 'logstash-codec-json'
28
+ s.add_runtime_dependency 'logstash-codec-json_lines'
29
+ s.add_runtime_dependency 'ffi'
30
+ s.add_runtime_dependency 'systemd-journal', '~> 1.2.2'
31
+ s.add_development_dependency 'logstash-devutils'
32
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "socket"
4
+ require "logstash/inputs/journald"
5
+
6
+ describe LogStash::Inputs::Journald do
7
+ context "Ummm" do
8
+ it "no tests here" do
9
+
10
+ end
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-journald
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - stuart-warren
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 1.4.0
19
+ - - <
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ name: logstash-core
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: logstash-codec-plain
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ name: logstash-codec-line
54
+ prerelease: false
55
+ type: :runtime
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ name: logstash-codec-json
68
+ prerelease: false
69
+ type: :runtime
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ name: logstash-codec-json_lines
82
+ prerelease: false
83
+ type: :runtime
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ name: ffi
96
+ prerelease: false
97
+ type: :runtime
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ version: 1.2.2
109
+ name: systemd-journal
110
+ prerelease: false
111
+ type: :runtime
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ~>
115
+ - !ruby/object:Gem::Version
116
+ version: 1.2.2
117
+ - !ruby/object:Gem::Dependency
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ name: logstash-devutils
124
+ prerelease: false
125
+ type: :development
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
132
+ email: stuart.warren@ocado.com
133
+ executables: []
134
+ extensions: []
135
+ extra_rdoc_files: []
136
+ files:
137
+ - .gitignore
138
+ - Gemfile
139
+ - LICENSE
140
+ - README.md
141
+ - Rakefile
142
+ - lib/logstash/inputs/journald.rb
143
+ - logstash-input-journald.gemspec
144
+ - spec/inputs/journald_spec.rb
145
+ homepage: http://www.elasticsearch.org/guide/en/logstash/current/index.html
146
+ licenses:
147
+ - Apache License (2.0)
148
+ metadata:
149
+ logstash_plugin: 'true'
150
+ logstash_group: input
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.4.8
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Read events from local systemd journal
171
+ test_files:
172
+ - spec/inputs/journald_spec.rb