aix-errlog 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6e98415b5db1bba3a83301429dbc6fb7d8e5f860a35c75225596c3f3493f9df
4
- data.tar.gz: 77e593f0c156f3dd12209eed4806d7d87e0cf15710ef42dbb3eb96f0804dc043
3
+ metadata.gz: e5294c01b19b7bd0a1977c511df790d5d002c34fa968c4c1ccc432d927f7406a
4
+ data.tar.gz: a7e9fe17605da84b4f4c0cc694c99886a3690859cbf52a37854a045e151a6e0f
5
5
  SHA512:
6
- metadata.gz: 7f20031f90faa552c4f99795b9fd2395b9658cd3b2aa3a02590b10bc68d3615ffab59fc21aeb84fb9ae46512f4644539a899ea97a79067325a065082845ecdc3
7
- data.tar.gz: 6d8753b599485fdc819c80e646d5b318794ed49ce89ad5112af38efa804fcb8982344f7b8891a84f6df8befc34a511c66e00e98799596c094a2732729fb2094a
6
+ metadata.gz: ee963b63a3877ca69c5e180e7f20613ac41c0a9ba424cdda648e1ba9aefb089b4280d8b7212081ea9e74dfe3f792a7edd7bbd82dd2d7cfc80f69d46e5953c286
7
+ data.tar.gz: 6d34ac53693e129524de2ddeac04559e1ed8a33d0cc0c12b80090977e95316bf8d54b04e9e229fbdcb5c2541be7404c2f83dca0bf671ed141124042efba29eab
@@ -4,14 +4,21 @@ require 'aix/errlog/constants'
4
4
 
5
5
  module AIX
6
6
  module Errlog
7
+ PARSE_REGEX = /(?:^Detail Data$\n(.*?))?(?:^Symptom Data$\n(.*))?\z/m.freeze
8
+
7
9
  ##
8
10
  # An errlog entry class. Used to parse the raw errlog_entry_t struct into a
9
11
  # more useful Ruby object.
10
12
  #
11
13
  # You shouldn't need to invoke this class directly; it is generated by the
12
14
  # Errlog#forward_each and Errlog#reverse_each.
15
+ #
16
+ # Unfortunately, the retreived detail and symptom fields aren't horribly
17
+ # useful, and IBM has presented no API for parsing these correctly, so the
18
+ # only canonical path to getting the correct detail and symptom data is
19
+ # through a call to the errpt command.
13
20
  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
21
+ attr_reader :magic, :sequence, :label, :timestamp, :crcid, :errdiag, :machineid, :nodeid, :class, :type, :resource, :rclass, :rtype, :vpd_ibm, :vpd_user, :in, :connwhere, :flags, :raw_detail, :raw_symptom, :dup_count, :dup_time1, :dup_time2, :wparid
15
22
 
16
23
  def initialize(raw)
17
24
  @magic = raw[:el_magic]
@@ -33,14 +40,37 @@ module AIX
33
40
  @connwhere = raw[:el_connwhere].to_s.freeze
34
41
  @flags = raw[:el_flags]
35
42
  length = raw[:el_detail_length]
36
- @detail = raw[:el_detail_data].to_ptr.get_bytes(0, length).freeze
43
+ @raw_detail = raw[:el_detail_data].to_ptr.get_bytes(0, length).freeze
37
44
  length = raw[:el_symptom_length]
38
- @symptom = raw[:el_symptom_data].to_ptr.get_bytes(0, length).freeze
45
+ @raw_symptom = raw[:el_symptom_data].to_ptr.get_bytes(0, length).freeze
39
46
  @dup_count = raw[:el_errdup][:ed_dupcount]
40
47
  @dup_time1 = Time.at(raw[:el_errdup][:ed_time1]).freeze
41
48
  @dup_time2 = Time.at(raw[:el_errdup][:ed_time2]).freeze
42
49
  @wparid = raw[:el_wparid].to_s.freeze
43
50
  end
51
+
52
+ def errpt
53
+ @errpt ||= %x(errpt -al#{@sequence}).freeze
54
+ end
55
+
56
+ def parse_errpt
57
+ unless @parsed
58
+ @detail, @symptom = errpt.match(PARSE_REGEX).captures
59
+ @detail ||= ''.freeze
60
+ @symptom ||= ''.freeze
61
+ @detail.freeze
62
+ @symptom.freeze
63
+ @parsed = true
64
+ end
65
+ end
66
+ def detail
67
+ parse_errpt unless @parsed
68
+ @detail
69
+ end
70
+ def symptom
71
+ parse_errpt unless @parsed
72
+ @symptom
73
+ end
44
74
  end
45
75
  end
46
76
  end
@@ -30,11 +30,10 @@ module AIX
30
30
  # operates as a cursor, so if you try to re-invoke one before it is
31
31
  # finished, the cursor will get reset, and you'll get jumbled results).
32
32
  # While one of these enumerators as active, trying to re-invoke one will
33
- # raise an EnumeratorError.
33
+ # raise an Errors::EnumeratorError.
34
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.
35
+ # If you need to do complex matching, use #match or ::match to build a match
36
+ # expression using a DSL.
38
37
  #
39
38
  # A simple example, showing how to get a list of all labels of all log
40
39
  # entries in forward order which contain the string 'KILL' in their label
@@ -47,19 +46,19 @@ module AIX
47
46
  # require 'aix/errlog'
48
47
  #
49
48
  # AIX::Errlog.open do |log|
50
- # log.forward_each(match: (
51
- # log.match_label.include?('KILL') & (
49
+ # log.forward_each(match: log.match {
50
+ # label.include?('KILL') & (
52
51
  # (
53
- # (log.match_sequence > 1000) &
54
- # (log.match_timestamp >= DateTime.new(2017, 1, 1)) &
55
- # (log.match_timestamp < DateTime.new(2017, 2, 1))
52
+ # (sequence > 1000) &
53
+ # (timestamp >= DateTime.new(2017, 1, 1)) &
54
+ # (timestamp < DateTime.new(2017, 2, 1))
56
55
  # ) | (
57
- # (log.match_sequence < 500) &
58
- # (log.match_timestamp >= DateTime.new(2016, 12, 1)) &
59
- # (log.match_timestamp < DateTime.new(2017, 1, 1))
56
+ # (sequence < 500) &
57
+ # (timestamp >= DateTime.new(2016, 12, 1)) &
58
+ # (timestamp < DateTime.new(2017, 1, 1))
60
59
  # )
61
60
  # )
62
- # )).map(&:label)
61
+ # }).map(&:label)
63
62
  # end
64
63
  #
65
64
  # Certainly, that looks a little complex, but it is a bit more efficient
@@ -156,7 +155,7 @@ module AIX
156
155
  # An active enumerator can not be nested within another active enumerator,
157
156
  # including the block form of this. If you invoke any of the #each_
158
157
  # methods while another has not finished and exited, you'll raise an
159
- # EnumeratorError. You can create an enumerator of one within the other,
158
+ # Errors::EnumeratorError. You can create an enumerator of one within the other,
160
159
  # as long as you don't activate it until the first one has exited.
161
160
  #
162
161
  # Warning: if the sequence does not exist (which is common when error logs
@@ -190,7 +189,7 @@ module AIX
190
189
  # An active enumerator can not be nested within another active enumerator,
191
190
  # including the block form of this. If you invoke any of the #each_
192
191
  # methods while another has not finished and exited, you'll raise an
193
- # EnumeratorError. You can create an enumerator of one within the other,
192
+ # Errors::EnumeratorError. You can create an enumerator of one within the other,
194
193
  # as long as you don't activate it until the first one has exited.
195
194
  #
196
195
  # Warning: if the sequence does not exist (which is common when error logs
@@ -208,129 +207,33 @@ module AIX
208
207
  end
209
208
 
210
209
  ##
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)
210
+ # Calls ::match
211
+ def match(&block)
212
+ Errlog.match(&block)
328
213
  end
214
+
329
215
  ##
330
- # Match convenience function. Gets a Leaf match for comparing against
331
- # wparid.
332
- def match_wparid
333
- Match.new(left: :wparid)
216
+ # Used to build a match expression using a DSL. This simply calls
217
+ # instance_eval on Match, so remember the semantics of block scope. If
218
+ # you have a local +sequence+ variable, for instance, you'll need to use
219
+ # an explicit self to escape that:
220
+ #
221
+ # [2] pry(main)> AIX::Errlog::Errlog.match { sequence }
222
+ # => #<AIX::Errlog::Match:0xeb32a4df @left=:sequence, @operator=nil, @right=nil>
223
+ # [3] pry(main)> sequence = 5
224
+ # => 5
225
+ # [4] pry(main)> AIX::Errlog::Errlog.match { sequence }
226
+ # => 5
227
+ # [5] pry(main)> AIX::Errlog::Errlog.match { self.sequence }
228
+ # => #<AIX::Errlog::Match:0xcb7d8c03 @left=:sequence, @operator=nil, @right=nil>
229
+ # [6] pry(main)> AIX::Errlog::Errlog.match { self.sequence > sequence }
230
+ # => #<AIX::Errlog::Match:0x7be0bbf5 @left=:sequence, @operator=:gt, @right=5>
231
+ #
232
+ # In any case, this function lets you use a block as a shortcut to call a
233
+ # bunch of public class methods on the Match class, in order to build
234
+ # complex match expressions, as shown in the summary of this class.
235
+ def self.match(&block)
236
+ Match.instance_eval(&block)
334
237
  end
335
238
 
336
239
  private
@@ -344,7 +247,7 @@ module AIX
344
247
  return if status == :done
345
248
  Errors.throw(status, "handle: #{@handle}, sequence: #{id}") unless status == :ok
346
249
 
347
- Entry.new(entry).freeze
250
+ Entry.new(entry)
348
251
  end
349
252
 
350
253
  ##
@@ -356,7 +259,7 @@ module AIX
356
259
  return if status == :done
357
260
  Errors.throw(status, "handle: #{@handle}, match: #{match}") unless status == :ok
358
261
 
359
- Entry.new(entry).freeze
262
+ Entry.new(entry)
360
263
  end
361
264
 
362
265
  ##
@@ -366,7 +269,7 @@ module AIX
366
269
  status = Lib.errlog_find_next(@handle, entry)
367
270
  return if status == :done
368
271
  Errors.throw(status, "handle: #{@handle}") unless status == :ok
369
- Entry.new(entry).freeze
272
+ Entry.new(entry)
370
273
  end
371
274
 
372
275
  ##
@@ -393,7 +296,7 @@ module AIX
393
296
  # An active enumerator can not be nested within another active enumerator,
394
297
  # including the block form of this. If you invoke any of the #each_
395
298
  # methods while another has not finished and exited, you'll raise an
396
- # EnumeratorError. You can create an enumerator of one within the other,
299
+ # Errors::EnumeratorError. You can create an enumerator of one within the other,
397
300
  # as long as you don't activate it until the first one has exited.
398
301
  #
399
302
  # Warning: if the sequence does not exist (which is common when error logs
@@ -9,8 +9,7 @@ module AIX
9
9
  # A class that is useful for building errlog matchers.
10
10
  #
11
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.
12
+ # create instances of it indirectly through the use of Errlog::match
14
13
  #
15
14
  # You can build field matchers using the methods on the errlog and standard
16
15
  # logical operators, and there are standard conversions for certain things
@@ -18,18 +17,18 @@ module AIX
18
17
  # entries only in January 2018 with +FOO+ in the label somewhere, you cold
19
18
  # use a match like this with an Errlog instance.
20
19
  #
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
- # )
20
+ # errlog.match {
21
+ # (timestamp >= DateTime.new(2018, 1, 1)) &
22
+ # (timestamp < DateTime.new(2018, 2, 1)) &
23
+ # label.include?('FOO')
24
+ # }
26
25
  #
27
26
  # It really is that easy. The rest of the magic is done for you behind the
28
27
  # scenes, as long as you follow the rules and know how to make these matches
29
28
  # in the C equivalent. Note that there must always be a Match on the left
30
29
  # side of all comparisons, so something like
31
30
  #
32
- # DateTime.new(2018, 1, 1) <= errlog.match_timestamp
31
+ # DateTime.new(2018, 1, 1) <= errlog.match{timestamp}
33
32
  #
34
33
  # is not possible.
35
34
  #
@@ -151,6 +150,132 @@ module AIX
151
150
  operator: :not,
152
151
  )
153
152
  end
153
+
154
+ ##
155
+ # Match convenience function. Gets a Leaf match for comparing against
156
+ # sequence.
157
+ def self.sequence
158
+ new(left: :sequence)
159
+ end
160
+ ##
161
+ # Match convenience function. Gets a Leaf match for comparing against
162
+ # label.
163
+ def self.label
164
+ new(left: :label)
165
+ end
166
+ ##
167
+ # Match convenience function. Gets a Leaf match for comparing against
168
+ # timestamp.
169
+ def self.timestamp
170
+ new(left: :timestamp)
171
+ end
172
+ ##
173
+ # Match convenience function. Gets a Leaf match for comparing against
174
+ # crcid.
175
+ def self.crcid
176
+ new(left: :crcid)
177
+ end
178
+ ##
179
+ # Match convenience function. Gets a Leaf match for comparing against
180
+ # machineid.
181
+ def self.machineid
182
+ new(left: :machineid)
183
+ end
184
+ ##
185
+ # Match convenience function. Gets a Leaf match for comparing against
186
+ # nodeid.
187
+ def self.nodeid
188
+ new(left: :nodeid)
189
+ end
190
+ ##
191
+ # Match convenience function. Gets a Leaf match for comparing against
192
+ # class.
193
+ def self.class
194
+ new(left: :class)
195
+ end
196
+ ##
197
+ # Match convenience function. Gets a Leaf match for comparing against
198
+ # type.
199
+ def self.type
200
+ new(left: :type)
201
+ end
202
+ ##
203
+ # Match convenience function. Gets a Leaf match for comparing against
204
+ # resource.
205
+ def self.resource
206
+ new(left: :resource)
207
+ end
208
+ ##
209
+ # Match convenience function. Gets a Leaf match for comparing against
210
+ # rclass.
211
+ def self.rclass
212
+ new(left: :rclass)
213
+ end
214
+ ##
215
+ # Match convenience function. Gets a Leaf match for comparing against
216
+ # rtype.
217
+ def self.rtype
218
+ new(left: :rtype)
219
+ end
220
+ ##
221
+ # Match convenience function. Gets a Leaf match for comparing against
222
+ # vpd_ibm.
223
+ def self.vpd_ibm
224
+ new(left: :vpd_ibm)
225
+ end
226
+ ##
227
+ # Match convenience function. Gets a Leaf match for comparing against
228
+ # vpd_user.
229
+ def self.vpd_user
230
+ new(left: :vpd_user)
231
+ end
232
+ ##
233
+ # Match convenience function. Gets a Leaf match for comparing against in.
234
+ def self.in
235
+ new(left: :in)
236
+ end
237
+ ##
238
+ # Match convenience function. Gets a Leaf match for comparing against
239
+ # connwhere.
240
+ def self.connwhere
241
+ new(left: :connwhere)
242
+ end
243
+ ##
244
+ # Match convenience function. Gets a Leaf match for comparing against
245
+ # flag_err64.
246
+ def self.flag_err64
247
+ new(left: :flag_err64)
248
+ end
249
+ ##
250
+ # Match convenience function. Gets a Leaf match for comparing against
251
+ # flag_errdup.
252
+ def self.flag_errdup
253
+ new(left: :flag_errdup)
254
+ end
255
+ ##
256
+ # Match convenience function. Gets a Leaf match for comparing against
257
+ # detail_data.
258
+ def self.detail_data
259
+ new(left: :detail_data)
260
+ end
261
+ ##
262
+ # Match convenience function. Gets a Leaf match for comparing against
263
+ # symptom_data.
264
+ def self.symptom_data
265
+ new(left: :symptom_data)
266
+ end
267
+ ##
268
+ # Match convenience function. Gets a Leaf match for comparing against
269
+ # errdiag.
270
+ def self.errdiag
271
+ new(left: :errdiag)
272
+ end
273
+ ##
274
+ # Match convenience function. Gets a Leaf match for comparing against
275
+ # wparid.
276
+ def self.wparid
277
+ new(left: :wparid)
278
+ end
154
279
  end
155
280
  end
156
281
  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: 1.0.0
4
+ version: 1.1.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-23 00:00:00.000000000 Z
11
+ date: 2018-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi