berkeley_library-logging 0.2.1 → 0.2.5
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/.github/workflows/build.yml +1 -1
- data/.idea/inspectionProfiles/Project_Default.xml +2 -1
- data/.idea/logging.iml +30 -30
- data/.simplecov +0 -1
- data/CHANGES.md +25 -0
- data/README.md +1 -1
- data/Rakefile +3 -1
- data/artifacts/.keep +0 -0
- data/berkeley_library-logging.gemspec +2 -2
- data/lib/berkeley_library/logging/configurator.rb +6 -2
- data/lib/berkeley_library/logging/events.rb +80 -24
- data/lib/berkeley_library/logging/exception_serializer.rb +15 -0
- data/lib/berkeley_library/logging/formatters.rb +22 -18
- data/lib/berkeley_library/logging/module_info.rb +1 -1
- data/lib/berkeley_library/logging/safe_serializer.rb +77 -0
- data/spec/rails/ucblit/logging/configurator_spec.rb +99 -29
- data/spec/rails/ucblit/logging/formatters_spec.rb +59 -5
- data/spec/rails/ucblit/logging/loggers_spec.rb +14 -0
- data/spec/rails/ucblit/logging/safe_serializer_spec.rb +23 -0
- data/spec/standalone/ucblit/logging/formatters_spec.rb +57 -5
- data/spec/standalone/ucblit/logging/loggers_spec.rb +21 -1
- data/spec/standalone/ucblit/logging/safe_serializer_spec.rb +137 -0
- metadata +24 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cafd11d3f9d11029ae88c9ed475e08d9c5227d56f2924085145e6363fe76bfc1
|
|
4
|
+
data.tar.gz: 42eb37cd205ee71cbe710d86ddafd0a342ca31b3f54b40d988b16d5786ef6335
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc1a877b7dd123c92aa2cbfdcb8f55676bb6ef2257857f4af395e19c2d27fb950e3fcbf69813a0a639dd372f50a711e3b5cc84dfd593aa67dd5035534447a339
|
|
7
|
+
data.tar.gz: 2fc6bbf11a1d51aa90a15d0841df1c49a38aad8add0a824e1dfcab0bfe4d3489bb6a40d8afe56e3da255d6caac62d68535acfd726f4673604fb1548f5c71d0d0
|
data/.github/workflows/build.yml
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<inspection_tool class="Rubocop" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
8
8
|
<inspection_tool class="RubyCaseWithoutElseBlockInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
9
9
|
<inspection_tool class="RubyNilAnalysis" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
10
|
+
<inspection_tool class="RubyParameterNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
10
11
|
<inspection_tool class="RubyStringKeysInHashInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
|
11
12
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
|
12
13
|
<option name="processCode" value="true" />
|
|
@@ -14,4 +15,4 @@
|
|
|
14
15
|
<option name="processComments" value="true" />
|
|
15
16
|
</inspection_tool>
|
|
16
17
|
</profile>
|
|
17
|
-
</component>
|
|
18
|
+
</component>
|
data/.idea/logging.iml
CHANGED
|
@@ -4,32 +4,28 @@
|
|
|
4
4
|
<shared />
|
|
5
5
|
</component>
|
|
6
6
|
<component name="NewModuleRootManager">
|
|
7
|
-
<content url="file://$MODULE_DIR$"
|
|
8
|
-
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
|
|
9
|
-
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
|
10
|
-
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
11
|
-
</content>
|
|
7
|
+
<content url="file://$MODULE_DIR$" />
|
|
12
8
|
<orderEntry type="jdk" jdkName="RVM: ruby-2.7.4" jdkType="RUBY_SDK" />
|
|
13
9
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
14
|
-
<orderEntry type="library" scope="PROVIDED" name="actioncable (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
15
|
-
<orderEntry type="library" scope="PROVIDED" name="actionmailbox (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
16
|
-
<orderEntry type="library" scope="PROVIDED" name="actionmailer (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
17
|
-
<orderEntry type="library" scope="PROVIDED" name="actionpack (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
18
|
-
<orderEntry type="library" scope="PROVIDED" name="actiontext (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
19
|
-
<orderEntry type="library" scope="PROVIDED" name="actionview (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
20
|
-
<orderEntry type="library" scope="PROVIDED" name="activejob (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
21
|
-
<orderEntry type="library" scope="PROVIDED" name="activemodel (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
22
|
-
<orderEntry type="library" scope="PROVIDED" name="activerecord (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
23
|
-
<orderEntry type="library" scope="PROVIDED" name="activestorage (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
24
|
-
<orderEntry type="library" scope="PROVIDED" name="activesupport (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
25
|
-
<orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.
|
|
10
|
+
<orderEntry type="library" scope="PROVIDED" name="actioncable (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
11
|
+
<orderEntry type="library" scope="PROVIDED" name="actionmailbox (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
12
|
+
<orderEntry type="library" scope="PROVIDED" name="actionmailer (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
13
|
+
<orderEntry type="library" scope="PROVIDED" name="actionpack (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
14
|
+
<orderEntry type="library" scope="PROVIDED" name="actiontext (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
15
|
+
<orderEntry type="library" scope="PROVIDED" name="actionview (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
16
|
+
<orderEntry type="library" scope="PROVIDED" name="activejob (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
17
|
+
<orderEntry type="library" scope="PROVIDED" name="activemodel (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
18
|
+
<orderEntry type="library" scope="PROVIDED" name="activerecord (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
19
|
+
<orderEntry type="library" scope="PROVIDED" name="activestorage (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
20
|
+
<orderEntry type="library" scope="PROVIDED" name="activesupport (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
21
|
+
<orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.4.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
26
22
|
<orderEntry type="library" scope="PROVIDED" name="ansi (v1.5.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
27
23
|
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
28
24
|
<orderEntry type="library" scope="PROVIDED" name="brakeman (v4.10.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
29
25
|
<orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
30
26
|
<orderEntry type="library" scope="PROVIDED" name="bundle-audit (v0.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
31
27
|
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.2.14, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
32
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler-audit (v0.
|
|
28
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler-audit (v0.9.0.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
33
29
|
<orderEntry type="library" scope="PROVIDED" name="ci_reporter (v2.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
34
30
|
<orderEntry type="library" scope="PROVIDED" name="ci_reporter_rspec (v1.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
35
31
|
<orderEntry type="library" scope="PROVIDED" name="colorize (v0.8.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -39,7 +35,7 @@
|
|
|
39
35
|
<orderEntry type="library" scope="PROVIDED" name="docile (v1.4.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
40
36
|
<orderEntry type="library" scope="PROVIDED" name="dotenv (v2.7.6, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
41
37
|
<orderEntry type="library" scope="PROVIDED" name="erubi (v1.10.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
42
|
-
<orderEntry type="library" scope="PROVIDED" name="ffi (v1.15.
|
|
38
|
+
<orderEntry type="library" scope="PROVIDED" name="ffi (v1.15.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
43
39
|
<orderEntry type="library" scope="PROVIDED" name="globalid (v0.5.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
44
40
|
<orderEntry type="library" scope="PROVIDED" name="i18n (v1.8.10, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
45
41
|
<orderEntry type="library" scope="PROVIDED" name="io-console (v0.5.9, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -48,23 +44,23 @@
|
|
|
48
44
|
<orderEntry type="library" scope="PROVIDED" name="lograge (v0.11.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
49
45
|
<orderEntry type="library" scope="PROVIDED" name="loofah (v2.12.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
50
46
|
<orderEntry type="library" scope="PROVIDED" name="mail (v2.7.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
51
|
-
<orderEntry type="library" scope="PROVIDED" name="marcel (v1.0.
|
|
47
|
+
<orderEntry type="library" scope="PROVIDED" name="marcel (v1.0.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
52
48
|
<orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
53
|
-
<orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.1.
|
|
49
|
+
<orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.1.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
54
50
|
<orderEntry type="library" scope="PROVIDED" name="minitest (v5.14.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
55
51
|
<orderEntry type="library" scope="PROVIDED" name="nio4r (v2.5.8, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
56
|
-
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.12.
|
|
57
|
-
<orderEntry type="library" scope="PROVIDED" name="oj (v3.13.
|
|
52
|
+
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.12.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
53
|
+
<orderEntry type="library" scope="PROVIDED" name="oj (v3.13.9, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
58
54
|
<orderEntry type="library" scope="PROVIDED" name="ougai (v1.9.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
59
|
-
<orderEntry type="library" scope="PROVIDED" name="parallel (v1.
|
|
55
|
+
<orderEntry type="library" scope="PROVIDED" name="parallel (v1.21.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
60
56
|
<orderEntry type="library" scope="PROVIDED" name="parser (v3.0.2.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
61
57
|
<orderEntry type="library" scope="PROVIDED" name="racc (v1.5.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
62
58
|
<orderEntry type="library" scope="PROVIDED" name="rack (v2.2.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
63
59
|
<orderEntry type="library" scope="PROVIDED" name="rack-test (v1.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
64
|
-
<orderEntry type="library" scope="PROVIDED" name="rails (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
60
|
+
<orderEntry type="library" scope="PROVIDED" name="rails (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
65
61
|
<orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
66
|
-
<orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.4.
|
|
67
|
-
<orderEntry type="library" scope="PROVIDED" name="railties (v6.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
62
|
+
<orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
63
|
+
<orderEntry type="library" scope="PROVIDED" name="railties (v6.1.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
68
64
|
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
69
65
|
<orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
70
66
|
<orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -89,14 +85,18 @@
|
|
|
89
85
|
<orderEntry type="library" scope="PROVIDED" name="simplecov_json_formatter (v0.1.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
90
86
|
<orderEntry type="library" scope="PROVIDED" name="sprockets (v4.0.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
91
87
|
<orderEntry type="library" scope="PROVIDED" name="sprockets-rails (v3.2.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
92
|
-
<orderEntry type="library" scope="PROVIDED" name="terminal-table (v3.0.
|
|
88
|
+
<orderEntry type="library" scope="PROVIDED" name="terminal-table (v3.0.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
93
89
|
<orderEntry type="library" scope="PROVIDED" name="thor (v1.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
94
90
|
<orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
95
|
-
<orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v1.
|
|
91
|
+
<orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v1.8.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
96
92
|
<orderEntry type="library" scope="PROVIDED" name="websocket-driver (v0.7.5, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
97
93
|
<orderEntry type="library" scope="PROVIDED" name="websocket-extensions (v0.1.5, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
98
94
|
<orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
99
95
|
</component>
|
|
96
|
+
<component name="RModuleSettingsStorage">
|
|
97
|
+
<LOAD_PATH number="2" string0="$MODULE_DIR$/lib" string1="$MODULE_DIR$/spec" />
|
|
98
|
+
<I18N_FOLDERS number="0" />
|
|
99
|
+
</component>
|
|
100
100
|
<component name="RakeTasksCache">
|
|
101
101
|
<option name="myRootTask">
|
|
102
102
|
<RakeTaskImpl id="rake">
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<RakeTaskImpl description="Remove artifacts directory" fullCommand="clean" id="clean" />
|
|
111
111
|
<RakeTaskImpl description="Run all specs in spec directory, with coverage" fullCommand="coverage" id="coverage" />
|
|
112
112
|
<RakeTaskImpl description="Clean, check, build gem" fullCommand="default" id="default" />
|
|
113
|
-
<RakeTaskImpl description="Build berkeley_library-logging.gemspec as berkeley_library-logging-0.2.
|
|
113
|
+
<RakeTaskImpl description="Build berkeley_library-logging.gemspec as berkeley_library-logging-0.2.4.gem" fullCommand="gem" id="gem" />
|
|
114
114
|
<RakeTaskImpl description="Run RuboCop" fullCommand="rubocop" id="rubocop" />
|
|
115
115
|
<RakeTaskImpl id="rubocop">
|
|
116
116
|
<subtasks>
|
data/.simplecov
CHANGED
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
# 0.2.5 (2021-11-04)
|
|
2
|
+
|
|
3
|
+
- Rails event logs now include a subset of session attributes (`session_id` and `_csrf_token`).
|
|
4
|
+
Set `Rails.config.lograge.verbose_session_logging` to log the full session hash.
|
|
5
|
+
|
|
6
|
+
# 0.2.4 (2021-11-02)
|
|
7
|
+
|
|
8
|
+
- Rails event logs now include the following, in addition to the
|
|
9
|
+
headers already logged:
|
|
10
|
+
|
|
11
|
+
- `request.origin`
|
|
12
|
+
- `request.base_url`
|
|
13
|
+
- `request.x_csrf_token`
|
|
14
|
+
- `params[:authenticity_token]`
|
|
15
|
+
|
|
16
|
+
# 0.2.3 (2021-09-02)
|
|
17
|
+
|
|
18
|
+
- JSON formatter now strips all ANSI 7-bit C1 escapes from strings
|
|
19
|
+
(fixes [#1](https://github.com/BerkeleyLibrary/logging/issues/1) properly)
|
|
20
|
+
|
|
21
|
+
# 0.2.2 (2021-09-02)
|
|
22
|
+
|
|
23
|
+
- JSON formatter now strips ANSI color escapes from strings
|
|
24
|
+
(fixes [#1](https://github.com/BerkeleyLibrary/logging/issues/1))
|
|
25
|
+
|
|
1
26
|
# 0.2.1 (2021-08-19)
|
|
2
27
|
|
|
3
28
|
- Recursively log error cause
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# BerkeleyLibrary::Logging
|
|
2
2
|
|
|
3
3
|
[](https://github.com/BerkeleyLibrary/logging/actions/workflows/build.yml)
|
|
4
|
-
[](https://
|
|
4
|
+
[](https://rubygems.org/gems/berkeley_library-logging/)
|
|
5
5
|
|
|
6
6
|
Opinionated logging for UCB Library IT Rails applications.
|
|
7
7
|
|
data/Rakefile
CHANGED
|
@@ -19,9 +19,11 @@ end
|
|
|
19
19
|
# ------------------------------------------------------------
|
|
20
20
|
# Custom tasks
|
|
21
21
|
|
|
22
|
-
desc 'Remove artifacts directory'
|
|
22
|
+
desc 'Remove artifacts directory, except for .keep file'
|
|
23
23
|
task :clean do
|
|
24
24
|
FileUtils.rm_rf('artifacts')
|
|
25
|
+
FileUtils.mkdir('artifacts')
|
|
26
|
+
FileUtils.touch(File.join('artifacts', '.keep'))
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
desc 'Check test coverage, check code style, check gems for vulnerabilities'
|
data/artifacts/.keep
ADDED
|
File without changes
|
|
@@ -20,20 +20,20 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
spec.homepage = BerkeleyLibrary::Logging::ModuleInfo::HOMEPAGE
|
|
21
21
|
|
|
22
22
|
spec.files = `git ls-files -z`.split("\x0")
|
|
23
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features|artifacts)/})
|
|
24
24
|
spec.require_paths = ['lib']
|
|
25
25
|
|
|
26
26
|
spec.required_ruby_version = ">= #{ruby_version}"
|
|
27
27
|
|
|
28
28
|
spec.add_dependency 'activesupport', '~> 6.0'
|
|
29
29
|
spec.add_dependency 'amazing_print', '~> 1.1'
|
|
30
|
+
spec.add_dependency 'colorize', '~> 0.8.1'
|
|
30
31
|
spec.add_dependency 'lograge', '~> 0.11'
|
|
31
32
|
spec.add_dependency 'ougai', '~> 1.8'
|
|
32
33
|
|
|
33
34
|
spec.add_development_dependency 'brakeman', '~> 4.9'
|
|
34
35
|
spec.add_development_dependency 'bundle-audit', '~> 0.1'
|
|
35
36
|
spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
|
|
36
|
-
spec.add_development_dependency 'colorize', '~> 0.8'
|
|
37
37
|
spec.add_development_dependency 'dotenv', '~> 2.7'
|
|
38
38
|
spec.add_development_dependency 'irb', '~> 1.2' # workaroundfor https://github.com/bundler/bundler/issues/6929
|
|
39
39
|
spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
|
|
@@ -22,9 +22,13 @@ module BerkeleyLibrary
|
|
|
22
22
|
def configure_lograge(config)
|
|
23
23
|
return unless config.respond_to?(:lograge)
|
|
24
24
|
|
|
25
|
-
config.lograge
|
|
25
|
+
lograge_config = config.lograge
|
|
26
|
+
|
|
27
|
+
custom_options = Events.extract_data_for_lograge(lograge_config)
|
|
28
|
+
|
|
29
|
+
lograge_config.tap do |lograge|
|
|
26
30
|
lograge.enabled = true
|
|
27
|
-
lograge.custom_options =
|
|
31
|
+
lograge.custom_options = custom_options
|
|
28
32
|
lograge.formatter = Formatters.lograge_formatter
|
|
29
33
|
end
|
|
30
34
|
end
|
|
@@ -1,37 +1,93 @@
|
|
|
1
|
+
require 'berkeley_library/logging/safe_serializer'
|
|
2
|
+
|
|
1
3
|
module BerkeleyLibrary
|
|
2
4
|
module Logging
|
|
3
5
|
module Events
|
|
6
|
+
LOGGED_REQUEST_ATTRIBUTES = %i[origin base_url x_csrf_token].freeze
|
|
7
|
+
LOGGED_SESSION_ATTRIBUTES = %i[session_id _csrf_token].freeze
|
|
8
|
+
LOGGED_PARAMETERS = [:authenticity_token].freeze
|
|
9
|
+
LOGGED_HEADERS = {
|
|
10
|
+
# yes, RFC 2616 uses a variant spelling for 'referrer', it's a known issue
|
|
11
|
+
# https://tools.ietf.org/html/rfc2616#section-14.36
|
|
12
|
+
referer: 'HTTP_REFERER',
|
|
13
|
+
request_id: 'action_dispatch.request_id',
|
|
14
|
+
remote_ip: 'action_dispatch.remote_ip',
|
|
15
|
+
remote_addr: 'REMOTE_ADDR',
|
|
16
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
|
17
|
+
forwarded: 'HTTP_FORWARDED' # RFC 7239
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
4
20
|
class << self
|
|
5
|
-
|
|
6
|
-
|
|
21
|
+
|
|
22
|
+
def extract_data_for_lograge(lograge_config)
|
|
23
|
+
verbose_session_logging = lograge_config.verbose_session_logging
|
|
24
|
+
|
|
25
|
+
->(event) { extract_event_data(event.payload, verbose_session_logging) }
|
|
7
26
|
end
|
|
8
27
|
|
|
9
28
|
private
|
|
10
29
|
|
|
11
|
-
def extract_event_data(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
30
|
+
def extract_event_data(payload, verbose_session_logging)
|
|
31
|
+
[
|
|
32
|
+
extract_headers(payload),
|
|
33
|
+
extract_request_attributes(payload),
|
|
34
|
+
extract_param_values(payload),
|
|
35
|
+
extract_session(payload, verbose_session_logging)
|
|
36
|
+
].inject({ time: Time.now }) do |data, values|
|
|
37
|
+
clean_values = SafeSerializer.serialize(values)
|
|
38
|
+
data.merge(clean_values)
|
|
39
|
+
end
|
|
15
40
|
end
|
|
16
41
|
|
|
17
|
-
def
|
|
18
|
-
return {} unless (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
def extract_param_values(payload)
|
|
43
|
+
return {} unless (params = payload[:params])
|
|
44
|
+
|
|
45
|
+
LOGGED_PARAMETERS.each_with_object({}) do |param, values|
|
|
46
|
+
next unless (param_val = params[param])
|
|
47
|
+
|
|
48
|
+
values[param] = param_val
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def extract_request_attributes(payload)
|
|
53
|
+
return {} unless (request = payload[:request])
|
|
54
|
+
|
|
55
|
+
LOGGED_REQUEST_ATTRIBUTES.each_with_object({}) do |attr, values|
|
|
56
|
+
next unless request.respond_to?(attr)
|
|
57
|
+
next if (attr_val = request.send(attr)).nil?
|
|
58
|
+
|
|
59
|
+
values[attr] = attr_val
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def extract_headers(payload)
|
|
64
|
+
return {} unless (headers = payload[:headers])
|
|
65
|
+
|
|
66
|
+
LOGGED_HEADERS.each_with_object({}) do |(key, header), values|
|
|
67
|
+
next unless (header_val = headers[header])
|
|
68
|
+
|
|
69
|
+
values[key] = header_val
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def extract_session(payload, verbose_session_logging)
|
|
74
|
+
return {} unless (request = payload[:request])
|
|
75
|
+
return {} unless (session = request.session)
|
|
76
|
+
return {} unless session.respond_to?(:to_hash)
|
|
77
|
+
|
|
78
|
+
session_hash = session_hash(session, verbose_session_logging)
|
|
79
|
+
|
|
80
|
+
{ session: session_hash }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def session_hash(session, verbose)
|
|
84
|
+
raw_session_hash = session.to_hash
|
|
85
|
+
return raw_session_hash if verbose
|
|
86
|
+
|
|
87
|
+
LOGGED_SESSION_ATTRIBUTES.filter_map do |attr|
|
|
88
|
+
attr_str = attr.to_s
|
|
89
|
+
[attr, raw_session_hash[attr_str]] if raw_session_hash.key?(attr_str)
|
|
90
|
+
end.to_h
|
|
35
91
|
end
|
|
36
92
|
end
|
|
37
93
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module BerkeleyLibrary
|
|
2
|
+
module Logging
|
|
3
|
+
module ExceptionSerializer
|
|
4
|
+
def serialize_exc(ex, serialized = Set.new)
|
|
5
|
+
raw_result = { name: ex.class.name, message: ex.message, stack: ex.backtrace }
|
|
6
|
+
raw_result.tap do |result|
|
|
7
|
+
next unless (cause = ex.cause)
|
|
8
|
+
next if (serialized << ex).include?(cause) # prevent circular references
|
|
9
|
+
|
|
10
|
+
result[:cause] = serialize_exc(cause, serialized)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
require 'ougai'
|
|
2
|
+
require 'berkeley_library/logging/exception_serializer'
|
|
2
3
|
|
|
3
4
|
module BerkeleyLibrary
|
|
4
5
|
module Logging
|
|
5
6
|
module Formatters
|
|
6
7
|
|
|
7
8
|
class << self
|
|
9
|
+
|
|
10
|
+
# See https://stackoverflow.com/a/14693789/27358
|
|
11
|
+
ANSI_7C1_RE = %r{\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])}.freeze
|
|
12
|
+
|
|
8
13
|
def new_json_formatter
|
|
9
14
|
Bunyan.new
|
|
10
15
|
end
|
|
@@ -23,26 +28,22 @@ module BerkeleyLibrary
|
|
|
23
28
|
|
|
24
29
|
{ msg: message }
|
|
25
30
|
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# ------------------------------------------------------------
|
|
29
|
-
# Private helper classes
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
def strip_ansi_escapes(message)
|
|
33
|
+
return unless message
|
|
34
|
+
return message.gsub(ANSI_7C1_RE, '') if message.is_a?(String)
|
|
35
|
+
return message.map { |v| strip_ansi_escapes(v) } if message.is_a?(Array)
|
|
36
|
+
return message.transform_values { |v| strip_ansi_escapes(v) } if message.is_a?(Hash)
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
end
|
|
38
|
+
message
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
# ------------------------------------------------------------
|
|
43
|
+
# Private helper classes
|
|
43
44
|
|
|
44
45
|
class Readable < Ougai::Formatters::Readable
|
|
45
|
-
include
|
|
46
|
+
include ExceptionSerializer
|
|
46
47
|
|
|
47
48
|
protected
|
|
48
49
|
|
|
@@ -58,9 +59,11 @@ module BerkeleyLibrary
|
|
|
58
59
|
" #{err_hash[:name]} (#{err_hash[:message]}):".tap do |msg|
|
|
59
60
|
next unless (stack = err_hash[:stack])
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
trace_indent = (' ' * @trace_indent)
|
|
63
|
+
trace_separator = "\n#{trace_indent}"
|
|
64
|
+
|
|
65
|
+
msg << trace_separator
|
|
66
|
+
msg << stack.join(trace_separator)
|
|
64
67
|
|
|
65
68
|
next unless (cause_hash = err_hash[:cause])
|
|
66
69
|
|
|
@@ -74,15 +77,16 @@ module BerkeleyLibrary
|
|
|
74
77
|
|
|
75
78
|
class Bunyan < Ougai::Formatters::Bunyan
|
|
76
79
|
include Ougai::Logging::Severity
|
|
77
|
-
include
|
|
80
|
+
include ExceptionSerializer
|
|
78
81
|
|
|
79
82
|
def _call(severity, time, progname, data)
|
|
80
83
|
original_data = Formatters.ensure_hash(data)
|
|
84
|
+
decolorized_data = Formatters.strip_ansi_escapes(original_data)
|
|
81
85
|
|
|
82
86
|
# Ougai::Formatters::Bunyan replaces the human-readable severity string
|
|
83
87
|
# with a numeric level, so we add it here as a separate attribute
|
|
84
88
|
severity = ensure_human_readable(severity)
|
|
85
|
-
merged_data = { severity: severity }.merge(
|
|
89
|
+
merged_data = { severity: severity }.merge(decolorized_data)
|
|
86
90
|
super(severity, time, progname, merged_data)
|
|
87
91
|
end
|
|
88
92
|
|
|
@@ -7,7 +7,7 @@ module BerkeleyLibrary
|
|
|
7
7
|
SUMMARY = 'Opinionated Ruby/Rails logging for UC Berkeley Library'.freeze
|
|
8
8
|
DESCRIPTION = 'A gem providing shared logging code for UC Berkeley Library gems and Rails applications'.freeze
|
|
9
9
|
LICENSE = 'MIT'.freeze
|
|
10
|
-
VERSION = '0.2.
|
|
10
|
+
VERSION = '0.2.5'.freeze
|
|
11
11
|
HOMEPAGE = 'https://github.com/BerkeleyLibrary/logging'.freeze
|
|
12
12
|
|
|
13
13
|
private_class_method :new
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
require 'berkeley_library/logging/exception_serializer'
|
|
3
|
+
|
|
4
|
+
module BerkeleyLibrary
|
|
5
|
+
module Logging
|
|
6
|
+
# Some of values include recursive structures
|
|
7
|
+
# that cause SystemStackErrors in JSON serialization,
|
|
8
|
+
# so we convert them all to strings
|
|
9
|
+
class SafeSerializer
|
|
10
|
+
include ExceptionSerializer
|
|
11
|
+
|
|
12
|
+
RAW_TYPES = [NilClass, FalseClass, TrueClass, Numeric, String, Symbol, Date, Time].freeze
|
|
13
|
+
|
|
14
|
+
def initialize(value)
|
|
15
|
+
@value = value
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def serialize(value)
|
|
20
|
+
SafeSerializer.new(value).serialized_value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def placeholder_for(value)
|
|
24
|
+
"#<#{value.class}:#{value.object_id}> (recursive reference)"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def serialized_value
|
|
29
|
+
@serialized_value ||= serialize(@value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
35
|
+
def serialize(value)
|
|
36
|
+
return value if safe_raw_value?(value)
|
|
37
|
+
return SafeSerializer.placeholder_for(value) if serialized_values.include?(value)
|
|
38
|
+
|
|
39
|
+
serialized_values << value
|
|
40
|
+
|
|
41
|
+
return serialize_hash(value) if value.is_a?(Hash)
|
|
42
|
+
return serialize_hash(value.to_hash) if value.respond_to?(:to_hash)
|
|
43
|
+
return serialize_array(value) if value.is_a?(Array)
|
|
44
|
+
return serialize_array(value.to_ary) if value.respond_to?(:to_ary)
|
|
45
|
+
return serialize_exc(value, serialized_values) if value.is_a?(Exception)
|
|
46
|
+
|
|
47
|
+
value.to_s
|
|
48
|
+
end
|
|
49
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
50
|
+
|
|
51
|
+
def safe_raw_value?(value)
|
|
52
|
+
return true if rails_time_with_zone?(value)
|
|
53
|
+
|
|
54
|
+
RAW_TYPES.any? { |t| value.is_a?(t) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rails_time_with_zone?(value)
|
|
58
|
+
defined?(ActiveSupport::TimeWithZone) && value.is_a?(ActiveSupport::TimeWithZone)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def serialize_array(value)
|
|
62
|
+
value.map { |v| serialize(v) }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def serialize_hash(value)
|
|
66
|
+
value.each_with_object({}) do |(k, v), h|
|
|
67
|
+
k1, v1 = [k, v].map { |x| serialize(x) }
|
|
68
|
+
h[k1] = v1
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def serialized_values
|
|
73
|
+
@serialized_values ||= Set.new
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -30,36 +30,106 @@ module BerkeleyLibrary
|
|
|
30
30
|
expect(lograge.enabled).to eq(true)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
context 'events' do
|
|
34
|
+
let(:params) { { authenticity_token: '8675309' } }
|
|
35
|
+
|
|
36
|
+
let(:session_hash) do
|
|
37
|
+
{
|
|
38
|
+
'session_id' => '17cd06b1b7cb9744e8fa626ef5f37c67',
|
|
39
|
+
'user' => {
|
|
40
|
+
'id' => 71,
|
|
41
|
+
'user_name' => 'Ms. Magoo',
|
|
42
|
+
'created_at' => '2021-10-14T09:24:42.730-07:00',
|
|
43
|
+
'updated_at' => '2021-10-14T09:24:42.729-07:00',
|
|
44
|
+
'user_role' => 'Administrator',
|
|
45
|
+
'user_active' => true,
|
|
46
|
+
'uid' => 1_684_944,
|
|
47
|
+
'updated_by' => 'Dr. Pibb'
|
|
48
|
+
},
|
|
49
|
+
'expires_at' => '2021-11-03T12:30:01.281-07:00',
|
|
50
|
+
'_csrf_token' => 'HiN1xUxFcOvWvoe2nwoBSGlmGSN6x0jprpSqDrzquxA='
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
let(:request_headers) do
|
|
55
|
+
{
|
|
56
|
+
'HTTP_REFERER' => 'value from HTTP_REFERER',
|
|
57
|
+
'action_dispatch.request_id' => 'value from action_dispatch.request_id',
|
|
58
|
+
'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
|
|
59
|
+
'REMOTE_ADDR' => 'value from REMOTE_ADDR',
|
|
60
|
+
'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
|
|
61
|
+
'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
let(:expected_header_map) do
|
|
66
|
+
{
|
|
67
|
+
referer: 'HTTP_REFERER',
|
|
68
|
+
request_id: 'action_dispatch.request_id',
|
|
69
|
+
remote_ip: 'action_dispatch.remote_ip',
|
|
70
|
+
remote_addr: 'REMOTE_ADDR',
|
|
71
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
|
72
|
+
forwarded: 'HTTP_FORWARDED'
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
attr_reader :session, :request, :payload, :event
|
|
77
|
+
|
|
78
|
+
before(:each) do
|
|
79
|
+
@session = instance_double(ActionDispatch::Request::Session)
|
|
80
|
+
allow(session).to receive(:to_hash).and_return(session_hash)
|
|
81
|
+
|
|
82
|
+
@request = instance_double(ActionDispatch::Request)
|
|
83
|
+
allow(request).to receive(:origin).and_return('http://example.org:3000')
|
|
84
|
+
allow(request).to receive(:base_url).and_return('https://example.org:3443')
|
|
85
|
+
allow(request).to receive(:x_csrf_token).and_return('5551212')
|
|
86
|
+
allow(request).to receive(:session).and_return(session)
|
|
87
|
+
|
|
88
|
+
@payload = {
|
|
89
|
+
params: params,
|
|
90
|
+
request: request,
|
|
91
|
+
headers: request_headers
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@event = instance_double(ActiveSupport::Notifications::Event)
|
|
95
|
+
allow(event).to receive(:payload).and_return(payload)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'extracts request info from log events' do
|
|
99
|
+
Configurator.configure(config)
|
|
100
|
+
data = config.lograge.custom_options.call(event)
|
|
36
101
|
|
|
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
|
-
|
|
102
|
+
expect(data).to be_a(Hash)
|
|
103
|
+
expect(data[:time]).to be_a(Time)
|
|
104
|
+
expect(data[:time].to_i).to be_within(60).of(Time.now.to_i)
|
|
105
|
+
|
|
106
|
+
expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
|
|
107
|
+
|
|
108
|
+
expect(data[:authenticity_token]).to eq(params[:authenticity_token])
|
|
109
|
+
|
|
110
|
+
Events::LOGGED_REQUEST_ATTRIBUTES.each do |attr|
|
|
111
|
+
expect(data[attr]).to eq(request.send(attr))
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'includes the entire session if `verbose_session_logging` is true' do
|
|
116
|
+
config.lograge.verbose_session_logging = true
|
|
117
|
+
Configurator.configure(config)
|
|
118
|
+
data = config.lograge.custom_options.call(event)
|
|
119
|
+
|
|
120
|
+
expect(data[:session]).to eq(session_hash)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'includes only the session ID by default' do
|
|
124
|
+
Configurator.configure(config)
|
|
125
|
+
data = config.lograge.custom_options.call(event)
|
|
126
|
+
|
|
127
|
+
expected_hash = Events::LOGGED_SESSION_ATTRIBUTES.each_with_object({}) do |attr, h|
|
|
128
|
+
h[attr] = session_hash[attr.to_s]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
expect(data[:session]).to eq(expected_hash)
|
|
132
|
+
end
|
|
63
133
|
end
|
|
64
134
|
|
|
65
135
|
it 'formats Lograge data as a hash' do
|
|
@@ -1,27 +1,81 @@
|
|
|
1
1
|
require 'rails_helper'
|
|
2
2
|
require 'json'
|
|
3
|
+
require 'colorize'
|
|
3
4
|
require 'berkeley_library/logging'
|
|
4
5
|
|
|
5
6
|
module BerkeleyLibrary
|
|
6
7
|
module Logging
|
|
7
8
|
describe Formatters do
|
|
8
9
|
describe :new_json_formatter do
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
attr_reader :out, :logger
|
|
11
|
+
|
|
12
|
+
before(:each) do
|
|
13
|
+
@out = StringIO.new
|
|
14
|
+
@logger = Logger.new(out)
|
|
12
15
|
logger.formatter = Formatters.new_json_formatter
|
|
16
|
+
end
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
it 'supports tagged logging' do
|
|
19
|
+
tagged_logger = ActiveSupport::TaggedLogging.new(logger)
|
|
15
20
|
|
|
16
21
|
expected_tag = 'hello'
|
|
17
22
|
expected_msg = 'this is a test'
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
tagged_logger.tagged(expected_tag) { tagged_logger.info(expected_msg) }
|
|
20
25
|
|
|
21
26
|
logged_json = JSON.parse(out.string)
|
|
22
27
|
expect(logged_json['msg']).to eq(expected_msg)
|
|
23
28
|
expect(logged_json['tags']).to eq([expected_tag])
|
|
24
29
|
end
|
|
30
|
+
|
|
31
|
+
it 'decolorizes ANSI-colored strings' do
|
|
32
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
33
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
34
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
35
|
+
|
|
36
|
+
expected_string = colors.map(&:to_s).join(' ')
|
|
37
|
+
|
|
38
|
+
logger.info(colorized_string)
|
|
39
|
+
logged_json = JSON.parse(out.string)
|
|
40
|
+
msg = logged_json['msg']
|
|
41
|
+
expect(msg).not_to include("\u001b")
|
|
42
|
+
expect(msg).to eq(expected_string)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'decolorizes ANSI-colored strings in attached data' do
|
|
46
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
47
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
48
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
49
|
+
|
|
50
|
+
expected_string = colors.map(&:to_s).join(' ')
|
|
51
|
+
|
|
52
|
+
data = {
|
|
53
|
+
the_string: colorized_string,
|
|
54
|
+
additional_data: {
|
|
55
|
+
not_a_string: 12,
|
|
56
|
+
another_string: colorized_string,
|
|
57
|
+
more_strings: [colorized_string, colorized_string]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
logger.info('a colorized string', data)
|
|
61
|
+
|
|
62
|
+
logged_json = JSON.parse(out.string)
|
|
63
|
+
data = logged_json
|
|
64
|
+
expect(data['the_string']).to eq(expected_string)
|
|
65
|
+
additional_data = data['additional_data']
|
|
66
|
+
expect(additional_data['not_a_string']).to eq(12)
|
|
67
|
+
expect(additional_data['another_string']).to eq(expected_string)
|
|
68
|
+
expect(additional_data['more_strings']).to eq([expected_string, expected_string])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'removes ANSI formatting from ActiveRecord logs' do
|
|
72
|
+
original = " \e[1m\e[36mLendingItem Load (2.0ms)\e[0m \e[1m\e[34mSELECT \"lending_items\".* FROM \"lending_items\" WHERE \"lending_items\".\"directory\" = $1 LIMIT $2\e[0m [[\"directory\", \"b135297126_C068087930\"], [\"LIMIT\", 1]]"
|
|
73
|
+
expected = ' LendingItem Load (2.0ms) SELECT "lending_items".* FROM "lending_items" WHERE "lending_items"."directory" = $1 LIMIT $2 [["directory", "b135297126_C068087930"], ["LIMIT", 1]]'
|
|
74
|
+
logger.info(original)
|
|
75
|
+
logged_json = JSON.parse(out.string)
|
|
76
|
+
msg = logged_json['msg']
|
|
77
|
+
expect(msg).to eq(expected)
|
|
78
|
+
end
|
|
25
79
|
end
|
|
26
80
|
|
|
27
81
|
describe :ensure_hash do
|
|
@@ -14,6 +14,20 @@ module BerkeleyLibrary
|
|
|
14
14
|
Rails.env = orig_rails_env
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
describe :new_readable_logger do
|
|
18
|
+
it 'logs ANSI colors' do
|
|
19
|
+
out = StringIO.new
|
|
20
|
+
|
|
21
|
+
logger = Loggers.new_readable_logger(out)
|
|
22
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
23
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
24
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
25
|
+
|
|
26
|
+
logger.info(colorized_string)
|
|
27
|
+
expect(out.string).to include(colorized_string)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
17
31
|
describe :new_json_logger do
|
|
18
32
|
it 'supports tagged logging' do
|
|
19
33
|
out = StringIO.new
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
require 'active_support/time'
|
|
4
|
+
|
|
5
|
+
module BerkeleyLibrary
|
|
6
|
+
module Logging
|
|
7
|
+
describe SafeSerializer do
|
|
8
|
+
describe :serialize do
|
|
9
|
+
it 'handles ActiveSupport::TimeWithZone' do
|
|
10
|
+
Time.zone = 'America/Los_Angeles'
|
|
11
|
+
|
|
12
|
+
t = Time.current
|
|
13
|
+
expect(t).to be_a(ActiveSupport::TimeWithZone) # just to be sure
|
|
14
|
+
|
|
15
|
+
expect(SafeSerializer.serialize(t)).to be(t)
|
|
16
|
+
|
|
17
|
+
h = { time: t }
|
|
18
|
+
expect(SafeSerializer.serialize(h)).to eq(h)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -1,27 +1,79 @@
|
|
|
1
1
|
require 'standalone_helper'
|
|
2
2
|
require 'json'
|
|
3
|
+
require 'colorize'
|
|
3
4
|
require 'berkeley_library/logging'
|
|
4
5
|
|
|
5
6
|
module BerkeleyLibrary
|
|
6
7
|
module Logging
|
|
7
8
|
describe Formatters do
|
|
8
9
|
describe :new_json_formatter do
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
attr_reader :out, :logger
|
|
11
|
+
|
|
12
|
+
before(:each) do
|
|
13
|
+
@out = StringIO.new
|
|
14
|
+
@logger = Logger.new(out)
|
|
12
15
|
logger.formatter = Formatters.new_json_formatter
|
|
16
|
+
end
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
it 'supports tagged logging' do
|
|
19
|
+
tagged_logger = ActiveSupport::TaggedLogging.new(logger)
|
|
15
20
|
|
|
16
21
|
expected_tag = 'hello'
|
|
17
22
|
expected_msg = 'this is a test'
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
tagged_logger.tagged(expected_tag) { tagged_logger.info(expected_msg) }
|
|
20
25
|
|
|
21
26
|
logged_json = JSON.parse(out.string)
|
|
22
27
|
expect(logged_json['msg']).to eq(expected_msg)
|
|
23
28
|
expect(logged_json['tags']).to eq([expected_tag])
|
|
24
29
|
end
|
|
30
|
+
|
|
31
|
+
it 'decolorizes ANSI-colored strings' do
|
|
32
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
33
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
34
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
35
|
+
|
|
36
|
+
expected_string = colors.map(&:to_s).join(' ')
|
|
37
|
+
|
|
38
|
+
logger.info(colorized_string)
|
|
39
|
+
logged_json = JSON.parse(out.string)
|
|
40
|
+
msg = logged_json['msg']
|
|
41
|
+
expect(msg).not_to include("\u001b")
|
|
42
|
+
expect(msg).to eq(expected_string)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'decolorizes ANSI-colored strings in attached data' do
|
|
46
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
47
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
48
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
49
|
+
|
|
50
|
+
expected_string = colors.map(&:to_s).join(' ')
|
|
51
|
+
|
|
52
|
+
data = {
|
|
53
|
+
the_string: colorized_string,
|
|
54
|
+
additional_data: {
|
|
55
|
+
another_string: colorized_string,
|
|
56
|
+
more_strings: [colorized_string, colorized_string]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
logger.info('a colorized string', data)
|
|
60
|
+
|
|
61
|
+
logged_json = JSON.parse(out.string)
|
|
62
|
+
data = logged_json
|
|
63
|
+
expect(data['the_string']).to eq(expected_string)
|
|
64
|
+
additional_data = data['additional_data']
|
|
65
|
+
expect(additional_data['another_string']).to eq(expected_string)
|
|
66
|
+
expect(additional_data['more_strings']).to eq([expected_string, expected_string])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'removes ANSI formatting from ActiveRecord logs' do
|
|
70
|
+
original = " \e[1m\e[36mLendingItem Load (2.0ms)\e[0m \e[1m\e[34mSELECT \"lending_items\".* FROM \"lending_items\" WHERE \"lending_items\".\"directory\" = $1 LIMIT $2\e[0m [[\"directory\", \"b135297126_C068087930\"], [\"LIMIT\", 1]]"
|
|
71
|
+
expected = ' LendingItem Load (2.0ms) SELECT "lending_items".* FROM "lending_items" WHERE "lending_items"."directory" = $1 LIMIT $2 [["directory", "b135297126_C068087930"], ["LIMIT", 1]]'
|
|
72
|
+
logger.info(original)
|
|
73
|
+
logged_json = JSON.parse(out.string)
|
|
74
|
+
msg = logged_json['msg']
|
|
75
|
+
expect(msg).to eq(expected)
|
|
76
|
+
end
|
|
25
77
|
end
|
|
26
78
|
|
|
27
79
|
describe :ensure_hash do
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'standalone_helper'
|
|
2
2
|
require 'json'
|
|
3
|
+
require 'colorize'
|
|
3
4
|
|
|
4
5
|
module BerkeleyLibrary
|
|
5
6
|
module Logging
|
|
@@ -23,6 +24,18 @@ module BerkeleyLibrary
|
|
|
23
24
|
Object.send(:remove_const, :TestError)
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
describe :new_readable_logger do
|
|
28
|
+
it 'logs ANSI colors' do
|
|
29
|
+
logger = Loggers.new_readable_logger(out)
|
|
30
|
+
colors = %i[red green yellow blue magenta cyan]
|
|
31
|
+
colorized_string = colors.map { |c| c.to_s.colorize(c) }.join(' ')
|
|
32
|
+
expect(colorized_string).to include("\u001b") # just to be sure
|
|
33
|
+
|
|
34
|
+
logger.info(colorized_string)
|
|
35
|
+
expect(out.string).to include(colorized_string)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
26
39
|
describe :new_json_logger do
|
|
27
40
|
|
|
28
41
|
# TODO: rewrite this as a matcher
|
|
@@ -114,7 +127,14 @@ module BerkeleyLibrary
|
|
|
114
127
|
end
|
|
115
128
|
end
|
|
116
129
|
|
|
117
|
-
|
|
130
|
+
begin
|
|
131
|
+
Loggers.new_json_logger(out).error(ex_outer)
|
|
132
|
+
rescue SystemStackError => e
|
|
133
|
+
RSpec::Expectations.fail_with("Expected no SystemStackError, but got #{e}: #{e.backtrace[0]}")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
expect(out.string).to include(msg_outer)
|
|
137
|
+
expect(out.string).to include(msg_inner)
|
|
118
138
|
end
|
|
119
139
|
# rubocop:enable Naming/RescuedExceptionsVariableName
|
|
120
140
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'standalone_helper'
|
|
2
|
+
|
|
3
|
+
module BerkeleyLibrary
|
|
4
|
+
module Logging
|
|
5
|
+
describe SafeSerializer do
|
|
6
|
+
describe :serialize do
|
|
7
|
+
it 'returns primitives unchanged' do
|
|
8
|
+
values = [
|
|
9
|
+
nil,
|
|
10
|
+
false,
|
|
11
|
+
true,
|
|
12
|
+
1,
|
|
13
|
+
1.0,
|
|
14
|
+
'1/3'.to_r,
|
|
15
|
+
'a string',
|
|
16
|
+
:a_symbol,
|
|
17
|
+
Date.today,
|
|
18
|
+
Time.now
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
aggregate_failures do
|
|
22
|
+
values.each do |original|
|
|
23
|
+
actual = SafeSerializer.serialize(original)
|
|
24
|
+
expect(actual).to be(original)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'returns an object as a string' do
|
|
30
|
+
value = Object.new
|
|
31
|
+
expect(SafeSerializer.serialize(value)).to eq(value.to_s)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'returns a hash as a hash' do
|
|
35
|
+
hash = { a: 1, b: 2 }
|
|
36
|
+
expect(SafeSerializer.serialize(hash)).to eq(hash)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'returns an array as an array' do
|
|
40
|
+
arr = [0, 1, 2, 'elvis', false]
|
|
41
|
+
expect(SafeSerializer.serialize(arr)).to eq(arr)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'cleans nested values' do
|
|
45
|
+
b_value = Object.new
|
|
46
|
+
c_key = Object.new
|
|
47
|
+
d_value = Object.new
|
|
48
|
+
|
|
49
|
+
d_array = ['d', :d, { d: "\ud7ff", 'd' => d_value }]
|
|
50
|
+
|
|
51
|
+
h = {
|
|
52
|
+
a: 1,
|
|
53
|
+
b: b_value,
|
|
54
|
+
c_key => 'c value',
|
|
55
|
+
0xd => d_array,
|
|
56
|
+
"\uEEEE" => 0xe
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
expected = {
|
|
60
|
+
a: 1,
|
|
61
|
+
b: b_value.to_s,
|
|
62
|
+
c_key.to_s => 'c value',
|
|
63
|
+
0xd => ['d', :d, { d: "\ud7ff", 'd' => d_value.to_s }],
|
|
64
|
+
"\uEEEE" => 0xe
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
actual = SafeSerializer.serialize(h)
|
|
68
|
+
expect(actual).to eq(expected)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'handles recursive structures' do
|
|
72
|
+
a = []
|
|
73
|
+
h = { a: a }
|
|
74
|
+
a << h
|
|
75
|
+
|
|
76
|
+
h_expected = { a: [SafeSerializer.placeholder_for(h)] }
|
|
77
|
+
a_expected = [{ a: SafeSerializer.placeholder_for(a) }]
|
|
78
|
+
|
|
79
|
+
expect(SafeSerializer.serialize(h)).to eq(h_expected)
|
|
80
|
+
expect(SafeSerializer.serialize(a)).to eq(a_expected)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context 'exceptions' do
|
|
84
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
|
85
|
+
before(:each) do
|
|
86
|
+
class ::TestError < StandardError
|
|
87
|
+
attr_writer :cause
|
|
88
|
+
|
|
89
|
+
def cause
|
|
90
|
+
@cause || super
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
|
95
|
+
|
|
96
|
+
after(:each) do
|
|
97
|
+
Object.send(:remove_const, :TestError)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# rubocop:disable Naming/RescuedExceptionsVariableName
|
|
101
|
+
it 'handles exceptions' do
|
|
102
|
+
msg_outer = 'Help I am trapped in the outer part of a unit test'
|
|
103
|
+
msg_inner = 'Help I am trapped in the inner part of a unit test'
|
|
104
|
+
|
|
105
|
+
begin
|
|
106
|
+
raise TestError, msg_inner
|
|
107
|
+
rescue TestError => ex_inner
|
|
108
|
+
begin
|
|
109
|
+
raise TestError, msg_outer
|
|
110
|
+
rescue TestError => ex_outer
|
|
111
|
+
ex_inner.cause = ex_outer
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
expect(ex_outer.cause).to eq(ex_inner) # just to be sure
|
|
116
|
+
expect(ex_inner.cause).to eq(ex_outer) # just to be sure
|
|
117
|
+
|
|
118
|
+
expected = {
|
|
119
|
+
name: 'TestError',
|
|
120
|
+
message: msg_outer,
|
|
121
|
+
stack: ex_outer.backtrace,
|
|
122
|
+
cause: {
|
|
123
|
+
name: 'TestError',
|
|
124
|
+
message: msg_inner,
|
|
125
|
+
stack: ex_inner.backtrace
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
expect(SafeSerializer.serialize(ex_outer)).to eq(expected)
|
|
130
|
+
end
|
|
131
|
+
# rubocop:enable Naming/RescuedExceptionsVariableName
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: berkeley_library-logging
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Moles
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-11-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -38,6 +38,20 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '1.1'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: colorize
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.8.1
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.8.1
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: lograge
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -108,20 +122,6 @@ dependencies:
|
|
|
108
122
|
- - "~>"
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
124
|
version: '1.0'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: colorize
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - "~>"
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '0.8'
|
|
118
|
-
type: :development
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - "~>"
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '0.8'
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: dotenv
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -290,17 +290,20 @@ files:
|
|
|
290
290
|
- LICENSE.md
|
|
291
291
|
- README.md
|
|
292
292
|
- Rakefile
|
|
293
|
+
- artifacts/.keep
|
|
293
294
|
- berkeley_library-logging.gemspec
|
|
294
295
|
- docker-compose.yml
|
|
295
296
|
- lib/berkeley_library/logging.rb
|
|
296
297
|
- lib/berkeley_library/logging/configurator.rb
|
|
297
298
|
- lib/berkeley_library/logging/env.rb
|
|
298
299
|
- lib/berkeley_library/logging/events.rb
|
|
300
|
+
- lib/berkeley_library/logging/exception_serializer.rb
|
|
299
301
|
- lib/berkeley_library/logging/formatters.rb
|
|
300
302
|
- lib/berkeley_library/logging/logger.rb
|
|
301
303
|
- lib/berkeley_library/logging/loggers.rb
|
|
302
304
|
- lib/berkeley_library/logging/module_info.rb
|
|
303
305
|
- lib/berkeley_library/logging/railtie.rb
|
|
306
|
+
- lib/berkeley_library/logging/safe_serializer.rb
|
|
304
307
|
- lib/berkeley_library/logging/tagged_logging_extensions.rb
|
|
305
308
|
- rakelib/.rubocop.yml
|
|
306
309
|
- rakelib/bundle.rake
|
|
@@ -314,12 +317,14 @@ files:
|
|
|
314
317
|
- spec/rails/ucblit/logging/formatters_spec.rb
|
|
315
318
|
- spec/rails/ucblit/logging/loggers_spec.rb
|
|
316
319
|
- spec/rails/ucblit/logging/railtie_spec.rb
|
|
320
|
+
- spec/rails/ucblit/logging/safe_serializer_spec.rb
|
|
317
321
|
- spec/rails/ucblit/logging_spec.rb
|
|
318
322
|
- spec/rails_helper.rb
|
|
319
323
|
- spec/spec_helper.rb
|
|
320
324
|
- spec/standalone/ucblit/logging/configurator_spec.rb
|
|
321
325
|
- spec/standalone/ucblit/logging/formatters_spec.rb
|
|
322
326
|
- spec/standalone/ucblit/logging/loggers_spec.rb
|
|
327
|
+
- spec/standalone/ucblit/logging/safe_serializer_spec.rb
|
|
323
328
|
- spec/standalone/ucblit/logging_spec.rb
|
|
324
329
|
- spec/standalone_helper.rb
|
|
325
330
|
homepage: https://github.com/BerkeleyLibrary/logging
|
|
@@ -346,17 +351,20 @@ signing_key:
|
|
|
346
351
|
specification_version: 4
|
|
347
352
|
summary: Opinionated Ruby/Rails logging for UC Berkeley Library
|
|
348
353
|
test_files:
|
|
354
|
+
- artifacts/.keep
|
|
349
355
|
- spec/.rubocop.yml
|
|
350
356
|
- spec/rails/ucblit/logging/configurator_spec.rb
|
|
351
357
|
- spec/rails/ucblit/logging/env_spec.rb
|
|
352
358
|
- spec/rails/ucblit/logging/formatters_spec.rb
|
|
353
359
|
- spec/rails/ucblit/logging/loggers_spec.rb
|
|
354
360
|
- spec/rails/ucblit/logging/railtie_spec.rb
|
|
361
|
+
- spec/rails/ucblit/logging/safe_serializer_spec.rb
|
|
355
362
|
- spec/rails/ucblit/logging_spec.rb
|
|
356
363
|
- spec/rails_helper.rb
|
|
357
364
|
- spec/spec_helper.rb
|
|
358
365
|
- spec/standalone/ucblit/logging/configurator_spec.rb
|
|
359
366
|
- spec/standalone/ucblit/logging/formatters_spec.rb
|
|
360
367
|
- spec/standalone/ucblit/logging/loggers_spec.rb
|
|
368
|
+
- spec/standalone/ucblit/logging/safe_serializer_spec.rb
|
|
361
369
|
- spec/standalone/ucblit/logging_spec.rb
|
|
362
370
|
- spec/standalone_helper.rb
|