k_log 0.0.19 → 0.0.30
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/.rubocop.yml +12 -0
- data/Gemfile +3 -8
- data/k_log.gemspec +1 -0
- data/lib/k_log/log_helper.rb +62 -1
- data/lib/k_log/log_structure.rb +436 -0
- data/lib/k_log/log_util.rb +25 -2
- data/lib/k_log/tools/build_formatter_configuration_for_log_structure.rb +51 -0
- data/lib/k_log/version.rb +1 -1
- data/lib/k_log.rb +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 328dd6fd19c8872158c3de15cbcb0bc2cf222ca2124b8d03ce81a81040cd1411
|
4
|
+
data.tar.gz: f44defe61b5895b2505725c2cbad5c27c45c93e155e25460a85d1a083f1cb775
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0753d0d203b0673a2526368fa92a6cd6fc0c7ba42f6d425dbaba54b489b9db8e8865bbba2a1b6c22804c6e47b74e1f885b1cb11c85cb9c922fb99d34c30ea21d
|
7
|
+
data.tar.gz: 436f881ffb78b39ded0f7d2649712286c74c39e104991b8fd28cfc7b7dc7417c91f64030d82ab9a54bb3d17ce6d6ae7c64bfe2ccc955b2ccff6f71b43d5dd72e
|
data/.rubocop.yml
CHANGED
@@ -40,6 +40,8 @@ Layout/LineLength:
|
|
40
40
|
# Ignores annotate output
|
41
41
|
IgnoredPatterns: ['\A# \*\*']
|
42
42
|
IgnoreCopDirectives: true
|
43
|
+
Exclude:
|
44
|
+
- "**/spec/**/*"
|
43
45
|
|
44
46
|
Lint/UnusedMethodArgument:
|
45
47
|
AllowUnusedKeywordArguments: true
|
@@ -61,6 +63,16 @@ Metrics/ClassLength:
|
|
61
63
|
Metrics/ModuleLength:
|
62
64
|
Exclude:
|
63
65
|
- "**/spec/**/*"
|
66
|
+
Metrics/CyclomaticComplexity:
|
67
|
+
Exclude:
|
68
|
+
- "lib/k_log/log_structure.rb"
|
69
|
+
Metrics/PerceivedComplexity:
|
70
|
+
Exclude:
|
71
|
+
- "lib/k_log/log_structure.rb"
|
72
|
+
Metrics/AbcSize:
|
73
|
+
Exclude:
|
74
|
+
- "lib/k_log/log_structure.rb"
|
75
|
+
|
64
76
|
Naming/MemoizedInstanceVariableName:
|
65
77
|
Enabled: false
|
66
78
|
Naming/VariableNumber:
|
data/Gemfile
CHANGED
@@ -2,23 +2,18 @@
|
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
|
-
# Specify your gem's dependencies in handlebars_helpers.gemspec
|
6
5
|
gemspec
|
7
6
|
|
8
|
-
# group :development do
|
9
|
-
# # Currently conflicts with GitHub actions and so I remove it on push
|
10
|
-
# # pry on steroids
|
11
|
-
# gem 'jazz_fingers'
|
12
|
-
# gem 'pry-coolline', github: 'owst/pry-coolline', branch: 'support_new_pry_config_api'
|
13
|
-
# end
|
14
|
-
|
15
7
|
group :development, :test do
|
8
|
+
gem 'dry-struct', '~> 1'
|
9
|
+
|
16
10
|
gem 'guard-bundler'
|
17
11
|
gem 'guard-rspec'
|
18
12
|
gem 'guard-rubocop'
|
19
13
|
gem 'rake', '~> 12.0'
|
20
14
|
gem 'rake-compiler', require: false
|
21
15
|
gem 'rspec', '~> 3.0'
|
16
|
+
gem 'rspec-collection_matchers'
|
22
17
|
gem 'rubocop'
|
23
18
|
gem 'rubocop-rake', require: false
|
24
19
|
gem 'rubocop-rspec', require: false
|
data/k_log.gemspec
CHANGED
data/lib/k_log/log_helper.rb
CHANGED
@@ -43,6 +43,14 @@ module KLog
|
|
43
43
|
green(character * size)
|
44
44
|
end
|
45
45
|
|
46
|
+
def self.dynamic_heading(heading, size: 70, type: :heading)
|
47
|
+
return heading(heading, size) if type == :heading
|
48
|
+
return subheading(heading, size) if type == :subheading
|
49
|
+
return [section_heading(heading, size)] if %i[section_heading section].include?(type)
|
50
|
+
|
51
|
+
[]
|
52
|
+
end
|
53
|
+
|
46
54
|
def self.heading(heading, size = 70)
|
47
55
|
line = line(size)
|
48
56
|
|
@@ -69,7 +77,8 @@ module KLog
|
|
69
77
|
def self.section_heading(heading, size = 70)
|
70
78
|
brace_open = green('[ ')
|
71
79
|
brace_close = green(' ]')
|
72
|
-
|
80
|
+
line_length = size - heading.length - 4
|
81
|
+
line = line_length.positive? ? line(line_length, '-') : ''
|
73
82
|
|
74
83
|
# It is important that you set the colour after you have calculated the size
|
75
84
|
"#{brace_open}#{heading}#{brace_close}#{green(line)}"
|
@@ -106,8 +115,60 @@ module KLog
|
|
106
115
|
end
|
107
116
|
# rubocop:enable Metrics/CyclomaticComplexity
|
108
117
|
|
118
|
+
def self.red(value)
|
119
|
+
"\033[31m#{value}\033[0m"
|
120
|
+
end
|
121
|
+
|
109
122
|
def self.green(value)
|
110
123
|
"\033[32m#{value}\033[0m"
|
111
124
|
end
|
125
|
+
|
126
|
+
def self.yellow(value)
|
127
|
+
"\033[33m#{value}\033[0m"
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.blue(value)
|
131
|
+
"\033[34m#{value}\033[0m"
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.purple(value)
|
135
|
+
"\033[35m#{value}\033[0m"
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.cyan(value)
|
139
|
+
"\033[36m#{value}\033[0m"
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.grey(value)
|
143
|
+
"\033[37m#{value}\033[0m"
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.bg_red(value)
|
147
|
+
"\033[41m#{value}\033[0m"
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.bg_green(value)
|
151
|
+
"\033[42m#{value}\033[0m"
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.bg_yellow(value)
|
155
|
+
"\033[43m#{value}\033[0m"
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.bg_blue(value)
|
159
|
+
"\033[44m#{value}\033[0m"
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.bg_purple(value)
|
163
|
+
"\033[45m#{value}\033[0m"
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.bg_cyan(value)
|
167
|
+
"\033[46m#{value}\033[0m"
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.bg_grey(value)
|
171
|
+
"\033[47m#{value}\033[0m"
|
172
|
+
end
|
112
173
|
end
|
113
174
|
end
|
@@ -0,0 +1,436 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'k_util'
|
4
|
+
|
5
|
+
module KLog
|
6
|
+
# Log Structure is flexible logger for working through a complex object graph
|
7
|
+
class LogStructure
|
8
|
+
attr_reader :indent
|
9
|
+
attr_reader :title
|
10
|
+
attr_reader :title_type
|
11
|
+
attr_reader :heading
|
12
|
+
attr_reader :heading_type
|
13
|
+
attr_reader :line_width
|
14
|
+
attr_reader :key_width
|
15
|
+
attr_reader :show_array_count
|
16
|
+
attr_reader :graph
|
17
|
+
attr_reader :formatter
|
18
|
+
attr_reader :convert_data_to
|
19
|
+
|
20
|
+
attr_reader :recursion_depth
|
21
|
+
attr_reader :key_format
|
22
|
+
attr_reader :graph_path
|
23
|
+
attr_reader :graph_node
|
24
|
+
|
25
|
+
attr_reader :lines
|
26
|
+
attr_reader :output_as
|
27
|
+
attr_reader :output_file
|
28
|
+
|
29
|
+
# Log a structure
|
30
|
+
#
|
31
|
+
# Can handle Hash, Array, OpenStruct, Struct, DryStruct, Hash convertible custom classes
|
32
|
+
#
|
33
|
+
# @option opts [String] :indent Indent with string, defaults to ' '
|
34
|
+
# @option opts [String] :heading Log heading using logger.dynamic_heading
|
35
|
+
# @option opts [String] :heading_type :heading, :subheading, :section_heading
|
36
|
+
# @option opts [String] :line_width line width defaults to 80, but can be overridden here
|
37
|
+
# @option opts [String] :key_width key width defaults to 30, but can be overridden here
|
38
|
+
# @option opts [String] :formatter is a complex configuration for formatting different data within the structure
|
39
|
+
def initialize(opts)
|
40
|
+
@indent = opts[:indent] || ' '
|
41
|
+
@title = opts[:title]
|
42
|
+
@title_type = opts[:title_type] || :heading
|
43
|
+
|
44
|
+
@heading = opts[:heading]
|
45
|
+
@heading_type = opts[:heading_type] || :heading
|
46
|
+
puts ':heading should be :title' if opts[:heading]
|
47
|
+
puts ':heading_type should be :title_type' if opts[:heading_type]
|
48
|
+
|
49
|
+
@formatter = opts[:formatter] || {}
|
50
|
+
@graph = parse_graph(opts[:graph] || {})
|
51
|
+
@convert_data_to = opts[:convert_data_to] || :raw # by default leave data as is
|
52
|
+
|
53
|
+
@line_width = opts[:line_width] || 80
|
54
|
+
@key_width = opts[:key_width] || 30
|
55
|
+
@show_array_count = opts[:show_array_count] || false
|
56
|
+
@output_as = opts[:output_as] || [:console]
|
57
|
+
@output_as = [@output_as] unless @output_as.is_a?(Array)
|
58
|
+
@output_file = opts[:output_file]
|
59
|
+
|
60
|
+
@recursion_depth = 0
|
61
|
+
@key_format = nil
|
62
|
+
@graph_path = []
|
63
|
+
@lines = []
|
64
|
+
|
65
|
+
update_indent_label
|
66
|
+
end
|
67
|
+
|
68
|
+
def l
|
69
|
+
@l ||= KLog::LogUtil.new(KLog.logger)
|
70
|
+
end
|
71
|
+
|
72
|
+
def log(data)
|
73
|
+
log_heading(title, title_type) if title
|
74
|
+
|
75
|
+
data = convert_data(data)
|
76
|
+
|
77
|
+
log_data(data)
|
78
|
+
|
79
|
+
add_line(KLog::LogHelper.line(line_width))
|
80
|
+
|
81
|
+
render_output
|
82
|
+
end
|
83
|
+
|
84
|
+
def content
|
85
|
+
@content ||= lines.join("\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
def clean_content
|
89
|
+
# remove color escape codes
|
90
|
+
@clean_content ||= content.gsub(/\x1B\[\d*m/, '')
|
91
|
+
end
|
92
|
+
|
93
|
+
def clean_lines
|
94
|
+
# remove color escape codes
|
95
|
+
lines.flat_map { |line| line.gsub(/\x1B\[\d*m/, '').split("\n") }
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_lines(lines)
|
99
|
+
@lines += lines
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_line(line)
|
103
|
+
@lines << line
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
# format_config = @formatter[:_root] if format_config.nil? && @recursion_depth.zero?
|
109
|
+
|
110
|
+
def data_enumerator(data)
|
111
|
+
return data.attributes if data.respond_to?(:attributes)
|
112
|
+
|
113
|
+
data
|
114
|
+
end
|
115
|
+
|
116
|
+
def log_data(data)
|
117
|
+
data_enumerator(data).each_pair do |k, v|
|
118
|
+
key = k.is_a?(String) ? k.to_sym : k
|
119
|
+
|
120
|
+
graph_path.push(key)
|
121
|
+
@graph_node = GraphNode.for(self, graph, graph_path)
|
122
|
+
# l.kv 'key', "#{key.to_s.ljust(15)}#{graph_node.skip?.to_s.ljust(6)}#{@recursion_depth}"
|
123
|
+
|
124
|
+
if graph_node.skip?
|
125
|
+
# l.kv 'key', 'skipping...'
|
126
|
+
@graph_path.pop
|
127
|
+
next
|
128
|
+
end
|
129
|
+
|
130
|
+
'puts xmen' if graph_node.pry_at?(:before_value)
|
131
|
+
|
132
|
+
value = graph_node.transform? ? graph_node.transform(v) : v
|
133
|
+
|
134
|
+
'puts xmen' if graph_node.pry_at?(:after_value)
|
135
|
+
if value.is_a?(OpenStruct) || value.respond_to?(:attributes)
|
136
|
+
|
137
|
+
# l.kv 'go', 'open struct ->'
|
138
|
+
'puts xmen' if graph_node.pry_at?(:before_structure)
|
139
|
+
log_structure(key, value)
|
140
|
+
# l.kv 'go', 'open struct <-'
|
141
|
+
elsif value.is_a?(Array)
|
142
|
+
# l.kv 'go', 'array ->'
|
143
|
+
log_array(key, value)
|
144
|
+
# l.kv 'go', 'array <-'
|
145
|
+
else
|
146
|
+
# l.kv 'go', 'value ->'
|
147
|
+
'puts xmen' if graph_node.pry_at?(:before_kv)
|
148
|
+
log_heading(graph_node.heading, graph_node.heading_type) if graph_node.heading
|
149
|
+
add_line KLog::LogHelper.kv("#{@indent_label}#{key}", value, key_width)
|
150
|
+
# l.kv 'go', 'value <-'
|
151
|
+
end
|
152
|
+
|
153
|
+
# l.line
|
154
|
+
# @graph_node = graph.for_path(graph_path)
|
155
|
+
# l.line
|
156
|
+
@graph_path.pop
|
157
|
+
end
|
158
|
+
nil
|
159
|
+
end
|
160
|
+
|
161
|
+
def log_structure(key, value)
|
162
|
+
log_heading(graph_node.heading, graph_node.heading_type) if graph_node.heading
|
163
|
+
add_line(KLog::LogHelper.green("#{@indent_label}#{key}"))
|
164
|
+
log_child_data(value)
|
165
|
+
end
|
166
|
+
|
167
|
+
def log_child_data(value)
|
168
|
+
depth_down
|
169
|
+
log_data(value)
|
170
|
+
depth_up
|
171
|
+
end
|
172
|
+
|
173
|
+
def log_array(key, array)
|
174
|
+
'puts xmen' if graph_node.pry_at?(:before_array)
|
175
|
+
|
176
|
+
items = array.clone
|
177
|
+
items.select! { |item| graph_node.filter(item) } if graph_node.filter?
|
178
|
+
items = items.take(graph_node.take) if graph_node.limited?
|
179
|
+
items.sort!(&graph_node.sort) if graph_node.sort?
|
180
|
+
|
181
|
+
'puts xmen' if graph_node.pry_at?(:before_array_print)
|
182
|
+
|
183
|
+
return if items.length.zero? && graph_node.skip_empty?
|
184
|
+
|
185
|
+
log_heading(graph_node.heading, graph_node.heading_type) if graph_node.heading
|
186
|
+
|
187
|
+
if primitive?(items)
|
188
|
+
add_line KLog::LogHelper.kv "#{@indent_label}#{key}", items.map(&:to_s).join(', ')
|
189
|
+
else
|
190
|
+
table_print items, tp_columns(items)
|
191
|
+
|
192
|
+
# NEED SUPPORT FOR A configured ARRAY COUNT with width and label
|
193
|
+
add_line KLog::LogHelper.kv key.to_s, items.count if show_array_count
|
194
|
+
end
|
195
|
+
rescue StandardError => e
|
196
|
+
KLog.logger.exception(e)
|
197
|
+
end
|
198
|
+
|
199
|
+
def table_print(items, columns)
|
200
|
+
io = TablePrintIo.new(self)
|
201
|
+
|
202
|
+
tp.set :io, io
|
203
|
+
tp items, columns
|
204
|
+
tp.clear :io
|
205
|
+
end
|
206
|
+
|
207
|
+
def primitive?(items)
|
208
|
+
item = items.first
|
209
|
+
KUtil.data.basic_type?(item)
|
210
|
+
end
|
211
|
+
|
212
|
+
def log_heading(heading, heading_type)
|
213
|
+
add_lines(KLog::LogHelper.dynamic_heading(heading, size: line_width, type: heading_type))
|
214
|
+
end
|
215
|
+
|
216
|
+
def tp_columns(items)
|
217
|
+
# Use configured array columns
|
218
|
+
return graph_node.columns if graph_node.columns
|
219
|
+
|
220
|
+
# Slow but complete list of keys
|
221
|
+
# items.flat_map { |v| v.to_h.keys }.uniq
|
222
|
+
|
223
|
+
items.first.to_h.keys
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_indent_label
|
227
|
+
# puts "indent_label: #{indent} - #{@recursion_depth} - #{(indent * @recursion_depth)}"
|
228
|
+
@indent_label = (indent * @recursion_depth)
|
229
|
+
end
|
230
|
+
|
231
|
+
def indent_in
|
232
|
+
@indent = "#{@indent} "
|
233
|
+
end
|
234
|
+
|
235
|
+
def indent_out
|
236
|
+
@indent = indent.chomp(' ')
|
237
|
+
end
|
238
|
+
|
239
|
+
def depth_down
|
240
|
+
@recursion_depth = recursion_depth + 1
|
241
|
+
update_indent_label
|
242
|
+
end
|
243
|
+
|
244
|
+
def depth_up
|
245
|
+
@recursion_depth = recursion_depth - 1
|
246
|
+
update_indent_label
|
247
|
+
end
|
248
|
+
|
249
|
+
def render_output
|
250
|
+
puts content if output_as.include?(:console)
|
251
|
+
File.write(output_file, clean_content) if output_as.include?(:file) && output_file
|
252
|
+
# content
|
253
|
+
end
|
254
|
+
|
255
|
+
# convert_data_to: :open_struct
|
256
|
+
def convert_data(data)
|
257
|
+
return KUtil.data.to_open_struct(data) if convert_data_to == :open_struct
|
258
|
+
|
259
|
+
data
|
260
|
+
end
|
261
|
+
|
262
|
+
def parse_graph(data)
|
263
|
+
if data.is_a?(Hash)
|
264
|
+
transform_hash = data.each_with_object({}) do |(key, value), new_hash|
|
265
|
+
new_hash[key] = if key == :columns && value.is_a?(Array)
|
266
|
+
# Don't transform the table_print GEM columns definition as it must stay as a hash
|
267
|
+
value
|
268
|
+
else
|
269
|
+
parse_graph(value)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
return OpenStruct.new(transform_hash.to_h)
|
274
|
+
end
|
275
|
+
|
276
|
+
return data.map { |o| parse_graph(o) } if data.is_a?(Array)
|
277
|
+
return parse_graph(data.to_h) if data.respond_to?(:to_h) # hash_convertible?(data)
|
278
|
+
|
279
|
+
# Some primitave type: String, True/False or an ObjectStruct
|
280
|
+
data
|
281
|
+
end
|
282
|
+
|
283
|
+
# def hash_convertible?(value)
|
284
|
+
# # Nil is a special case, it responds to :to_h but generally
|
285
|
+
# # you only want to convert nil to {} in specific scenarios
|
286
|
+
# return false if value.nil?
|
287
|
+
|
288
|
+
# value.is_a?(Array) ||
|
289
|
+
# value.is_a?(Hash) ||
|
290
|
+
# value.is_a?(Struct) ||
|
291
|
+
# value.is_a?(OpenStruct) ||
|
292
|
+
# value.respond_to?(:to_h)
|
293
|
+
# end
|
294
|
+
|
295
|
+
# Format configuration for a specific key
|
296
|
+
#
|
297
|
+
# @example Example configuration for key: tables
|
298
|
+
#
|
299
|
+
# configuration = {
|
300
|
+
# tables: {
|
301
|
+
# heading: 'Database Tables',
|
302
|
+
# take: :all,
|
303
|
+
# columns: [
|
304
|
+
# :name,
|
305
|
+
# :force,
|
306
|
+
# :primary_key,
|
307
|
+
# :id,
|
308
|
+
# columns: { display_method: lambda { |row| row.columns.map { |c| c.name }.join(', ') }, width: 100 }
|
309
|
+
# ]
|
310
|
+
# },
|
311
|
+
# people: {
|
312
|
+
# ... people configuration goes here
|
313
|
+
# }
|
314
|
+
# }
|
315
|
+
#
|
316
|
+
|
317
|
+
# Override table_print IO stream so that it writes into the structure
|
318
|
+
class TablePrintIo
|
319
|
+
def initialize(log_structure)
|
320
|
+
@log_structure = log_structure
|
321
|
+
end
|
322
|
+
|
323
|
+
def puts(line)
|
324
|
+
@log_structure.add_line(line)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
class GraphNode
|
329
|
+
attr_reader :log_structure
|
330
|
+
attr_accessor :config
|
331
|
+
|
332
|
+
class << self
|
333
|
+
def null
|
334
|
+
@null ||= OpenStruct.new
|
335
|
+
end
|
336
|
+
|
337
|
+
def for(log_structure, graph, graph_path)
|
338
|
+
# node_config = graph_path.inject(graph, :send) # (uses deep nesting, but fails when nil is returned) https://stackoverflow.com/questions/15862455/ruby-nested-send
|
339
|
+
# node.nil? ? null : node.send(name) || null
|
340
|
+
node_config = graph_path.reduce(graph) do |node, name|
|
341
|
+
result = node.send(name)
|
342
|
+
|
343
|
+
break null if result.nil?
|
344
|
+
|
345
|
+
result
|
346
|
+
end
|
347
|
+
|
348
|
+
new(log_structure, node_config)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def initialize(log_structure, config)
|
353
|
+
@log_structure = log_structure
|
354
|
+
@config = config || OpenStruct.new
|
355
|
+
end
|
356
|
+
|
357
|
+
# table_print compatible configuration for displaying columns for an array
|
358
|
+
def columns
|
359
|
+
config.columns
|
360
|
+
end
|
361
|
+
|
362
|
+
# Optional heading for the node
|
363
|
+
def heading
|
364
|
+
config.heading
|
365
|
+
end
|
366
|
+
|
367
|
+
# Type of heading [:heading, :subheading, :section]
|
368
|
+
def heading_type
|
369
|
+
config.heading_type || :section
|
370
|
+
end
|
371
|
+
|
372
|
+
# Node data is to be transformed
|
373
|
+
def transform?
|
374
|
+
config&.transform.respond_to?(:call)
|
375
|
+
end
|
376
|
+
|
377
|
+
# Transform node value
|
378
|
+
def transform(value)
|
379
|
+
config.transform.call(value)
|
380
|
+
end
|
381
|
+
|
382
|
+
# Array rows are filtered
|
383
|
+
def filter?
|
384
|
+
config&.filter.respond_to?(:call)
|
385
|
+
end
|
386
|
+
|
387
|
+
# Array rows are filtered via this predicate
|
388
|
+
def filter(value)
|
389
|
+
config.filter.call(value)
|
390
|
+
end
|
391
|
+
|
392
|
+
# How any array rows to take
|
393
|
+
def take
|
394
|
+
config.take
|
395
|
+
end
|
396
|
+
|
397
|
+
# Array rows are limited, see take
|
398
|
+
def limited?
|
399
|
+
config.take&.is_a?(Integer)
|
400
|
+
end
|
401
|
+
|
402
|
+
# Array rows are sorted using .sort
|
403
|
+
def sort?
|
404
|
+
config&.sort.respond_to?(:call)
|
405
|
+
end
|
406
|
+
|
407
|
+
# Use array.sort?
|
408
|
+
def sort
|
409
|
+
config.sort
|
410
|
+
end
|
411
|
+
|
412
|
+
# Skip this node
|
413
|
+
def skip?
|
414
|
+
config.skip == true
|
415
|
+
end
|
416
|
+
|
417
|
+
# Useful in complex debug scenarios
|
418
|
+
def pry_at
|
419
|
+
config.pry_at || []
|
420
|
+
end
|
421
|
+
|
422
|
+
def pry_at?(section)
|
423
|
+
pry_at.include?(section)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Skip empty array node (my be useful for other nodes, but not yet)
|
427
|
+
def skip_empty?
|
428
|
+
config.skip_empty == true
|
429
|
+
end
|
430
|
+
|
431
|
+
def show_array_count
|
432
|
+
log_structure.show_array_count
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
data/lib/k_log/log_util.rb
CHANGED
@@ -72,6 +72,12 @@ module KLog
|
|
72
72
|
@logger.info(message)
|
73
73
|
end
|
74
74
|
|
75
|
+
def dynamic_heading(heading, size: 70, type: :heading)
|
76
|
+
KLog.logger.heading(heading, size) if type == :heading
|
77
|
+
KLog.logger.subheading(heading, size) if type == :subheading
|
78
|
+
KLog.logger.section_heading(heading, size) if %i[section_heading section].include?(type)
|
79
|
+
end
|
80
|
+
|
75
81
|
def heading(heading, size = 70)
|
76
82
|
lines = LogHelper.heading(heading, size)
|
77
83
|
info_multi_lines(lines)
|
@@ -131,7 +137,23 @@ module KLog
|
|
131
137
|
end
|
132
138
|
alias j json
|
133
139
|
|
140
|
+
# Log a structure
|
141
|
+
#
|
142
|
+
# Can handle Hash, Array, OpenStruct, Struct, DryStruct, Hash convertible custom classes
|
143
|
+
#
|
144
|
+
# @param [Hash] **opts Options
|
145
|
+
# @option opts [String] :indent Indent with string, defaults to ''
|
146
|
+
# @option opts [String] :depth is a computered
|
147
|
+
# @option opts [String] :heading Log title using logger.dynamic_heading
|
148
|
+
# @option opts [String] :heading_type :heading, :subheading, :section_heading
|
149
|
+
# @option opts [Boolean] :skip_array Arrays items can be skipped
|
150
|
+
def structure(data, **opts)
|
151
|
+
structure = LogStructure.new(opts)
|
152
|
+
structure.log(data)
|
153
|
+
end
|
154
|
+
|
134
155
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/AbcSize
|
156
|
+
# DEPRECATE
|
135
157
|
def open_struct(data, indent = '', **opts)
|
136
158
|
KLog.logger.heading(opts[:heading], 88) unless opts[:heading].nil?
|
137
159
|
KLog.logger.subheading(opts[:subheading], 88) unless opts[:subheading].nil?
|
@@ -176,8 +198,9 @@ module KLog
|
|
176
198
|
def exception(exception)
|
177
199
|
line
|
178
200
|
|
179
|
-
@logger.info(exception.message)
|
180
|
-
|
201
|
+
@logger.info(KLog::LogHelper.bg_red(exception.message))
|
202
|
+
|
203
|
+
@logger.info(KLog::LogHelper.yellow(exception.backtrace.map { |row| row.start_with?(Dir.pwd) ? KLog::LogHelper.yellow(row) : KLog::LogHelper.red(row) }.join("\n")))
|
181
204
|
|
182
205
|
line
|
183
206
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'k_util'
|
4
|
+
|
5
|
+
module KLog
|
6
|
+
module Tools
|
7
|
+
# This tool will build a Log Structure Formatter configuration by working
|
8
|
+
# through the object graph you would like to use with Log Structure
|
9
|
+
class BuildFormatterConfigurationForLogStructure
|
10
|
+
# Build a sample configuration based on the structure
|
11
|
+
def build_sample_config(data)
|
12
|
+
open_struct_data = KUtil.data.to_open_struct(data)
|
13
|
+
|
14
|
+
lines = [
|
15
|
+
'# Usage:',
|
16
|
+
'',
|
17
|
+
"formatter = #{infer_config(open_struct_data)}",
|
18
|
+
'',
|
19
|
+
"log.structure(data, heading: 'Insert Heading', line_width: 150, formatter: formatter)"
|
20
|
+
]
|
21
|
+
KLog.logger.line
|
22
|
+
puts lines
|
23
|
+
KLog.logger.line
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def infer_config(data)
|
29
|
+
result = {}
|
30
|
+
|
31
|
+
data.each_pair do |key, value|
|
32
|
+
next unless value.is_a?(Array)
|
33
|
+
next if KUtil.data.basic_type?(value.first)
|
34
|
+
|
35
|
+
result[key] = {
|
36
|
+
heading: key.to_s,
|
37
|
+
take: :all,
|
38
|
+
array_columns: value.first.to_h.keys
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
# This is essentially a pretty hash
|
43
|
+
JSON.pretty_generate(result)
|
44
|
+
.gsub(/(?:"|')(?<key>[^"]*)(?:"|')(?=:)(?::)/) do |_|
|
45
|
+
"#{Regexp.last_match(:key)}:"
|
46
|
+
end
|
47
|
+
.gsub('take: "all"', 'take: :all')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/k_log/version.rb
CHANGED
data/lib/k_log.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: k_log
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.30
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Cruwys
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: k_util
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: table_print
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -55,8 +69,10 @@ files:
|
|
55
69
|
- lib/k_log/examples.rb
|
56
70
|
- lib/k_log/log_formatter.rb
|
57
71
|
- lib/k_log/log_helper.rb
|
72
|
+
- lib/k_log/log_structure.rb
|
58
73
|
- lib/k_log/log_util.rb
|
59
74
|
- lib/k_log/logging.rb
|
75
|
+
- lib/k_log/tools/build_formatter_configuration_for_log_structure.rb
|
60
76
|
- lib/k_log/version.rb
|
61
77
|
- usage.png
|
62
78
|
homepage: http://appydave.com/gems/k-log
|