aix-errlog 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|