yeti_logger 3.0.0 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3e5e9a8554d3123f83bd27c2cefe1663025fa9b9
4
- data.tar.gz: 8f79e414571cbc0c5815eb5ce888892be8114231
2
+ SHA256:
3
+ metadata.gz: f58be8ecadfe9be95d8517795d6d28b68d3c870957f73477e9a9780c78089c9d
4
+ data.tar.gz: b693a3f73e811f9f2d773755d05339b083517bbf288dcb96cf7c2710819ce326
5
5
  SHA512:
6
- metadata.gz: 3fa2b8fedb91ee5f6cb0d0dcf41b4219cc16a5c98092c574ee55576d2c1ad9e0ce702c2d6e05c87af6445fbf80016e8f4e9134afc0d210a7554728fc8e99432a
7
- data.tar.gz: 61e988b8d18bc89954b49cbd49a6d4d288280bc53312f9507f15e7404ac3e828f0fd433548599005ca49f8136c41caf02c47db2bdafb12f230dc65ae0823ebf4
6
+ metadata.gz: '010960813b5a5cabea56c2299a692a5111682a330262350bd68da570c435ca9a61cfcdf79ff66c20c18424a596179ea2423681d3acb42262ce35d61b4e3db45f'
7
+ data.tar.gz: 5f1a528a27bbc3b851c4980f3fe5af6c135a37874da3744c9a958488b351fa41e772725241204d87e61f4e946de96814defd08ddafa26e15ac9bdade103c5b3c
@@ -0,0 +1,32 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.6', '2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Run tests
32
+ run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
1
  # yeti_logger changelog
2
2
 
3
+ ## v3.3.2
4
+ - CustomFormatter does not include timestamp in log in production and staging environments
5
+
6
+ ## v3.3.1
7
+ - CustomFormatter uses Time.now instead of Time.now.utc
8
+
9
+ ## v3.3.0
10
+ - Add custom rails logger formatter
11
+
12
+ ## v3.2.0
13
+ - Added configuration to override debug logging for specific users
14
+
15
+ ## v3.1.0
16
+ - Added `YetiLogger::TestHelper.expect_to_not_see_log_message[s]` for testing
17
+ that given messages were not logged at the given log level.
18
+
3
19
  ## v3.0.0
4
20
  - First public release
data/Gemfile CHANGED
@@ -1,4 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ if RUBY_VERSION < '2.2.2'
4
+ gem 'activesupport', '< 5'
5
+ end
6
+
3
7
  # Specify your gem's dependencies in yeti_logger.gemspec
4
8
  gemspec
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Provides standardized logging across Yesware apps.
4
4
 
5
- [![Build Status](https://travis-ci.org/Yesware/yeti_logger.svg?branch=master)](https://travis-ci.org/Yesware/yeti_logger)
5
+ [![Ruby](https://github.com/Yesware/yeti_logger/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/Yesware/yeti_logger/actions/workflows/ruby.yml)
6
+
6
7
 
7
8
  ## Installation
8
9
 
@@ -105,6 +106,17 @@ is a hash, then the exception in injected into the hash and printed as
105
106
  additional `key=value` pairs. Classname, message and backtrace are included in
106
107
  the message.
107
108
 
109
+ ### Custom formatter
110
+ To add a set of tags to every log output by the underlying logger, initialize
111
+ `YetiLogger::CustomFormatter` and assign it to your logger's formatter. Pass a
112
+ hash to the initializer mapping the name of the tags to the proc that evaluates
113
+ to their value. The procs are evaluated lazily when the log generated.
114
+
115
+ Rails.logger.formatter = CustomFormatter.new({
116
+ "thread_id": -> { Thread.current.object_id.to_s(36) },
117
+ "trace_id": -> { OpenTelemetry::Trace.current_span ? OpenTelemetry::Trace.current_span.context.hex_trace_id : "0" },
118
+ })
119
+
108
120
  ### Nested Hashes
109
121
 
110
122
  For hash logging, each key and value are converted to strings which means
@@ -118,6 +130,25 @@ this behavior, pass in the serialized format for the hash, such as:
118
130
  log_info { hash.to_s }
119
131
  log_info { hash.to_my_log_format }
120
132
 
133
+ ### Override Debug Logging Level
134
+
135
+
136
+ You can configure conditions under which to override the app-wide log level for `log_debug` calls, so that it emit logs from `log_debug` calls even if the app's log level is configured as `info` or higher. For example, using the [settings-in-redis gem](https://github.com/Yesware/settings-in-redis), you can specify user IDs in `Settings.extra_logging_user_ids` so that if the log hash contains those user IDs in its `user_id` key, we'll log at `info` level instead:
137
+
138
+ ```ruby
139
+ YetiLogger.configure do |config|
140
+ def config.promote_debug_to_info?(log_hash)
141
+ Settings.extra_logging_user_ids.is_a?(Array) &&
142
+ log_hash.is_a?(Hash) &&
143
+ log_hash.with_indifferent_access[:user_id].to_i.in?(Settings.extra_logging_user_ids)
144
+ end
145
+ end
146
+ ```
147
+
148
+ In this example, the user ID is taken from the `user_id` key of the log payload, so this won't work with the block syntax.
149
+
150
+ This feature enables us to get more logging for (and hence more insight into) specific users who are experiencing problems, without hardcoding user IDs or increasing the overall log volume with logs we're not interested in. Depending on your configuration, you may avoid setting environment variables and restarting the app too.
151
+
121
152
  ## Test Support
122
153
 
123
154
  There are a couple helpers provided to support testing of YetiLogger calls. All
@@ -0,0 +1,34 @@
1
+ # CustomFormatter is a custom Rails log formatter.
2
+ # It has support for adding arbitrary tags to every log created by the Rails logger.
3
+ # Tag values are generated at log creation time.
4
+ class YetiLogger::CustomFormatter
5
+ # @param tags [Hash] - maps names of tags to procs that return their value.
6
+ def initialize(tags = {})
7
+ super()
8
+ @tags = tags
9
+ end
10
+
11
+ # @param tags [Hash] - maps names of tags to procs that return their value
12
+ def add_tags(tags)
13
+ @tags.merge!(tags)
14
+ end
15
+
16
+ # @param severity [String]
17
+ # @param time [Time] unused
18
+ # @param progname [String] unused
19
+ # @param msg [String] - log body
20
+ def call(severity, time, progname, msg)
21
+ timestamp = %w(production staging).include?(ENV['RAILS_ENV']) ? "" : "#{Time.now.iso8601(3)} "
22
+ pid = Process.pid
23
+ msg = msg.inspect unless msg.is_a?(String)
24
+ msg = "#{msg}\n" unless msg[-1] == ?\n
25
+ log_str = "#{timestamp}pid=#{pid}"
26
+
27
+ tag_str = @tags.map { |k, v|
28
+ value = v.call
29
+ "#{k}=#{value}" unless value.to_s.empty?
30
+ }.compact.join(' ')
31
+
32
+ "#{log_str}#{tag_str.empty? ? '' : ' ' + tag_str} [#{severity}] - #{msg}"
33
+ end
34
+ end
@@ -24,17 +24,7 @@ module YetiLogger::TestHelper
24
24
 
25
25
  # Plural version of above
26
26
  def expect_to_see_log_messages(messages, level = :debug, &block)
27
- log_messages = []
28
-
29
- allow(YetiLogger.logger).to receive(level) do |log_line|
30
- log_messages << log_line
31
- end
32
-
33
- block.call
34
-
35
- # There is no unstub in rspec 3, but the closest to that would be to
36
- # continue to stub it, but defer to the original implementation.
37
- allow(YetiLogger.logger).to receive(level).and_call_original
27
+ log_messages = get_log_messages(level, &block)
38
28
 
39
29
  # Find each message, removing the first occurrence.
40
30
  messages.each do |message|
@@ -54,6 +44,47 @@ module YetiLogger::TestHelper
54
44
  end
55
45
  end
56
46
 
47
+ # Execute a block and ensure that the supplied log message is not among the
48
+ # messages logged at the specified level.
49
+ def expect_to_not_see_log_message(message, level = :debug, &block)
50
+ expect_to_not_see_log_messages([message], level, &block)
51
+ end
52
+
53
+ # Plural version of above
54
+ def expect_to_not_see_log_messages(messages, level = :debug, &block)
55
+ log_messages = get_log_messages(level, &block)
56
+
57
+ found = messages.find do |message|
58
+ if message.is_a?(Regexp)
59
+ log_messages.find do |log_message|
60
+ log_message =~ message
61
+ end
62
+ else
63
+ log_messages.include?(message)
64
+ end
65
+ end
66
+
67
+ if found.present?
68
+ fail "Should not have found #{found.inspect} amongst #{log_messages.inspect}"
69
+ end
70
+ end
71
+
72
+ def get_log_messages(level = :debug, &block)
73
+ log_messages = []
74
+
75
+ allow(YetiLogger.logger).to receive(level) do |log_line|
76
+ log_messages << log_line
77
+ end
78
+
79
+ block.call
80
+
81
+ # There is no unstub in rspec 3, but the closest to that would be to
82
+ # continue to stub it, but defer to the original implementation.
83
+ allow(YetiLogger.logger).to receive(level).and_call_original
84
+
85
+ log_messages
86
+ end
87
+
57
88
  def should_log(level = :info)
58
89
  expect(YetiLogger.logger).to(receive(level))
59
90
  end
@@ -1,3 +1,3 @@
1
1
  module YetiLogger
2
- VERSION = "3.0.0"
2
+ VERSION = "3.3.2"
3
3
  end
data/lib/yeti_logger.rb CHANGED
@@ -74,14 +74,18 @@ module YetiLogger
74
74
  # passed to the log method.
75
75
  # Define these methods explicitly allows the use of yield.
76
76
  module LogMethods
77
+ # See usage at https://github.com/Yesware/yeti_logger/blob/master/README.md#user-based-logging
77
78
  def log_debug(obj = nil, ex = nil)
78
- if YetiLogger.logger.level <= Logger::DEBUG
79
+ should_log_as_info = YetiLogger.try(:promote_debug_to_info?, obj)
80
+
81
+ if YetiLogger.logger.level <= Logger::DEBUG ||
82
+ (should_log_as_info && YetiLogger.logger.level <= Logger::INFO)
79
83
  msg = if block_given?
80
84
  MessageFormatters.build_log_message(log_class_name, yield)
81
85
  else
82
86
  MessageFormatters.build_log_message(log_class_name, obj, ex)
83
87
  end
84
- YetiLogger.logger.send(:debug, msg)
88
+ YetiLogger.logger.send(should_log_as_info ? :info : :debug, msg)
85
89
  end
86
90
  end
87
91
 
@@ -1,3 +1,4 @@
1
+ require "active_support"
1
2
  require 'spec_helper.rb'
2
3
 
3
4
  # Class used for class and instance level testing
@@ -121,6 +121,95 @@ describe YetiLogger::TestHelper do
121
121
 
122
122
  end
123
123
 
124
+ describe '.expect_to_not_see_log_messages' do
125
+ it 'has a singular form' do
126
+ expect_to_not_see_log_message('YetiLogger::TestLogger: foo', :warn) do
127
+ instance.log_warn('bar')
128
+ end
129
+ end
130
+
131
+ it 'checks for multiple messages' do
132
+ messages = [
133
+ 'YetiLogger::TestLogger: one',
134
+ 'YetiLogger::TestLogger: two'
135
+ ]
136
+ expect_to_not_see_log_messages(messages, :info) do
137
+ instance.log_info('three')
138
+ instance.log_info('four')
139
+ end
140
+ end
141
+
142
+ it 'only stubs the log level you request' do
143
+ expect(YetiLogger.logger).to receive(:info).with('YetiLogger::TestLogger: msg')
144
+
145
+ expect_to_not_see_log_message('YetiLogger::TestLogger: msg', :warn) do
146
+ instance.log_info { 'msg' }
147
+ instance.log_error { 'msg' }
148
+ end
149
+ end
150
+
151
+ it 'supports regexes' do
152
+ messages = [
153
+ 'YetiLogger::TestLogger: one',
154
+ /two-\d/,
155
+ 'YetiLogger::TestLogger: three'
156
+ ]
157
+ expect_to_not_see_log_messages(messages, :info) do
158
+ instance.log_info('four')
159
+ instance.log_info('five')
160
+ end
161
+ end
162
+
163
+ it 'fails when it finds the string message' do
164
+ expect do
165
+ message = 'YetiLogger::TestLogger: should not be there'
166
+ expect_to_not_see_log_message(message, :info) do
167
+ instance.log_info('should not be there')
168
+ end
169
+ end.to raise_exception(RuntimeError)
170
+ end
171
+
172
+ it 'fails when it matches the regexp message' do
173
+ expect do
174
+ expect_to_not_see_log_message(/bazinga/, :info) do
175
+ instance.log_info('bazinga, punk!')
176
+ end
177
+ end.to raise_exception(RuntimeError)
178
+ end
179
+
180
+ it 'fails when it finds one of the string messages' do
181
+ expect do
182
+ messages = [
183
+ 'YetiLogger::TestLogger: one',
184
+ /two-\d/,
185
+ 'YetiLogger::TestLogger: three',
186
+ 'YetiLogger::TestLogger: four'
187
+ ]
188
+ expect_to_not_see_log_messages(messages, :info) do
189
+ instance.log_info('one')
190
+ instance.log_info('five')
191
+ instance.log_info('six')
192
+ end
193
+ end.to raise_exception(RuntimeError)
194
+ end
195
+
196
+ it 'fails when it finds matches one of the regexps' do
197
+ expect do
198
+ messages = [
199
+ 'YetiLogger::TestLogger: one',
200
+ /two-\d/,
201
+ /three/,
202
+ 'YetiLogger::TestLogger: four'
203
+ ]
204
+ expect_to_not_see_log_messages(messages, :info) do
205
+ instance.log_info('two-2')
206
+ instance.log_info('five')
207
+ instance.log_info('six')
208
+ end
209
+ end.to raise_exception(RuntimeError)
210
+ end
211
+ end
212
+
124
213
  describe '.should_log' do
125
214
  it 'verifies a log message came through' do
126
215
  should_log(:info).with("YetiLogger::TestLogger: hello!")
@@ -97,10 +97,63 @@ describe YetiLogger do
97
97
 
98
98
  end
99
99
 
100
- # There is a lot of debug output, so we can't verify it like we do the other
101
- # levels. For now, just validate the method is there.
102
- it "can call a #{target_type} debug method" do
103
- target.log_debug("#{target_type} debuggin")
100
+ describe "log_debug" do
101
+ let(:user_id) { rand(9000) }
102
+
103
+ shared_examples_for "it logs at the expected level" do |expected_level|
104
+ it "logs at #{expected_level} level" do
105
+ regex = /#{class_name}:.*#{target_type}.*debuggin.*user_id=#{user_id}/
106
+ expect_to_see_log_message(regex, expected_level) do
107
+ target.log_debug(msg: "#{target_type} debuggin", user_id: user_id)
108
+ end
109
+ end
110
+ end
111
+
112
+ after(:each) do
113
+ if described_class.respond_to?(:promote_debug_to_info?)
114
+ class <<described_class
115
+ undef_method(:promote_debug_to_info?)
116
+ end
117
+ end
118
+ end
119
+
120
+ context "when promote_debug_to_info? isn't configured," do
121
+ before(:each) do
122
+ if described_class.respond_to?(:promote_debug_to_info?)
123
+ class <<described_class
124
+ undef_method(:promote_debug_to_info?)
125
+ end
126
+ end
127
+ end
128
+
129
+ it_behaves_like "it logs at the expected level", :debug
130
+ end
131
+
132
+ context "when promote_debug_to_info? is configured," do
133
+ context "when promote_debug_to_info is true," do
134
+ before(:each) do
135
+ described_class.configure do |config|
136
+ def config.promote_debug_to_info?(log_hash)
137
+ true
138
+ end
139
+ end
140
+ end
141
+
142
+ it_behaves_like "it logs at the expected level", :info
143
+ end
144
+
145
+ context "when promote_debug_to_info is false," do
146
+ before(:each) do
147
+ described_class.configure do |config|
148
+ def config.promote_debug_to_info?(log_hash)
149
+ false
150
+ end
151
+ end
152
+ end
153
+
154
+ it_behaves_like "it logs at the expected level", :debug
155
+ end
156
+ end
104
157
  end
105
158
 
106
159
  it "can log key value pairs at #{target_type} level" do
data/yeti_logger.gemspec CHANGED
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "yard"
26
26
  spec.add_development_dependency "kramdown"
27
27
  spec.add_development_dependency "simplecov"
28
+ spec.add_development_dependency "byebug"
28
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeti_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yesware, Inc
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-27 00:00:00.000000000 Z
11
+ date: 2024-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Provides standardized logging
98
112
  email:
99
113
  - engineering@yesware.com
@@ -101,10 +115,9 @@ executables: []
101
115
  extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
118
+ - ".github/workflows/ruby.yml"
104
119
  - ".gitignore"
105
120
  - ".rspec"
106
- - ".ruby-version"
107
- - ".travis.yml"
108
121
  - CHANGELOG.md
109
122
  - Gemfile
110
123
  - MIT-LICENSE
@@ -113,6 +126,7 @@ files:
113
126
  - lib/yeti_logger.rb
114
127
  - lib/yeti_logger/configuration.rb
115
128
  - lib/yeti_logger/constants.rb
129
+ - lib/yeti_logger/custom_formatter.rb
116
130
  - lib/yeti_logger/message_formatters.rb
117
131
  - lib/yeti_logger/test_helper.rb
118
132
  - lib/yeti_logger/version.rb
@@ -127,7 +141,7 @@ homepage: ''
127
141
  licenses:
128
142
  - MIT
129
143
  metadata: {}
130
- post_install_message:
144
+ post_install_message:
131
145
  rdoc_options: []
132
146
  require_paths:
133
147
  - lib
@@ -142,9 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
156
  - !ruby/object:Gem::Version
143
157
  version: '0'
144
158
  requirements: []
145
- rubyforge_project:
146
- rubygems_version: 2.4.6
147
- signing_key:
159
+ rubygems_version: 3.5.3
160
+ signing_key:
148
161
  specification_version: 4
149
162
  summary: Provides standardized logging
150
163
  test_files:
@@ -153,4 +166,3 @@ test_files:
153
166
  - spec/lib/yeti_logger/wrapped_logger_spec.rb
154
167
  - spec/lib/yeti_logger_spec.rb
155
168
  - spec/spec_helper.rb
156
- has_rdoc:
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- ruby-2.2.2
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 1.9.3
5
- - 2.0
6
- - 2.1
7
- - 2.2
8
- - jruby-19mode
9
-
10
- script:
11
- - bundle exec rake ci
12
-
13
- sudo: false
14
-
15
- env:
16
- global:
17
- # To allow JRUBY to install c-extension gems
18
- - "JRUBY_OPTS=-Xcext.enabled=true"