dontbugme 0.1.6 → 0.1.8

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: 6f71bd0ef418ea0d47ca94a5242d3677a00d82cf36e2fd0d8b69f3f4ce323f9c
4
- data.tar.gz: c9692d06855f24fc322e218588958881a0a8d9ee4b278125961143b7527fdf3a
3
+ metadata.gz: a70194048020fbf4381c723046b6349ae9ab9751fd60627b1edede6aa2a19052
4
+ data.tar.gz: c71e4e997ea83b35ecf4f4c3f624a3f061837521587b99a7baa40ade7d8daab1
5
5
  SHA512:
6
- metadata.gz: 85e2c35aa316839754b10c22353ef1b89970c893f78f537708fce9a5af7653c4532219a98bd035c833bfdc9e3f3d4fbd3c61a6ad8fb9f60a6d8bff2f1a301511
7
- data.tar.gz: 646af28b63c0f177fcc68b48c0892f3a92c0b1dd102aad33b70d2c54915b85fa325bdcf5b6661c4e2b8c5b13af735d10a6b088643df9335f8967ab8569e918b9
6
+ metadata.gz: e0ecd98974183c4f56242d4f0a5cdb051f50101ce3cf1cbff7bdb292e9e781e9153a031ad0f78f44c90e34e5d73c0d9250519983975a9a485d17d789196724cf
7
+ data.tar.gz: 279e5cd7f6a62056eec771220f81eb9c4e1151c13caed79a6677be1b59e6ba549f360da590eb57c65889301b5d39d657de1efcadd4b1b242f96e05b67301b642
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dontbugme
4
+ module Store
5
+ # Sanitizes data for JSON encoding by replacing invalid UTF-8 sequences.
6
+ # Trace data can contain binary from SQL binds, HTTP bodies, Redis, etc.
7
+ module JsonSafe
8
+ REPLACEMENT = "\uFFFD".freeze
9
+
10
+ module_function
11
+
12
+ def sanitize(obj)
13
+ case obj
14
+ when String
15
+ sanitize_string(obj)
16
+ when Hash
17
+ obj.transform_values { |v| sanitize(v) }
18
+ when Array
19
+ obj.map { |v| sanitize(v) }
20
+ when Symbol
21
+ sanitize_string(obj.to_s)
22
+ when Numeric, TrueClass, FalseClass, NilClass
23
+ obj
24
+ when Time
25
+ obj.respond_to?(:iso8601) ? obj.iso8601(3) : obj.to_s
26
+ else
27
+ sanitize_string(obj.to_s)
28
+ end
29
+ end
30
+
31
+ def sanitize_string(str)
32
+ return str if str.nil?
33
+ return str if str.encoding == Encoding::UTF_8 && str.valid_encoding?
34
+
35
+ str.encode('UTF-8', invalid: :replace, undef: :replace, replace: REPLACEMENT)
36
+ rescue StandardError
37
+ REPLACEMENT
38
+ end
39
+ end
40
+ end
41
+ end
@@ -17,14 +17,14 @@ module Dontbugme
17
17
  params = [
18
18
  data[:id],
19
19
  data[:kind].to_s,
20
- data[:identifier],
20
+ JsonSafe.sanitize_string(data[:identifier].to_s),
21
21
  data[:status].to_s,
22
22
  data[:started_at],
23
23
  data[:duration_ms],
24
24
  correlation_id,
25
- data[:metadata].to_json,
26
- data[:spans].to_json,
27
- data[:error]&.to_json
25
+ JsonSafe.sanitize(data[:metadata]).to_json,
26
+ JsonSafe.sanitize(data[:spans]).to_json,
27
+ data[:error] ? JsonSafe.sanitize(data[:error]).to_json : nil
28
28
  ]
29
29
  exec_params(<<~SQL, params)
30
30
  INSERT INTO dontbugme_traces
@@ -15,19 +15,25 @@ module Dontbugme
15
15
  def save_trace(trace)
16
16
  data = trace.to_h
17
17
  correlation_id = data[:correlation_id] || data[:metadata]&.dig(:correlation_id)
18
+ metadata_json = json_safe(data[:metadata])
19
+ spans_json = json_safe(data[:spans])
20
+ error_json = data[:error] ? json_safe(data[:error]) : nil
18
21
  db.execute(
19
22
  'INSERT OR REPLACE INTO traces (id, kind, identifier, status, started_at, duration_ms, correlation_id, metadata_json, spans_json, error_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
20
23
  data[:id],
21
24
  data[:kind].to_s,
22
- data[:identifier],
25
+ sanitize_identifier(data[:identifier]),
23
26
  data[:status].to_s,
24
27
  data[:started_at],
25
28
  data[:duration_ms],
26
29
  correlation_id,
27
- data[:metadata].to_json,
28
- data[:spans].to_json,
29
- data[:error]&.to_json
30
+ metadata_json,
31
+ spans_json,
32
+ error_json
30
33
  )
34
+ rescue SQLite3::ReadOnlyException
35
+ # Database is read-only (e.g. production deploy with SQLite on read-only filesystem).
36
+ # Silently skip persistence to avoid crashing the app.
31
37
  end
32
38
 
33
39
  def find_trace(trace_id)
@@ -108,6 +114,16 @@ module Dontbugme
108
114
  db.execute('CREATE INDEX IF NOT EXISTS idx_traces_correlation_id ON traces(correlation_id)')
109
115
  end
110
116
 
117
+ def json_safe(obj)
118
+ JsonSafe.sanitize(obj).to_json
119
+ end
120
+
121
+ def sanitize_identifier(str)
122
+ return str if str.nil?
123
+
124
+ JsonSafe.sanitize_string(str.to_s)
125
+ end
126
+
111
127
  def migrate_add_correlation_id
112
128
  return if db.execute("PRAGMA table_info(traces)").any? { |col| col[1] == 'correlation_id' }
113
129
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dontbugme
4
- VERSION = '0.1.6'
4
+ VERSION = '0.1.8'
5
5
  end
data/lib/dontbugme.rb CHANGED
@@ -160,6 +160,7 @@ require 'dontbugme/subscribers/cache'
160
160
  require 'dontbugme/subscribers/action_mailer'
161
161
  require 'dontbugme/subscribers/active_job'
162
162
  require 'dontbugme/store/base'
163
+ require 'dontbugme/store/json_safe'
163
164
  require 'dontbugme/store/memory'
164
165
  require 'dontbugme/store/sqlite'
165
166
  require 'dontbugme/store/postgresql'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dontbugme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Inspector Contributors
@@ -149,6 +149,7 @@ files:
149
149
  - lib/dontbugme/span_collection.rb
150
150
  - lib/dontbugme/store/async.rb
151
151
  - lib/dontbugme/store/base.rb
152
+ - lib/dontbugme/store/json_safe.rb
152
153
  - lib/dontbugme/store/memory.rb
153
154
  - lib/dontbugme/store/postgresql.rb
154
155
  - lib/dontbugme/store/sqlite.rb