systemd-journal 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|