nrser 0.2.2 → 0.3.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 +4 -4
- data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
- data/lib/nrser/char.rb +0 -6
- data/lib/nrser/core_ext/array.rb +120 -0
- data/lib/nrser/core_ext/binding.rb +44 -0
- data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
- data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
- data/lib/nrser/core_ext/exception.rb +30 -0
- data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
- data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
- data/lib/nrser/core_ext/hash.rb +50 -0
- data/lib/nrser/core_ext/module/method_objects.rb +96 -0
- data/lib/nrser/core_ext/module/names.rb +69 -0
- data/lib/nrser/core_ext/module/source_locations.rb +214 -0
- data/lib/nrser/core_ext/module.rb +2 -0
- data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
- data/lib/nrser/core_ext/object.rb +46 -0
- data/lib/nrser/core_ext/open_struct.rb +6 -0
- data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
- data/lib/nrser/{ext → core_ext}/string.rb +6 -12
- data/lib/nrser/core_ext/symbol.rb +13 -0
- data/lib/nrser/core_ext/time.rb +46 -0
- data/lib/nrser/core_ext.rb +13 -0
- data/lib/nrser/errors/abstract_method_error.rb +150 -0
- data/lib/nrser/errors/argument_error.rb +42 -0
- data/lib/nrser/errors/nicer_error.rb +298 -72
- data/lib/nrser/errors/type_error.rb +46 -0
- data/lib/nrser/errors.rb +4 -53
- data/lib/nrser/ext/tree.rb +3 -0
- data/lib/nrser/functions/enumerable/associate.rb +6 -9
- data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
- data/lib/nrser/functions/enumerable.rb +1 -3
- data/lib/nrser/functions/exception.rb +1 -1
- data/lib/nrser/functions/hash.rb +0 -6
- data/lib/nrser/functions/merge_by.rb +2 -2
- data/lib/nrser/functions/module/method_objects.rb +77 -0
- data/lib/nrser/functions/module.rb +1 -2
- data/lib/nrser/functions/open_struct.rb +25 -35
- data/lib/nrser/functions/proc.rb +1 -6
- data/lib/nrser/functions/string/looks_like.rb +32 -1
- data/lib/nrser/functions/string.rb +1 -40
- data/lib/nrser/functions/text/lines.rb +2 -1
- data/lib/nrser/functions.rb +0 -1
- data/lib/nrser/graph/tsorter.rb +41 -0
- data/lib/nrser/labs/core_ext/binding.rb +37 -0
- data/lib/nrser/labs/stash.rb +372 -0
- data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
- data/lib/nrser/log/appender.rb +3 -0
- data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
- data/lib/nrser/log/formatters/mixin.rb +270 -0
- data/lib/nrser/{logging → log}/formatters.rb +0 -0
- data/lib/nrser/log/logger.rb +229 -0
- data/lib/nrser/log/mixin.rb +56 -0
- data/lib/nrser/log.rb +723 -0
- data/lib/nrser/message.rb +24 -3
- data/lib/nrser/meta/source/location.rb +158 -0
- data/lib/nrser/meta.rb +1 -1
- data/lib/nrser/props/class_methods.rb +118 -0
- data/lib/nrser/props/immutable/hash.rb +111 -0
- data/lib/nrser/props/immutable/hash_variable.rb +82 -0
- data/lib/nrser/props/immutable/instance_variables.rb +48 -0
- data/lib/nrser/props/immutable/vector.rb +107 -0
- data/lib/nrser/props/instance_methods.rb +184 -0
- data/lib/nrser/props/metadata.rb +359 -0
- data/lib/nrser/props/mutable/instance_variables.rb +60 -0
- data/lib/nrser/props/mutable/stash.rb +199 -0
- data/lib/nrser/{meta/props → props}/prop.rb +217 -112
- data/lib/nrser/props/storage/instance_variable.rb +85 -0
- data/lib/nrser/props/storage/instance_variables.rb +67 -0
- data/lib/nrser/props/storage/key.rb +88 -0
- data/lib/nrser/props.rb +9 -0
- data/lib/nrser/refinements/sugar.rb +41 -0
- data/lib/nrser/refinements/types.rb +2 -2
- data/lib/nrser/refinements.rb +14 -16
- data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
- data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
- data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
- data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
- data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
- data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
- data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
- data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
- data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
- data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
- data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
- data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
- data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
- data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
- data/lib/nrser/rspex/example_group/overrides.rb +66 -0
- data/lib/nrser/rspex/example_group.rb +20 -252
- data/lib/nrser/rspex/format.rb +83 -17
- data/lib/nrser/rspex.rb +4 -34
- data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
- data/lib/nrser/{env → sys/env}/path.rb +1 -2
- data/lib/nrser/{env.rb → sys/env.rb} +2 -1
- data/lib/nrser/sys.rb +5 -0
- data/lib/nrser/types/any.rb +36 -7
- data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
- data/lib/nrser/types/attrs.rb +68 -15
- data/lib/nrser/types/booleans.rb +95 -34
- data/lib/nrser/types/bounded.rb +12 -10
- data/lib/nrser/types/combinators.rb +74 -37
- data/lib/nrser/types/errors/check_error.rb +86 -0
- data/lib/nrser/types/errors/from_string_error.rb +82 -0
- data/lib/nrser/types/factory.rb +91 -0
- data/lib/nrser/types/hashes.rb +171 -26
- data/lib/nrser/types/in.rb +25 -12
- data/lib/nrser/types/is.rb +50 -18
- data/lib/nrser/types/is_a.rb +52 -33
- data/lib/nrser/types/labels.rb +6 -33
- data/lib/nrser/types/maybe.rb +12 -4
- data/lib/nrser/types/nil.rb +24 -4
- data/lib/nrser/types/not.rb +6 -16
- data/lib/nrser/types/numbers.rb +94 -57
- data/lib/nrser/types/pairs.rb +57 -57
- data/lib/nrser/types/paths.rb +112 -133
- data/lib/nrser/types/responds.rb +64 -74
- data/lib/nrser/types/shape.rb +29 -24
- data/lib/nrser/types/strings.rb +25 -17
- data/lib/nrser/types/symbols.rb +19 -17
- data/lib/nrser/types/trees.rb +18 -70
- data/lib/nrser/types/tuples.rb +36 -40
- data/lib/nrser/types/type.rb +342 -91
- data/lib/nrser/types/when.rb +40 -18
- data/lib/nrser/types/where.rb +94 -9
- data/lib/nrser/types.rb +72 -63
- data/lib/nrser/version.rb +1 -1
- data/lib/nrser.rb +18 -18
- data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
- data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
- data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
- data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
- data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
- data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
- data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
- data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
- data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
- data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
- data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
- data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
- data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
- data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
- data/spec/lib/nrser/refinements/array_spec.rb +2 -15
- data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
- data/spec/lib/nrser/refinements/set_spec.rb +2 -15
- data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
- data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
- data/spec/lib/nrser/types/array_spec.rb +8 -8
- data/spec/lib/nrser/types/paths_spec.rb +15 -18
- data/spec/spec_helper.rb +4 -0
- metadata +109 -69
- data/lib/nrser/ext/binding.rb +0 -36
- data/lib/nrser/ext/module.rb +0 -62
- data/lib/nrser/ext.rb +0 -8
- data/lib/nrser/functions/binding.rb +0 -76
- data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
- data/lib/nrser/functions/enumerable/map_values.rb +0 -94
- data/lib/nrser/functions/hash/deep_merge.rb +0 -57
- data/lib/nrser/functions/hash/except_keys.rb +0 -44
- data/lib/nrser/functions/hash/slice_keys.rb +0 -43
- data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
- data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
- data/lib/nrser/functions/hash/transform_keys.rb +0 -140
- data/lib/nrser/functions/module/methods.rb +0 -206
- data/lib/nrser/functions/module/source_locations.rb +0 -213
- data/lib/nrser/logging/appender.rb +0 -3
- data/lib/nrser/logging.rb +0 -353
- data/lib/nrser/meta/props/base.rb +0 -31
- data/lib/nrser/meta/props.rb +0 -357
- data/lib/nrser/refinements/array.rb +0 -133
- data/lib/nrser/refinements/binding.rb +0 -6
- data/lib/nrser/refinements/enumerator.rb +0 -5
- data/lib/nrser/refinements/exception.rb +0 -35
- data/lib/nrser/refinements/hash.rb +0 -150
- data/lib/nrser/refinements/module.rb +0 -5
- data/lib/nrser/refinements/object.rb +0 -42
- data/lib/nrser/refinements/open_struct.rb +0 -28
- data/lib/nrser/refinements/pathname.rb +0 -5
- data/lib/nrser/refinements/set.rb +0 -5
- data/lib/nrser/refinements/string.rb +0 -5
- data/lib/nrser/refinements/symbol.rb +0 -20
- data/lib/nrser/rspex/described.rb +0 -99
- data/spec/design/mapping_spec.rb +0 -42
- data/spec/lib/nrser/functions/hash_spec.rb +0 -41
- data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
- data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
data/lib/nrser/log.rb
ADDED
@@ -0,0 +1,723 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# What NRSER's logging is based off
|
14
|
+
require 'semantic_logger'
|
15
|
+
|
16
|
+
# We need a {Concurrent::Map} to hold reference to loggers.
|
17
|
+
require "concurrent/map"
|
18
|
+
|
19
|
+
# Project / Package
|
20
|
+
# -----------------------------------------------------------------------
|
21
|
+
|
22
|
+
|
23
|
+
# Definitions
|
24
|
+
# =======================================================================
|
25
|
+
|
26
|
+
# Unified logging support via {SemanticLogger}.
|
27
|
+
#
|
28
|
+
# @see https://rocketjob.github.io/semantic_logger/index.html
|
29
|
+
#
|
30
|
+
module NRSER::Log
|
31
|
+
|
32
|
+
# Sub-Tree Requirements
|
33
|
+
# ========================================================================
|
34
|
+
|
35
|
+
require_relative './log/mixin'
|
36
|
+
require_relative './log/logger'
|
37
|
+
require_relative './log/formatters'
|
38
|
+
require_relative './log/appender'
|
39
|
+
|
40
|
+
|
41
|
+
# Constants
|
42
|
+
# ========================================================================
|
43
|
+
|
44
|
+
|
45
|
+
# Mixins
|
46
|
+
# ========================================================================
|
47
|
+
|
48
|
+
# Mix in {.logger} and {#logger}
|
49
|
+
include Mixin
|
50
|
+
|
51
|
+
# We want to forward some methods directly to {SemanticLogger}
|
52
|
+
extend SingleForwardable
|
53
|
+
|
54
|
+
|
55
|
+
# Delegation
|
56
|
+
# ========================================================================
|
57
|
+
#
|
58
|
+
# Send some things up to {SemanticLogger}.
|
59
|
+
#
|
60
|
+
|
61
|
+
def_single_delegators(
|
62
|
+
SemanticLogger,
|
63
|
+
:application,
|
64
|
+
:application=,
|
65
|
+
:[],
|
66
|
+
# NOTE These are funky due to different in SemLog's int level and Ruby
|
67
|
+
# stdlib / Rails logger int levels, so omit for now.
|
68
|
+
#
|
69
|
+
# :index_to_level,
|
70
|
+
# :level_to_index
|
71
|
+
)
|
72
|
+
|
73
|
+
|
74
|
+
# Module Attributes
|
75
|
+
# ========================================================================
|
76
|
+
|
77
|
+
# Used in {.setup!} to make sure we don't have multiple threads trying to
|
78
|
+
# muck around at the same time.
|
79
|
+
#
|
80
|
+
@__mutex__ = Mutex.new
|
81
|
+
|
82
|
+
# We need to store references to {NRSER::Log::Logger} objects by name so
|
83
|
+
# we can apply rules that are added afterwards.
|
84
|
+
#
|
85
|
+
@__loggers__ = Concurrent::Map.new
|
86
|
+
|
87
|
+
|
88
|
+
# Class Methods
|
89
|
+
# ========================================================================
|
90
|
+
|
91
|
+
def self.[] subject
|
92
|
+
# key = logger_type_and_name_from subject
|
93
|
+
#
|
94
|
+
# if @__loggers__.key? key
|
95
|
+
# ref = @__loggers__[key]
|
96
|
+
#
|
97
|
+
# if ref.weakref_alive?
|
98
|
+
# return
|
99
|
+
#
|
100
|
+
instance = NRSER::Log::Logger.new subject
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# @!group Utility Class Methods
|
105
|
+
# ------------------------------------------------------------------------
|
106
|
+
|
107
|
+
|
108
|
+
# @todo Document logger_name_and_type method.
|
109
|
+
#
|
110
|
+
# @param [type] arg_name
|
111
|
+
# @todo Add name param description.
|
112
|
+
#
|
113
|
+
# @return [return_type]
|
114
|
+
# @todo Document return value.
|
115
|
+
#
|
116
|
+
def self.logger_type_and_name_from subject
|
117
|
+
case subject
|
118
|
+
when String
|
119
|
+
[:string, subject]
|
120
|
+
|
121
|
+
when Module
|
122
|
+
[:const, subject.safe_name]
|
123
|
+
|
124
|
+
when Array
|
125
|
+
# NOTE Prob bad to use {NRSER::Types} here since logging gets
|
126
|
+
# required so early, and we want it to *work* then... seems like
|
127
|
+
# it would introduce lots of dependency mess. So just use plain
|
128
|
+
# ol' Ruby.
|
129
|
+
unless subject.length == 2 &&
|
130
|
+
subject[0].is_a?( Symbol ) &&
|
131
|
+
subject[1].is_a?( String )
|
132
|
+
raise NRSER::ArgumentError.new \
|
133
|
+
"Subject arrays must be [Symbol, String]; received", subject,
|
134
|
+
subject: subject,
|
135
|
+
details: -> {
|
136
|
+
<<~END
|
137
|
+
When passing an {Array}, it must be a pair:
|
138
|
+
|
139
|
+
1. `[0]` must be a {Symbol} that is the logger's subject
|
140
|
+
*type*.
|
141
|
+
|
142
|
+
2. `[1]` must be a {String} that is the logger's subject
|
143
|
+
*name*.
|
144
|
+
END
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
pair = subject.dup
|
149
|
+
pair[0] = :const if [:module, :class].include? pair[0]
|
150
|
+
pair
|
151
|
+
|
152
|
+
when Hash
|
153
|
+
unless subject.length == 1
|
154
|
+
raise NRSER::ArgumentError.new \
|
155
|
+
"Hash subjects must be a single key/value pair",
|
156
|
+
subject: subject
|
157
|
+
end
|
158
|
+
|
159
|
+
pair = subject.first
|
160
|
+
|
161
|
+
unless pair[0].is_a?( Symbol ) &&
|
162
|
+
pair[1].is_a?( String )
|
163
|
+
raise NRSER::ArgumentError.new \
|
164
|
+
"Subject hashes must be a Symbol key and String value",
|
165
|
+
subject: subject
|
166
|
+
end
|
167
|
+
|
168
|
+
pair[0] = :const if [:module, :class].include? pair[0]
|
169
|
+
|
170
|
+
pair
|
171
|
+
|
172
|
+
else
|
173
|
+
raise NRSER::TypeError.new \
|
174
|
+
"Expected `subject` to be String, Module, Array or Hash, ",
|
175
|
+
"found #{ subject.class }",
|
176
|
+
subject: subject
|
177
|
+
end
|
178
|
+
end # .logger_type_and_name_from
|
179
|
+
|
180
|
+
|
181
|
+
# Normalize a level name or number to a symbol, raising if it's not valid.
|
182
|
+
#
|
183
|
+
# Relies on Semantic Logger's "internal" {SemanticLogger.level_to_index}
|
184
|
+
# method.
|
185
|
+
#
|
186
|
+
# @see https://github.com/rocketjob/semantic_logger/blob/97247126de32e6ecbf74cbccaa3b3732768d52c5/lib/semantic_logger/semantic_logger.rb#L454
|
187
|
+
#
|
188
|
+
# @param [Symbol | String | Integer]
|
189
|
+
# Representation of a level in one of the following formats:
|
190
|
+
#
|
191
|
+
# 1. {Symbol} - verified as member of {SemanticLogger::LEVELS} and
|
192
|
+
# returned.
|
193
|
+
#
|
194
|
+
# 2. {String} - accepts string representations of the level symbols,
|
195
|
+
# case insensitive.
|
196
|
+
#
|
197
|
+
# 3. {Integer} - interpreted as a Ruby StdLib Logger / Rails Logger
|
198
|
+
# level, which are **different** than Semantic Logger's!
|
199
|
+
#
|
200
|
+
# @return [:trace | :debug | :info | :warn | :error | :fatal]
|
201
|
+
# Log level symbol.
|
202
|
+
#
|
203
|
+
# @raise
|
204
|
+
# When `level` is invalid.
|
205
|
+
#
|
206
|
+
def self.level_sym_for level
|
207
|
+
if SemanticLogger::LEVELS.include? level
|
208
|
+
level
|
209
|
+
else
|
210
|
+
SemanticLogger.index_to_level SemanticLogger.level_to_index( level )
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
# Global / default log level, which we always normalize to a symbol.
|
216
|
+
#
|
217
|
+
# @return [:trace | :debug | :info | :warn | :error | :fatal]
|
218
|
+
#
|
219
|
+
def self.level
|
220
|
+
level_sym_for SemanticLogger.default_level
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
# Integer level index. Forwards to {SemanticLogger.default_level_index}.
|
225
|
+
#
|
226
|
+
# @note
|
227
|
+
# There is some funkiness around level indexes that I think/hope I wrote
|
228
|
+
# down somewhere, so use with some caution/research.
|
229
|
+
#
|
230
|
+
# @return [Fixnum]
|
231
|
+
#
|
232
|
+
def self.level_index
|
233
|
+
SemanticLogger.default_level_index
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
# Set the global default log level.
|
238
|
+
#
|
239
|
+
# @param level (see .level_sym_for)
|
240
|
+
# @return (see .level_sym_for)
|
241
|
+
# @raise (see .level_sym_for)
|
242
|
+
#
|
243
|
+
def self.level= level
|
244
|
+
SemanticLogger.default_level = level_sym_for level
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
def self.level_from_ENV prefix:
|
249
|
+
if NRSER.truthy? ENV["#{ prefix }_TRACE"]
|
250
|
+
return :trace
|
251
|
+
elsif NRSER.truthy? ENV["#{ prefix }_DEBUG"]
|
252
|
+
return :debug
|
253
|
+
end
|
254
|
+
|
255
|
+
level = ENV["#{ prefix }_LOG_LEVEL"]
|
256
|
+
|
257
|
+
unless level.nil? || level == ''
|
258
|
+
return level
|
259
|
+
end
|
260
|
+
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
|
264
|
+
# @!endgroup Utility Class Methods
|
265
|
+
|
266
|
+
|
267
|
+
# @!group Setup Class Methods
|
268
|
+
# --------------------------------------------------------------------------
|
269
|
+
|
270
|
+
# Setup logging.
|
271
|
+
#
|
272
|
+
# @param [type] arg_name
|
273
|
+
# @todo Add name param description.
|
274
|
+
#
|
275
|
+
# @return [nil]
|
276
|
+
#
|
277
|
+
def self.setup! level: nil,
|
278
|
+
dest: nil,
|
279
|
+
sync: nil,
|
280
|
+
say_hi: :debug,
|
281
|
+
application: nil,
|
282
|
+
env_var_prefix: nil,
|
283
|
+
header: nil,
|
284
|
+
body: nil
|
285
|
+
|
286
|
+
unless @__mutex__.try_lock
|
287
|
+
raise ThreadError, <<~END
|
288
|
+
Mutex is already held.
|
289
|
+
|
290
|
+
You should pretty generally NOT have multiple threads trying to
|
291
|
+
setup logging at once or re-enter {NRSER::Log.setup}!
|
292
|
+
END
|
293
|
+
end
|
294
|
+
|
295
|
+
# Wrap around everything to make sure we release the mutex
|
296
|
+
begin
|
297
|
+
# Setup main appender if needed
|
298
|
+
setup_appender! dest
|
299
|
+
|
300
|
+
# Set sync/async processor state
|
301
|
+
setup_sync! sync
|
302
|
+
|
303
|
+
# If we didn't receive a level, check the ENV
|
304
|
+
if level.nil?
|
305
|
+
if env_var_prefix.nil? && !application.nil?
|
306
|
+
env_var_prefix = application.gsub( /[^a-zA-Z0-0_]+/, '_' ).upcase
|
307
|
+
end
|
308
|
+
|
309
|
+
level = level_from_ENV prefix: env_var_prefix
|
310
|
+
end
|
311
|
+
|
312
|
+
# If we ended up with a level, try to set it (will only log a warning
|
313
|
+
# if it fails, not raise, which could crash things on boot)
|
314
|
+
setup_level! level unless level.nil?
|
315
|
+
|
316
|
+
self.application = application unless application.nil?
|
317
|
+
|
318
|
+
# Setup formatter header and body tokens, if needed
|
319
|
+
setup_formatter_tokens! :header, header
|
320
|
+
setup_formatter_tokens! :body, body
|
321
|
+
|
322
|
+
ensure
|
323
|
+
# Make sure we release the mutex; don't need to hold it for the rest
|
324
|
+
@__mutex__.unlock
|
325
|
+
end
|
326
|
+
|
327
|
+
# Name the main thread so that `process_info` doesn't look so lame
|
328
|
+
setup_main_thread_name!
|
329
|
+
|
330
|
+
# Possibly say hi
|
331
|
+
setup_say_hi say_hi, dest, sync
|
332
|
+
|
333
|
+
nil
|
334
|
+
|
335
|
+
rescue Exception => error
|
336
|
+
# Suppress errors in favor of a warning
|
337
|
+
|
338
|
+
logger.warn \
|
339
|
+
message: "Error setting up logging",
|
340
|
+
payload: {
|
341
|
+
args: {
|
342
|
+
level: level,
|
343
|
+
dest: dest,
|
344
|
+
env_var_prefix: env_var_prefix,
|
345
|
+
say_hi: say_hi,
|
346
|
+
},
|
347
|
+
},
|
348
|
+
exception: error
|
349
|
+
|
350
|
+
nil
|
351
|
+
end # .setup!
|
352
|
+
|
353
|
+
|
354
|
+
# Call {.setup!} with some default keywords that are nice for CLI apps.
|
355
|
+
#
|
356
|
+
# @param (see .setup!)
|
357
|
+
# @return (see .setup!)
|
358
|
+
#
|
359
|
+
def self.setup_for_CLI! dest: $stderr,
|
360
|
+
sync: true,
|
361
|
+
**kwds
|
362
|
+
setup! dest: dest, sync: sync, **kwds
|
363
|
+
end # .setup_for_CLI!
|
364
|
+
|
365
|
+
# Old name
|
366
|
+
singleton_class.send :alias_method, :setup_for_cli!, :setup_for_CLI!
|
367
|
+
|
368
|
+
|
369
|
+
# Call {.setup!} with some default keywords that are nice for interactive
|
370
|
+
# session (console/REPL) usage.
|
371
|
+
#
|
372
|
+
# @param (see .setup!)
|
373
|
+
# @return (see .setup!)
|
374
|
+
#
|
375
|
+
def self.setup_for_console! dest: $stderr,
|
376
|
+
sync: true,
|
377
|
+
header: { delete: :process_info },
|
378
|
+
**kwds
|
379
|
+
setup! \
|
380
|
+
dest: dest,
|
381
|
+
sync: sync,
|
382
|
+
header: header,
|
383
|
+
**kwds
|
384
|
+
end # .setup_for_console!
|
385
|
+
|
386
|
+
|
387
|
+
# Call {.setup!} but provides default for running RSpec tests: sync,
|
388
|
+
# write to
|
389
|
+
#
|
390
|
+
# @param (see .setup!)
|
391
|
+
# @return (see .setup!)
|
392
|
+
#
|
393
|
+
def self.setup_for_rspec! dest: $stderr,
|
394
|
+
sync: true,
|
395
|
+
header: { delete: :process_info },
|
396
|
+
**kwds
|
397
|
+
setup! \
|
398
|
+
dest: dest,
|
399
|
+
sync: sync,
|
400
|
+
header: header,
|
401
|
+
**kwds
|
402
|
+
end # .setup_for_rspec!
|
403
|
+
|
404
|
+
# @!endgroup Setup Class Methods
|
405
|
+
|
406
|
+
# ************************************************************************
|
407
|
+
|
408
|
+
|
409
|
+
# Shortcut to {SemanticLogger::Processor.instance}.
|
410
|
+
#
|
411
|
+
# @return [SemanticLogger::Subscriber]
|
412
|
+
# You would think this would be a {SemanticLogger::Processor}, but it's
|
413
|
+
# actually an *appender* ({SemanticLogger::Subscriber} is the base class
|
414
|
+
# of appenders, sigh...).
|
415
|
+
#
|
416
|
+
def self.processor
|
417
|
+
SemanticLogger::Processor.instance
|
418
|
+
end
|
419
|
+
|
420
|
+
|
421
|
+
def self.sync?
|
422
|
+
processor.is_a? NRSER::Log::Appender::Sync
|
423
|
+
end
|
424
|
+
|
425
|
+
|
426
|
+
# The current "main" appender (destination), if any.
|
427
|
+
#
|
428
|
+
# This is just to simplify things in simple cases, you can always still
|
429
|
+
# add multiple appenders.
|
430
|
+
#
|
431
|
+
# @return [SemanticLogger::Subscriber | nil]
|
432
|
+
#
|
433
|
+
def self.appender
|
434
|
+
@appender
|
435
|
+
end
|
436
|
+
|
437
|
+
|
438
|
+
# Short-cut for `.appender.formatter`.
|
439
|
+
#
|
440
|
+
# @return [nil]
|
441
|
+
# If there is no {.appender}.
|
442
|
+
#
|
443
|
+
# @return [SemanticLogger::Formatters::Default]
|
444
|
+
# If there is an {.appender}, the appender's `#formatter` attribute.
|
445
|
+
#
|
446
|
+
def self.formatter
|
447
|
+
appender.formatter if appender
|
448
|
+
end
|
449
|
+
|
450
|
+
|
451
|
+
# Is there a header formatter?
|
452
|
+
#
|
453
|
+
# @return [Boolean]
|
454
|
+
# `true` if there is an {.formatter} and it responds to ':header'.
|
455
|
+
#
|
456
|
+
# If it returns `false`, it means there is no {.appender} attached
|
457
|
+
# or it's formatter does not mix in {NRSER::Log::Formatters::Mixin}.
|
458
|
+
#
|
459
|
+
# In this case you can't read or write to the header, so {.header=}
|
460
|
+
# won't do anything.
|
461
|
+
#
|
462
|
+
def self.header?
|
463
|
+
formatter && formatter.respond_to?( :header )
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
# Calls `.formatter.header` if there is a {.header?}.
|
468
|
+
#
|
469
|
+
# @see NRSER::Log::Formatters::Mixin#header
|
470
|
+
# @param (see NRSER::Log::Formatters::Mixin#header)
|
471
|
+
# @return (see NRSER::Log::Formatters::Mixin#header)
|
472
|
+
# @raise (see NRSER::Log::Formatters::Mixin#header)
|
473
|
+
#
|
474
|
+
# @return [nil]
|
475
|
+
# If there is no {.appender} or it's formatter doesn't have a header.
|
476
|
+
#
|
477
|
+
def self.header *tokens
|
478
|
+
formatter.header( *tokens ) if header?
|
479
|
+
end
|
480
|
+
|
481
|
+
|
482
|
+
def self.header= tokens
|
483
|
+
if header?
|
484
|
+
formatter.header = tokens
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
|
489
|
+
def self.body?
|
490
|
+
formatter && formatter.respond_to?( :body )
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
def self.body *tokens
|
495
|
+
formatter.body( *tokens ) if body?
|
496
|
+
end
|
497
|
+
|
498
|
+
|
499
|
+
def self.body= tokens
|
500
|
+
if body?
|
501
|
+
formatter.body = tokens
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
|
506
|
+
# @!group Setup Helpers
|
507
|
+
# ------------------------------------------------------------------------
|
508
|
+
#
|
509
|
+
# Break-outs from the monstrosity that {#setup!} became. Only called
|
510
|
+
# from there, and only *should* be called from there! Hence these methods
|
511
|
+
# are all private as well.
|
512
|
+
#
|
513
|
+
|
514
|
+
# Try to set the level, logging a warning and returning `nil` if it fails.
|
515
|
+
#
|
516
|
+
# @param level (see .level=)
|
517
|
+
#
|
518
|
+
# @return [Symbol]
|
519
|
+
# The level symbol if it was set successfully.
|
520
|
+
#
|
521
|
+
# @return [nil]
|
522
|
+
# If the set failed (also logs a warning).
|
523
|
+
#
|
524
|
+
def self.setup_level! level
|
525
|
+
logger.catch.warn(
|
526
|
+
"Unable to set level, probably bad value",
|
527
|
+
level: level
|
528
|
+
) do
|
529
|
+
self.level = level
|
530
|
+
end
|
531
|
+
end # .try_set_level
|
532
|
+
|
533
|
+
private_class_method :setup_level!
|
534
|
+
|
535
|
+
|
536
|
+
# Possibly say hi. Params are from {#setup!}.
|
537
|
+
#
|
538
|
+
# @private
|
539
|
+
# @return [nil]
|
540
|
+
#
|
541
|
+
def self.setup_say_hi say_hi, dest, sync
|
542
|
+
will_say_hi = case say_hi
|
543
|
+
when true, false
|
544
|
+
say_hi
|
545
|
+
when Symbol, String, Fixnum
|
546
|
+
logger.catch( on_fail: false ).warn(
|
547
|
+
"Bad `say_hi` kwd in {NRSER::Log.setup}",
|
548
|
+
say_hi: say_hi,
|
549
|
+
expected: "Symbol, String, or Fixnum representing log level"
|
550
|
+
) do
|
551
|
+
level_index < SemanticLogger.level_to_index( say_hi )
|
552
|
+
end
|
553
|
+
|
554
|
+
else
|
555
|
+
logger.warn "Bad `say_hi` kwd in {NRSER::Log.setup}",
|
556
|
+
say_hi: say_hi,
|
557
|
+
expected: [true, false, Symbol, String, Fixnum]
|
558
|
+
|
559
|
+
false
|
560
|
+
end
|
561
|
+
|
562
|
+
if will_say_hi
|
563
|
+
logger.info "Hi! Logging is setup",
|
564
|
+
level: self.level,
|
565
|
+
dest: dest,
|
566
|
+
sync: sync
|
567
|
+
end
|
568
|
+
|
569
|
+
nil
|
570
|
+
end # .setup_say_hi
|
571
|
+
|
572
|
+
private_class_method :setup_say_hi
|
573
|
+
|
574
|
+
|
575
|
+
# Make sure the main thread has a {Thread#name} (a core_ext added by
|
576
|
+
# SemanticLogger).
|
577
|
+
#
|
578
|
+
# We do this so that the `process_info` section in log messages isn't so
|
579
|
+
# distracting and useless ({Thread#name} defaults to the thread's
|
580
|
+
# `#object_id`).
|
581
|
+
#
|
582
|
+
# If it has no name, we name it "main".
|
583
|
+
#
|
584
|
+
# @private
|
585
|
+
# @return [nil]
|
586
|
+
#
|
587
|
+
def self.setup_main_thread_name!
|
588
|
+
main = Thread.main
|
589
|
+
main.name = 'main' unless main.instance_variable_defined? :@name
|
590
|
+
nil
|
591
|
+
end # .name_main_thread
|
592
|
+
|
593
|
+
private_class_method :setup_main_thread_name!
|
594
|
+
|
595
|
+
|
596
|
+
def self.setup_sync! sync
|
597
|
+
# Do nothing if `sync` is `nil`
|
598
|
+
return nil if sync.nil?
|
599
|
+
|
600
|
+
# Make sure we have a bool
|
601
|
+
bool = !!sync
|
602
|
+
|
603
|
+
# Take no action if we're already in the desired state
|
604
|
+
return bool if bool == sync?
|
605
|
+
|
606
|
+
# Ok, need to make a change
|
607
|
+
if sync?
|
608
|
+
# Switch to async
|
609
|
+
|
610
|
+
# We *should* already have the async processor
|
611
|
+
@async_processor ||= SemanticLogger::Appender::Async.new(
|
612
|
+
name: 'SemanticLogger::Processor',
|
613
|
+
appender: SemanticLogger::Processor.instance.appender,
|
614
|
+
max_queue_size: -1,
|
615
|
+
)
|
616
|
+
|
617
|
+
@sync_processor ||= SemanticLogger::Processor.instance
|
618
|
+
|
619
|
+
# Swap the async in for our sync
|
620
|
+
SemanticLogger::Processor.instance_variable_set \
|
621
|
+
:@processor,
|
622
|
+
@async_processor
|
623
|
+
|
624
|
+
else
|
625
|
+
@async_processor ||= SemanticLogger::Processor.instance
|
626
|
+
@sync_processor ||= NRSER::Log::Appender::Sync.new \
|
627
|
+
appender: SemanticLogger::Processor.instance.appender
|
628
|
+
|
629
|
+
# Swap our sync in for the async
|
630
|
+
SemanticLogger::Processor.instance_variable_set \
|
631
|
+
:@processor,
|
632
|
+
@sync_processor
|
633
|
+
end
|
634
|
+
|
635
|
+
bool
|
636
|
+
end
|
637
|
+
|
638
|
+
private_class_method :setup_sync!
|
639
|
+
|
640
|
+
|
641
|
+
# Setup formatter tokens for the {#header} or {#body}.
|
642
|
+
#
|
643
|
+
# @private
|
644
|
+
#
|
645
|
+
# @param [:header | :body] name
|
646
|
+
# What formatter tokens we're setting up.
|
647
|
+
#
|
648
|
+
# @return [nil]
|
649
|
+
#
|
650
|
+
def self.setup_formatter_tokens! name, arg
|
651
|
+
# Bail out on `nil`
|
652
|
+
return nil if arg.nil?
|
653
|
+
|
654
|
+
# `self.header` or `self.body`
|
655
|
+
target = send name
|
656
|
+
|
657
|
+
# Bail out if we don't have it
|
658
|
+
return nil if target.nil?
|
659
|
+
|
660
|
+
case arg
|
661
|
+
when Array
|
662
|
+
# It's an array, just set it through the forwarder method
|
663
|
+
send "#{ name }=", arg
|
664
|
+
when Hash
|
665
|
+
# It's a hash, so look for a `:delete` or `:remove` key, and delete
|
666
|
+
# each of those from the target
|
667
|
+
Array( arg.fetch( :delete, arg[:remove] ) ).
|
668
|
+
each { |token| target.delete token.try( :to_sym ) }
|
669
|
+
end
|
670
|
+
|
671
|
+
nil
|
672
|
+
end # .setup_formatter_tokens!
|
673
|
+
|
674
|
+
private_class_method :setup_formatter_tokens!
|
675
|
+
|
676
|
+
|
677
|
+
# @param [SemanticLogger::Subscriber | Hash | String | Pathname | IO] dest
|
678
|
+
# Where to log with the "main" appender (what goes in {#appender}).
|
679
|
+
#
|
680
|
+
def self.setup_appender! dest
|
681
|
+
# Bail out if nothing to do
|
682
|
+
return nil if dest.nil?
|
683
|
+
|
684
|
+
# Save ref to current appender (if any) so we can remove it after adding
|
685
|
+
# the new one.
|
686
|
+
old_appender = @appender
|
687
|
+
|
688
|
+
@appender = case dest
|
689
|
+
when SemanticLogger::Subscriber, Hash
|
690
|
+
# Can be handled directly
|
691
|
+
SemanticLogger.add_appender dest
|
692
|
+
|
693
|
+
when String, Pathname
|
694
|
+
# Assume these are file paths
|
695
|
+
SemanticLogger.add_appender file_name: dest.to_s
|
696
|
+
|
697
|
+
else
|
698
|
+
SemanticLogger.add_appender \
|
699
|
+
io: dest,
|
700
|
+
formatter: NRSER::Log::Formatters::Color.new
|
701
|
+
end
|
702
|
+
|
703
|
+
# Remove the old appender (if there was one). This is done after adding
|
704
|
+
# the new one so that failing won't result with no appenders.
|
705
|
+
SemanticLogger.remove_appender( old_appender ) if old_appender
|
706
|
+
|
707
|
+
@appender
|
708
|
+
end
|
709
|
+
|
710
|
+
private_class_method :setup_appender!
|
711
|
+
|
712
|
+
|
713
|
+
# @!endgroup Setup Helpers
|
714
|
+
|
715
|
+
end # module NRSER::Log
|
716
|
+
|
717
|
+
|
718
|
+
# Post-Processing
|
719
|
+
# ========================================================================
|
720
|
+
|
721
|
+
# Mix-in the Mixin to NRSER itself
|
722
|
+
#
|
723
|
+
NRSER.include NRSER::Log::Mixin
|