aix-errlog 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/aix/errlog.rb +1 -0
- data/lib/aix/errlog/constants.rb +93 -0
- data/lib/aix/errlog/entry.rb +46 -0
- data/lib/aix/errlog/errlog.rb +436 -0
- data/lib/aix/errlog/errors.rb +54 -0
- data/lib/aix/errlog/lib.rb +167 -0
- data/lib/aix/errlog/match.rb +156 -0
- metadata +7 -3
- data/lib/aix/errlog/ffi.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6e98415b5db1bba3a83301429dbc6fb7d8e5f860a35c75225596c3f3493f9df
|
4
|
+
data.tar.gz: 77e593f0c156f3dd12209eed4806d7d87e0cf15710ef42dbb3eb96f0804dc043
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f20031f90faa552c4f99795b9fd2395b9658cd3b2aa3a02590b10bc68d3615ffab59fc21aeb84fb9ae46512f4644539a899ea97a79067325a065082845ecdc3
|
7
|
+
data.tar.gz: 6d8753b599485fdc819c80e646d5b318794ed49ce89ad5112af38efa804fcb8982344f7b8891a84f6df8befc34a511c66e00e98799596c094a2732729fb2094a
|
data/lib/aix/errlog.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
require 'aix/errlog/errlog'
|
data/lib/aix/errlog/constants.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
module AIX
|
2
|
+
module Errlog
|
3
|
+
module Constants
|
4
|
+
ERR_REC_MAX = 4096
|
5
|
+
O_RDONLY = 0x00
|
6
|
+
O_WRONLY = 0x01
|
7
|
+
O_RDWR = 0x02
|
8
|
+
O_ACCMODE = 0x03
|
9
|
+
O_NONBLOCK = 0x04
|
10
|
+
O_APPEND = 0x08
|
11
|
+
O_CREAT = 0x100
|
12
|
+
O_TRUNC = 0x200
|
13
|
+
O_EXCL = 0x400
|
14
|
+
O_NOCTTY = 0x800
|
15
|
+
O_DIRECTORY = 0x80000
|
16
|
+
|
17
|
+
LE_MAGIC540 = 0x0C4DF540
|
18
|
+
LE_MAGIC = LE_MAGIC540
|
19
|
+
|
20
|
+
LE_LABEL_MAX = 20
|
21
|
+
LE_MACHINE_ID_MAX = 32
|
22
|
+
LE_NODE_ID_MAX = 32
|
23
|
+
LE_CLASS_MAX = 2
|
24
|
+
LE_TYPE_MAX = 5
|
25
|
+
LE_RESOURCE_MAX = 16
|
26
|
+
LE_RCLASS_MAX = 16
|
27
|
+
LE_RTYPE_MAX = 16
|
28
|
+
LE_VPD_MAX = 512
|
29
|
+
LE_IN_MAX = 256
|
30
|
+
LE_CONN_MAX = 20
|
31
|
+
LE_DETAIL_MAX = ERR_REC_MAX
|
32
|
+
LE_SYMPTOM_MAX = 312
|
33
|
+
LE_ERRDUP_MAX = 16
|
34
|
+
LE_WPAR_ID_MAX = 28
|
35
|
+
|
36
|
+
LE_FLAG_ERR64 = 0x01
|
37
|
+
LE_FLAG_ERRDUP = 0x100
|
38
|
+
LE_FLAG_ERRWPAR = 0x200
|
39
|
+
|
40
|
+
LE_OP_EQUAL = 0x01
|
41
|
+
LE_OP_NE = 0x02
|
42
|
+
LE_OP_SUBSTR = 0x03
|
43
|
+
LE_OP_LT = 0x04
|
44
|
+
LE_OP_LE = 0x05
|
45
|
+
LE_OP_GT = 0x06
|
46
|
+
LE_OP_GE = 0x07
|
47
|
+
LE_OP_LEAF = 0x100
|
48
|
+
LE_OP_NOT = 0x101
|
49
|
+
LE_OP_AND = 0x201
|
50
|
+
LE_OP_OR = 0x202
|
51
|
+
LE_OP_XOR = 0x203
|
52
|
+
|
53
|
+
LE_TYPE = 0xff00
|
54
|
+
LE_TYPE_INT = 0x0100
|
55
|
+
LE_TYPE_STRING = 0x0200
|
56
|
+
LE_TYPE_BOOLEAN = 0x0300
|
57
|
+
|
58
|
+
LE_MATCH_FIELD = 0xff
|
59
|
+
LE_MATCH_SEQUENCE = (0x01|LE_TYPE_INT)
|
60
|
+
LE_MATCH_LABEL = (0x02|LE_TYPE_STRING)
|
61
|
+
LE_MATCH_TIMESTAMP = (0x03|LE_TYPE_INT)
|
62
|
+
LE_MATCH_CRCID = (0x04|LE_TYPE_INT)
|
63
|
+
LE_MATCH_MACHINEID = (0x05|LE_TYPE_STRING)
|
64
|
+
LE_MATCH_NODEID = (0x06|LE_TYPE_STRING)
|
65
|
+
LE_MATCH_CLASS = (0x07|LE_TYPE_STRING)
|
66
|
+
LE_MATCH_TYPE = (0x08|LE_TYPE_STRING)
|
67
|
+
LE_MATCH_RESOURCE = (0x09|LE_TYPE_STRING)
|
68
|
+
LE_MATCH_RCLASS = (0x0a|LE_TYPE_STRING)
|
69
|
+
LE_MATCH_RTYPE = (0x0b|LE_TYPE_STRING)
|
70
|
+
LE_MATCH_VPD_IBM = (0x0c|LE_TYPE_STRING)
|
71
|
+
LE_MATCH_VPD_USER = (0x0d|LE_TYPE_STRING)
|
72
|
+
LE_MATCH_IN = (0x0e|LE_TYPE_STRING)
|
73
|
+
LE_MATCH_CONNWHERE = (0x0f|LE_TYPE_STRING)
|
74
|
+
LE_MATCH_FLAG_ERR64 = (0x10|LE_TYPE_BOOLEAN)
|
75
|
+
LE_MATCH_FLAG_ERRDUP = (0x11|LE_TYPE_BOOLEAN)
|
76
|
+
LE_MATCH_DETAIL_DATA = (0x12|LE_TYPE_STRING)
|
77
|
+
LE_MATCH_SYMPTOM_DATA = (0x13|LE_TYPE_STRING)
|
78
|
+
LE_MATCH_ERRDIAG = (0x14|LE_TYPE_INT)
|
79
|
+
LE_MATCH_WPARID = (0x15|LE_TYPE_STRING)
|
80
|
+
|
81
|
+
LE_FORWARD = 0x01
|
82
|
+
LE_REVERSE = 0x02
|
83
|
+
|
84
|
+
LE_ERR_INVARG = 0x01
|
85
|
+
LE_ERR_NOFILE = 0x02
|
86
|
+
LE_ERR_INVFILE = 0x03
|
87
|
+
LE_ERR_NOMEM = 0x04
|
88
|
+
LE_ERR_NOWRITE = 0x05
|
89
|
+
LE_ERR_IO = 0x06
|
90
|
+
LE_ERR_DONE = 0x07
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
require 'aix/errlog/constants'
|
4
|
+
|
5
|
+
module AIX
|
6
|
+
module Errlog
|
7
|
+
##
|
8
|
+
# An errlog entry class. Used to parse the raw errlog_entry_t struct into a
|
9
|
+
# more useful Ruby object.
|
10
|
+
#
|
11
|
+
# You shouldn't need to invoke this class directly; it is generated by the
|
12
|
+
# Errlog#forward_each and Errlog#reverse_each.
|
13
|
+
class Entry
|
14
|
+
attr_reader :magic, :sequence, :label, :timestamp, :crcid, :errdiag, :machineid, :nodeid, :class, :type, :resource, :rclass, :rtype, :vpd_ibm, :vpd_user, :in, :connwhere, :flags, :detail, :symptom, :dup_count, :dup_time1, :dup_time2, :wparid
|
15
|
+
|
16
|
+
def initialize(raw)
|
17
|
+
@magic = raw[:el_magic]
|
18
|
+
@sequence = raw[:el_sequence]
|
19
|
+
@label = raw[:el_label].to_s.freeze
|
20
|
+
@timestamp = Time.at(raw[:el_timestamp]).freeze
|
21
|
+
@crcid = raw[:el_crcid]
|
22
|
+
@errdiag = raw[:el_errdiag]
|
23
|
+
@machineid = raw[:el_machineid].to_s.freeze
|
24
|
+
@nodeid = raw[:el_nodeid].to_s.freeze
|
25
|
+
@class = raw[:el_class].to_s.freeze
|
26
|
+
@type = raw[:el_type].to_s.freeze
|
27
|
+
@resource = raw[:el_resource].to_s.freeze
|
28
|
+
@rclass = raw[:el_rclass].to_s.freeze
|
29
|
+
@rtype = raw[:el_rtype].to_s.freeze
|
30
|
+
@vpd_ibm = raw[:el_vpd_ibm].to_s.freeze
|
31
|
+
@vpd_user = raw[:el_vpd_user].to_s.freeze
|
32
|
+
@in = raw[:el_in].to_s
|
33
|
+
@connwhere = raw[:el_connwhere].to_s.freeze
|
34
|
+
@flags = raw[:el_flags]
|
35
|
+
length = raw[:el_detail_length]
|
36
|
+
@detail = raw[:el_detail_data].to_ptr.get_bytes(0, length).freeze
|
37
|
+
length = raw[:el_symptom_length]
|
38
|
+
@symptom = raw[:el_symptom_data].to_ptr.get_bytes(0, length).freeze
|
39
|
+
@dup_count = raw[:el_errdup][:ed_dupcount]
|
40
|
+
@dup_time1 = Time.at(raw[:el_errdup][:ed_time1]).freeze
|
41
|
+
@dup_time2 = Time.at(raw[:el_errdup][:ed_time2]).freeze
|
42
|
+
@wparid = raw[:el_wparid].to_s.freeze
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,436 @@
|
|
1
|
+
require 'aix/errlog/constants'
|
2
|
+
require 'aix/errlog/lib'
|
3
|
+
require 'aix/errlog/entry'
|
4
|
+
require 'aix/errlog/errors'
|
5
|
+
require 'aix/errlog/match'
|
6
|
+
|
7
|
+
module AIX
|
8
|
+
module Errlog
|
9
|
+
##
|
10
|
+
# Simple convenince shortcut to access AIX::Errlog::Errlog.open
|
11
|
+
def self.open(*args, &block)
|
12
|
+
::AIX::Errlog::Errlog.open(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# The core errlog class. Used to open an errlog file.
|
17
|
+
#
|
18
|
+
# The main method that should be used here is ::open (more likely
|
19
|
+
# AIX::Errlog.open for convenience), and the block form is strongly
|
20
|
+
# recommended wherever possible. If you do not use the block form, make
|
21
|
+
# sure you call #close when you are done with it (enforce it with an ensure
|
22
|
+
# block if possible). The garbage collector will not do this automatically,
|
23
|
+
# and you can leak.
|
24
|
+
#
|
25
|
+
# #forward_each and #reverse_each should do everything you need to do. If
|
26
|
+
# you use the enumerator form, or even the block form of these, make sure
|
27
|
+
# you consume the entire enumerator before opening a new one. If you need
|
28
|
+
# to enumerate the errlog in a nested loop or something like that, you'll
|
29
|
+
# need multuple instances of this open, otherwise it will fail (the handle
|
30
|
+
# operates as a cursor, so if you try to re-invoke one before it is
|
31
|
+
# finished, the cursor will get reset, and you'll get jumbled results).
|
32
|
+
# While one of these enumerators as active, trying to re-invoke one will
|
33
|
+
# raise an EnumeratorError.
|
34
|
+
#
|
35
|
+
# If you need to do complex matching, use the #match_* methods in here to
|
36
|
+
# create Match objects to work with. You can see Match for more details as
|
37
|
+
# to how to create those.
|
38
|
+
#
|
39
|
+
# A simple example, showing how to get a list of all labels of all log
|
40
|
+
# entries in forward order which contain the string 'KILL' in their label
|
41
|
+
# and happen in the month of January 2017, and which have a sequence ID
|
42
|
+
# above 1000, or that happen in December 2016 and have a sequence ID below
|
43
|
+
# 500, might look something like this:
|
44
|
+
#
|
45
|
+
# require 'date'
|
46
|
+
#
|
47
|
+
# require 'aix/errlog'
|
48
|
+
#
|
49
|
+
# AIX::Errlog.open do |log|
|
50
|
+
# log.forward_each(match: (
|
51
|
+
# log.match_label.include?('KILL') & (
|
52
|
+
# (
|
53
|
+
# (log.match_sequence > 1000) &
|
54
|
+
# (log.match_timestamp >= DateTime.new(2017, 1, 1)) &
|
55
|
+
# (log.match_timestamp < DateTime.new(2017, 2, 1))
|
56
|
+
# ) | (
|
57
|
+
# (log.match_sequence < 500) &
|
58
|
+
# (log.match_timestamp >= DateTime.new(2016, 12, 1)) &
|
59
|
+
# (log.match_timestamp < DateTime.new(2017, 1, 1))
|
60
|
+
# )
|
61
|
+
# )
|
62
|
+
# )).map(&:label)
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# Certainly, that looks a little complex, but it is a bit more efficient
|
66
|
+
# than iterating all log entries as a whole and then filtering after the
|
67
|
+
# fact, and it's a lot more pleasant than building the Match tree from
|
68
|
+
# scratch in C.
|
69
|
+
class Errlog
|
70
|
+
##
|
71
|
+
# path is the string path to the file.
|
72
|
+
# mode matches as closely as possible to the semantics of the fopen mode.
|
73
|
+
def initialize(path='/var/adm/ras/errlog'.freeze, mode='r'.freeze)
|
74
|
+
mode_r = mode.include? 'r'
|
75
|
+
mode_w = mode.include? 'w'
|
76
|
+
mode_a = mode.include? 'a'
|
77
|
+
mode_x = mode.include? 'x'
|
78
|
+
mode_p = mode.include? '+'
|
79
|
+
|
80
|
+
mode_flags =
|
81
|
+
if mode_p
|
82
|
+
Constants::O_RDRW
|
83
|
+
elsif mode_r
|
84
|
+
Constants::O_RDONLY
|
85
|
+
else
|
86
|
+
Constants::O_WRONLY
|
87
|
+
end
|
88
|
+
mode_flags |= Constants::O_CREAT unless mode_r
|
89
|
+
mode_flags |= Constants::O_TRUNC if mode_w
|
90
|
+
mode_flags |= Constants::O_APPEND if mode_a
|
91
|
+
mode_flags |= Constants::O_EXCL if mode_x
|
92
|
+
|
93
|
+
handle_p = FFI::MemoryPointer.new(:pointer)
|
94
|
+
|
95
|
+
status = Lib.errlog_open(
|
96
|
+
path,
|
97
|
+
mode_flags,
|
98
|
+
Constants::LE_MAGIC,
|
99
|
+
handle_p,
|
100
|
+
)
|
101
|
+
|
102
|
+
Errors.throw(status, "path: #{path}, mode: #{mode}") unless status == :ok
|
103
|
+
|
104
|
+
@enum_active = false
|
105
|
+
|
106
|
+
# Just hold the handle directly
|
107
|
+
@handle = handle_p.get_pointer
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Opens the given error log. Arguments are passed directly into ::new
|
112
|
+
#
|
113
|
+
# If a block is given, #close will be automatically called when the block
|
114
|
+
# exits, and the return value of the block will be the return value of
|
115
|
+
# this.
|
116
|
+
def self.open(*args)
|
117
|
+
errlog = new(*args)
|
118
|
+
if block_given?
|
119
|
+
begin
|
120
|
+
return yield errlog
|
121
|
+
ensure
|
122
|
+
errlog.close
|
123
|
+
end
|
124
|
+
else
|
125
|
+
log
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Closes the handle. This must be called, either directly or indirectly
|
131
|
+
# through ::open with a block. This may be called multiple times, but
|
132
|
+
# after this is called, no other functions that try to use the errlog
|
133
|
+
# handle may be called.
|
134
|
+
def close
|
135
|
+
unless @handle.nil?
|
136
|
+
status = Lib.errlog_close(@handle)
|
137
|
+
Errors.throw(status, "handle: #{@handle}") unless status == :ok
|
138
|
+
@handle = nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Enumerate log Entry objects in forward order (default is reverse). If
|
144
|
+
# no block is given, returns an enumerator.
|
145
|
+
#
|
146
|
+
# sequence specifies the sequence ID to start with. It will be included
|
147
|
+
# in the results if specifed
|
148
|
+
#
|
149
|
+
# match takes a Match object, which specifies which entries to match.
|
150
|
+
#
|
151
|
+
# match and sequence must not be both specified. If neither are
|
152
|
+
# specified, this simply iterates from the beginning (or from the previous
|
153
|
+
# stopped position, if #find_sequence or #find_first have already been
|
154
|
+
# called).
|
155
|
+
#
|
156
|
+
# An active enumerator can not be nested within another active enumerator,
|
157
|
+
# including the block form of this. If you invoke any of the #each_
|
158
|
+
# methods while another has not finished and exited, you'll raise an
|
159
|
+
# EnumeratorError. You can create an enumerator of one within the other,
|
160
|
+
# as long as you don't activate it until the first one has exited.
|
161
|
+
#
|
162
|
+
# Warning: if the sequence does not exist (which is common when error logs
|
163
|
+
# are cleaned), no entries will be returned, even if they follow the
|
164
|
+
# sequence ID. If you want all entries based on their sequence number,
|
165
|
+
# use match instead. You're usually better off using the timestamp
|
166
|
+
# instead of sequence number, because the sequence number is 32 bits and
|
167
|
+
# might wrap.
|
168
|
+
def forward_each(match: nil, sequence: nil, &block)
|
169
|
+
raise 'match and sequence must not be both specified' if match && sequence
|
170
|
+
|
171
|
+
return to_enum(:forward_each, match: match, sequence: sequence) unless block_given?
|
172
|
+
set_direction :forward
|
173
|
+
each(match: match, sequence: sequence, &block)
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# Enumerate log Entry objects in reverse order (default is reverse). If
|
178
|
+
# no block is given, returns an enumerator.
|
179
|
+
#
|
180
|
+
# sequence specifies the sequence ID to start with. It will be included
|
181
|
+
# in the results if specifed
|
182
|
+
#
|
183
|
+
# match takes a Match object, which specifies which entries to match.
|
184
|
+
#
|
185
|
+
# match and sequence must not be both specified. If neither are
|
186
|
+
# specified, this simply iterates from the beginning (or from the previous
|
187
|
+
# stopped position, if #find_sequence or #find_first have already been
|
188
|
+
# called).
|
189
|
+
#
|
190
|
+
# An active enumerator can not be nested within another active enumerator,
|
191
|
+
# including the block form of this. If you invoke any of the #each_
|
192
|
+
# methods while another has not finished and exited, you'll raise an
|
193
|
+
# EnumeratorError. You can create an enumerator of one within the other,
|
194
|
+
# as long as you don't activate it until the first one has exited.
|
195
|
+
#
|
196
|
+
# Warning: if the sequence does not exist (which is common when error logs
|
197
|
+
# are cleaned), no entries will be returned, even if they follow the
|
198
|
+
# sequence ID. If you want all entries based on their sequence number,
|
199
|
+
# use match instead. You're usually better off using the timestamp
|
200
|
+
# instead of sequence number, because the sequence number is 32 bits and
|
201
|
+
# might wrap.
|
202
|
+
def reverse_each(match: nil, sequence: nil, &block)
|
203
|
+
raise 'match and sequence must not be both specified' if match && sequence
|
204
|
+
|
205
|
+
return to_enum(:reverse_each, match: match, sequence: sequence) unless block_given?
|
206
|
+
set_direction :reverse
|
207
|
+
each(match: match, sequence: sequence, &block)
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
212
|
+
# sequence.
|
213
|
+
def match_sequence
|
214
|
+
Match.new(left: :sequence)
|
215
|
+
end
|
216
|
+
##
|
217
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
218
|
+
# label.
|
219
|
+
def match_label
|
220
|
+
Match.new(left: :label)
|
221
|
+
end
|
222
|
+
##
|
223
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
224
|
+
# timestamp.
|
225
|
+
def match_timestamp
|
226
|
+
Match.new(left: :timestamp)
|
227
|
+
end
|
228
|
+
##
|
229
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
230
|
+
# crcid.
|
231
|
+
def match_crcid
|
232
|
+
Match.new(left: :crcid)
|
233
|
+
end
|
234
|
+
##
|
235
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
236
|
+
# machineid.
|
237
|
+
def match_machineid
|
238
|
+
Match.new(left: :machineid)
|
239
|
+
end
|
240
|
+
##
|
241
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
242
|
+
# nodeid.
|
243
|
+
def match_nodeid
|
244
|
+
Match.new(left: :nodeid)
|
245
|
+
end
|
246
|
+
##
|
247
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
248
|
+
# class.
|
249
|
+
def match_class
|
250
|
+
Match.new(left: :class)
|
251
|
+
end
|
252
|
+
##
|
253
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
254
|
+
# type.
|
255
|
+
def match_type
|
256
|
+
Match.new(left: :type)
|
257
|
+
end
|
258
|
+
##
|
259
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
260
|
+
# resource.
|
261
|
+
def match_resource
|
262
|
+
Match.new(left: :resource)
|
263
|
+
end
|
264
|
+
##
|
265
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
266
|
+
# rclass.
|
267
|
+
def match_rclass
|
268
|
+
Match.new(left: :rclass)
|
269
|
+
end
|
270
|
+
##
|
271
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
272
|
+
# rtype.
|
273
|
+
def match_rtype
|
274
|
+
Match.new(left: :rtype)
|
275
|
+
end
|
276
|
+
##
|
277
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
278
|
+
# vpd_ibm.
|
279
|
+
def match_vpd_ibm
|
280
|
+
Match.new(left: :vpd_ibm)
|
281
|
+
end
|
282
|
+
##
|
283
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
284
|
+
# vpd_user.
|
285
|
+
def match_vpd_user
|
286
|
+
Match.new(left: :vpd_user)
|
287
|
+
end
|
288
|
+
##
|
289
|
+
# Match convenience function. Gets a Leaf match for comparing against in.
|
290
|
+
def match_in
|
291
|
+
Match.new(left: :in)
|
292
|
+
end
|
293
|
+
##
|
294
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
295
|
+
# connwhere.
|
296
|
+
def match_connwhere
|
297
|
+
Match.new(left: :connwhere)
|
298
|
+
end
|
299
|
+
##
|
300
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
301
|
+
# flag_err64.
|
302
|
+
def match_flag_err64
|
303
|
+
Match.new(left: :flag_err64)
|
304
|
+
end
|
305
|
+
##
|
306
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
307
|
+
# flag_errdup.
|
308
|
+
def match_flag_errdup
|
309
|
+
Match.new(left: :flag_errdup)
|
310
|
+
end
|
311
|
+
##
|
312
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
313
|
+
# detail_data.
|
314
|
+
def match_detail_data
|
315
|
+
Match.new(left: :detail_data)
|
316
|
+
end
|
317
|
+
##
|
318
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
319
|
+
# symptom_data.
|
320
|
+
def match_symptom_data
|
321
|
+
Match.new(left: :symptom_data)
|
322
|
+
end
|
323
|
+
##
|
324
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
325
|
+
# errdiag.
|
326
|
+
def match_errdiag
|
327
|
+
Match.new(left: :errdiag)
|
328
|
+
end
|
329
|
+
##
|
330
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
331
|
+
# wparid.
|
332
|
+
def match_wparid
|
333
|
+
Match.new(left: :wparid)
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
##
|
339
|
+
# Get an entry for the specified sequence, if there is any, and nil
|
340
|
+
# otherwise.
|
341
|
+
def find_sequence(id)
|
342
|
+
entry = Lib::ErrlogEntry.new
|
343
|
+
status = Lib.errlog_find_sequence(@handle, id, entry)
|
344
|
+
return if status == :done
|
345
|
+
Errors.throw(status, "handle: #{@handle}, sequence: #{id}") unless status == :ok
|
346
|
+
|
347
|
+
Entry.new(entry).freeze
|
348
|
+
end
|
349
|
+
|
350
|
+
##
|
351
|
+
# Get an entry matching the passed-in Match, if there is any, and nil
|
352
|
+
# otherwise.
|
353
|
+
def find_first(match)
|
354
|
+
entry = Lib::ErrlogEntry.new
|
355
|
+
status = Lib.errlog_find_first(@handle, match.to_struct, entry)
|
356
|
+
return if status == :done
|
357
|
+
Errors.throw(status, "handle: #{@handle}, match: #{match}") unless status == :ok
|
358
|
+
|
359
|
+
Entry.new(entry).freeze
|
360
|
+
end
|
361
|
+
|
362
|
+
##
|
363
|
+
# Get the next entry.
|
364
|
+
def find_next
|
365
|
+
entry = Lib::ErrlogEntry.new
|
366
|
+
status = Lib.errlog_find_next(@handle, entry)
|
367
|
+
return if status == :done
|
368
|
+
Errors.throw(status, "handle: #{@handle}") unless status == :ok
|
369
|
+
Entry.new(entry).freeze
|
370
|
+
end
|
371
|
+
|
372
|
+
##
|
373
|
+
# Sets the search direction for iteration.
|
374
|
+
def set_direction(direction)
|
375
|
+
status = Lib.errlog_set_direction(@handle, direction)
|
376
|
+
Errors.throw(status, "handle: #{@handle}, direction: #{direction}") unless status == :ok
|
377
|
+
end
|
378
|
+
|
379
|
+
##
|
380
|
+
# Enumerate log entries in the order set in #set_direction (default is
|
381
|
+
# reverse).
|
382
|
+
#
|
383
|
+
# sequence specifies the sequence ID to start with. It will be included
|
384
|
+
# in the results if specifed
|
385
|
+
#
|
386
|
+
# match takes a Match object, which specifies which entries to match.
|
387
|
+
#
|
388
|
+
# match and sequence must not be both specified. If neither are
|
389
|
+
# specified, this simply iterates from the beginning (or from the previous
|
390
|
+
# stopped position, if #find_sequence or #find_first have already been
|
391
|
+
# called).
|
392
|
+
#
|
393
|
+
# An active enumerator can not be nested within another active enumerator,
|
394
|
+
# including the block form of this. If you invoke any of the #each_
|
395
|
+
# methods while another has not finished and exited, you'll raise an
|
396
|
+
# EnumeratorError. You can create an enumerator of one within the other,
|
397
|
+
# as long as you don't activate it until the first one has exited.
|
398
|
+
#
|
399
|
+
# Warning: if the sequence does not exist (which is common when error logs
|
400
|
+
# are cleaned), no entries will be returned, even if they follow the
|
401
|
+
# sequence ID. If you want all entries based on their sequence number,
|
402
|
+
# use match instead. You're usually better off using the timestamp
|
403
|
+
# instead of sequence number, because the sequence number is 32 bits and
|
404
|
+
# might wrap.
|
405
|
+
#
|
406
|
+
# The user-facing entry points to this are #forward_each and #reverse_each
|
407
|
+
def each(match: nil, sequence: nil)
|
408
|
+
# Does not return an enumerator, because this will always be called with
|
409
|
+
# an active block
|
410
|
+
|
411
|
+
begin
|
412
|
+
raise Errors::EnumeratorError if @enum_active
|
413
|
+
@enum_active = true
|
414
|
+
|
415
|
+
if sequence
|
416
|
+
entry = find_sequence(sequence)
|
417
|
+
return if entry.nil?
|
418
|
+
yield entry
|
419
|
+
end
|
420
|
+
|
421
|
+
if match
|
422
|
+
entry = find_first(match)
|
423
|
+
return if entry.nil?
|
424
|
+
yield entry
|
425
|
+
end
|
426
|
+
|
427
|
+
while entry = find_next
|
428
|
+
yield entry
|
429
|
+
end
|
430
|
+
ensure
|
431
|
+
@enum_active = false
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module AIX
|
2
|
+
module Errlog
|
3
|
+
module Errors
|
4
|
+
class EnumeratorError < StandardError
|
5
|
+
def initialize
|
6
|
+
super 'Do not nest enumerators, or invoke another one while the first is still active.'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class ErrlogError < StandardError
|
10
|
+
end
|
11
|
+
class InvalidArgument < ErrlogError
|
12
|
+
def initialize(message)
|
13
|
+
super "A parameter error was detected. Detail: #{message}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class NoFile < ErrlogError
|
17
|
+
def initialize(message)
|
18
|
+
super "The log file does not exist. Detail: #{message}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class NoMem < ErrlogError
|
22
|
+
def initialize(message)
|
23
|
+
super "Memory could not be allocated. Detail: #{message}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
class IO < ErrlogError
|
27
|
+
def initialize(message)
|
28
|
+
super "An i/o error occurred. Detail: #{message}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class InvalidFile < ErrlogError
|
32
|
+
def initialize(message)
|
33
|
+
super "The file is not a valid error log. Detail: #{message}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
class UnknownError < ErrlogError
|
37
|
+
def initialize(message)
|
38
|
+
super "An error occured that could not be diagnosed. Detail: #{message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
LOOKUP = {
|
42
|
+
invarg: InvalidArgument,
|
43
|
+
nofile: NoFile,
|
44
|
+
nomem: NoMem,
|
45
|
+
io: IO,
|
46
|
+
invfile: InvalidFile,
|
47
|
+
}
|
48
|
+
def self.throw(status, detail)
|
49
|
+
errorClass = LOOKUP[status] || UnknownError
|
50
|
+
raise errorClass, detail
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
require 'aix/errlog/constants'
|
4
|
+
|
5
|
+
module AIX
|
6
|
+
module Errlog
|
7
|
+
##
|
8
|
+
# The ffi interface to the errlog library.
|
9
|
+
#
|
10
|
+
# You should never need to access this directly. All necessary functionality
|
11
|
+
# should be accessible via Errlog.
|
12
|
+
module Lib
|
13
|
+
extend FFI::Library
|
14
|
+
ffi_lib 'liberrlog.a(shr_64.o)'
|
15
|
+
|
16
|
+
typedef :pointer, :errlog_handle_t
|
17
|
+
typedef :pointer, :errlog_handle_t_ptr
|
18
|
+
|
19
|
+
Err = enum(
|
20
|
+
:ok, 0,
|
21
|
+
:invarg, Constants::LE_ERR_INVARG,
|
22
|
+
:nofile, Constants::LE_ERR_NOFILE,
|
23
|
+
:invfile, Constants::LE_ERR_INVFILE,
|
24
|
+
:nomem, Constants::LE_ERR_NOMEM,
|
25
|
+
:nowrite, Constants::LE_ERR_NOWRITE,
|
26
|
+
:io, Constants::LE_ERR_IO,
|
27
|
+
:done, Constants::LE_ERR_DONE,
|
28
|
+
)
|
29
|
+
|
30
|
+
Direction = enum(
|
31
|
+
:forward, Constants::LE_FORWARD,
|
32
|
+
:reverse, Constants::LE_REVERSE,
|
33
|
+
)
|
34
|
+
|
35
|
+
Operator = enum(
|
36
|
+
:equal, Constants::LE_OP_EQUAL,
|
37
|
+
:ne, Constants::LE_OP_NE,
|
38
|
+
:substr, Constants::LE_OP_SUBSTR,
|
39
|
+
:lt, Constants::LE_OP_LT,
|
40
|
+
:le, Constants::LE_OP_LE,
|
41
|
+
:gt, Constants::LE_OP_GT,
|
42
|
+
:ge, Constants::LE_OP_GE,
|
43
|
+
:not, Constants::LE_OP_NOT,
|
44
|
+
:and, Constants::LE_OP_AND,
|
45
|
+
:or, Constants::LE_OP_OR,
|
46
|
+
:xor, Constants::LE_OP_XOR,
|
47
|
+
)
|
48
|
+
|
49
|
+
Match = enum(
|
50
|
+
:sequence, Constants::LE_MATCH_SEQUENCE,
|
51
|
+
:label, Constants::LE_MATCH_LABEL,
|
52
|
+
:timestamp, Constants::LE_MATCH_TIMESTAMP,
|
53
|
+
:crcid, Constants::LE_MATCH_CRCID,
|
54
|
+
:machineid, Constants::LE_MATCH_MACHINEID,
|
55
|
+
:nodeid, Constants::LE_MATCH_NODEID,
|
56
|
+
:class, Constants::LE_MATCH_CLASS,
|
57
|
+
:type, Constants::LE_MATCH_TYPE,
|
58
|
+
:resource, Constants::LE_MATCH_RESOURCE,
|
59
|
+
:rclass, Constants::LE_MATCH_RCLASS,
|
60
|
+
:rtype, Constants::LE_MATCH_RTYPE,
|
61
|
+
:vpd_ibm, Constants::LE_MATCH_VPD_IBM,
|
62
|
+
:vpd_user, Constants::LE_MATCH_VPD_USER,
|
63
|
+
:in, Constants::LE_MATCH_IN,
|
64
|
+
:connwhere, Constants::LE_MATCH_CONNWHERE,
|
65
|
+
:flag_err64, Constants::LE_MATCH_FLAG_ERR64,
|
66
|
+
:flag_errdup, Constants::LE_MATCH_FLAG_ERRDUP,
|
67
|
+
:detail_data, Constants::LE_MATCH_DETAIL_DATA,
|
68
|
+
:symptom_data, Constants::LE_MATCH_SYMPTOM_DATA,
|
69
|
+
:errdiag, Constants::LE_MATCH_ERRDIAG,
|
70
|
+
:wparid, Constants::LE_MATCH_WPARID,
|
71
|
+
)
|
72
|
+
|
73
|
+
class Errdup < FFI::Struct
|
74
|
+
layout(
|
75
|
+
:ed_dupcount, :uint,
|
76
|
+
:ed_time1, :uint32,
|
77
|
+
:ed_time2, :uint32,
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
class ErrlogEntry < FFI::Struct
|
82
|
+
layout(
|
83
|
+
:el_magic, :uint,
|
84
|
+
:el_sequence, :uint,
|
85
|
+
:el_label, [:char, Constants::LE_LABEL_MAX],
|
86
|
+
:el_timestamp, :uint,
|
87
|
+
:el_crcid, :uint,
|
88
|
+
:el_errdiag, :uint,
|
89
|
+
:el_machineid, [:char, Constants::LE_MACHINE_ID_MAX],
|
90
|
+
:el_nodeid, [:char, Constants::LE_NODE_ID_MAX],
|
91
|
+
:el_class, [:char, Constants::LE_CLASS_MAX],
|
92
|
+
:el_type, [:char, Constants::LE_TYPE_MAX],
|
93
|
+
:el_resource, [:char, Constants::LE_RESOURCE_MAX],
|
94
|
+
:el_rclass, [:char, Constants::LE_RCLASS_MAX],
|
95
|
+
:el_rtype, [:char, Constants::LE_RTYPE_MAX],
|
96
|
+
:el_vpd_ibm, [:char, Constants::LE_VPD_MAX],
|
97
|
+
:el_vpd_user, [:char, Constants::LE_VPD_MAX],
|
98
|
+
:el_in, [:char, Constants::LE_IN_MAX],
|
99
|
+
:el_connwhere, [:char, Constants::LE_CONN_MAX],
|
100
|
+
:el_flags, :ushort,
|
101
|
+
:el_detail_length, :ushort,
|
102
|
+
:el_detail_data, [:char, Constants::LE_DETAIL_MAX],
|
103
|
+
:el_symptom_length, :uint,
|
104
|
+
:el_symptom_data, [:char, Constants::LE_SYMPTOM_MAX],
|
105
|
+
:el_errdup, Errdup,
|
106
|
+
:el_wparid, [:char, Constants::LE_WPAR_ID_MAX],
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
class ErrlogMatch1U < FFI::Union
|
111
|
+
layout(
|
112
|
+
:emu_left, :pointer,
|
113
|
+
:emu_field, Match,
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
class ErrlogMatch2U < FFI::Union
|
118
|
+
layout(
|
119
|
+
:emu_right, :pointer,
|
120
|
+
:emu_intvalue, :uint,
|
121
|
+
:emu_strvalue, :string,
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
class ErrlogMatch < FFI::Struct
|
126
|
+
layout(
|
127
|
+
:em_op, Operator,
|
128
|
+
:emu1, ErrlogMatch1U,
|
129
|
+
:emu2, ErrlogMatch2U,
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
attach_function :errlog_open, [
|
134
|
+
:string, # path
|
135
|
+
:int, # mode
|
136
|
+
:uint, # magic
|
137
|
+
:errlog_handle_t_ptr, # handle
|
138
|
+
], Err
|
139
|
+
|
140
|
+
attach_function :errlog_close, [
|
141
|
+
:errlog_handle_t, # handle
|
142
|
+
], Err
|
143
|
+
|
144
|
+
attach_function :errlog_find_first, [
|
145
|
+
:errlog_handle_t, # handle
|
146
|
+
ErrlogMatch, # filter
|
147
|
+
ErrlogEntry, # result
|
148
|
+
], Err
|
149
|
+
|
150
|
+
attach_function :errlog_find_next, [
|
151
|
+
:errlog_handle_t, # handle
|
152
|
+
ErrlogEntry, # result
|
153
|
+
], Err
|
154
|
+
|
155
|
+
attach_function :errlog_find_sequence, [
|
156
|
+
:errlog_handle_t, # handle
|
157
|
+
:int, # sequence
|
158
|
+
ErrlogEntry, # result
|
159
|
+
], Err
|
160
|
+
|
161
|
+
attach_function :errlog_set_direction, [
|
162
|
+
:errlog_handle_t, # handle
|
163
|
+
Direction, # direction
|
164
|
+
], Err
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
require 'aix/errlog/constants'
|
4
|
+
require 'aix/errlog/lib'
|
5
|
+
|
6
|
+
module AIX
|
7
|
+
module Errlog
|
8
|
+
##
|
9
|
+
# A class that is useful for building errlog matchers.
|
10
|
+
#
|
11
|
+
# You usually won't need to access this class directly; you'll be able to
|
12
|
+
# create instances of it indirectly through the field accessors that are
|
13
|
+
# available in Errlog.
|
14
|
+
#
|
15
|
+
# You can build field matchers using the methods on the errlog and standard
|
16
|
+
# logical operators, and there are standard conversions for certain things
|
17
|
+
# like Time and DateTime operations. For instance, if you wanted errlog
|
18
|
+
# entries only in January 2018 with +FOO+ in the label somewhere, you cold
|
19
|
+
# use a match like this with an Errlog instance.
|
20
|
+
#
|
21
|
+
# (
|
22
|
+
# (errlog.match_timestamp >= DateTime.new(2018, 1, 1)) &
|
23
|
+
# (errlog.match_timestamp < DateTime.new(2018, 2, 1)) &
|
24
|
+
# errlog.match_label.include?('FOO')
|
25
|
+
# )
|
26
|
+
#
|
27
|
+
# It really is that easy. The rest of the magic is done for you behind the
|
28
|
+
# scenes, as long as you follow the rules and know how to make these matches
|
29
|
+
# in the C equivalent. Note that there must always be a Match on the left
|
30
|
+
# side of all comparisons, so something like
|
31
|
+
#
|
32
|
+
# DateTime.new(2018, 1, 1) <= errlog.match_timestamp
|
33
|
+
#
|
34
|
+
# is not possible.
|
35
|
+
#
|
36
|
+
# This class should allow you to build matches for errlog_find_first in a
|
37
|
+
# simple and natural way. Note that & is the +LE_OP_AND+ operator, and | is
|
38
|
+
# the +LE_OP_OR+ operator, not &&, +and+, ||, or +or+, because those can't
|
39
|
+
# be overridden.
|
40
|
+
class Match
|
41
|
+
attr_accessor :left, :operator, :right
|
42
|
+
|
43
|
+
def initialize(left:, operator: nil, right: nil)
|
44
|
+
@left = left
|
45
|
+
@operator = operator
|
46
|
+
@right = right
|
47
|
+
end
|
48
|
+
|
49
|
+
# Uses the structure of this object to build a errlog_match_t structure.
|
50
|
+
# Does not check whether operators only work on leaves or any other
|
51
|
+
# specifics as that (for instance, an and operator needs two Match leaves,
|
52
|
+
# and won't work between a field and a Match or anything like that). The
|
53
|
+
# function itself might check some of the operators to make sure that
|
54
|
+
# they're set and throw an error for you, but something like a segfault is
|
55
|
+
# more likely if you screw up the structure. Make sure you know what
|
56
|
+
# you're doing.
|
57
|
+
def to_struct
|
58
|
+
raise "operator must be a symbol, but is #{@operator}" unless @operator.is_a? Symbol
|
59
|
+
|
60
|
+
# We want to be sure the struct is not garbage collected before it's
|
61
|
+
# used, so we need to retain a reference to it that ensures that it will
|
62
|
+
# live as long as this object
|
63
|
+
@struct = Lib::ErrlogMatch.new
|
64
|
+
|
65
|
+
@struct[:em_op] = @operator
|
66
|
+
|
67
|
+
case @left
|
68
|
+
when Match
|
69
|
+
@struct[:emu1][:emu_left] = @left.to_struct
|
70
|
+
when Symbol
|
71
|
+
@struct[:emu1][:emu_field] = @left
|
72
|
+
else
|
73
|
+
raise "left should be either a Match or Symbol object, but is #{@left}"
|
74
|
+
end
|
75
|
+
|
76
|
+
case @right
|
77
|
+
when Match
|
78
|
+
@struct[:emu2][:emu_right] = @right.to_struct
|
79
|
+
when String
|
80
|
+
@struct[:emu2][:emu_strvalue] = @right
|
81
|
+
when Numeric, Time
|
82
|
+
@struct[:emu2][:emu_intvalue] = @right.to_i
|
83
|
+
when DateTime
|
84
|
+
@struct[:emu2][:emu_intvalue] = @right.to_time.to_i
|
85
|
+
else
|
86
|
+
raise "left should be either a Match or Symbol object, but is #{@left}"
|
87
|
+
end
|
88
|
+
|
89
|
+
@struct
|
90
|
+
end
|
91
|
+
|
92
|
+
def ==(other)
|
93
|
+
@operator = :equal
|
94
|
+
@right = other
|
95
|
+
self
|
96
|
+
end
|
97
|
+
def !=(other)
|
98
|
+
@operator = :ne
|
99
|
+
@right = other
|
100
|
+
self
|
101
|
+
end
|
102
|
+
def include?(other)
|
103
|
+
@operator = :substr
|
104
|
+
@right = other
|
105
|
+
self
|
106
|
+
end
|
107
|
+
def <(other)
|
108
|
+
@operator = :lt
|
109
|
+
@right = other
|
110
|
+
self
|
111
|
+
end
|
112
|
+
def <=(other)
|
113
|
+
@operator = :le
|
114
|
+
@right = other
|
115
|
+
self
|
116
|
+
end
|
117
|
+
def >(other)
|
118
|
+
@operator = :gt
|
119
|
+
@right = other
|
120
|
+
self
|
121
|
+
end
|
122
|
+
def >=(other)
|
123
|
+
@operator = :ge
|
124
|
+
@right = other
|
125
|
+
self
|
126
|
+
end
|
127
|
+
def &(other)
|
128
|
+
Match.new(
|
129
|
+
left: self,
|
130
|
+
operator: :and,
|
131
|
+
right: other,
|
132
|
+
)
|
133
|
+
end
|
134
|
+
def |(other)
|
135
|
+
Match.new(
|
136
|
+
left: self,
|
137
|
+
operator: :or,
|
138
|
+
right: other,
|
139
|
+
)
|
140
|
+
end
|
141
|
+
def ^(other)
|
142
|
+
Match.new(
|
143
|
+
left: self,
|
144
|
+
operator: :xor,
|
145
|
+
right: other,
|
146
|
+
)
|
147
|
+
end
|
148
|
+
def !
|
149
|
+
Match.new(
|
150
|
+
left: self,
|
151
|
+
operator: :not,
|
152
|
+
)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aix-errlog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taylor C. Richberger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -32,7 +32,11 @@ extra_rdoc_files: []
|
|
32
32
|
files:
|
33
33
|
- lib/aix/errlog.rb
|
34
34
|
- lib/aix/errlog/constants.rb
|
35
|
-
- lib/aix/errlog/
|
35
|
+
- lib/aix/errlog/entry.rb
|
36
|
+
- lib/aix/errlog/errlog.rb
|
37
|
+
- lib/aix/errlog/errors.rb
|
38
|
+
- lib/aix/errlog/lib.rb
|
39
|
+
- lib/aix/errlog/match.rb
|
36
40
|
homepage: https://github.com/absperf/aix-errlog
|
37
41
|
licenses:
|
38
42
|
- MIT
|
data/lib/aix/errlog/ffi.rb
DELETED
File without changes
|