Class: Conrad::Recorder

Inherits:
Object
  • Object
show all
Defined in:
lib/conrad/recorder.rb

Overview

Provides the ability to record an event took place. Currently recording an event accepts a hash and passes it through the configured processors, formatter, and emitter. Each of these may transform, validate, format, and send the event as the user sees fit.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(formatter: Conrad::Formatters::JSON.new, emitter: Conrad::Emitters::Stdout.new, processors: []) ⇒ Recorder

All arguments passed must explicitly respond to a ‘call` method.

Parameters:

  • formatter (#call) (defaults to: Conrad::Formatters::JSON.new)

    formatter for creating the final event

  • emitter (#call) (defaults to: Conrad::Emitters::Stdout.new)

    emitter for sending the final event

  • processors (Array<#call>) (defaults to: [])

    processors for processing the event pre-formatting and emission

Raises:

  • (ArgumentError)

    if the formatter, emitter, or any of the processors do not respond_to? ‘call` with a truthy value.



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/conrad/recorder.rb', line 35

def initialize(
  formatter: Conrad::Formatters::JSON.new,
  emitter: Conrad::Emitters::Stdout.new,
  processors: []
)
  check_callability(formatter: formatter, emitter: emitter)

  @formatter = formatter
  @emitter = emitter
  @processors = processors
  @processor_stack = Conrad::ProcessorStack.new(processors)
end

Instance Attribute Details

#emitterObject (readonly)

Configured emitter for sending the final event. Defaults to Stdout.

See Also:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/conrad/recorder.rb', line 23

class Recorder
  attr_reader :formatter, :emitter, :processors

  # All arguments passed must *explicitly* respond to a `call` method.
  #
  # @param formatter [#call] formatter for creating the final event
  # @param emitter [#call] emitter for sending the final event
  # @param processors [Array<#call>] processors for processing the event
  #   pre-formatting and emission
  #
  # @raise [ArgumentError] if the formatter, emitter, or any of the
  #   processors do not respond_to? `call` with a truthy value.
  def initialize(
    formatter: Conrad::Formatters::JSON.new,
    emitter: Conrad::Emitters::Stdout.new,
    processors: []
  )
    check_callability(formatter: formatter, emitter: emitter)

    @formatter = formatter
    @emitter = emitter
    @processors = processors
    @processor_stack = Conrad::ProcessorStack.new(processors)
  end

  # Processes the given event, formats it, then emits it. It is possible
  # to `throw :halt_conrad_processing` to stop the processing stack. There
  # should be no additional arguments to the `throw` call. At this point, the
  # processing will stop and the audit event will be discarded. The formatter
  # and the emitter will not be called.
  #
  # @param event [Hash] the set of key value pairs to be emitted
  #   as a single audit event. It is expected that all keys will be given as
  #   Symbols or Strings.
  #
  # @raise [ForbiddenKey] when a key is neither a Symbol nor a String
  def audit_event(event)
    processed_event = processor_stack.call(event)

    return unless processed_event

    validate_event_keys(processed_event)

    format_and_emit(processed_event)
  end

  private

  attr_reader :processor_stack

  def validate_event_keys(event)
    event.each_key do |key|
      raise ForbiddenKey, key unless key.is_a?(Symbol) || key.is_a?(String)
    end
  end

  def format_and_emit(event)
    emitter.call(
      formatter.call(event)
    )
  end

  def check_callability(formatter:, emitter:)
    [formatter, emitter].each do |callable|
      raise ArgumentError, "#{callable} does not respond to `#call`" unless callable.respond_to?(:call)
    end
  end
end

#formatterObject (readonly)

Configured formatter for creating the final event. Defaults to JSON.

See Also:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/conrad/recorder.rb', line 23

class Recorder
  attr_reader :formatter, :emitter, :processors

  # All arguments passed must *explicitly* respond to a `call` method.
  #
  # @param formatter [#call] formatter for creating the final event
  # @param emitter [#call] emitter for sending the final event
  # @param processors [Array<#call>] processors for processing the event
  #   pre-formatting and emission
  #
  # @raise [ArgumentError] if the formatter, emitter, or any of the
  #   processors do not respond_to? `call` with a truthy value.
  def initialize(
    formatter: Conrad::Formatters::JSON.new,
    emitter: Conrad::Emitters::Stdout.new,
    processors: []
  )
    check_callability(formatter: formatter, emitter: emitter)

    @formatter = formatter
    @emitter = emitter
    @processors = processors
    @processor_stack = Conrad::ProcessorStack.new(processors)
  end

  # Processes the given event, formats it, then emits it. It is possible
  # to `throw :halt_conrad_processing` to stop the processing stack. There
  # should be no additional arguments to the `throw` call. At this point, the
  # processing will stop and the audit event will be discarded. The formatter
  # and the emitter will not be called.
  #
  # @param event [Hash] the set of key value pairs to be emitted
  #   as a single audit event. It is expected that all keys will be given as
  #   Symbols or Strings.
  #
  # @raise [ForbiddenKey] when a key is neither a Symbol nor a String
  def audit_event(event)
    processed_event = processor_stack.call(event)

    return unless processed_event

    validate_event_keys(processed_event)

    format_and_emit(processed_event)
  end

  private

  attr_reader :processor_stack

  def validate_event_keys(event)
    event.each_key do |key|
      raise ForbiddenKey, key unless key.is_a?(Symbol) || key.is_a?(String)
    end
  end

  def format_and_emit(event)
    emitter.call(
      formatter.call(event)
    )
  end

  def check_callability(formatter:, emitter:)
    [formatter, emitter].each do |callable|
      raise ArgumentError, "#{callable} does not respond to `#call`" unless callable.respond_to?(:call)
    end
  end
end

#processorsObject (readonly)

Configured processors for processing the event pre-formatting and emission. Defaults to an empty enumerable.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/conrad/recorder.rb', line 23

class Recorder
  attr_reader :formatter, :emitter, :processors

  # All arguments passed must *explicitly* respond to a `call` method.
  #
  # @param formatter [#call] formatter for creating the final event
  # @param emitter [#call] emitter for sending the final event
  # @param processors [Array<#call>] processors for processing the event
  #   pre-formatting and emission
  #
  # @raise [ArgumentError] if the formatter, emitter, or any of the
  #   processors do not respond_to? `call` with a truthy value.
  def initialize(
    formatter: Conrad::Formatters::JSON.new,
    emitter: Conrad::Emitters::Stdout.new,
    processors: []
  )
    check_callability(formatter: formatter, emitter: emitter)

    @formatter = formatter
    @emitter = emitter
    @processors = processors
    @processor_stack = Conrad::ProcessorStack.new(processors)
  end

  # Processes the given event, formats it, then emits it. It is possible
  # to `throw :halt_conrad_processing` to stop the processing stack. There
  # should be no additional arguments to the `throw` call. At this point, the
  # processing will stop and the audit event will be discarded. The formatter
  # and the emitter will not be called.
  #
  # @param event [Hash] the set of key value pairs to be emitted
  #   as a single audit event. It is expected that all keys will be given as
  #   Symbols or Strings.
  #
  # @raise [ForbiddenKey] when a key is neither a Symbol nor a String
  def audit_event(event)
    processed_event = processor_stack.call(event)

    return unless processed_event

    validate_event_keys(processed_event)

    format_and_emit(processed_event)
  end

  private

  attr_reader :processor_stack

  def validate_event_keys(event)
    event.each_key do |key|
      raise ForbiddenKey, key unless key.is_a?(Symbol) || key.is_a?(String)
    end
  end

  def format_and_emit(event)
    emitter.call(
      formatter.call(event)
    )
  end

  def check_callability(formatter:, emitter:)
    [formatter, emitter].each do |callable|
      raise ArgumentError, "#{callable} does not respond to `#call`" unless callable.respond_to?(:call)
    end
  end
end

Instance Method Details

#audit_event(event) ⇒ Object

Processes the given event, formats it, then emits it. It is possible to ‘throw :halt_conrad_processing` to stop the processing stack. There should be no additional arguments to the `throw` call. At this point, the processing will stop and the audit event will be discarded. The formatter and the emitter will not be called.

Parameters:

  • event (Hash)

    the set of key value pairs to be emitted as a single audit event. It is expected that all keys will be given as Symbols or Strings.

Raises:

  • (ForbiddenKey)

    when a key is neither a Symbol nor a String



59
60
61
62
63
64
65
66
67
# File 'lib/conrad/recorder.rb', line 59

def audit_event(event)
  processed_event = processor_stack.call(event)

  return unless processed_event

  validate_event_keys(processed_event)

  format_and_emit(processed_event)
end