mirror of
https://gitea.invidious.io/iv-org/shard-backtracer.cr.git
synced 2024-08-15 00:53:13 +00:00
Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
|
d461ca301b | ||
|
abdac766c5 | ||
|
b4d0390bcd | ||
|
7e92356a50 | ||
|
a7eed4b230 | ||
|
8410b11478 | ||
|
07d6dc4381 | ||
|
30287e3025 | ||
|
14f5d77cdd | ||
|
5649a04adf | ||
|
f18b0546f8 | ||
|
5e1ea0bd78 | ||
|
1ff793f00b | ||
|
63ca71ba56 | ||
|
521bf7ff28 | ||
|
0663fbfa01 | ||
|
d88a17f3e6 | ||
|
0300476813 | ||
|
e3ee3a494d | ||
|
7d7192ec09 | ||
|
45b9cefe73 | ||
|
57f5746d6e | ||
|
c41fcb5d28 | ||
|
8ad814c7c1 | ||
|
742b723237 |
18 changed files with 568 additions and 276 deletions
3
.ameba.yml
Normal file
3
.ameba.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Lint/NotNil:
|
||||||
|
Excluded:
|
||||||
|
- spec/backtracer/backtrace/frame/parser_spec.cr
|
46
.github/workflows/ci.yml
vendored
Normal file
46
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 3 * * 1" # Every monday at 3 AM
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest]
|
||||||
|
crystal: [latest, nightly]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Crystal
|
||||||
|
uses: oprypin/install-crystal@v1
|
||||||
|
with:
|
||||||
|
crystal: ${{ matrix.crystal }}
|
||||||
|
|
||||||
|
- name: Download source
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: shards install
|
||||||
|
env:
|
||||||
|
SHARDS_OPTS: --ignore-crystal-version
|
||||||
|
|
||||||
|
- name: Run specs
|
||||||
|
run: |
|
||||||
|
crystal spec
|
||||||
|
crystal spec --no-debug
|
||||||
|
|
||||||
|
- name: Run specs (release)
|
||||||
|
run: |
|
||||||
|
crystal spec --release
|
||||||
|
crystal spec --release --no-debug
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: crystal tool format --check
|
||||||
|
|
||||||
|
- name: Run ameba linter
|
||||||
|
run: bin/ameba
|
20
.travis.yml
20
.travis.yml
|
@ -1,20 +0,0 @@
|
||||||
language: crystal
|
|
||||||
|
|
||||||
crystal:
|
|
||||||
- latest
|
|
||||||
- nightly
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
allow_failures:
|
|
||||||
- crystal: nightly
|
|
||||||
|
|
||||||
install:
|
|
||||||
- shards install
|
|
||||||
|
|
||||||
script:
|
|
||||||
- crystal spec
|
|
||||||
- crystal spec --no-debug
|
|
||||||
- crystal spec --release
|
|
||||||
- crystal spec --release --no-debug
|
|
||||||
- crystal tool format --check
|
|
||||||
- bin/ameba
|
|
|
@ -1,4 +1,4 @@
|
||||||
# backtracer.cr [](https://travis-ci.com/Sija/backtracer.cr) [](https://github.com/Sija/backtracer.cr/releases) [](https://github.com/Sija/backtracer.cr/blob/master/LICENSE)
|
# backtracer.cr [](https://github.com/Sija/backtracer.cr/actions/workflows/ci.yml) [](https://github.com/Sija/backtracer.cr/releases) [](https://github.com/Sija/backtracer.cr/blob/master/LICENSE)
|
||||||
|
|
||||||
Crystal shard aiming to assist with parsing backtraces into a structured form.
|
Crystal shard aiming to assist with parsing backtraces into a structured form.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: backtracer
|
name: backtracer
|
||||||
version: 1.0.0
|
version: 1.2.2
|
||||||
|
|
||||||
authors:
|
authors:
|
||||||
- Sijawusz Pur Rahnama <sija@sija.pl>
|
- Sijawusz Pur Rahnama <sija@sija.pl>
|
||||||
|
@ -7,7 +7,7 @@ authors:
|
||||||
development_dependencies:
|
development_dependencies:
|
||||||
ameba:
|
ameba:
|
||||||
github: crystal-ameba/ameba
|
github: crystal-ameba/ameba
|
||||||
version: ~> 0.13.0
|
version: ~> 1.5.0
|
||||||
|
|
||||||
crystal: ">= 0.35.0"
|
crystal: ">= 0.35.0"
|
||||||
|
|
||||||
|
|
60
spec/backtracer/backtrace/frame/context_spec.cr
Normal file
60
spec/backtracer/backtrace/frame/context_spec.cr
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
require "../../../spec_helper"
|
||||||
|
|
||||||
|
def with_foo_context(&)
|
||||||
|
yield Backtracer::Backtrace::Frame::Context.new(
|
||||||
|
lineno: 10,
|
||||||
|
pre: %w[foo bar baz],
|
||||||
|
line: "violent offender!",
|
||||||
|
post: %w[boo far faz],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Backtracer::Backtrace::Frame::Context do
|
||||||
|
describe ".to_a" do
|
||||||
|
it "works with empty #pre and #post" do
|
||||||
|
context = Backtracer::Backtrace::Frame::Context.new(
|
||||||
|
lineno: 1,
|
||||||
|
pre: %w[],
|
||||||
|
line: "violent offender!",
|
||||||
|
post: %w[],
|
||||||
|
)
|
||||||
|
context.to_a.should eq(["violent offender!"])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns array with #pre, #line and #post strings" do
|
||||||
|
with_foo_context do |context|
|
||||||
|
context.to_a.should eq([
|
||||||
|
"foo", "bar", "baz",
|
||||||
|
"violent offender!",
|
||||||
|
"boo", "far", "faz",
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".to_h" do
|
||||||
|
it "works with empty #pre and #post" do
|
||||||
|
context = Backtracer::Backtrace::Frame::Context.new(
|
||||||
|
lineno: 1,
|
||||||
|
pre: %w[],
|
||||||
|
line: "violent offender!",
|
||||||
|
post: %w[],
|
||||||
|
)
|
||||||
|
context.to_h.should eq({1 => "violent offender!"})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns hash with #pre, #line and #post strings" do
|
||||||
|
with_foo_context do |context|
|
||||||
|
context.to_h.should eq({
|
||||||
|
7 => "foo",
|
||||||
|
8 => "bar",
|
||||||
|
9 => "baz",
|
||||||
|
10 => "violent offender!",
|
||||||
|
11 => "boo",
|
||||||
|
12 => "far",
|
||||||
|
13 => "faz",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
202
spec/backtracer/backtrace/frame/parser_spec.cr
Normal file
202
spec/backtracer/backtrace/frame/parser_spec.cr
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
require "../../../spec_helper"
|
||||||
|
|
||||||
|
describe Backtracer::Backtrace::Frame::Parser do
|
||||||
|
describe ".parse" do
|
||||||
|
it "fails to parse an empty string" do
|
||||||
|
expect_raises(ArgumentError) { with_frame("", &.itself) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when --no-debug flag is set" do
|
||||||
|
it "parses frame with any value as method" do
|
||||||
|
backtrace_line = "__crystal_main"
|
||||||
|
|
||||||
|
with_frame(backtrace_line) do |frame|
|
||||||
|
frame.lineno.should be_nil
|
||||||
|
frame.column.should be_nil
|
||||||
|
frame.method.should eq(backtrace_line)
|
||||||
|
frame.path.should be_nil
|
||||||
|
frame.relative_path.should be_nil
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with ~proc signature" do
|
||||||
|
it "parses absolute path outside of src/ dir" do
|
||||||
|
path = "/usr/local/Cellar/crystal/0.27.2/src/fiber.cr"
|
||||||
|
backtrace_line = "~proc2Proc(Fiber, (IO::FileDescriptor | Nil))@#{path}:72"
|
||||||
|
|
||||||
|
with_frame(backtrace_line) do |frame|
|
||||||
|
frame.lineno.should eq(72)
|
||||||
|
frame.column.should be_nil
|
||||||
|
frame.method.should eq("~proc2Proc(Fiber, (IO::FileDescriptor | Nil))")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(frame.path)
|
||||||
|
frame.relative_path.should be_nil
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "parses relative path inside of lib/ dir" do
|
||||||
|
with_configuration do |configuration|
|
||||||
|
path = "lib/kemal/src/kemal/route.cr"
|
||||||
|
backtrace_line = "~procProc(HTTP::Server::Context, String)@#{path}:11"
|
||||||
|
|
||||||
|
with_frame(backtrace_line) do |frame|
|
||||||
|
frame.lineno.should eq(11)
|
||||||
|
frame.column.should be_nil
|
||||||
|
frame.method.should eq("~procProc(HTTP::Server::Context, String)")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(
|
||||||
|
File.join(configuration.src_path.not_nil!, path)
|
||||||
|
)
|
||||||
|
frame.relative_path.should eq(frame.path)
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should eq("kemal")
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "parses absolute path outside of configuration.src_path" do
|
||||||
|
path = "/some/absolute/path/to/foo.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(frame.path)
|
||||||
|
frame.relative_path.should be_nil
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with in_app? = false" do
|
||||||
|
it "parses absolute path outside of src/ dir" do
|
||||||
|
with_foo_frame(path: "#{__DIR__}/foo.cr") do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq("#{__DIR__}/foo.cr")
|
||||||
|
frame.absolute_path.should eq(frame.path)
|
||||||
|
frame.relative_path.should eq("spec/backtracer/backtrace/frame/foo.cr")
|
||||||
|
frame.under_src_path?.should be_true
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "parses relative path outside of src/ dir" do
|
||||||
|
with_configuration do |configuration|
|
||||||
|
path = "some/relative/path/to/foo.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(
|
||||||
|
File.join(configuration.src_path.not_nil!, path)
|
||||||
|
)
|
||||||
|
frame.relative_path.should eq(frame.path)
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with in_app? = true" do
|
||||||
|
it "parses absolute path inside of src/ dir" do
|
||||||
|
src_path = File.expand_path("../../../../src", __DIR__)
|
||||||
|
path = "#{src_path}/foo.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(frame.path)
|
||||||
|
frame.relative_path.should eq("src/foo.cr")
|
||||||
|
frame.under_src_path?.should be_true
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "parses relative path inside of src/ dir" do
|
||||||
|
with_configuration do |configuration|
|
||||||
|
path = "src/foo.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(
|
||||||
|
File.join(configuration.src_path.not_nil!, path)
|
||||||
|
)
|
||||||
|
frame.relative_path.should eq(path)
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
frame.in_app?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with shard path" do
|
||||||
|
it "parses absolute path inside of lib/ dir" do
|
||||||
|
lib_path = File.expand_path("../../../../lib/bar", __DIR__)
|
||||||
|
path = "#{lib_path}/src/bar.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(frame.path)
|
||||||
|
frame.relative_path.should eq("lib/bar/src/bar.cr")
|
||||||
|
frame.under_src_path?.should be_true
|
||||||
|
frame.shard_name.should eq "bar"
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "parses relative path inside of lib/ dir" do
|
||||||
|
with_configuration do |configuration|
|
||||||
|
path = "lib/bar/src/bar.cr"
|
||||||
|
|
||||||
|
with_foo_frame(path: path) do |frame|
|
||||||
|
frame.lineno.should eq(1)
|
||||||
|
frame.column.should eq(7)
|
||||||
|
frame.method.should eq("foo_bar?")
|
||||||
|
frame.path.should eq(path)
|
||||||
|
frame.absolute_path.should eq(
|
||||||
|
File.join(configuration.src_path.not_nil!, path)
|
||||||
|
)
|
||||||
|
frame.relative_path.should eq(path)
|
||||||
|
frame.under_src_path?.should be_false
|
||||||
|
frame.shard_name.should eq "bar"
|
||||||
|
frame.in_app?.should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses only folders for shard names" do
|
||||||
|
with_foo_frame(path: "lib/bar.cr") do |frame|
|
||||||
|
frame.shard_name.should be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,207 +1,6 @@
|
||||||
require "../../spec_helper"
|
require "../../spec_helper"
|
||||||
|
|
||||||
private def parse_frame(line)
|
|
||||||
Backtracer::Backtrace::Frame::Parser.parse(line)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def with_frame(method, path = nil, lineno = nil, column = nil)
|
|
||||||
line = String.build do |io|
|
|
||||||
if path
|
|
||||||
io << path
|
|
||||||
io << ':' << lineno if lineno
|
|
||||||
io << ':' << column if column
|
|
||||||
io << " in '" << method << '\''
|
|
||||||
else
|
|
||||||
io << method
|
|
||||||
end
|
|
||||||
end
|
|
||||||
yield parse_frame(line)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def with_foo_frame(
|
|
||||||
method = "foo_bar?",
|
|
||||||
path = "#{__DIR__}/foo.cr",
|
|
||||||
lineno = 1,
|
|
||||||
column = 7
|
|
||||||
)
|
|
||||||
with_frame(method, path, lineno, column) do |frame|
|
|
||||||
yield frame
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Backtracer::Backtrace::Frame do
|
describe Backtracer::Backtrace::Frame do
|
||||||
describe ".parse" do
|
|
||||||
it "fails to parse an empty string" do
|
|
||||||
expect_raises(ArgumentError) { parse_frame("") }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when --no-debug flag is set" do
|
|
||||||
it "parses frame with any value as method" do
|
|
||||||
backtrace_line = "__crystal_main"
|
|
||||||
|
|
||||||
with_frame(backtrace_line) do |frame|
|
|
||||||
frame.lineno.should be_nil
|
|
||||||
frame.column.should be_nil
|
|
||||||
frame.method.should eq(backtrace_line)
|
|
||||||
frame.path.should be_nil
|
|
||||||
frame.relative_path.should be_nil
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with ~proc signature" do
|
|
||||||
it "parses absolute path outside of src/ dir" do
|
|
||||||
backtrace_line = "~proc2Proc(Fiber, (IO::FileDescriptor | Nil))@/usr/local/Cellar/crystal/0.27.2/src/fiber.cr:72"
|
|
||||||
|
|
||||||
with_frame(backtrace_line) do |frame|
|
|
||||||
frame.lineno.should eq(72)
|
|
||||||
frame.column.should be_nil
|
|
||||||
frame.method.should eq("~proc2Proc(Fiber, (IO::FileDescriptor | Nil))")
|
|
||||||
frame.path.should eq("/usr/local/Cellar/crystal/0.27.2/src/fiber.cr")
|
|
||||||
frame.relative_path.should be_nil
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "parses relative path inside of lib/ dir" do
|
|
||||||
backtrace_line = "~procProc(HTTP::Server::Context, String)@lib/kemal/src/kemal/route.cr:11"
|
|
||||||
|
|
||||||
with_frame(backtrace_line) do |frame|
|
|
||||||
frame.lineno.should eq(11)
|
|
||||||
frame.column.should be_nil
|
|
||||||
frame.method.should eq("~procProc(HTTP::Server::Context, String)")
|
|
||||||
frame.path.should eq("lib/kemal/src/kemal/route.cr")
|
|
||||||
frame.relative_path.should eq("lib/kemal/src/kemal/route.cr")
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should eq("kemal")
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "parses absolute path outside of configuration.src_path" do
|
|
||||||
path = "/some/absolute/path/to/foo.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should be_nil
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with in_app? = false" do
|
|
||||||
it "parses absolute path outside of src/ dir" do
|
|
||||||
with_foo_frame do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq("#{__DIR__}/foo.cr")
|
|
||||||
frame.relative_path.should eq("spec/backtracer/backtrace/foo.cr")
|
|
||||||
frame.under_src_path?.should be_true
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "parses relative path outside of src/ dir" do
|
|
||||||
path = "some/relative/path/to/foo.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should eq(path)
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with in_app? = true" do
|
|
||||||
it "parses absolute path inside of src/ dir" do
|
|
||||||
src_path = File.expand_path("../../../src", __DIR__)
|
|
||||||
path = "#{src_path}/foo.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should eq("src/foo.cr")
|
|
||||||
frame.under_src_path?.should be_true
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "parses relative path inside of src/ dir" do
|
|
||||||
path = "src/foo.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should eq(path)
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
frame.in_app?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with shard path" do
|
|
||||||
it "parses absolute path inside of lib/ dir" do
|
|
||||||
lib_path = File.expand_path("../../../lib/bar", __DIR__)
|
|
||||||
path = "#{lib_path}/src/bar.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should eq("lib/bar/src/bar.cr")
|
|
||||||
frame.under_src_path?.should be_true
|
|
||||||
frame.shard_name.should eq "bar"
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "parses relative path inside of lib/ dir" do
|
|
||||||
path = "lib/bar/src/bar.cr"
|
|
||||||
|
|
||||||
with_foo_frame(path: path) do |frame|
|
|
||||||
frame.lineno.should eq(1)
|
|
||||||
frame.column.should eq(7)
|
|
||||||
frame.method.should eq("foo_bar?")
|
|
||||||
frame.path.should eq(path)
|
|
||||||
frame.relative_path.should eq(path)
|
|
||||||
frame.under_src_path?.should be_false
|
|
||||||
frame.shard_name.should eq "bar"
|
|
||||||
frame.in_app?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "uses only folders for shard names" do
|
|
||||||
with_foo_frame(path: "lib/bar.cr") do |frame|
|
|
||||||
frame.shard_name.should be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#inspect" do
|
it "#inspect" do
|
||||||
with_foo_frame do |frame|
|
with_foo_frame do |frame|
|
||||||
frame.inspect.should match(/Backtrace::Frame(.*)$/)
|
frame.inspect.should match(/Backtrace::Frame(.*)$/)
|
||||||
|
@ -209,7 +8,7 @@ describe Backtracer::Backtrace::Frame do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "#to_s" do
|
it "#to_s" do
|
||||||
with_foo_frame do |frame|
|
with_foo_frame(path: "#{__DIR__}/foo.cr") do |frame|
|
||||||
frame.to_s.should eq "`foo_bar?` at #{__DIR__}/foo.cr:1:7"
|
frame.to_s.should eq "`foo_bar?` at #{__DIR__}/foo.cr:1:7"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -219,9 +18,44 @@ describe Backtracer::Backtrace::Frame do
|
||||||
with_foo_frame do |frame2|
|
with_foo_frame do |frame2|
|
||||||
frame.should eq(frame2)
|
frame.should eq(frame2)
|
||||||
end
|
end
|
||||||
with_foo_frame(method: "other_method") do |frame2|
|
with_foo_frame(method: "other_method") do |frame3|
|
||||||
frame.should_not eq(frame2)
|
frame.should_not eq(frame3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
{% unless flag?(:release) || !flag?(:debug) %}
|
||||||
|
describe "#context" do
|
||||||
|
it "returns proper lines" do
|
||||||
|
with_configuration do |configuration|
|
||||||
|
with_backtrace(caller) do |backtrace|
|
||||||
|
backtrace.frames.first.tap do |first_frame|
|
||||||
|
context_lines = configuration.context_lines.should_not be_nil
|
||||||
|
context = first_frame.context.should_not be_nil
|
||||||
|
|
||||||
|
lines = File.read_lines(__FILE__)
|
||||||
|
lineidx = context.lineno - 1
|
||||||
|
|
||||||
|
context.pre
|
||||||
|
.should eq(lines[Math.max(0, lineidx - context_lines), context_lines]?)
|
||||||
|
context.line
|
||||||
|
.should eq(lines[lineidx]?)
|
||||||
|
context.post
|
||||||
|
.should eq(lines[Math.min(lines.size, lineidx + 1), context_lines]?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns given amount of lines" do
|
||||||
|
with_backtrace(caller) do |backtrace|
|
||||||
|
backtrace.frames.first.tap do |first_frame|
|
||||||
|
context = first_frame.context(3).should_not be_nil
|
||||||
|
context.pre.size.should eq(3)
|
||||||
|
context.post.size.should eq(3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
end
|
end
|
||||||
|
|
21
spec/backtracer/backtrace/parser_spec.cr
Normal file
21
spec/backtracer/backtrace/parser_spec.cr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
require "../../spec_helper"
|
||||||
|
|
||||||
|
describe Backtracer::Backtrace::Parser do
|
||||||
|
describe ".parse" do
|
||||||
|
it "handles `caller` as an input" do
|
||||||
|
with_backtrace(caller) do |backtrace|
|
||||||
|
backtrace.frames.should_not be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles `Exception#backtrace` as an input" do
|
||||||
|
begin
|
||||||
|
raise "Oh, no!"
|
||||||
|
rescue ex
|
||||||
|
with_backtrace(ex.backtrace) do |backtrace|
|
||||||
|
backtrace.frames.should_not be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,24 +1,31 @@
|
||||||
require "../spec_helper"
|
require "../spec_helper"
|
||||||
|
|
||||||
describe Backtracer::Backtrace do
|
describe Backtracer::Backtrace do
|
||||||
backtrace = Backtracer.parse(caller)
|
|
||||||
|
|
||||||
it "#frames" do
|
it "#frames" do
|
||||||
|
with_backtrace(caller) do |backtrace|
|
||||||
backtrace.frames.should be_a(Array(Backtracer::Backtrace::Frame))
|
backtrace.frames.should be_a(Array(Backtracer::Backtrace::Frame))
|
||||||
|
backtrace.frames.should_not be_empty
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "#inspect" do
|
it "#inspect" do
|
||||||
backtrace.inspect.should match(/#<Backtrace: .*>$/)
|
with_backtrace(caller) do |backtrace|
|
||||||
|
backtrace.inspect.should match(/#<Backtrace: .+>$/)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
{% unless flag?(:release) || !flag?(:debug) %}
|
{% unless flag?(:release) || !flag?(:debug) %}
|
||||||
it "#to_s" do
|
it "#to_s" do
|
||||||
backtrace.to_s.should match(/backtrace_spec.cr:4/)
|
with_backtrace(caller) do |backtrace|
|
||||||
|
backtrace.to_s.should match(/backtrace_spec.cr/)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
it "#==" do
|
it "#==" do
|
||||||
|
with_backtrace(caller) do |backtrace|
|
||||||
backtrace2 = Backtracer::Backtrace.new(backtrace.frames)
|
backtrace2 = Backtracer::Backtrace.new(backtrace.frames)
|
||||||
backtrace2.should eq(backtrace)
|
backtrace2.should eq(backtrace)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
require "../spec_helper"
|
require "../spec_helper"
|
||||||
|
|
||||||
private def with_configuration
|
|
||||||
yield Backtracer::Configuration.new
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Backtracer::Configuration do
|
describe Backtracer::Configuration do
|
||||||
it "should set #src_path to current dir from default" do
|
it "should set #src_path to current dir from default" do
|
||||||
with_configuration do |configuration|
|
with_configuration do |configuration|
|
||||||
|
|
|
@ -1,2 +1,37 @@
|
||||||
require "spec"
|
require "spec"
|
||||||
require "../src/backtracer"
|
require "../src/backtracer"
|
||||||
|
|
||||||
|
def with_configuration(shared = true, &)
|
||||||
|
yield shared ? Backtracer.configuration : Backtracer::Configuration.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_backtrace(backtrace, **options, &)
|
||||||
|
yield Backtracer::Backtrace::Parser.parse(backtrace, **options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_frame(method, path = nil, lineno = nil, column = nil, **options, &)
|
||||||
|
line = String.build do |io|
|
||||||
|
if path
|
||||||
|
io << path
|
||||||
|
io << ':' << lineno if lineno
|
||||||
|
io << ':' << column if column
|
||||||
|
io << " in '" << method << '\''
|
||||||
|
else
|
||||||
|
io << method
|
||||||
|
end
|
||||||
|
end
|
||||||
|
yield Backtracer::Backtrace::Frame::Parser.parse(line, **options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_foo_frame(
|
||||||
|
method = "foo_bar?",
|
||||||
|
path = "#{__DIR__}/foo.cr",
|
||||||
|
lineno = 1,
|
||||||
|
column = 7,
|
||||||
|
**options,
|
||||||
|
&
|
||||||
|
)
|
||||||
|
with_frame(method, path, lineno, column, **options) do |frame|
|
||||||
|
yield frame
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
module Backtracer
|
module Backtracer
|
||||||
class_getter(configuration) { Configuration.new }
|
class_getter(configuration) { Configuration.new }
|
||||||
|
|
||||||
|
def self.configure(&) : Nil
|
||||||
|
yield configuration
|
||||||
|
end
|
||||||
|
|
||||||
def self.parse(backtrace : Array(String) | String, **options) : Backtrace
|
def self.parse(backtrace : Array(String) | String, **options) : Backtrace
|
||||||
Backtrace::Parser.parse(backtrace, **options)
|
Backtrace::Parser.parse(backtrace, **options)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
module Backtracer
|
module Backtracer
|
||||||
# An object representation of a stack frame.
|
# An object representation of a stack frame.
|
||||||
struct Backtrace::Frame
|
struct Backtrace::Frame
|
||||||
|
@context_cache = {} of Int32 => Context
|
||||||
|
|
||||||
# The method of this frame (such as `User.find`).
|
# The method of this frame (such as `User.find`).
|
||||||
getter method : String
|
getter method : String
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ module Backtracer
|
||||||
|
|
||||||
def_equals_and_hash @method, @path, @lineno, @column
|
def_equals_and_hash @method, @path, @lineno, @column
|
||||||
|
|
||||||
# Reconstructs the frame in a readable fashion
|
# Reconstructs the frame in a readable fashion.
|
||||||
def to_s(io : IO) : Nil
|
def to_s(io : IO) : Nil
|
||||||
io << '`' << @method << '`'
|
io << '`' << @method << '`'
|
||||||
if @path
|
if @path
|
||||||
|
@ -37,11 +39,24 @@ module Backtracer
|
||||||
io << ')'
|
io << ')'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns `true` if `path` of this frame is within
|
||||||
|
# the `configuration.src_path`, `false` otherwise.
|
||||||
|
#
|
||||||
|
# See `Configuration#src_path`
|
||||||
def under_src_path? : Bool
|
def under_src_path? : Bool
|
||||||
return false unless src_path = configuration.src_path
|
return false unless src_path = configuration.src_path
|
||||||
!!path.try(&.starts_with?(src_path))
|
!!path.try(&.starts_with?(src_path))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
#
|
||||||
|
# - `path` as is, unless it's absolute - i.e. starts with `/`
|
||||||
|
# - `path` relative to `configuration.src_path` when `under_src_path?` is `true`
|
||||||
|
# - `nil` otherwise
|
||||||
|
#
|
||||||
|
# NOTE: returned path is not required to be `under_src_path?` - see point no. 1
|
||||||
|
#
|
||||||
|
# See `Configuration#src_path`
|
||||||
def relative_path : String?
|
def relative_path : String?
|
||||||
return unless path = @path
|
return unless path = @path
|
||||||
return path unless path.starts_with?('/')
|
return path unless path.starts_with?('/')
|
||||||
|
@ -51,6 +66,13 @@ module Backtracer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
#
|
||||||
|
# - `path` as is, if it's absolute - i.e. starts with `/`
|
||||||
|
# - `path` appended to `configuration.src_path`
|
||||||
|
# - `nil` otherwise
|
||||||
|
#
|
||||||
|
# See `Configuration#src_path`
|
||||||
def absolute_path : String?
|
def absolute_path : String?
|
||||||
return unless path = @path
|
return unless path = @path
|
||||||
return path if path.starts_with?('/')
|
return path if path.starts_with?('/')
|
||||||
|
@ -59,51 +81,67 @@ module Backtracer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns name of the shard from which this frame originated.
|
||||||
|
#
|
||||||
|
# See `Configuration#modules_path_pattern`
|
||||||
def shard_name : String?
|
def shard_name : String?
|
||||||
relative_path
|
relative_path
|
||||||
.try(&.match(configuration.modules_path_pattern))
|
.try(&.match(configuration.modules_path_pattern))
|
||||||
.try(&.["name"])
|
.try(&.["name"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns `true` if this frame originated from the app source code,
|
||||||
|
# `false` otherwise.
|
||||||
|
#
|
||||||
|
# See `Configuration#app_dirs_pattern`
|
||||||
def in_app? : Bool
|
def in_app? : Bool
|
||||||
!!(path.try(&.matches?(configuration.in_app_pattern)))
|
!!(relative_path.try(&.matches?(configuration.app_dirs_pattern)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def context(context_lines : Int32? = nil) : {Array(String), String, Array(String)}?
|
# Returns `Context` record consisting of 3 elements - an array of context lines
|
||||||
|
# before the `lineno`, line at `lineno`, and an array of context lines
|
||||||
|
# after the `lineno`. In case of failure it returns `nil`.
|
||||||
|
#
|
||||||
|
# Amount of returned context lines is taken from the *context_lines*
|
||||||
|
# argument if given, or `configuration.context_lines` otherwise.
|
||||||
|
#
|
||||||
|
# NOTE: amount of returned context lines might be lower than given
|
||||||
|
# in cases where `lineno` is near the start or the end of the file.
|
||||||
|
#
|
||||||
|
# See `Configuration#context_lines`
|
||||||
|
def context(context_lines : Int32? = nil) : Context?
|
||||||
context_lines ||= configuration.context_lines
|
context_lines ||= configuration.context_lines
|
||||||
|
|
||||||
return unless context_lines && (context_lines > 0)
|
return unless context_lines && (context_lines > 0)
|
||||||
|
|
||||||
|
cached = @context_cache[context_lines]?
|
||||||
|
return cached if cached
|
||||||
|
|
||||||
return unless (lineno = @lineno) && (lineno > 0)
|
return unless (lineno = @lineno) && (lineno > 0)
|
||||||
return unless (path = @path) && File.readable?(path)
|
return unless (path = @path) && File.readable?(path)
|
||||||
|
|
||||||
lines = File.read_lines(path)
|
context_line = nil
|
||||||
lineidx = lineno - 1
|
pre_context, post_context = %w[], %w[]
|
||||||
|
|
||||||
if context_line = lines[lineidx]?
|
i = 0
|
||||||
pre_context = lines[Math.max(0, lineidx - context_lines), context_lines]
|
File.each_line(path) do |line|
|
||||||
post_context = lines[Math.min(lines.size, lineidx + 1), context_lines]
|
case i += 1
|
||||||
{pre_context, context_line, post_context}
|
when lineno - context_lines...lineno
|
||||||
|
pre_context << line
|
||||||
|
when lineno
|
||||||
|
context_line = line
|
||||||
|
when lineno + 1..lineno + context_lines
|
||||||
|
post_context << line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def context_hash(context_lines : Int32? = nil) : Hash(Int32, String)?
|
if context_line
|
||||||
return unless context = self.context(context_lines)
|
@context_cache[context_lines] =
|
||||||
return unless lineno = @lineno
|
Context.new(
|
||||||
|
lineno: lineno,
|
||||||
pre_context, context_line, post_context = context
|
pre: pre_context,
|
||||||
|
line: context_line,
|
||||||
({} of Int32 => String).tap do |hash|
|
post: post_context,
|
||||||
pre_context.each_with_index do |code, index|
|
)
|
||||||
line = (lineno - pre_context.size) + index
|
|
||||||
hash[line] = code
|
|
||||||
end
|
|
||||||
|
|
||||||
hash[lineno] = context_line
|
|
||||||
|
|
||||||
post_context.each_with_index do |code, index|
|
|
||||||
line = lineno + (index + 1)
|
|
||||||
hash[line] = code
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
46
src/backtracer/backtrace/frame/context.cr
Normal file
46
src/backtracer/backtrace/frame/context.cr
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
module Backtracer
|
||||||
|
struct Backtrace::Frame::Context
|
||||||
|
# The line number this `Context` refers to.
|
||||||
|
getter lineno : Int32
|
||||||
|
|
||||||
|
# An array of lines before `lineno`.
|
||||||
|
getter pre : Array(String)
|
||||||
|
|
||||||
|
# The line at `lineno`.
|
||||||
|
getter line : String
|
||||||
|
|
||||||
|
# An array of lines after `lineno`.
|
||||||
|
getter post : Array(String)
|
||||||
|
|
||||||
|
def initialize(@lineno, @pre, @line, @post)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an array composed of context lines from `pre`,
|
||||||
|
# `line` and `post`.
|
||||||
|
def to_a : Array(String)
|
||||||
|
([] of String).tap do |ary|
|
||||||
|
ary.concat(pre)
|
||||||
|
ary << line
|
||||||
|
ary.concat(post)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns hash with context lines, where line numbers are
|
||||||
|
# the keys and the lines itself are the values.
|
||||||
|
def to_h : Hash(Int32, String)
|
||||||
|
({} of Int32 => String).tap do |hash|
|
||||||
|
base_index = lineno - pre.size
|
||||||
|
pre.each_with_index do |code, index|
|
||||||
|
hash[base_index + index] = code
|
||||||
|
end
|
||||||
|
|
||||||
|
hash[lineno] = line
|
||||||
|
|
||||||
|
base_index = lineno + 1
|
||||||
|
post.each_with_index do |code, index|
|
||||||
|
hash[base_index + index] = code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,10 +2,13 @@ module Backtracer
|
||||||
module Backtrace::Frame::Parser
|
module Backtrace::Frame::Parser
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
# Parses a single line of a given backtrace, where *unparsed_line* is
|
# Parses a single line of a given backtrace, where *line* is
|
||||||
# the raw line from `caller` or some backtrace.
|
# the raw line from `caller` or some backtrace.
|
||||||
#
|
#
|
||||||
# Returns the parsed backtrace frame on success or `nil` otherwise.
|
# Accepts options:
|
||||||
|
# - `configuration`: `Configuration` object - uses `Backtracer.configuration` if `nil`
|
||||||
|
#
|
||||||
|
# Returns parsed `Backtrace::Frame` on success or `nil` otherwise.
|
||||||
def parse?(line : String, **options) : Backtrace::Frame?
|
def parse?(line : String, **options) : Backtrace::Frame?
|
||||||
return unless Configuration::LINE_PATTERNS.any? &.match(line)
|
return unless Configuration::LINE_PATTERNS.any? &.match(line)
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ module Backtracer
|
||||||
configuration: options[:configuration]?
|
configuration: options[:configuration]?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Same as `parse?` but raises `ArgumentError` on error.
|
||||||
def parse(line : String, **options) : Backtrace::Frame
|
def parse(line : String, **options) : Backtrace::Frame
|
||||||
parse?(line, **options) ||
|
parse?(line, **options) ||
|
||||||
raise ArgumentError.new("Error parsing line: #{line.inspect}")
|
raise ArgumentError.new("Error parsing line: #{line.inspect}")
|
||||||
|
|
|
@ -2,6 +2,14 @@ module Backtracer
|
||||||
module Backtrace::Parser
|
module Backtrace::Parser
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
|
# Parses *backtrace* (possibly obtained as a return value
|
||||||
|
# from `caller` or `Exception#backtrace` methods).
|
||||||
|
#
|
||||||
|
# Accepts options:
|
||||||
|
# - `configuration`: `Configuration` object - uses `Backtracer.configuration` if `nil`
|
||||||
|
# - `filters`: additional line filters - see `Configuration#line_filters`
|
||||||
|
#
|
||||||
|
# Returns parsed `Backtrace` object or raises `ArgumentError` otherwise.
|
||||||
def parse(backtrace : Array(String), **options) : Backtrace
|
def parse(backtrace : Array(String), **options) : Backtrace
|
||||||
configuration = options[:configuration]? || Backtracer.configuration
|
configuration = options[:configuration]? || Backtracer.configuration
|
||||||
|
|
||||||
|
|
|
@ -53,24 +53,32 @@ module Backtracer
|
||||||
/^(?<method>.+?)$/,
|
/^(?<method>.+?)$/,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Used in `#in_app_pattern`.
|
# Path considered as "root" of your project.
|
||||||
|
#
|
||||||
|
# See `Frame#under_src_path?`
|
||||||
property src_path : String? = {{ Process::INITIAL_PWD }}
|
property src_path : String? = {{ Process::INITIAL_PWD }}
|
||||||
|
|
||||||
# Directories to be recognized as part of your app. e.g. if you
|
# Directories to be recognized as part of your app. e.g. if you
|
||||||
# have an `engines` dir at the root of your project, you may want
|
# have an `engines` dir at the root of your project, you may want
|
||||||
# to set this to something like `/(src|engines)/`
|
# to set this to something like `/^(src|engines)\//`
|
||||||
property app_dirs_pattern = /src/
|
#
|
||||||
|
# See `Frame#in_app?`
|
||||||
# `Regex` pattern matched against `Backtrace::Frame#file`.
|
property app_dirs_pattern = /^src\//
|
||||||
property in_app_pattern : Regex { /^(#{src_path}\/)?(#{app_dirs_pattern})/ }
|
|
||||||
|
|
||||||
# Path pattern matching directories to be recognized as your app modules.
|
# Path pattern matching directories to be recognized as your app modules.
|
||||||
# Defaults to standard Shards setup (`lib/shard-name/...`).
|
# Defaults to standard Shards setup (`lib/shard-name/...`).
|
||||||
|
#
|
||||||
|
# See `Frame#shard_name`
|
||||||
property modules_path_pattern = /^lib\/(?<name>[^\/]+)\/(?:.+)/
|
property modules_path_pattern = /^lib\/(?<name>[^\/]+)\/(?:.+)/
|
||||||
|
|
||||||
# Number of lines of code context to capture, or `nil` for none.
|
# Number of lines of code context to return by default, or `nil` for none.
|
||||||
|
#
|
||||||
|
# See `Frame#context`
|
||||||
property context_lines : Int32? = 5
|
property context_lines : Int32? = 5
|
||||||
|
|
||||||
|
# Array of procs used for filtering backtrace lines before parsing.
|
||||||
|
# Each filter is expected to return a string, which is then passed
|
||||||
|
# onto the next filter, or ignored althoghether if `nil` is returned.
|
||||||
getter(line_filters) {
|
getter(line_filters) {
|
||||||
[
|
[
|
||||||
->(line : String) { line unless line.matches?(IGNORED_LINES_PATTERN) },
|
->(line : String) { line unless line.matches?(IGNORED_LINES_PATTERN) },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue