Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend/replace implementation with ruby/debug's tracers? #8

Closed
st0012 opened this issue May 15, 2022 · 15 comments
Closed

Extend/replace implementation with ruby/debug's tracers? #8

st0012 opened this issue May 15, 2022 · 15 comments

Comments

@st0012
Copy link
Member

st0012 commented May 15, 2022

ruby/debug has 4 types of tracers:

  • LineTracer
  • CallTracer
  • ExceptionTracer
  • ObjectTracer

All of them are super powerful and the implementation is mostly debugger-independent. With a few tweaks they can be completely extracted. So I'm thinking maybe we can move those tracers here so users can use it without the debugger? With API like

Tracer.trace_line # LineTracer
Tracer.trace_call # CallTracer
Tracer.trace_exception # ExceptionTracer
Tracer.trace_object(obj) # ObjectTracer

And we can support 2 ways to turn it on/off

tracer = Tracer.trace_line
# code
tracer.off

# or

Tracer.trace_line do
  # code
end

And the debugger can depend on this gem, similar to it depends on irb and reline.

Benefits

  • Users can use those tracers without the debugger
  • Users can extend/build their tracers based on the standardized tracer APIs
  • Other debugging tools can also require it
  • irb --tracer can be more powerful

We need to think about coloring more carefully though. Ideally, the updated tracer should support out-of-box coloring. But it means we need to replicate the irb's coloring logic because we can't depend on irb. Perhaps extracting that to a colorable utility gem will be better in the long-term?

Wdyt? @ko1 @hsbt

@hsbt
Copy link
Member

hsbt commented May 17, 2022

I have no opinion about that. I'm not sure how many people use the current implementation.

@st0012
Copy link
Member Author

st0012 commented May 17, 2022

Yeah given that it only has 200k downloads, it probably doesn't have many users. And the current implementation is pretty outdated so it won't be too helpful for most users.

I've discussed about this with @ko1 and he doesn't want to maintain the debugger tracers in a separate gem. So I guess it's one less incentive to update this project. Perhaps it's ready to be deprecated? 🤔

@thiagofm
Copy link

Hey @st0012 I quite like the idea as well. Also to make it extensible. Tracer has a lot of potential, but we need to find a good way of actually showing partial traces in a nice way.

I also like the block-style you've mentioned. We could definitely give it more love.

@st0012
Copy link
Member Author

st0012 commented Jun 16, 2022

@thiagofm I'm glad that you like the idea!

Given my past experience building object_tracer, I'm definitely behind having a simple tracing library vs always loading the debugger just for tracing. I now mainly use

debugger(do: "trace call")
# stuff
debugger(do: "trace off")

to mimic the block API I imagined, which is a bit clunky.

But I think it ultimately comes down to how many users will use this if we put more effort on it. I'm actually quite surprised that you found this issue because I don't know much developers using tracers. Do you know any other Rubyists that use tracing for debugging?

@thiagofm
Copy link

thiagofm commented Jun 16, 2022

(skip this if you are just skimming through the issue, it's a bit offtopic)

@st0012 hey there! To be honest, it's a topic I think about often, or debuggers themselves, like reverse debuggers. Also, I think many developers end up using tracing in a way or the other, one common being like an exception tracker or tools like Datadog or New Relic. Every developer in the world has bugs to fix or understand code 😄

I think currently, what we are used to in Software Development(from printing statements to debugging), we are not there yet. There's probably a better way of seeing the executing of a program that doesn't involve setting many breakpoints and would let you navigate this. Or Trace. There's a lot of cargo-cult in the debuggers/tracers that we use day to day and little innovation.

On tracing, so you wrap some code around and see what happened. The thing is, currently tracing is very clunky. Most of it you want actually filtered out, but if you filter too much, you might end up with an issue.

Debuggers with "next" functionality try to achieve some of it, but you miss too much context. Sometimes you use "next" and end up somewhere you didn't want.

Ideally, tracing is actually better than debugging if it wouldn't be so clunky. My thought is, how to remove the clunkiness from tracing in a smart way?

Btw, let's move this discussion somewhere else 😄 Send me an e-mail at thiagown @ gmail, let's have a chat.

@st0012
Copy link
Member Author

st0012 commented Jun 16, 2022

I feel this discussion is actually relevant to the issue because there's very few discussion about (development) tracing!

To me, debugging usually consists of 2 steps: explore and locate.

  1. Explore: get a higher level understanding on how the program (or a feature) works.
  2. Locate: locate the exact code that cause the issue, usually by bisecting a code path.

This is because in reality, our programs have many code paths, and we rarely know the exact code path that triggers the bug from beginning to end. So step 1 is to find the code path, and step 2 is to find the problematic method (usually) on that code path.

I think currently many devs use breakpoint for both phases, which does the job but not efficient. Breakpoint pins on a single point so it works really well on one path (think about git bisect), therefore great for 2. But for 1, tracing is what we really need.

(I know you already know these but I just want to vent them out 😛)

So how do we make tracing accurate enough? The thing I'm pushing for is to create different tracers for different targets instead of always start from tracing method calls. That's why we have these in the debugger

  • ExceptionTracer - traces a single exception class
  • ObjectTracer - traces a single object

So I'm already doing something like this:

  1. Use trace call /regexp/ to get the rough code paths and what objects may involve in the process
  2. Use break Class#method do: trace object self to see what an object does
    • It breaks at Class#method, run trace object self, and continue the program
    • trace object prints when the object receives a method call or when it is passed into a method (super useful)
  3. Repeat 2 a few times and then locate the exact code path
    • Unlike breakpoints, I don't need to type anything in the REPL
    • Unlike puts, I don't need to type variable names or format my messages
  4. Use breakpoints to pinpoint the cause, which is quite easy at this stage

Now you may think "so it looks like tracers need to be used with breakpoints, why do we want to extract them?". It's because:

  1. If you're a Pry guy, you don't need to switch to ruby/debug for using tracers (which is likely results in not using tracers at all). You can put Tracer.trace_object(obj) just like binding.pry everywhere.
  2. Debuggers, especially ruby/debug are relatively intrusive to your program (e.g. registers at_exit callback, intercepts singals, starts additional threads...etc.) and you may not want to invoke it depends on the project and the bug you're tracking.

To wrap up: I'm totally confident that we can make tracers not clunky and practical to use (which I think is already true for ruby/debug's tracers). The question is, will having a dedicated tracer library (this repo) helps promoting this technique?

@st0012
Copy link
Member Author

st0012 commented Jun 20, 2022

@hsbt @ko1 If you are not oppose to this project, I'd like to start working on this project as an outside collaborator. I will use v0.2.0 as the first prototype release target, which you can use to decide whether we're continuing on it or not. If you do like it, the end goal is to make v1.0.0 before the Ruby 3.2 release. But if you don't, we can stop there and your can revert it back to the current version without anything being released.

As for substituting ruby/debug's tracer implementation, we can wait till this project reach 1.0 and decide whether it'll make sense or not.

@ko1
Copy link

ko1 commented Jul 5, 2022

I have no opinion too. Now tracer.rb is not bundled with Ruby package, so it is one of gems.
So I think the author can decide it and

Keiju ISHITSUKA(keiju@ishitsuka.com)

the author seems Ishituka-san.

@st0012
Copy link
Member Author

st0012 commented Jul 5, 2022

@ko1 Thank you for the information. I've wrote him a letter 👍

@st0012
Copy link
Member Author

st0012 commented Aug 6, 2022

It's been a month since I sent the email, but I still got no feedback. I guess it's a no then 😞

@st0012 st0012 closed this as completed Aug 6, 2022
@st0012
Copy link
Member Author

st0012 commented Feb 10, 2023

I recently implemented the extraction in my ruby_tracer project.

I'll use it to explore:

  • What's the best APIs for direct usages
  • How can other tools, like IRB, integrates with it

I also found that it's a lot easier to write tests after the extraction, and therefore found a few ObjectTracer bugs. So IMO, it'd be beneficial in the long-term to have a shared tracer library.

@hsbt hsbt reopened this May 13, 2023
@hsbt
Copy link
Member

hsbt commented May 13, 2023

I discussed this with @st0012. I'm okay to replace this repository and rubygems with ruby_tracer implementation because the old implementation of tracer used by a few people(or no one use it).

@st0012 How about the following instructions for replacing tracer?

  1. I rename the current master to v0.1.
  2. I will push main branch of ruby_tracer into this repository.
  3. (optional) change default branch master to main.
  4. I will add you to https://rubygems.org/gems/tracer as owner.
  5. You archive your repository and rename ruby_tracer to tracer on default branch.
  6. ship new version of tracer

@st0012
Copy link
Member Author

st0012 commented May 15, 2023

@hsbt The plan looks great, thank you 👍
I will keep the default branch here to master to be consistent with other projects.

And in step 5 I have these todos:

  • Add Ishitsuka-san to the author and email list
  • Change the license to ["Ruby", "BSD-2-Clause"]
  • Update license file

@hsbt
Copy link
Member

hsbt commented May 19, 2023

@st0012 👋 I finished to do with 1-4. Let me know if you have any concerns.

@st0012
Copy link
Member Author

st0012 commented May 19, 2023

@hsbt Thank you for the help! I've completed the remaining steps 😄

@st0012 st0012 closed this as completed May 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants