Class: Systemd::Journal

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Filterable, Navigable, Waitable, Writable
Defined in:
lib/systemd/journal.rb,
lib/systemd/journal/flags.rb,
lib/systemd/journal/fields.rb,
lib/systemd/journal/native.rb,
lib/systemd/journal/version.rb,
lib/systemd/journal/waitable.rb,
lib/systemd/journal/writable.rb,
lib/systemd/journal/navigable.rb,
lib/systemd/journal/filterable.rb

Overview

Class to allow interacting with the systemd journal. To read from the journal, instantiate a new Journal; to write to the journal, use Journal.message or Journal.print.

Defined Under Namespace

Modules: Filterable, Flags, Native, Navigable, Waitable, Writable

Constant Summary collapse

USER_FIELDS =

Fields directly passed by client programs and stored in the journal.

%w( MESSAGE MESSAGE_ID PRIORITY CODE_FILE CODE_LINE CODE_FUNC
ERRNO SYSLOG_FACILITY SYSLOG_IDENTIFIER SYSLOG_PID )
TRUSTED_FIELDS =

Fields generated by the journal and added to each event.

%w( _PID _UID _GID _COMM _EXE _CMDLINE _AUDIT_SESSION
_AUDIT_LOGINUID _SYSTEMD_CGROUP _SYSTEMD_SESSION
_SYSTEMD_UNIT _SYSTEMD_USER_UNIT _SYSTEMD_OWNER_UID
_SELINUX_CONTEXT _SOURCE_REALTIME_TIMESTAMP _BOOT_ID
_MACHINE_ID _HOSTNAME _TRANSPORT )
KERNEL_FIELDS =

Fields used in messages originating from the kernel.

%w( _KERNEL_DEVICE _KERNEL_SUBSYSTEM _UDEV_SYSNAME
_UDEV_DEVNODE _UDEV_DEVLINK )
VERSION =

The version of the systemd-journal gem.

'1.4.2'.freeze

Constants included from Waitable

Waitable::IS_JRUBY

Constants included from Writable

Writable::LOG_ALERT, Writable::LOG_CRIT, Writable::LOG_DEBUG, Writable::LOG_EMERG, Writable::LOG_ERR, Writable::LOG_INFO, Writable::LOG_NOTICE, Writable::LOG_WARNING

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Waitable

#wait, #wait_select_reliable?, #watch

Methods included from Filterable

#add_conjunction, #add_disjunction, #add_filter, #add_filters, #clear_filters, #filter

Methods included from Navigable

#cursor, #cursor?, #move, #move_next, #move_next_skip, #move_previous, #move_previous_skip, #seek

Methods included from Writable

included

Constructor Details

#initialize(opts = {}) ⇒ Journal

Returns a new instance of a Journal, opened with the provided options.

Examples:

Read only system journal entries

j = Systemd::Journal.new(flags: Systemd::Journal::Flags::SYSTEM_ONLY)

Directly open a journal directory

j = Systemd::Journal.new(
  path: '/var/log/journal/5f5777e46c5f4131bd9b71cbed6b9abf'
)

Parameters:

  • opts (Hash) (defaults to: {})

    optional initialization parameters.

Options Hash (opts):

  • :flags (Integer)

    a set of bitwise OR-ed Flags which control what journal files are opened. Defaults to ‘0`, meaning all journals avaiable to the current user.

  • :path (String)

    if provided, open the journal files living in the provided directory only. Any provided flags will be ignored since sd_journal_open_directory does not currently accept any flags.

  • :files (Array)

    if provided, open the provided journal files only. Any provided flags will be ignored since sd_journal_open_files does not currently accept any flags.

  • :container (String)

    if provided, open the journal files from the container with the provided machine name only.

Raises:



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/systemd/journal.rb', line 47

def initialize(opts = {})
  open_type, flags = validate_options!(opts)
  ptr = FFI::MemoryPointer.new(:pointer, 1)

  @finalize = (opts.key?(:finalize) ? opts.delete(:finalize) : true)
  rc = open_journal(open_type, ptr, opts, flags)
  raise JournalError, rc if rc < 0

  @ptr = ptr.read_pointer
  file_descriptor
  ObjectSpace.define_finalizer(self, self.class.finalize(@ptr)) if @finalize
end

Class Method Details

.catalog_for(message_id) ⇒ Object

Raises:



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/systemd/journal.rb', line 137

def self.catalog_for(message_id)
  out_ptr = FFI::MemoryPointer.new(:pointer, 1)

  rc = Native.sd_journal_get_catalog_for_message_id(
    Systemd::Id128::Native::Id128.from_s(message_id),
    out_ptr
  )
  raise JournalError, rc if rc < 0

  read_and_free_outstr(out_ptr.read_pointer)
end

.open(opts = {}) ⇒ Object



60
61
62
63
64
65
# File 'lib/systemd/journal.rb', line 60

def self.open(opts = {})
  j = new(opts.merge(finalize: false))
  yield j
ensure
  j.close if j
end

Instance Method Details

#closeObject

Explicitly close the underlying Journal file. Once this is done, any operations on the instance will fail and raise an exception.



206
207
208
209
210
211
212
213
# File 'lib/systemd/journal.rb', line 206

def close
  return if @ptr.nil?

  ObjectSpace.undefine_finalizer(self) if @finalize
  Native.sd_journal_close(@ptr)

  @ptr = nil
end

#closed?Boolean

Returns:

  • (Boolean)


215
216
217
# File 'lib/systemd/journal.rb', line 215

def closed?
  @ptr.nil?
end

#current_catalogObject

Raises:



128
129
130
131
132
133
134
135
# File 'lib/systemd/journal.rb', line 128

def current_catalog
  out_ptr = FFI::MemoryPointer.new(:pointer, 1)

  rc = Native.sd_journal_get_catalog(@ptr, out_ptr)
  raise JournalError, rc if rc < 0

  Journal.read_and_free_outstr(out_ptr.read_pointer)
end

#current_entryHash

Read the contents of all fields from the current journal entry. If given a block, it will yield each field in the form of ‘(fieldname, value)`.

Systemd::Journal::Navigable#move_next or Systemd::Journal::Navigable#move_previous must be called at least once after initialization or seeking prior to calling #current_entry

Examples:

Print all items in the current entry

j = Systemd::Journal.new
j.move_next
j.current_entry{ |field, value| puts "#{field}: #{value}" }

Returns:

  • (Hash)

    the contents of the current journal entry.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/systemd/journal.rb', line 111

def current_entry
  Native.sd_journal_restart_data(@ptr)
  results = {}

  while (kvpair = enumerate_helper(:sd_journal_enumerate_data))
    key, value = kvpair
    results[key] = value
    yield(key, value) if block_given?
  end

  JournalEntry.new(
    results,
    realtime_ts:  read_realtime,
    monotonic_ts: read_monotonic
  )
end

#data_thresholdInteger

Get the maximum length of a data field that will be returned. Fields longer than this will be truncated. Default is 64K.

Returns:

  • (Integer)

    size in bytes.



186
187
188
189
190
191
192
193
# File 'lib/systemd/journal.rb', line 186

def data_threshold
  size_ptr = FFI::MemoryPointer.new(:size_t, 1)
  if (rc = Native.sd_journal_get_data_threshold(@ptr, size_ptr)) < 0
    raise JournalError, rc
  end

  size_ptr.read_size_t
end

#data_threshold=(threshold) ⇒ Object

Set the maximum length of a data field that will be returned. Fields longer than this will be truncated.



197
198
199
200
201
# File 'lib/systemd/journal.rb', line 197

def data_threshold=(threshold)
  if (rc = Native.sd_journal_set_data_threshold(@ptr, threshold)) < 0
    raise JournalError, rc
  end
end

#disk_usageInteger

Get the number of bytes the Journal is currently using on disk. If Systemd::Journal::Flags::LOCAL_ONLY was passed when opening the journal, this value will only reflect the size of journal files of the local host, otherwise of all hosts.

Returns:

  • (Integer)

    size in bytes

Raises:



175
176
177
178
179
180
181
# File 'lib/systemd/journal.rb', line 175

def disk_usage
  size_ptr = FFI::MemoryPointer.new(:uint64)
  rc = Native.sd_journal_get_usage(@ptr, size_ptr)

  raise JournalError, rc if rc < 0
  size_ptr.read_uint64
end

#eachObject

Iterate over each entry in the journal, respecting the applied conjunctions/disjunctions. If a block is given, it is called with each entry until no more entries remain. Otherwise, returns an enumerator which can be chained.



71
72
73
74
75
76
# File 'lib/systemd/journal.rb', line 71

def each
  return to_enum(:each) unless block_given?

  seek(:head)
  yield current_entry while move_next
end

#inspectObject



220
221
222
223
224
225
226
227
228
# File 'lib/systemd/journal.rb', line 220

def inspect
  format(
    '#<%s:0x%016x target: "%s", flags: 0x%08x>',
    self.class.name,
    object_id,
    @open_target,
    @open_flags
  )
end

#query_unique(field) ⇒ Array

Get the list of unique values stored in the journal for the given field. If passed a block, each possible value will be yielded.

Examples:

Fetch all possible boot ids from the journal

j = Systemd::Journal.new
j.query_unique('_BOOT_ID')

Returns:

  • (Array)

    the list of possible values.

Raises:



155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/systemd/journal.rb', line 155

def query_unique(field)
  results = []

  Native.sd_journal_restart_unique(@ptr)

  rc = Native.sd_journal_query_unique(@ptr, field.to_s.upcase)
  raise JournalError, rc if rc < 0

  while (kvpair = enumerate_helper(:sd_journal_enumerate_unique))
    results << kvpair.last
  end

  results
end

#read_field(field) ⇒ String

Read the contents of the provided field from the current journal entry.

{#move_next} or {#move_previous} must be called at least once after
initialization or seeking prior to attempting to read data.

Examples:

Read the ‘MESSAGE` field from the current entry

j = Systemd::Journal.new
j.move_next
puts j.read_field('MESSAGE')

Parameters:

  • field (String)

    the name of the field to read.

Returns:

  • (String)

    the value of the requested field.

Raises:



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/systemd/journal.rb', line 87

def read_field(field)
  len_ptr = FFI::MemoryPointer.new(:size_t, 1)
  out_ptr = FFI::MemoryPointer.new(:pointer, 1)
  field   = field.to_s.upcase
  rc = Native.sd_journal_get_data(@ptr, field, out_ptr, len_ptr)

  raise JournalError, rc if rc < 0

  len = len_ptr.read_size_t
  string_from_out_ptr(out_ptr, len).split('=', 2).last
end