systemd-journal 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f9a1f4583f555e4c8832ce277fc87d02eeabb2f
4
- data.tar.gz: a4bc24e388cf2211574a5f138df8d05dc7f97505
3
+ metadata.gz: df7fe5c76f75b85e1c6ae332b5dc4db8268956c9
4
+ data.tar.gz: ddb32ec9f34855f7fe8ae5bfef85f5c8606b9295
5
5
  SHA512:
6
- metadata.gz: 25274b48c5eba590dd4904f10142932fc4c6458170a49f93453c4d7e0cbb9822c6d045e2d9536f0d79244528081d2725fe99ab1aafacb3ebb4ae891a2076e05c
7
- data.tar.gz: 2f863c1a90d35b999115eedd3b160b5d36db4cc273f80fdad5a91fca74dcc9f8c1189b9e1cd9c47dbc6e69df3b180d02ab15be8718ec46383539ebc1e22c14ce
6
+ metadata.gz: 1aa3dd8871ac3b44fe9e063a5fef7ed300f2580a76ebb0a122951dd1136fe86c99322f5342515fafcaf723c337b90ccc59a4a89c47cb02fe007912ba9e493b6f
7
+ data.tar.gz: 30018c03c4cc3178e2798c9f7edf60d290cdef165ee41bccc5a9256f0fe922b5f9473a6f6fb6d3fe8662f56111eef6878729874b05bc69b06729c4e521a1c6b5
data/.rubocop.yml CHANGED
@@ -6,3 +6,12 @@ RaiseArgs:
6
6
 
7
7
  SpaceAroundBlockBraces:
8
8
  EnforcedStyle: space_inside_braces
9
+ Lambda:
10
+ Enabled: false
11
+
12
+ GlobalVars:
13
+ AllowedVariables:
14
+ - $NO_FFI_SPEC
15
+
16
+ Documentation:
17
+ Enabled: false
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Systemd::Journal [![Gem Version](https://badge.fury.io/rb/systemd-journal.png)](http://badge.fury.io/rb/systemd-journal) [![Build Status](https://travis-ci.org/ledbettj/systemd-journal.png?branch=master)](https://travis-ci.org/ledbettj/systemd-journal)
1
+ # Systemd::Journal [![Gem Version](https://badge.fury.io/rb/systemd-journal.png)](http://badge.fury.io/rb/systemd-journal) [![Build Status](https://travis-ci.org/ledbettj/systemd-journal.png?branch=master)](https://travis-ci.org/ledbettj/systemd-journal) [![Code Climate](https://codeclimate.com/github/ledbettj/systemd-journal.png)](https://codeclimate.com/github/ledbettj/systemd-journal)
2
2
 
3
3
  Ruby bindings for reading from the systemd journal.
4
4
 
@@ -9,7 +9,7 @@ Ruby bindings for reading from the systemd journal.
9
9
 
10
10
  Add this line to your application's Gemfile:
11
11
 
12
- gem 'systemd-journal', '~> 1.0.0'
12
+ gem 'systemd-journal', '~> 1.1.0'
13
13
 
14
14
  And then execute:
15
15
 
@@ -62,6 +62,27 @@ Moving around the journal:
62
62
  # seek the entry that occured closest to this time
63
63
  j.seek(Time.parse("2013-10-31T12:00:00+04:00:00"))
64
64
 
65
+ Waiting for things to happen:
66
+
67
+ j = Systemd::Journal.new
68
+ j.seek(:tail)
69
+ # wait up to one second for something to happen
70
+ if j.wait(1_000_000)
71
+ puts 'something changed!'
72
+ # same as above, but can be interrupted with Control+C.
73
+ if j.wait(1_000_000, select: true)
74
+ puts 'something changed!'
75
+
76
+ Accessing the catalog:
77
+
78
+ j = Systemd::Journal.new
79
+ j.move_next
80
+ j.move_next while !j.current_entry.catalog?
81
+
82
+ puts j.current_entry.catalog
83
+ # or if you have a message id:
84
+ puts Systemd::Journal.catalog_for(j.current_entry.message_id)
85
+
65
86
 
66
87
  See the documentation for more examples.
67
88
 
@@ -78,3 +99,5 @@ If you run into problems or have questions, please open an
78
99
  4. Push to the branch (`git push origin my-new-feature`)
79
100
  5. Create new Pull Request, targeting the __develop__ branch.
80
101
  6. Wipe hands on pants, you're done.
102
+
103
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ledbettj/systemd-journal/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
data/Rakefile CHANGED
@@ -1,15 +1,15 @@
1
- require "bundler/gem_tasks"
2
- require "yard"
3
- require "rspec/core/rake_task"
4
- require "rubocop/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'yard'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
5
 
6
- desc "open a console with systemd/journal required"
6
+ desc 'open a console with systemd/journal required'
7
7
  task :console do
8
8
  exec 'pry -I./lib -r systemd/journal'
9
9
  end
10
10
 
11
11
  Rubocop::RakeTask.new(:rubocop) do |task|
12
- task.patterns = ['lib/**/*.rb']
12
+ task.patterns = ['lib/**/*.rb', 'spec/**/*.rb']
13
13
  task.fail_on_error = false
14
14
  end
15
15
 
data/lib/systemd/id128.rb CHANGED
@@ -62,6 +62,15 @@ module Systemd
62
62
  def to_s
63
63
  ('%02x' * 16) % self[:bytes].to_a
64
64
  end
65
+
66
+ def self.from_s(str)
67
+ r = Id128.new
68
+ [str].pack('H*').bytes.each_with_index do |b, i|
69
+ r[:bytes][i] = b
70
+ end
71
+
72
+ r
73
+ end
65
74
  end
66
75
  end
67
76
  end
@@ -1,7 +1,10 @@
1
1
  require 'systemd/journal/native'
2
2
  require 'systemd/journal/flags'
3
- require 'systemd/journal/compat'
3
+ require 'systemd/journal/writable'
4
4
  require 'systemd/journal/fields'
5
+ require 'systemd/journal/navigable'
6
+ require 'systemd/journal/filterable'
7
+ require 'systemd/journal/waitable'
5
8
  require 'systemd/journal_error'
6
9
  require 'systemd/journal_entry'
7
10
  require 'systemd/id128'
@@ -12,11 +15,14 @@ module Systemd
12
15
  # Class to allow interacting with the systemd journal.
13
16
  # To read from the journal, instantiate a new {Systemd::Journal}; to write to
14
17
  # the journal, use
15
- # {Systemd::Journal::Compat::ClassMethods#message Journal.message} or
16
- # {Systemd::Journal::Compat::ClassMethods#print Journal.print}.
18
+ # {Systemd::Journal::Writable::ClassMethods#message Journal.message} or
19
+ # {Systemd::Journal::Writable::ClassMethods#print Journal.print}.
17
20
  class Journal
18
21
  include Enumerable
19
- include Systemd::Journal::Compat
22
+ include Systemd::Journal::Writable
23
+ include Systemd::Journal::Navigable
24
+ include Systemd::Journal::Filterable
25
+ include Systemd::Journal::Waitable
20
26
 
21
27
  # Returns a new instance of a Journal, opened with the provided options.
22
28
  # @param [Hash] opts optional initialization parameters.
@@ -60,115 +66,6 @@ module Systemd
60
66
  yield current_entry while move_next
61
67
  end
62
68
 
63
- # Move the read pointer by `offset` entries.
64
- # @param [Integer] offset how many entries to move the read pointer by. If
65
- # this value is positive, the read pointer moves forward. Otherwise, it
66
- # moves backwards.
67
- # @return [Integer] the number of entries the read pointer actually moved.
68
- def move(offset)
69
- offset > 0 ? move_next_skip(offset) : move_previous_skip(-offset)
70
- end
71
-
72
- # Filter the journal at a high level.
73
- # Takes any number of arguments; each argument should be a hash representing
74
- # a condition to filter based on. Fields inside the hash will be ANDed
75
- # together. Each hash will be ORed with the others. Fields in hashes with
76
- # Arrays as values are treated as an OR statement, since otherwise they
77
- # would never match.
78
- # @example
79
- # j = Systemd::Journal.filter(
80
- # {_systemd_unit: 'session-4.scope'},
81
- # {priority: [4, 6]},
82
- # {_exe: '/usr/bin/sshd', priority: 1}
83
- # )
84
- # # equivalent to
85
- # (_systemd_unit == 'session-4.scope') ||
86
- # (priority == 4 || priority == 6) ||
87
- # (_exe == '/usr/bin/sshd' && priority == 1)
88
- def filter(*conditions)
89
- clear_filters
90
-
91
- last_index = conditions.length - 1
92
-
93
- conditions.each_with_index do |condition, index|
94
- add_filters(condition)
95
- add_disjunction unless index == last_index
96
- end
97
- end
98
-
99
- # Move the read pointer to the next entry in the journal.
100
- # @return [Boolean] True if moving to the next entry was successful.
101
- # @return [Boolean] False if unable to move to the next entry, indicating
102
- # that the pointer has reached the end of the journal.
103
- def move_next
104
- rc = Native.sd_journal_next(@ptr)
105
- raise JournalError.new(rc) if rc < 0
106
- rc > 0
107
- end
108
-
109
- # Move the read pointer forward by `amount` entries.
110
- # @return [Integer] the actual number of entries by which the read pointer
111
- # moved. If this number is less than the requested amount, the read
112
- # pointer has reached the end of the journal.
113
- def move_next_skip(amount)
114
- rc = Native.sd_journal_next_skip(@ptr, amount)
115
- raise JournalError.new(rc) if rc < 0
116
- rc
117
- end
118
-
119
- # Move the read pointer to the previous entry in the journal.
120
- # @return [Boolean] True if moving to the previous entry was successful.
121
- # @return [Boolean] False if unable to move to the previous entry,
122
- # indicating that the pointer has reached the beginning of the journal.
123
- def move_previous
124
- rc = Native.sd_journal_previous(@ptr)
125
- raise JournalError.new(rc) if rc < 0
126
- rc > 0
127
- end
128
-
129
- # Move the read pointer backwards by `amount` entries.
130
- # @return [Integer] the actual number of entries by which the read pointer
131
- # was moved. If this number is less than the requested amount, the read
132
- # pointer has reached the beginning of the journal.
133
- def move_previous_skip(amount)
134
- rc = Native.sd_journal_previous_skip(@ptr, amount)
135
- raise JournalError.new(rc) if rc < 0
136
- rc
137
- end
138
-
139
- # Seek to a position in the journal.
140
- # Note: after seeking, you must call {#move_next} or {#move_previous}
141
- # before you can call {#read_field} or {#current_entry}.
142
- #
143
- # @param [Symbol, Time] whence one of :head, :tail, or a Time instance.
144
- # `:head` (or `:start`) will seek to the beginning of the journal.
145
- # `:tail` (or `:end`) will seek to the end of the journal. When a `Time`
146
- # is provided, seek to the journal entry logged closest to that time. When
147
- # a String is provided, assume it is a cursor from {#cursor} and seek to
148
- # that entry.
149
- # @return [True]
150
- def seek(whence)
151
- rc = case whence
152
- when :head, :start
153
- Native.sd_journal_seek_head(@ptr)
154
- when :tail, :end
155
- Native.sd_journal_seek_tail(@ptr)
156
- else
157
- if whence.is_a?(Time)
158
- # TODO: is this right? who knows.
159
- Native.sd_journal_seek_realtime_usec(@ptr, whence.to_i * 1_000_000)
160
- elsif whence.is_a?(String)
161
- Native.sd_journal_seek_cursor(@ptr, whence)
162
- else
163
- raise ArgumentError.new("Unknown seek type: #{whence.class}")
164
- end
165
- end
166
-
167
- raise JournalErrornew(rc) if rc < 0
168
-
169
- true
170
- end
171
-
172
69
  # Read the contents of the provided field from the current journal entry.
173
70
  # {#move_next} or {#move_previous} must be called at least once after
174
71
  # initialization or seeking prior to attempting to read data.
@@ -215,6 +112,27 @@ module Systemd
215
112
  JournalEntry.new(results)
216
113
  end
217
114
 
115
+ def current_catalog
116
+ out_ptr = FFI::MemoryPointer.new(:pointer, 1)
117
+
118
+ rc = Native.sd_journal_get_catalog(@ptr, out_ptr)
119
+ raise JournalError.new(rc) if rc < 0
120
+
121
+ Journal.read_and_free_outstr(out_ptr.read_pointer)
122
+ end
123
+
124
+ def self.catalog_for(message_id)
125
+ out_ptr = FFI::MemoryPointer.new(:pointer, 1)
126
+
127
+ rc = Native.sd_journal_get_catalog_for_message_id(
128
+ Systemd::Id128::Native::Id128.from_s(message_id),
129
+ out_ptr
130
+ )
131
+ raise JournalError.new(rc) if rc < 0
132
+
133
+ read_and_free_outstr(out_ptr.read_pointer)
134
+ end
135
+
218
136
  # Get the list of unique values stored in the journal for the given field.
219
137
  # If passed a block, each possible value will be yielded.
220
138
  # @return [Array] the list of possible values.
@@ -241,112 +159,6 @@ module Systemd
241
159
  results
242
160
  end
243
161
 
244
- # Block until the journal is changed.
245
- # @param timeout_usec [Integer] the maximum number of microseconds to wait
246
- # or `-1` to wait indefinitely.
247
- # @example Wait for an event for a maximum of 3 seconds
248
- # j = Systemd::Journal.new
249
- # j.seek(:tail)
250
- # if j.wait(3 * 1_000_000)
251
- # # event occurred
252
- # end
253
- # @return [Nil] if the wait time was reached (no events occured).
254
- # @return [Symbol] :append if new entries were appened to the journal.
255
- # @return [Symbol] :invalidate if journal files were added/removed/rotated.
256
- def wait(timeout_usec = -1)
257
- rc = Native.sd_journal_wait(@ptr, timeout_usec)
258
- raise JournalError.new(rc) if rc.is_a?(Fixnum) && rc < 0
259
- rc == :nop ? nil : rc
260
- end
261
-
262
- # Blocks and waits for new entries to be appended to the journal. When new
263
- # entries are written, yields them in turn. Note that this function does
264
- # not automatically seek to the end of the journal prior to waiting.
265
- # This method Does not return.
266
- # @example Print out events as they happen
267
- # j = Systemd::Journal.new
268
- # j.seek(:tail)
269
- # j.watch do |event|
270
- # puts event.message
271
- # end
272
- def watch
273
- loop do
274
- if wait
275
- yield current_entry while move_next
276
- end
277
- end
278
- end
279
-
280
- # Add a filter to journal, such that only entries where the given filter
281
- # matches are returned.
282
- # {#move_next} or {#move_previous} must be invoked after adding a filter
283
- # before attempting to read from the journal.
284
- # @param [String] field the column to filter on, e.g. _PID, _EXE.
285
- # @param [String] value the match to search for, e.g. '/usr/bin/sshd'
286
- # @return [nil]
287
- def add_filter(field, value)
288
- match = "#{field.to_s.upcase}=#{value}"
289
- rc = Native.sd_journal_add_match(@ptr, match, match.length)
290
- raise JournalError.new(rc) if rc < 0
291
- end
292
-
293
- # Add a set of filters to the journal, such that only entries where the
294
- # given filters match are returned.
295
- # @param [Hash] filters a set of field/filter value pairs.
296
- # If the filter value is an array, each value in the array is added
297
- # and entries where the specified field matches any of the values is
298
- # returned.
299
- # @example Filter by PID and EXE
300
- # j.add_filters(_pid: 6700, _exe: '/usr/bin/sshd')
301
- def add_filters(filters)
302
- filters.each do |field, value|
303
- Array(value).each{ |v| add_filter(field, v) }
304
- end
305
- end
306
-
307
- # Add an OR condition to the filter. All previously added matches
308
- # will be ORed with the terms following the disjunction.
309
- # {#move_next} or {#move_previous} must be invoked after adding a match
310
- # before attempting to read from the journal.
311
- # @return [nil]
312
- # @example Filter entries returned using an OR condition
313
- # j = Systemd::Journal.new
314
- # j.add_filter('PRIORITY', 5)
315
- # j.add_disjunction
316
- # j.add_filter('_EXE', '/usr/bin/sshd')
317
- # while j.move_next
318
- # # current_entry is either an sshd event or
319
- # # has priority 5
320
- # end
321
- def add_disjunction
322
- rc = Native.sd_journal_add_disjunction(@ptr)
323
- raise JournalError.new(rc) if rc < 0
324
- end
325
-
326
- # Add an AND condition to the filter. All previously added terms will be
327
- # ANDed together with terms following the conjunction.
328
- # {#move_next} or {#move_previous} must be invoked after adding a match
329
- # before attempting to read from the journal.
330
- # @return [nil]
331
- # @example Filter entries returned using an AND condition
332
- # j = Systemd::Journal.new
333
- # j.add_filter('PRIORITY', 5)
334
- # j.add_conjunction
335
- # j.add_filter('_EXE', '/usr/bin/sshd')
336
- # while j.move_next
337
- # # current_entry is an sshd event with priority 5
338
- # end
339
- def add_conjunction
340
- rc = Native.sd_journal_add_conjunction(@ptr)
341
- raise JournalError.new(rc) if rc < 0
342
- end
343
-
344
- # Remove all filters and conjunctions/disjunctions.
345
- # @return [nil]
346
- def clear_filters
347
- Native.sd_journal_flush_matches(@ptr)
348
- end
349
-
350
162
  # Get the number of bytes the Journal is currently using on disk.
351
163
  # If {Systemd::Journal::Flags::LOCAL_ONLY} was passed when opening the
352
164
  # journal, this value will only reflect the size of journal files of the
@@ -380,35 +192,10 @@ module Systemd
380
192
  end
381
193
  end
382
194
 
383
- # returns a string representing the current read position.
384
- # This string can be passed to {#seek} or {#cursor?}.
385
- # @return [String] a cursor token.
386
- def cursor
387
- out_ptr = FFI::MemoryPointer.new(:pointer, 1)
388
- if (rc = Native.sd_journal_get_cursor(@ptr, out_ptr)) < 0
389
- raise JournalError.new(rc)
390
- end
391
-
392
- read_and_free_outstr(out_ptr.read_pointer)
393
- end
394
-
395
- # Check if the read position is currently at the entry represented by the
396
- # provided cursor value.
397
- # @param c [String] a cursor token returned from {#cursor}.
398
- # @return [Boolean] True if the current entry is the one represented by the
399
- # provided cursor, False otherwise.
400
- def cursor?(c)
401
- if (rc = Native.sd_journal_test_cursor(@ptr, c)) < 0
402
- raise JournalError.new(rc)
403
- end
404
-
405
- rc > 0
406
- end
407
-
408
195
  private
409
196
 
410
197
  def self.finalize(ptr)
411
- proc{ Native.sd_journal_close(ptr) unless ptr.nil? }
198
+ proc { Native.sd_journal_close(ptr) unless ptr.nil? }
412
199
  end
413
200
 
414
201
  def enumerate_helper(enum_function)
@@ -430,7 +217,7 @@ module Systemd
430
217
  # some sd_journal_* functions return strings that we're expected to free
431
218
  # ourselves. This function copies the string from a char* to a ruby string,
432
219
  # frees the char*, and returns the ruby string.
433
- def read_and_free_outstr(ptr)
220
+ def self.read_and_free_outstr(ptr)
434
221
  str = ptr.read_string
435
222
  LibC.free(ptr)
436
223
  str
@@ -0,0 +1,102 @@
1
+ module Systemd
2
+ class Journal
3
+ module Filterable
4
+ # Filter the journal at a high level.
5
+ # Takes any number of arguments; each argument should be a hash
6
+ # representing a condition to filter based on. Fields inside the hash
7
+ # will be ANDed together. Each hash will be ORed with the others.
8
+ # Fields in hashes with Arrays as values are treated as an OR statement,
9
+ # since otherwise they would never match.
10
+ # @example
11
+ # j = Systemd::Journal.filter(
12
+ # {_systemd_unit: 'session-4.scope'},
13
+ # {priority: [4, 6]},
14
+ # {_exe: '/usr/bin/sshd', priority: 1}
15
+ # )
16
+ # # equivalent to
17
+ # (_systemd_unit == 'session-4.scope') ||
18
+ # (priority == 4 || priority == 6) ||
19
+ # (_exe == '/usr/bin/sshd' && priority == 1)
20
+ def filter(*conditions)
21
+ clear_filters
22
+
23
+ last_index = conditions.length - 1
24
+
25
+ conditions.each_with_index do |condition, index|
26
+ add_filters(condition)
27
+ add_disjunction unless index == last_index
28
+ end
29
+ end
30
+
31
+ # Add a filter to journal, such that only entries where the given filter
32
+ # matches are returned.
33
+ # {#move_next} or {#move_previous} must be invoked after adding a filter
34
+ # before attempting to read from the journal.
35
+ # @param [String] field the column to filter on, e.g. _PID, _EXE.
36
+ # @param [String] value the match to search for, e.g. '/usr/bin/sshd'
37
+ # @return [nil]
38
+ def add_filter(field, value)
39
+ match = "#{field.to_s.upcase}=#{value}"
40
+ rc = Native.sd_journal_add_match(@ptr, match, match.length)
41
+ raise JournalError.new(rc) if rc < 0
42
+ end
43
+
44
+ # Add a set of filters to the journal, such that only entries where the
45
+ # given filters match are returned.
46
+ # @param [Hash] filters a set of field/filter value pairs.
47
+ # If the filter value is an array, each value in the array is added
48
+ # and entries where the specified field matches any of the values is
49
+ # returned.
50
+ # @example Filter by PID and EXE
51
+ # j.add_filters(_pid: 6700, _exe: '/usr/bin/sshd')
52
+ def add_filters(filters)
53
+ filters.each do |field, value|
54
+ Array(value).each { |v| add_filter(field, v) }
55
+ end
56
+ end
57
+
58
+ # Add an OR condition to the filter. All previously added matches
59
+ # will be ORed with the terms following the disjunction.
60
+ # {#move_next} or {#move_previous} must be invoked after adding a match
61
+ # before attempting to read from the journal.
62
+ # @return [nil]
63
+ # @example Filter entries returned using an OR condition
64
+ # j = Systemd::Journal.new
65
+ # j.add_filter('PRIORITY', 5)
66
+ # j.add_disjunction
67
+ # j.add_filter('_EXE', '/usr/bin/sshd')
68
+ # while j.move_next
69
+ # # current_entry is either an sshd event or
70
+ # # has priority 5
71
+ # end
72
+ def add_disjunction
73
+ rc = Native.sd_journal_add_disjunction(@ptr)
74
+ raise JournalError.new(rc) if rc < 0
75
+ end
76
+
77
+ # Add an AND condition to the filter. All previously added terms will be
78
+ # ANDed together with terms following the conjunction.
79
+ # {#move_next} or {#move_previous} must be invoked after adding a match
80
+ # before attempting to read from the journal.
81
+ # @return [nil]
82
+ # @example Filter entries returned using an AND condition
83
+ # j = Systemd::Journal.new
84
+ # j.add_filter('PRIORITY', 5)
85
+ # j.add_conjunction
86
+ # j.add_filter('_EXE', '/usr/bin/sshd')
87
+ # while j.move_next
88
+ # # current_entry is an sshd event with priority 5
89
+ # end
90
+ def add_conjunction
91
+ rc = Native.sd_journal_add_conjunction(@ptr)
92
+ raise JournalError.new(rc) if rc < 0
93
+ end
94
+
95
+ # Remove all filters and conjunctions/disjunctions.
96
+ # @return [nil]
97
+ def clear_filters
98
+ Native.sd_journal_flush_matches(@ptr)
99
+ end
100
+ end
101
+ end
102
+ end