salopulse 0.3.0 → 0.4.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/CHANGELOG.md +11 -0
- data/lib/salopulse/client.rb +4 -1
- data/lib/salopulse/configuration.rb +12 -1
- data/lib/salopulse/stack_frame_builder.rb +97 -0
- data/lib/salopulse/version.rb +1 -1
- data/lib/salopulse.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54e35ff25bd4f509773e4121f6f18612741353a90fdcfb2f8d17444b48019ebc
|
|
4
|
+
data.tar.gz: a0b1d4b69b96151d2de4a2662c6bde1ebfb4160ccc23320b9d5c6e9e89685147
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a22fbc00d2411e2b88a6af24fbc854ef13be0d4f7e10f1ba2b50d082861ece0582e86ed783aff4cfb01b3e86f560fb7090e1a83a56829d1634248831bdc6be91
|
|
7
|
+
data.tar.gz: 0fd9d36419e61fe1b0633cdc49685cc2599fde166f852a5eba0435fb5fe6e27c8f06de1a22f1bc788b1cfdf7c87a7b0cf9b66e3afda3184025f3bdf600d6a0d1
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
4
4
|
|
|
5
|
+
## [0.4.0] - 2026-06-10
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `StackFrameBuilder` parses exception backtraces into structured frames and
|
|
9
|
+
attaches `pre_context`, `context_line`, and `post_context` source lines for
|
|
10
|
+
in-app frames. `capture_exception` now sends a `stack_frames` array
|
|
11
|
+
alongside the existing `stack_trace` string, enabling source-snippet
|
|
12
|
+
rendering in the dashboard
|
|
13
|
+
- `Configuration#app_root` controls which paths are treated as in-app; defaults
|
|
14
|
+
to `Rails.root` when Rails is loaded and `Dir.pwd` otherwise
|
|
15
|
+
|
|
5
16
|
## [0.3.0] - 2026-06-08
|
|
6
17
|
|
|
7
18
|
### Added
|
data/lib/salopulse/client.rb
CHANGED
|
@@ -9,6 +9,7 @@ require_relative "flusher"
|
|
|
9
9
|
require_relative "sanitizer"
|
|
10
10
|
require_relative "local_fingerprint"
|
|
11
11
|
require_relative "request_context"
|
|
12
|
+
require_relative "stack_frame_builder"
|
|
12
13
|
|
|
13
14
|
module Salopulse
|
|
14
15
|
class Client
|
|
@@ -92,10 +93,12 @@ module Salopulse
|
|
|
92
93
|
return unless sample?
|
|
93
94
|
|
|
94
95
|
ctx = RequestContext.current
|
|
96
|
+
backtrace = Array(error.backtrace)
|
|
95
97
|
data = {
|
|
96
98
|
"error_class" => error.class.name,
|
|
97
99
|
"message" => error.message.to_s,
|
|
98
|
-
"stack_trace" =>
|
|
100
|
+
"stack_trace" => backtrace.join("\n"),
|
|
101
|
+
"stack_frames" => StackFrameBuilder.call(backtrace, app_root: configuration&.app_root),
|
|
99
102
|
"endpoint" => ctx&.dig(:endpoint),
|
|
100
103
|
"http_method" => ctx&.dig(:http_method)
|
|
101
104
|
}
|
|
@@ -4,7 +4,8 @@ module Salopulse
|
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_accessor :dsn, :release, :environment, :sample_rate,
|
|
6
6
|
:flush_interval, :flush_batch_size, :n1_threshold,
|
|
7
|
-
:before_send, :logger, :enabled, :max_buffer_size
|
|
7
|
+
:before_send, :logger, :enabled, :max_buffer_size,
|
|
8
|
+
:app_root
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
@release = nil
|
|
@@ -17,6 +18,16 @@ module Salopulse
|
|
|
17
18
|
@logger = Logger.new($stdout, level: Logger::WARN)
|
|
18
19
|
@enabled = true
|
|
19
20
|
@max_buffer_size = 10_000
|
|
21
|
+
@app_root = detect_app_root
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def detect_app_root
|
|
27
|
+
return Rails.root.to_s if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
|
|
28
|
+
Dir.pwd
|
|
29
|
+
rescue StandardError
|
|
30
|
+
Dir.pwd
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module Salopulse
|
|
2
|
+
class StackFrameBuilder
|
|
3
|
+
BACKTRACE_LINE = /\A(?<file>.+?):(?<line>\d+):in\s+[`'](?<method>.+?)['`]\z/
|
|
4
|
+
CONTEXT_LINES = 5
|
|
5
|
+
MAX_FRAMES = 50
|
|
6
|
+
FRAMEWORK_MARKERS = [ "/gems/", "/rubygems/", "/bundle/" ].freeze
|
|
7
|
+
|
|
8
|
+
SOURCE_CACHE = {}
|
|
9
|
+
SOURCE_CACHE_MUTEX = Mutex.new
|
|
10
|
+
SOURCE_CACHE_LIMIT = 512
|
|
11
|
+
|
|
12
|
+
def self.call(backtrace, app_root: nil)
|
|
13
|
+
new(backtrace, app_root: app_root).call
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(backtrace, app_root:)
|
|
17
|
+
@backtrace = Array(backtrace)
|
|
18
|
+
@app_root = app_root && File.expand_path(app_root.to_s)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
@backtrace.first(MAX_FRAMES).filter_map { |line| build_frame(line.to_s) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def build_frame(raw)
|
|
28
|
+
match = BACKTRACE_LINE.match(raw)
|
|
29
|
+
return nil unless match
|
|
30
|
+
|
|
31
|
+
abs_path = match[:file]
|
|
32
|
+
lineno = match[:line].to_i
|
|
33
|
+
in_app = in_app?(abs_path)
|
|
34
|
+
|
|
35
|
+
frame = {
|
|
36
|
+
"file" => relative_file(abs_path),
|
|
37
|
+
"abs_path" => abs_path,
|
|
38
|
+
"line" => lineno,
|
|
39
|
+
"method" => match[:method],
|
|
40
|
+
"in_app" => in_app,
|
|
41
|
+
"package" => detect_package(abs_path)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
attach_source_context(frame, abs_path, lineno) if in_app
|
|
45
|
+
frame
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def in_app?(file)
|
|
49
|
+
return false if FRAMEWORK_MARKERS.any? { |marker| file.include?(marker) }
|
|
50
|
+
return true unless @app_root
|
|
51
|
+
|
|
52
|
+
File.expand_path(file).start_with?(@app_root)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def detect_package(file)
|
|
56
|
+
match = file.match(%r{/gems/(?<package>[^/]+)/})
|
|
57
|
+
match && match[:package]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def relative_file(file)
|
|
61
|
+
return file unless @app_root
|
|
62
|
+
|
|
63
|
+
expanded = File.expand_path(file)
|
|
64
|
+
return file unless expanded.start_with?(@app_root)
|
|
65
|
+
|
|
66
|
+
expanded.sub(/\A#{Regexp.escape(@app_root)}\/?/, "")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def attach_source_context(frame, file, lineno)
|
|
70
|
+
lines = read_source(file)
|
|
71
|
+
return if lines.empty?
|
|
72
|
+
|
|
73
|
+
idx = lineno - 1
|
|
74
|
+
return if idx.negative? || idx >= lines.length
|
|
75
|
+
|
|
76
|
+
pre_start = [ idx - CONTEXT_LINES, 0 ].max
|
|
77
|
+
post_end = [ idx + CONTEXT_LINES, lines.length - 1 ].min
|
|
78
|
+
|
|
79
|
+
frame["pre_context"] = lines[pre_start...idx].map { |l| l.to_s.chomp }
|
|
80
|
+
frame["context_line"] = lines[idx].to_s.chomp
|
|
81
|
+
frame["post_context"] = lines[(idx + 1)..post_end].to_a.map { |l| l.to_s.chomp }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def read_source(file)
|
|
85
|
+
SOURCE_CACHE_MUTEX.synchronize do
|
|
86
|
+
return SOURCE_CACHE[file] if SOURCE_CACHE.key?(file)
|
|
87
|
+
|
|
88
|
+
SOURCE_CACHE.shift if SOURCE_CACHE.size >= SOURCE_CACHE_LIMIT
|
|
89
|
+
SOURCE_CACHE[file] = begin
|
|
90
|
+
File.readlines(file)
|
|
91
|
+
rescue StandardError
|
|
92
|
+
[]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/salopulse/version.rb
CHANGED
data/lib/salopulse.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "salopulse/buffer"
|
|
|
7
7
|
require_relative "salopulse/sanitizer"
|
|
8
8
|
require_relative "salopulse/local_fingerprint"
|
|
9
9
|
require_relative "salopulse/request_context"
|
|
10
|
+
require_relative "salopulse/stack_frame_builder"
|
|
10
11
|
require_relative "salopulse/transport"
|
|
11
12
|
require_relative "salopulse/flusher"
|
|
12
13
|
require_relative "salopulse/client"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: salopulse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Salih İmran Büker
|
|
@@ -94,6 +94,7 @@ files:
|
|
|
94
94
|
- lib/salopulse/railtie.rb
|
|
95
95
|
- lib/salopulse/request_context.rb
|
|
96
96
|
- lib/salopulse/sanitizer.rb
|
|
97
|
+
- lib/salopulse/stack_frame_builder.rb
|
|
97
98
|
- lib/salopulse/transport.rb
|
|
98
99
|
- lib/salopulse/version.rb
|
|
99
100
|
homepage: https://github.com/mersieS/salopulse-ruby-sdk
|