semantic_logger 4.17.0 → 4.18.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a10d5e24ca0c3542ec98c53268bd56f96c3432fd7b8de39c55d0f7938f5b6d44
4
- data.tar.gz: 95bdc9df3003bf78c4146847303e8d345600a587fb6fd817343f8822fc62f42b
3
+ metadata.gz: 98c3a3e01f125e81eb58559ca0f7931c55bb787102d89d0c10dd9c9a7ea2e221
4
+ data.tar.gz: 8d82c20b77fe2c98773b72ab2483bdfb2d1267c65f9b8102cb2ffba00c141ee9
5
5
  SHA512:
6
- metadata.gz: 1167fd1b55ffa9805721f598c5ee3e53f9759562ec86088c1237d6c21fc2359c58edf4e6dd81ac91016a36f470636f70ac120939b255e62c0a075a3e6a2190d4
7
- data.tar.gz: 815b6f851d8f7c9ccee2f3e8185c66176bd9263becdab417b8afef70b9aa3e005e78864b135f5c06d6f3a201da3070fe1fe046aee68922c15f9be0170ae9af07
6
+ metadata.gz: c014af737549553d82d1d65ac1f46fbb09cefae9cb5aca3d5c39a4bbc180587fea4a65fa6756cad87eb031af52806693ddf11b9c2a4564bb140b1b1261b216c7
7
+ data.tar.gz: f0c050cb59d1a3022fbf2b5ca180b644493c8630103e09498e7a9097bbda97df3cb3a28b84f125331196819123cad128f85a142c7952918d9df376acfd1dff69
data/Rakefile CHANGED
@@ -9,8 +9,8 @@ task :gem do
9
9
  end
10
10
 
11
11
  task publish: :gem do
12
- system "git tag -a v#{SemanticLogger::VERSION} -m 'Tagging #{SemanticLogger::VERSION}'"
13
- system "git push --tags"
12
+ # system "git tag -a v#{SemanticLogger::VERSION} -m 'Tagging #{SemanticLogger::VERSION}'"
13
+ # system "git push --tags"
14
14
  system "gem push semantic_logger-#{SemanticLogger::VERSION}.gem"
15
15
  system "rm semantic_logger-#{SemanticLogger::VERSION}.gem"
16
16
  end
@@ -43,7 +43,7 @@ module SemanticLogger
43
43
 
44
44
  # Send log to honeybadger events API
45
45
  def log(log)
46
- event = formatter.call(log, self)
46
+ event = formatter.call(log, self).merge(event_type: "log")
47
47
 
48
48
  ::Honeybadger.event(event)
49
49
 
@@ -23,6 +23,11 @@ require "semantic_logger/formatters/new_relic_logs"
23
23
  module SemanticLogger
24
24
  module Appender
25
25
  class NewRelicLogs < SemanticLogger::Subscriber
26
+ CAPTURE_CONTEXT = lambda do |log|
27
+ meta = ::NewRelic::Agent.linking_metadata
28
+ log.set_context(:new_relic_metadata, meta) unless meta.empty?
29
+ end
30
+
26
31
  # Create Appender
27
32
  #
28
33
  # Parameters
@@ -42,6 +47,11 @@ module SemanticLogger
42
47
  # The Proc must return true or false.
43
48
  def initialize(formatter: SemanticLogger::Formatters::NewRelicLogs.new, **args, &block)
44
49
  super
50
+
51
+ # Record NewRelic's "trace.id"/"entity.name"/"hostname"/etc, so we can include them later in the formatted output.
52
+ # These are thread-local, so need to be captured as soon as the log-message is created.
53
+ # https://rubydoc.info/gems/newrelic_rpm/NewRelic/Agent#linking_metadata-instance_method
54
+ SemanticLogger.on_log(CAPTURE_CONTEXT)
45
55
  end
46
56
 
47
57
  # Send an error notification to New Relic
@@ -12,7 +12,7 @@ end
12
12
  module SemanticLogger
13
13
  module Appender
14
14
  class OpenTelemetry < SemanticLogger::Subscriber
15
- attr_reader :name, :version, :logger
15
+ attr_reader :name, :version, :provider, :logger
16
16
 
17
17
  CAPTURE_CONTEXT = ->(log) { log.set_context(:open_telemetry, ::OpenTelemetry::Context.current) }
18
18
 
@@ -30,9 +30,10 @@ module SemanticLogger
30
30
  metrics: true,
31
31
  **args,
32
32
  &block)
33
- @name = name
34
- @version = version
35
- @logger = ::OpenTelemetry.logger_provider.logger(name: @name, version: @version)
33
+ @name = name
34
+ @version = version
35
+ @provider = ::OpenTelemetry.logger_provider
36
+ @logger = @provider.logger(name: @name, version: @version)
36
37
 
37
38
  # Capture the current Open Telemetry context when a log entry is captured.
38
39
  # Prevents duplicate subscribers as long as it is from a constant.
@@ -63,12 +64,23 @@ module SemanticLogger
63
64
 
64
65
  # Flush all pending logs.
65
66
  def flush
66
- @logger.logger_provider.force_flush
67
+ return unless @provider
68
+
69
+ @provider.force_flush if @provider.respond_to?(:force_flush)
70
+ rescue StandardError => e
71
+ # Swallow to avoid noisy shutdown exceptions.
72
+ SemanticLogger.logger.warn("Flush failed: #{e.class}: #{e.message}")
67
73
  end
68
74
 
69
- # Flush pending logs and close the appender
75
+ # Close the appender and release resources.
70
76
  def close
71
- @logger.logger_provider.shutdown
77
+ return unless @provider
78
+
79
+ @provider.shutdown if @provider.respond_to?(:shutdown)
80
+ rescue StandardError => e
81
+ SemanticLogger.logger.warn("Shutdown failed: #{e.class}: #{e.message}")
82
+ ensure
83
+ @provider = nil
72
84
  end
73
85
 
74
86
  # For logging metrics only log events.
@@ -40,7 +40,12 @@ module SemanticLogger
40
40
  def initialize(level: :error, **args, &block)
41
41
  # Replace the Sentry Ruby logger so that we can identify its log
42
42
  # messages and not forward them to Sentry
43
- ::Sentry.init { |config| config.logger = SemanticLogger[::Sentry] } unless ::Sentry.initialized?
43
+ unless ::Sentry.initialized?
44
+ ::Sentry.init do |config|
45
+ logger = SemanticLogger[::Sentry]
46
+ config.respond_to?(:sdk_logger=) ? config.sdk_logger = logger : config.logger = logger
47
+ end
48
+ end
44
49
  super
45
50
  end
46
51
 
@@ -34,6 +34,19 @@ module SemanticLogger
34
34
  @level || SemanticLogger.default_level
35
35
  end
36
36
 
37
+ # Set the logging level for this logger during the execution of the given block
38
+ #
39
+ # Refer to the documentation for `#level=` for more information about the possible log levels.
40
+ def with_level(new_level)
41
+ old_level = level
42
+
43
+ self.level = new_level
44
+
45
+ yield
46
+ ensure
47
+ self.level = old_level
48
+ end
49
+
37
50
  # Implement the log level calls
38
51
  # logger.debug(message, hash|exception=nil, &block)
39
52
  #
@@ -47,7 +47,7 @@ module SemanticLogger
47
47
  hash = super
48
48
 
49
49
  result = {
50
- **newrelic_metadata,
50
+ **linking_metadata(log),
51
51
  message: hash[:message].to_s,
52
52
  tags: hash[:tags],
53
53
  metric: hash[:metric],
@@ -115,11 +115,9 @@ module SemanticLogger
115
115
 
116
116
  private
117
117
 
118
- # NOTE: This function will already include trace.id and span.id if they
119
- # are available so I believe the previous implementation of this is redundant
120
- # https://rubydoc.info/gems/newrelic_rpm/NewRelic/Agent#linking_metadata-instance_method
121
- def newrelic_metadata
122
- NewRelic::Agent.linking_metadata.transform_keys(&:to_sym)
118
+ # returns "entity.name", "trace.id" etc from NewRelic::Agent.linking_metadata
119
+ def linking_metadata(log)
120
+ (log.context && log.context[:new_relic_metadata]) || {}
123
121
  end
124
122
  end
125
123
  end
@@ -2,6 +2,9 @@ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class OpenTelemetry < Raw
5
+ # primitives allowed by OTLP logs in Ruby: String, Integer, Float, TrueClass, FalseClass
6
+ PRIMS = [String, Integer, Float, TrueClass, FalseClass].freeze
7
+
5
8
  # Log level
6
9
  def level
7
10
  hash[:level] = log.level.to_s
@@ -12,11 +15,36 @@ module SemanticLogger
12
15
  def payload
13
16
  return unless log.payload.respond_to?(:empty?) && !log.payload.empty?
14
17
 
15
- hash[:payload] = log.payload.transform_keys!(&:to_s)
18
+ hash[:payload] = coerce_map(log.payload)
16
19
  end
17
20
 
18
21
  private
19
22
 
23
+ def coerce_value(v)
24
+ case v
25
+ when *PRIMS then v
26
+ when Array then v.map { |e| coerce_value(e) }.compact # arrays of scalars only.
27
+ when NilClass then nil # drop nils by caller.
28
+ else v.to_s # stringify objects / hashes.
29
+ end
30
+ end
31
+
32
+ def coerce_map(h)
33
+ h.each_with_object({}) do |(k, v), out|
34
+ next if v.nil?
35
+
36
+ out[k.to_s] =
37
+ if v.is_a?(Hash)
38
+ # Stringify whole hash.
39
+ v.transform_values { |vv| coerce_value(vv) }.
40
+ transform_keys!(&:to_s).
41
+ to_json
42
+ else
43
+ coerce_value(v)
44
+ end
45
+ end
46
+ end
47
+
20
48
  def severity_number(severity)
21
49
  case severity
22
50
  when :trace
@@ -93,6 +93,11 @@ module SemanticLogger
93
93
  self.dimensions = dimensions
94
94
 
95
95
  if exception
96
+ unless exception.is_a?(Exception)
97
+ exception = ArgumentError.new("Invalid value for logger exception: #{exception.inspect}")
98
+ exception.set_backtrace(Utils.extract_backtrace(caller))
99
+ end
100
+
96
101
  case log_exception
97
102
  when :full
98
103
  self.exception = exception
@@ -23,7 +23,7 @@ module SemanticLogger
23
23
 
24
24
  attr_reader :appenders
25
25
 
26
- def initialize(max_queue_size: -1)
26
+ def initialize(max_queue_size: 10_000)
27
27
  @appenders = Appenders.new(self.class.logger.dup)
28
28
  super(appender: @appenders, max_queue_size: max_queue_size)
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger
2
- VERSION = "4.17.0".freeze
2
+ VERSION = "4.18.0".freeze
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.17.0
4
+ version: 4.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2026-04-10 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: concurrent-ruby
@@ -104,7 +104,7 @@ licenses:
104
104
  metadata:
105
105
  bug_tracker_uri: https://github.com/reidmorrison/semantic_logger/issues
106
106
  documentation_uri: https://logger.rocketjob.io
107
- source_code_uri: https://github.com/reidmorrison/semantic_logger/tree/v4.17.0
107
+ source_code_uri: https://github.com/reidmorrison/semantic_logger/tree/v4.18.0
108
108
  rubygems_mfa_required: 'true'
109
109
  rdoc_options: []
110
110
  require_paths:
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  - !ruby/object:Gem::Version
121
121
  version: '0'
122
122
  requirements: []
123
- rubygems_version: 3.6.9
123
+ rubygems_version: 3.6.2
124
124
  specification_version: 4
125
125
  summary: Feature rich logging framework, and replacement for existing Ruby & Rails
126
126
  loggers.