Module: RailsTracepointStack::LogFormatter

Defined in:
lib/rails_tracepoint_stack/log_formatter.rb

Class Method Summary collapse

Class Method Details

.default_string_representation?(value, json_value) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 98

def self.default_string_representation?(value, json_value)
  json_value.is_a?(String) &&
    value.method(:to_s).owner == Kernel &&
    json_value == value.to_s
rescue SystemStackError, StandardError
  false
end

.inspect_fallback(value, error) ⇒ Object



129
130
131
132
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 129

def self.inspect_fallback(value, error)
  class_name = value.nil? ? "NilClass" : value.class.to_s
  "#<#{class_name} unserializable: #{error.class}: #{error.message}>"
end

.json(trace) ⇒ Object



18
19
20
21
22
23
24
25
26
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 18

def self.json(trace)
  JSON.generate(
    class: stringify(trace.class_name),
    method_name: stringify(trace.method_name),
    path: stringify(trace.file_path),
    line: trace.line_number,
    params: safe_value(trace.params)
  )
end

.message(trace) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 5

def self.message(trace)
  case RailsTracepointStack.configuration&.log_format
  when :json
    json trace
  else
    text trace
  end
end

.recursive_placeholder(value) ⇒ Object



134
135
136
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 134

def self.recursive_placeholder(value)
  "[recursive #{value.class}]"
end

.safe_array(value, ancestry) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 53

def self.safe_array(value, ancestry)
  object_id = value.__id__
  return recursive_placeholder(value) if ancestry.key?(object_id)

  ancestry[object_id] = true
  value.map { |item| safe_value(item, ancestry) }
ensure
  ancestry.delete(object_id)
end

.safe_hash(value, ancestry) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 63

def self.safe_hash(value, ancestry)
  object_id = value.__id__
  return recursive_placeholder(value) if ancestry.key?(object_id)

  ancestry[object_id] = true
  value.each_with_object({}) do |(key, item), result|
    result[safe_hash_key(key, ancestry)] = safe_value(item, ancestry)
  end
ensure
  ancestry.delete(object_id)
end

.safe_hash_key(key, ancestry = {}) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 75

def self.safe_hash_key(key, ancestry = {})
  case key
  when String
    key
  when Symbol, Numeric
    key.to_s
  when true, false, nil
    key.inspect
  else
    stringify_hash_key(key, ancestry)
  end
end

.safe_json_object(value) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 88

def self.safe_json_object(value)
  json_value = JSON.parse(JSON.generate(value))

  return json_value unless default_string_representation?(value, json_value)

  safe_object_string(value)
rescue SystemStackError, StandardError
  safe_object_string(value)
end

.safe_object_string(value) ⇒ Object



123
124
125
126
127
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 123

def self.safe_object_string(value)
  value.inspect
rescue SystemStackError, StandardError => error
  inspect_fallback(value, error)
end

.safe_value(value, ancestry = {}) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 36

def self.safe_value(value, ancestry = {})
  case value
  when nil, true, false, Numeric, String
    value
  when Symbol
    value.to_s
  when Array
    safe_array(value, ancestry)
  when Hash
    safe_hash(value, ancestry)
  else
    safe_json_object(value)
  end
rescue SystemStackError, StandardError => error
  inspect_fallback(value, error)
end

.stringify(value) ⇒ Object



28
29
30
31
32
33
34
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 28

def self.stringify(value)
  return nil if value.nil?

  value.to_s
rescue SystemStackError, StandardError => error
  inspect_fallback(value, error)
end

.stringify_hash_key(key, ancestry) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 106

def self.stringify_hash_key(key, ancestry)
  normalized_key = safe_value(key, ancestry)

  case normalized_key
  when String
    normalized_key
  when nil
    "null"
  when true, false, Numeric
    normalized_key.to_s
  else
    JSON.generate(normalized_key)
  end
rescue SystemStackError, StandardError
  safe_object_string(key)
end

.text(trace) ⇒ Object



14
15
16
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 14

def self.text(trace)
  "called: #{trace.class_name}##{trace.method_name} in #{trace.file_path}:#{trace.line_number} with params: #{text_value(trace.params)}"
end

.text_array(value, ancestry) ⇒ Object



159
160
161
162
163
164
165
166
167
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 159

def self.text_array(value, ancestry)
  object_id = value.__id__
  return recursive_placeholder(value) if ancestry.key?(object_id)

  ancestry[object_id] = true
  "[#{value.map { |item| text_value(item, ancestry) }.join(", ")}]"
ensure
  ancestry.delete(object_id)
end

.text_hash(value, ancestry) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 169

def self.text_hash(value, ancestry)
  object_id = value.__id__
  return recursive_placeholder(value) if ancestry.key?(object_id)

  ancestry[object_id] = true
  pairs = value.map do |key, item|
    "#{text_hash_key(key, ancestry)}=>#{text_value(item, ancestry)}"
  end

  "{#{pairs.join(", ")}}"
ensure
  ancestry.delete(object_id)
end

.text_hash_key(key, ancestry = {}) ⇒ Object



183
184
185
186
187
188
189
190
191
192
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 183

def self.text_hash_key(key, ancestry = {})
  case key
  when Symbol
    ":#{key}"
  when String
    key.inspect
  else
    text_value(key, ancestry)
  end
end

.text_value(value, ancestry = {}) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rails_tracepoint_stack/log_formatter.rb', line 138

def self.text_value(value, ancestry = {})
  case value
  when nil
    "nil"
  when true, false, Numeric
    value.to_s
  when String
    value.inspect
  when Symbol
    ":#{value}"
  when Array
    text_array(value, ancestry)
  when Hash
    text_hash(value, ancestry)
  else
    safe_object_string(value)
  end
rescue SystemStackError, StandardError => error
  inspect_fallback(value, error)
end