Module: JsonLogging::StructuredHashJsonEncoder

Defined in:
lib/json_logging/structured_hash_json_encoder.rb

Constant Summary collapse

LEAF_THRESHOLD =
40

Class Method Summary collapse

Class Method Details

.append_json_line(tree, severity:, timestamp:, field_overrides:) ⇒ Object



100
101
102
103
104
105
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 100

def append_json_line(tree, severity:, timestamp:, field_overrides:)
  body = JSON.generate(tree)
  extras = field_overrides.merge("severity" => severity, "timestamp" => timestamp)
  extra_json = extras.map { |key, value| "#{JSON.generate(key.to_s)}:#{JSON.generate(value)}" }.join(",")
  "#{body.chop},#{extra_json}}\n"
end

.eligible?(hash) ⇒ Boolean

Returns:

  • (Boolean)


9
10
11
12
13
14
15
16
17
18
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 9

def eligible?(hash)
  return false if Sanitizer.primitive_log_hash?(hash)
  return false unless Sanitizer::StructuredHash.structured_log_hash?(hash)
  return false unless large_structured_hash?(hash)

  filter = Sanitizer.rails_parameter_filter
  return true unless filter

  !Sanitizer.rails_parameter_filter_requires_full_tree_walk?
end

.encode_line(hash, severity:, timestamp:, field_overrides: {}) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 50

def encode_line(hash, severity:, timestamp:, field_overrides: {})
  tree = encode_tree(hash, field_overrides: field_overrides)
  append_json_line(
    tree,
    severity: severity,
    timestamp: timestamp,
    field_overrides: field_overrides
  )
end

.encode_tree(hash, field_overrides: {}) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 60

def encode_tree(hash, field_overrides: {})
  limited_hash = Sanitizer.limited_hash_for_sanitization(hash)
  filter = Sanitizer.rails_parameter_filter
  omit_keys = override_keys(field_overrides)
  jsonable = Sanitizer::StructuredHash.jsonable_tree(limited_hash, omit_keys: omit_keys)
  filtered_jsonable_tree(jsonable, filter: filter)
end

.filtered_jsonable_tree(jsonable, filter:) ⇒ Object



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

def filtered_jsonable_tree(jsonable, filter:)
  return jsonable.tree unless filter
  return jsonable.tree if Sanitizer.rails_parameter_filter_requires_full_tree_walk?

  tree = if jsonable.owned
    jsonable.tree
  else
    Sanitizer::StructuredHash.stringify_keys_copy(jsonable.tree)
  end

  filter.filter(tree)
end

.large_structured_hash?(hash, leaf_threshold: LEAF_THRESHOLD) ⇒ Boolean

Returns:

  • (Boolean)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 20

def large_structured_hash?(hash, leaf_threshold: LEAF_THRESHOLD)
  leaf_count = 0
  walker = lambda do |value|
    case value
    when Hash
      value.each_value { |entry| walker.call(entry) }
    when Array
      value.each { |entry| walker.call(entry) }
    else
      leaf_count += 1
      throw(:enough, true) if leaf_count > leaf_threshold
    end
  end

  catch(:enough) { walker.call(hash) }
  leaf_count > leaf_threshold
end

.override_keys(field_overrides) ⇒ Object



107
108
109
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 107

def override_keys(field_overrides)
  field_overrides.keys.map(&:to_s)
end

.prepared_tree(hash, field_overrides: {}) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 68

def prepared_tree(hash, field_overrides: {})
  return nil if Sanitizer.primitive_log_hash?(hash)

  filter = Sanitizer.rails_parameter_filter
  return nil if filter && Sanitizer.rails_parameter_filter_requires_full_tree_walk?
  return nil unless Sanitizer::StructuredHash.structured_log_hash?(hash)

  limited_hash = Sanitizer.limited_hash_for_sanitization(hash)
  omit_keys = override_keys(field_overrides)
  jsonable = Sanitizer::StructuredHash.jsonable_tree(
    limited_hash,
    omit_keys: omit_keys,
    count_leaves: true
  )
  return nil if jsonable.leaf_count <= LEAF_THRESHOLD

  filtered_jsonable_tree(jsonable, filter: filter)
end

.try_encode_line(hash, severity:, timestamp:, field_overrides: {}) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/json_logging/structured_hash_json_encoder.rb', line 38

def try_encode_line(hash, severity:, timestamp:, field_overrides: {})
  tree = prepared_tree(hash, field_overrides: field_overrides)
  return nil unless tree

  append_json_line(
    tree,
    severity: severity,
    timestamp: timestamp,
    field_overrides: field_overrides
  )
end