systemd-journal 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +11 -0
- data/examples/journal_directory.rb +16 -0
- data/examples/ssh_watcher.rb +37 -0
- data/lib/systemd/journal/compat.rb +49 -0
- data/lib/systemd/journal/flags.rb +15 -0
- data/lib/systemd/journal/native.rb +46 -0
- data/lib/systemd/journal/version.rb +5 -0
- data/lib/systemd/journal.rb +224 -0
- data/lib/systemd/journal_error.rb +27 -0
- data/lib/systemd-journal.rb +2 -46
- data/systemd-journal.gemspec +21 -0
- metadata +35 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1c86b79ec4112caca8d17887e2b0fdea3096a470
|
4
|
+
data.tar.gz: 52e39912dc156aa0a7a75639b255f027b8c4b816
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c2a59f402dd49f61cc8586cb743413f317c0e9f1852e7c6199a63aeacafabfce77f76039a58d1ec050f40196f3c79663c11882897586be71f9a1868adb1eb8f1
|
7
|
+
data.tar.gz: fb9c8f267606434664ce7e52a7822a72d4684b8f81646571a161c3bb14920c7a6b86dce08b0f67b7584ae7c541667ff3d48f7b6d744840290f7fbfad222dad1b
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 John Ledbetter
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Systemd::Journal
|
2
|
+
|
3
|
+
Ruby bindings for reading from the systemd journal.
|
4
|
+
|
5
|
+
* [documentation](http://rubydoc.info/github/ledbettj/systemd-journal)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'systemd-journal', git: 'https://github.com/ledbettj/systemd-journal.git'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
For example, printing all messages:
|
20
|
+
|
21
|
+
require 'systemd/journal'
|
22
|
+
|
23
|
+
j = Systemd::Journal.new
|
24
|
+
j.seek(:head)
|
25
|
+
|
26
|
+
while j.move_next
|
27
|
+
puts j.read_field('MESSAGE')
|
28
|
+
end
|
29
|
+
|
30
|
+
Or to print all data in each entry:
|
31
|
+
|
32
|
+
require 'systemd/journal'
|
33
|
+
|
34
|
+
j = Systemd::Journal.new
|
35
|
+
j.seek(:head)
|
36
|
+
|
37
|
+
while j.move_next
|
38
|
+
j.current_entry do |key, value|
|
39
|
+
puts "#{key}: #{value}"
|
40
|
+
end
|
41
|
+
puts "\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
51
|
+
6. Wipe hands on pants
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'systemd/journal'
|
4
|
+
|
5
|
+
if ARGV.length == 0
|
6
|
+
puts "usage: ./#{File.basename(__FILE__)} /var/log/journal/{machine-id}"
|
7
|
+
exit(1)
|
8
|
+
end
|
9
|
+
|
10
|
+
j = Systemd::Journal.new(path: ARGV[0])
|
11
|
+
j.seek(:head)
|
12
|
+
|
13
|
+
while j.move_next
|
14
|
+
entry = j.current_entry
|
15
|
+
puts "PID #{entry['_PID']}: #{entry['MESSAGE']}"
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'systemd/journal'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
class SSHWatcher
|
6
|
+
def initialize
|
7
|
+
@journal = Systemd::Journal.new(flags: Systemd::Journal::Flags::SYSTEM_ONLY)
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
@journal.add_match('_EXE', '/usr/bin/sshd')
|
12
|
+
# skip all existing entries
|
13
|
+
while @journal.move_next ; end
|
14
|
+
|
15
|
+
while true
|
16
|
+
@journal.wait(1_000_000 * 5)
|
17
|
+
process_event(@journal.current_entry) while @journal.move_next
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
LOGIN_REGEXP = /Accepted\s+(?<auth_method>[^\s]+)\s+for\s+(?<user>[^\s]+)\s+from\s+(?<address>[^\s]+)/
|
25
|
+
|
26
|
+
def process_event(entry)
|
27
|
+
if (m = entry['MESSAGE'].match(LOGIN_REGEXP))
|
28
|
+
timestamp = DateTime.strptime(
|
29
|
+
(entry['_SOURCE_REALTIME_TIMESTAMP'].to_i / 1_000_000).to_s,
|
30
|
+
"%s"
|
31
|
+
)
|
32
|
+
puts "login via #{m[:auth_method]} for #{m[:user]} from #{m[:address]} at #{timestamp.ctime}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
SSHWatcher.new.run
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'systemd/journal/native'
|
2
|
+
require 'systemd/journal_error'
|
3
|
+
|
4
|
+
module Systemd
|
5
|
+
class Journal
|
6
|
+
# This module provides compatibility with the systemd-journal.gem
|
7
|
+
# by Daniel Mack (https://github.com/zonque/systemd-journal.gem)
|
8
|
+
module Compat
|
9
|
+
|
10
|
+
LOG_EMERG = 0 # system is unusable
|
11
|
+
LOG_ALERT = 1 # action must be taken immediately
|
12
|
+
LOG_CRIT = 2 # critical conditions
|
13
|
+
LOG_ERR = 3 # error conditions
|
14
|
+
LOG_WARNING = 4 # warning conditions
|
15
|
+
LOG_NOTICE = 5 # normal but significant condition
|
16
|
+
LOG_INFO = 6 # informational
|
17
|
+
LOG_DEBUG = 7 # debug-level messages
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.extend(ClassMethods)
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
# write a simple message to the systemd journal.
|
26
|
+
# @param [Integer] level one of the LOG_* constants defining the
|
27
|
+
# severity of the event.
|
28
|
+
# @param [String] message the content of the message to write.
|
29
|
+
def print(level, message)
|
30
|
+
rc = Native::sd_journal_print(level, message)
|
31
|
+
raise JournalError.new(rc) if rc < 0
|
32
|
+
end
|
33
|
+
|
34
|
+
# write an event to the systemd journal.
|
35
|
+
# @param [Hash] contents the set of key-value pairs defining the event.
|
36
|
+
def message(contents)
|
37
|
+
items = contents.flat_map do |k,v|
|
38
|
+
[:string, "#{k.to_s.upcase}=#{v}"]
|
39
|
+
end
|
40
|
+
# add a null pointer to terminate the varargs
|
41
|
+
items += [:string, nil]
|
42
|
+
rc = Native::sd_journal_send(*items)
|
43
|
+
raise JournalError.new(rc) if rc < 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Systemd
|
2
|
+
class Journal
|
3
|
+
# contains a set of constants which maybe bitwise OR-ed together and passed
|
4
|
+
# to the Journal constructor:
|
5
|
+
# `Journal.new(flags: Systemd::Journal::Flags::LOCAL_ONLY)`
|
6
|
+
module Flags
|
7
|
+
# Only open journal files generated on the local machine.
|
8
|
+
LOCAL_ONLY = 1
|
9
|
+
# Only open non-persistent journal files.
|
10
|
+
RUNTIME_ONLY = 2
|
11
|
+
# Only open kernel and system service journal files.
|
12
|
+
SYSTEM_ONLY = 4
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Systemd
|
2
|
+
class Journal
|
3
|
+
module Native
|
4
|
+
require 'ffi'
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib %w[libsystemd-journal.so libsystemd-journal.so.0]
|
7
|
+
|
8
|
+
# setup/teardown
|
9
|
+
attach_function :sd_journal_open, [:pointer, :int], :int
|
10
|
+
attach_function :sd_journal_open_directory, [:pointer, :string, :int], :int
|
11
|
+
attach_function :sd_journal_close, [:pointer], :void
|
12
|
+
|
13
|
+
# navigation
|
14
|
+
attach_function :sd_journal_next, [:pointer], :int
|
15
|
+
attach_function :sd_journal_next_skip, [:pointer, :uint64], :int
|
16
|
+
attach_function :sd_journal_previous, [:pointer], :int
|
17
|
+
attach_function :sd_journal_previous_skip, [:pointer, :uint64], :int
|
18
|
+
|
19
|
+
attach_function :sd_journal_seek_head, [:pointer], :int
|
20
|
+
attach_function :sd_journal_seek_tail, [:pointer], :int
|
21
|
+
attach_function :sd_journal_seek_realtime_usec, [:pointer, :uint64], :int
|
22
|
+
|
23
|
+
# data reading
|
24
|
+
attach_function :sd_journal_get_data, [:pointer, :string, :pointer, :pointer], :int
|
25
|
+
attach_function :sd_journal_restart_data, [:pointer], :void
|
26
|
+
attach_function :sd_journal_enumerate_data, [:pointer, :pointer, :pointer], :int
|
27
|
+
|
28
|
+
# event notification
|
29
|
+
attach_function :sd_journal_wait, [:pointer, :uint64], :int
|
30
|
+
|
31
|
+
# filtering
|
32
|
+
attach_function :sd_journal_add_match, [:pointer, :string, :size_t], :int
|
33
|
+
attach_function :sd_journal_flush_matches, [:pointer], :void
|
34
|
+
attach_function :sd_journal_add_disjunction, [:pointer], :int
|
35
|
+
attach_function :sd_journal_add_conjunction, [:pointer], :int
|
36
|
+
|
37
|
+
# writing
|
38
|
+
attach_function :sd_journal_print, [:int, :string], :int
|
39
|
+
attach_function :sd_journal_send, [:varargs], :int
|
40
|
+
|
41
|
+
# misc
|
42
|
+
attach_function :sd_journal_get_usage, [:pointer, :pointer], :int
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'systemd/journal/native'
|
2
|
+
require 'systemd/journal/flags'
|
3
|
+
require 'systemd/journal/compat'
|
4
|
+
require 'systemd/journal_error'
|
5
|
+
|
6
|
+
module Systemd
|
7
|
+
class Journal
|
8
|
+
include Systemd::Journal::Compat
|
9
|
+
|
10
|
+
# Returns a new instance of a Journal, opened with the provided options.
|
11
|
+
# @param [Hash] opts optional initialization parameters.
|
12
|
+
# @option opts [Integer] :flags a set of bitwise OR-ed `Journal::Flags`
|
13
|
+
# which control what journal files are opened. Defaults to 0 (all).
|
14
|
+
# @option opts [String] :path if provided, open the journal files living
|
15
|
+
# in the provided directory only. Any provided flags will be ignored per
|
16
|
+
# since sd_journal_open_directory does not currently accept any flags.
|
17
|
+
def initialize(opts = {})
|
18
|
+
flags = opts[:flags] || 0
|
19
|
+
path = opts[:path]
|
20
|
+
ptr = FFI::MemoryPointer.new(:pointer, 1)
|
21
|
+
|
22
|
+
rc = if path
|
23
|
+
Native::sd_journal_open_directory(ptr, path, 0)
|
24
|
+
else
|
25
|
+
Native::sd_journal_open(ptr, flags)
|
26
|
+
end
|
27
|
+
|
28
|
+
raise JournalError.new(rc) if rc < 0
|
29
|
+
|
30
|
+
@ptr = ptr.read_pointer
|
31
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@ptr))
|
32
|
+
end
|
33
|
+
|
34
|
+
# Move the read pointer to the next entry in the journal.
|
35
|
+
# @return [Boolean] True if moving to the next entry was successful. False
|
36
|
+
# indicates that we've reached the end of the journal.
|
37
|
+
def move_next
|
38
|
+
case (rc = Native::sd_journal_next(@ptr))
|
39
|
+
when 0 then false # EOF
|
40
|
+
when 1 then true
|
41
|
+
when rc < 0 then raise JournalError.new(rc)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Move the read pointer forward by `amount` entries.
|
46
|
+
# @return the actual number of entries which the pointer was moved by. If
|
47
|
+
# this number is less than the requested, we've reached the end of the
|
48
|
+
# journal.
|
49
|
+
def move_next_skip(amount)
|
50
|
+
rc = Native::sd_journal_next_skip(@ptr, amount)
|
51
|
+
raise JournalError.new(rc) if rc < 0
|
52
|
+
rc
|
53
|
+
end
|
54
|
+
|
55
|
+
# Move the read pointer to the previous entry in the journal.
|
56
|
+
# @return [Boolean] True if moving to the previous entry was successful.
|
57
|
+
# False indicates that we've reached the start of the journal.
|
58
|
+
def move_previous
|
59
|
+
case (rc = Native::sd_journal_previous(@ptr))
|
60
|
+
when 0 then false # EOF
|
61
|
+
when 1 then true
|
62
|
+
when rc < 0 then raise JournalError.new(rc)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Move the read pointer backwards by `amount` entries.
|
67
|
+
# @return the actual number of entries which the pointer was moved by. If
|
68
|
+
# this number is less than the requested, we've reached the start of the
|
69
|
+
# journal.
|
70
|
+
def move_previous_skip(amount)
|
71
|
+
rc = Native::sd_journal_previous_skip(@ptr, amount)
|
72
|
+
raise JournalError.new(rc) if rc < 0
|
73
|
+
rc
|
74
|
+
end
|
75
|
+
|
76
|
+
# Seek to a position in the journal.
|
77
|
+
# Note: after seeking, you must call move_next or move_previous before
|
78
|
+
# you can call read_field or current_entry
|
79
|
+
#
|
80
|
+
# @param [Symbol, Time] whence one of :head, :tail, or a Time instance.
|
81
|
+
# :head (or :start) will seek to the beginning of the journal.
|
82
|
+
# :tail (or :end) will seek to the end of the journal.
|
83
|
+
# when a Time is provided, seek to the journal entry logged closest to
|
84
|
+
# the provided time.
|
85
|
+
# @return [Boolean] True on success, otherwise an error is raised.
|
86
|
+
def seek(whence)
|
87
|
+
rc = case whence
|
88
|
+
when :head, :start
|
89
|
+
Native::sd_journal_seek_head(@ptr)
|
90
|
+
when :tail, :end
|
91
|
+
Native::sd_journal_seek_tail(@ptr)
|
92
|
+
when whence.is_a?(Time)
|
93
|
+
# TODO: is this right? who knows.
|
94
|
+
Native::sd_journal_seek_realtime_usec(@ptr, whence.to_i * 1_000_000)
|
95
|
+
else
|
96
|
+
raise ArgumentError.new("Unknown seek type: #{whence}")
|
97
|
+
end
|
98
|
+
|
99
|
+
raise JournalErrornew(rc) if rc < 0
|
100
|
+
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
# Read the contents of the provided field from the current journal entry.
|
105
|
+
# move_next or move_previous must be called at least once after
|
106
|
+
# initialization or seeking prior to attempting to read data.
|
107
|
+
# @param [String] field the name of the field to read -- e.g., 'MESSAGE'
|
108
|
+
# @return [String] the value of the requested field.
|
109
|
+
def read_field(field)
|
110
|
+
len_ptr = FFI::MemoryPointer.new(:size_t, 1)
|
111
|
+
out_ptr = FFI::MemoryPointer.new(:pointer, 1)
|
112
|
+
|
113
|
+
rc = Native::sd_journal_get_data(@ptr, field, out_ptr, len_ptr)
|
114
|
+
|
115
|
+
raise JournalError.new(rc) if rc < 0
|
116
|
+
|
117
|
+
len = read_size_t(len_ptr)
|
118
|
+
out_ptr.read_pointer.read_string_length(len).split('=', 2).last
|
119
|
+
end
|
120
|
+
|
121
|
+
# Read the contents of all fields from the current journal entry.
|
122
|
+
# If given a block, it will yield each field in the form of
|
123
|
+
# (fieldname, value).
|
124
|
+
#
|
125
|
+
# move_next or move_previous must be called at least once after
|
126
|
+
# initialization or seeking prior to calling current_entry
|
127
|
+
#
|
128
|
+
# @return [Hash] the contents of the current journal entry.
|
129
|
+
def current_entry
|
130
|
+
Native::sd_journal_restart_data(@ptr)
|
131
|
+
|
132
|
+
len_ptr = FFI::MemoryPointer.new(:size_t, 1)
|
133
|
+
out_ptr = FFI::MemoryPointer.new(:pointer, 1)
|
134
|
+
results = {}
|
135
|
+
|
136
|
+
while
|
137
|
+
rc = Native::sd_journal_enumerate_data(@ptr, out_ptr, len_ptr)
|
138
|
+
raise JournalError.new(rc) if rc < 0
|
139
|
+
break if rc == 0
|
140
|
+
|
141
|
+
len = read_size_t(len_ptr)
|
142
|
+
key, value = out_ptr.read_pointer.read_string_length(len).split('=', 2)
|
143
|
+
results[key] = value
|
144
|
+
|
145
|
+
yield(key, value) if block_given?
|
146
|
+
end
|
147
|
+
|
148
|
+
results
|
149
|
+
end
|
150
|
+
|
151
|
+
# Block until the journal is changed.
|
152
|
+
# @param timeout_usec [Integer] the maximum number of microseconds to wait
|
153
|
+
# or -1 to wait indefinitely.
|
154
|
+
def wait(timeout_usec = -1)
|
155
|
+
rc = Native::sd_journal_wait(@ptr, timeout_usec)
|
156
|
+
raise JournalError.new(rc) if rc < 0
|
157
|
+
end
|
158
|
+
|
159
|
+
# Add a filter to journal, such that only entries where the given filter
|
160
|
+
# matches are returned.
|
161
|
+
# move_next or move_previous must be invoked after adding a match before
|
162
|
+
# attempting to read from the journal.
|
163
|
+
# @param [String] field the column to filter on, e.g. _PID, _EXE.
|
164
|
+
# @param [String] value the match to search for, e.g. '/usr/bin/sshd'
|
165
|
+
def add_match(field, value)
|
166
|
+
match = "#{field.to_s.upcase}=#{value}"
|
167
|
+
rc = Native::sd_journal_add_match(@ptr, match, match.length)
|
168
|
+
raise JournalError.new(rc) if rc < 0
|
169
|
+
end
|
170
|
+
|
171
|
+
# Add an OR condition to the filter. All previously added matches
|
172
|
+
# and any matches added afterwards will be OR-ed together.
|
173
|
+
# move_next or move_previous must be invoked after adding a match before
|
174
|
+
# attempting to read from the journal.
|
175
|
+
def add_disjunction
|
176
|
+
rc = Native::sd_journal_add_disjunction(@ptr)
|
177
|
+
raise JournalError.new(rc) if rc < 0
|
178
|
+
end
|
179
|
+
|
180
|
+
# Add an AND condition to the filter. All previously added matches
|
181
|
+
# and any matches added afterwards will be AND-ed together.
|
182
|
+
# move_next or move_previous must be invoked after adding a match before
|
183
|
+
# attempting to read from the journal.
|
184
|
+
def add_conjunction
|
185
|
+
rc = Native::sd_journal_add_conjunction(@ptr)
|
186
|
+
raise JournalError.new(rc) if rc < 0
|
187
|
+
end
|
188
|
+
|
189
|
+
# remove all matches and conjunctions/disjunctions.
|
190
|
+
def clear_matches
|
191
|
+
Native::sd_journal_flush_matches(@ptr)
|
192
|
+
end
|
193
|
+
|
194
|
+
# @return the amount of disk usage in bytes used for systemd journal
|
195
|
+
# files. If Systemd::Journal::Flags::LOCAL_ONLY was passed when
|
196
|
+
# opening the journal, this value will only reflect the size of journal
|
197
|
+
#files of the local host, otherwise of all hosts.
|
198
|
+
def disk_usage
|
199
|
+
size_ptr = FFI::MemoryPointer.new(:uint64)
|
200
|
+
rc = Native::sd_journal_get_usage(@ptr, size_ptr)
|
201
|
+
|
202
|
+
raise JournalError.new(rc) if rc < 0
|
203
|
+
size_ptr.read_uint64
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def self.finalize(ptr)
|
209
|
+
proc{ Native::sd_journal_close(@ptr) unless @ptr.nil? }
|
210
|
+
end
|
211
|
+
|
212
|
+
def read_size_t(ptr)
|
213
|
+
case ptr.size
|
214
|
+
when 8
|
215
|
+
ptr.read_uint64
|
216
|
+
when 4
|
217
|
+
ptr.read_uint32
|
218
|
+
else
|
219
|
+
raise StandardError.new("Unhandled size_t size: #{ptr.size}")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Systemd
|
2
|
+
# This execption is raised whenever a sd_journal_* call returns an error.
|
3
|
+
class JournalError < StandardError
|
4
|
+
|
5
|
+
# Returns the (negated) error number.
|
6
|
+
attr_reader :code
|
7
|
+
|
8
|
+
# Instantiate a new JournalError based on the specified return code.
|
9
|
+
# `message` will be filled in by calling `strerror()` with the provided
|
10
|
+
# return code.
|
11
|
+
def initialize(code)
|
12
|
+
@code = -code
|
13
|
+
super(LIBC::strerror(@code))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# @private
|
19
|
+
module LIBC
|
20
|
+
extend FFI::Library
|
21
|
+
ffi_lib FFI::Library::LIBC
|
22
|
+
|
23
|
+
attach_function :strerror, [:int], :string
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/systemd-journal.rb
CHANGED
@@ -1,46 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
module FFI
|
5
|
-
require 'ffi'
|
6
|
-
extend ::FFI::Library
|
7
|
-
ffi_lib %w[libsystemd-journal.so libsystemd-journal.so.0]
|
8
|
-
|
9
|
-
attach_function :sd_journal_print, [:int, :string], :int
|
10
|
-
attach_function :sd_journal_send, [:varargs], :int
|
11
|
-
|
12
|
-
def self.to_string_varargs(arr)
|
13
|
-
varargs = []
|
14
|
-
|
15
|
-
arr.each do |entry|
|
16
|
-
varargs << :string
|
17
|
-
varargs << entry
|
18
|
-
end
|
19
|
-
|
20
|
-
varargs << :string
|
21
|
-
varargs << nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# log levels
|
26
|
-
LOG_EMERG = 0
|
27
|
-
LOG_ALERT = 1
|
28
|
-
LOG_CRIT = 2
|
29
|
-
LOG_ERR = 3
|
30
|
-
LOG_WARNING = 4
|
31
|
-
LOG_NOTICE = 5
|
32
|
-
LOG_INFO = 6
|
33
|
-
LOG_DEBUG = 7
|
34
|
-
|
35
|
-
def self.print(level, message)
|
36
|
-
FFI::sd_journal_print(level, message)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.message(details = {})
|
40
|
-
arr = details.collect { |k,v| "#{k}=#{v}" }
|
41
|
-
varargs = FFI::to_string_varargs(arr)
|
42
|
-
FFI::sd_journal_send(*varargs)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
1
|
+
# included for backwards compatibility with older versions
|
2
|
+
require 'systemd/journal'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'systemd/journal/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "systemd-journal"
|
8
|
+
gem.version = Systemd::Journal::VERSION
|
9
|
+
gem.authors = ["John Ledbetter", "Daniel Mack"]
|
10
|
+
gem.email = ["john@throttle.io"]
|
11
|
+
gem.description = %q{Provides the ability to navigate and read entries from the systemd journal in ruby, as well as write events to the journal.}
|
12
|
+
gem.summary = %q{Ruby bindings to libsystemd-journal}
|
13
|
+
gem.homepage = "https://github.com/ledbettj/systemd-journal"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'ffi', '~>1.9.0'
|
21
|
+
end
|
metadata
CHANGED
@@ -1,58 +1,75 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: systemd-journal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
7
|
+
- John Ledbetter
|
8
8
|
- Daniel Mack
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
|
-
requirement:
|
17
|
-
none: false
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
18
17
|
requirements:
|
19
18
|
- - ~>
|
20
19
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.0
|
20
|
+
version: 1.9.0
|
22
21
|
type: :runtime
|
23
22
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
|
26
|
-
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.9.0
|
28
|
+
description: Provides the ability to navigate and read entries from the systemd journal
|
29
|
+
in ruby, as well as write events to the journal.
|
27
30
|
email:
|
28
|
-
-
|
31
|
+
- john@throttle.io
|
29
32
|
executables: []
|
30
33
|
extensions: []
|
31
34
|
extra_rdoc_files: []
|
32
35
|
files:
|
36
|
+
- .gitignore
|
37
|
+
- Gemfile
|
38
|
+
- LICENSE.txt
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- examples/journal_directory.rb
|
42
|
+
- examples/ssh_watcher.rb
|
33
43
|
- lib/systemd-journal.rb
|
34
|
-
|
44
|
+
- lib/systemd/journal.rb
|
45
|
+
- lib/systemd/journal/compat.rb
|
46
|
+
- lib/systemd/journal/flags.rb
|
47
|
+
- lib/systemd/journal/native.rb
|
48
|
+
- lib/systemd/journal/version.rb
|
49
|
+
- lib/systemd/journal_error.rb
|
50
|
+
- systemd-journal.gemspec
|
51
|
+
homepage: https://github.com/ledbettj/systemd-journal
|
35
52
|
licenses: []
|
53
|
+
metadata: {}
|
36
54
|
post_install_message:
|
37
55
|
rdoc_options: []
|
38
56
|
require_paths:
|
39
57
|
- lib
|
40
58
|
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
59
|
requirements:
|
43
|
-
- -
|
60
|
+
- - '>='
|
44
61
|
- !ruby/object:Gem::Version
|
45
62
|
version: '0'
|
46
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
64
|
requirements:
|
49
|
-
- -
|
65
|
+
- - '>='
|
50
66
|
- !ruby/object:Gem::Version
|
51
67
|
version: '0'
|
52
68
|
requirements: []
|
53
69
|
rubyforge_project:
|
54
|
-
rubygems_version:
|
70
|
+
rubygems_version: 2.0.5
|
55
71
|
signing_key:
|
56
|
-
specification_version:
|
57
|
-
summary: Ruby
|
72
|
+
specification_version: 4
|
73
|
+
summary: Ruby bindings to libsystemd-journal
|
58
74
|
test_files: []
|
75
|
+
has_rdoc:
|