Skip to content

Commit

Permalink
Debugging (#158)
Browse files Browse the repository at this point in the history
* Outline

* Outline to sections

* Bump checkout version in workflow and make it possible to fetch history

* Fix bash script for generating contributors file

---------

Co-authored-by: Erik Stenman <[email protected]>
Co-authored-by: Tobias Lindahl <[email protected]>
  • Loading branch information
3 people authored May 27, 2023
1 parent 2965fd8 commit e26eb1e
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 33 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ jobs:

steps:
- name: Checkout
uses: actions/[email protected]
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: install tools
run: apk add git rsync erlang
- name: build
Expand Down
4 changes: 2 additions & 2 deletions bin/gitlog.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
echo `git --no-pager shortlog -s HEAD | sort -n -r | awk '{$1=""}1' | grep -v "Erik Stenman" | grep -v "Your Name" > $1`
git --no-pager log HEAD | git --no-pager shortlog -s -n | awk '{$1=""}1' | grep -v "Your Name" > $1
git config --global --add safe.directory /__w/theBeamBook/theBeamBook
git --no-pager log | git --no-pager shortlog -s -n | awk '{$1=""}1' | grep -v "Your Name" > $1
159 changes: 129 additions & 30 deletions chapters/debugging.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,98 @@ still welcome to submit your feedback using a GitHub Issue. You can
use the same mechanism to suggest sections that you believe should be
included in this chapter, too.

=== Preliminary Outline

* Introduction
* debugger
* dbg
* redbug
* Crash dumps
* ...

=== Introduction
In long-running, 24/7 systems, the occasional bug or unwanted feature is bound to emerge. This chapter goes into the various methods for finding and fixing bugs without disrupting the services in progress. As a reader, you will explore testing techniques, tools, and frameworks that aid in testing and debugging your code. We'll also shed light on some common bug sources, such as deadlocks, message overflow, and memory issues, providing guidance on identifying and resolving these problems.

Debugging is the _art_ of identifying and removing errors
(i.e. _bugs_) from software. This section covers the most common
Erlang debugging tools and techniques. Even if step-by-step debugging
tools such as the
http://erlang.org/doc/apps/debugger/debugger_chapter.html[_Debugger_]
exist in Erlang, the most effective debugging techniques in Erlang are
the ones based on the so-called Erlang _tracing facilities_, which
will be discussed in detail in chapter xref:CH-Tracing[]. This chapter
also covers the concept of _Crash Dump_, a readable text file
generated by the Erlang Runtime System when an unrecoverable error is
detected, for example when the system runs out of memory or when an
emulator limit is reached. _Crash Dumps_ can are extremely precious
for post-mortem analysis of Erlang nodes and you will learn how to
read and interpret them.

=== debugger
Debugging is the process of identifying and eliminating errors, or "bugs," from software. While Erlang offers step-by-step debugging tools like the link:http://erlang.org/doc/apps/debugger/debugger_chapter.html[_Debugger_], the most effective debugging methods often rely on Erlang's tracing facilities. These facilities will be thoroughly discussed in Chapter xref:CH-Tracing[].

TODO
This chapter also explores the concept of "Crash Dumps," which are human-readable text files generated by the Erlang Runtime System when an unrecoverable error occurs, such as running out of memory or reaching an emulator limit. Crash Dumps are invaluable for post-mortem analysis of Erlang nodes, and you will learn how to interpret and understand them.

In addition to the aforementioned topics, this chapter will also provide an overview of various other essential aspects of debugging in Erlang systems. We will discuss different testing methodologies, including EUnit and Common Test, which are crucial for ensuring the reliability and robustness of your code. The importance of mocking in testing will be examined, along with its best practices.

Moreover, we will address common sources of bugs, such as deadlocks, mailbox overflow, and memory issues, and provide guidance on how to identify and resolve these problems. You will become acquainted with the "let it crash" principle and the ways to effectively implement it within your system. You'll gain insights into the workings of exceptions and supervisor tree design.

We'll also touch upon Erlang debugger usage, the role of redbug in making debugging easier and safer on live systems, and the basics of utilizing gdb for ERTS-level debugging. Furthermore, you will become familiar with dtrace and systemtap, possibly even picking up some debugging philosophy along the way.

By the end of this chapter, you'll be equipped with the knowledge to systematically test your system and its individual components. You will be able to identify common mistakes and problems, and wield the debugger effectively.



=== Testing tools
In this chapter, we will delve into the world of testing and explore how to ensure the reliability and robustness of your Erlang code. We will start with EUnit, a popular testing framework that makes it easy to write and run tests on your applications.

==== EUnit
EUnit is an Erlang unit testing framework that allows you to test individual program units. These units can range from functions and modules to processes and even whole applications. EUnit helps you write, run, and analyze the results of tests, ensuring your code is correct and reliable.

===== Basics and setup
To use EUnit in your Erlang module, include the following line after the -module declaration:


[source,erlang]
----
-include_lib("eunit/include/eunit.hrl").
----

This line provides access to EUnit's features and exports a `test()` function for running all the unit tests in your module.

===== Writing test cases and test suites
To create a simple test function, define a function with a name ending in `_test()` that takes no arguments. It should succeed by returning a value or fail by throwing an exception.

Use pattern matching with = to create more advanced test cases. For example:

[source,erlang]
----
reverse_nil_test() -> [] = lists:reverse([]).
----

Alternatively, you can use the `?assert(Expression)` macro to write test cases that evaluate expressions:

[source,erlang]
----
length_test() -> ?assert(length([1,2,3]) =:= 3).
----

===== Running tests and analyzing results
If you've included the EUnit declaration in your module, compile the module and run the automatically exported `test()` function. For example, if your module is named `m`, call `m:test()` to run EUnit on all the tests in the module.

EUnit can also run tests using the `eunit:test/1` function. For instance, calling `eunit:test(m)` is equivalent to calling `m:test()`.

=== dbg
To separate your test code from your normal code, write the test functions in a module named `m_tests` if your module is named `m`. When you ask EUnit to test the module `m`, it will also look for the module `m_tests` and run those tests.

EUnit captures standard output from test functions, so if your test code writes to the standard output, the text will not appear on the console. To bypass this, use the EUnit debugging macros or write to the user output stream, like `io:format(user, "~w", [Term])`.

For more information on checking the output produced by the unit under test, see the link:https://www.erlang.org/doc/apps/eunit/chapter.html[EUnit documentation] on macros for checking output.


==== Common Test
TODO
===== Basics and setup
TODO
===== Writing test cases and test suites
TODO
===== Running tests and analyzing results
TODO

=== Debugging Tools and Techniques

=== Redbug
==== The Erlang debugger (dbg)
===== Getting started with dbg
===== Tracing and breakpoints
===== Analyzing debugger output




==== Redbug

_Redbug_ is a debugging utility which allows you to easily interact
with the Erlang _tracing facilities_. It is an external library and
therefore it has to be installed separately. One of the best Redbug
features is its ability to shut itself down in case of overload.

==== Installing Redbug
===== Installing Redbug

You can clone redbug via:

Expand Down Expand Up @@ -85,7 +135,9 @@ automatically at every startup:
code:add_patha("/path/to/redbug/ebin").
----

==== Using Redbug


===== Using Redbug

Redbug is safe to be used in production, thanks to a self-protecting
mechanism against overload, which kills the tool in case too many
Expand Down Expand Up @@ -325,6 +377,53 @@ available options for redbug, you can ask the tool itself:
18> redbug:help().
----

=== Crash Dumps
==== Crash dumps
===== Understanding and reading crash dumps
===== Investigating why crash dumps may not be generated

==== Debugging the Runtime System
===== Using GDB
====== Basics of GDB for Erlang
====== Using GDB macros

===== SystemTap and DTrace
====== Introduction to SystemTap and DTrace
====== Using SystemTap and DTrace with Erlang



=== Mocking
==== Overview and benefits
==== Using mocks in Erlang tests
==== Best practices for mocking

=== Property Based Testing
==== QuickCheck and PropEr

=== The Usual Suspects: Common Sources of Bugs
==== Deadlocks
===== Identifying and diagnosing deadlocks
===== Techniques for resolving deadlocks
==== Mailbox overflow
===== Causes and symptoms
===== Preventing and resolving mailbox overflow issues
==== Memory issues
===== Identifying memory leaks
===== Managing binary memory usage
===== Optimizing memory usage in Erlang systems

=== Let it Crash Principle

===== Overview and rationale

===== Exceptions in Erlang

===== Designing systems with supervisor trees


=== Debugging Philosophy
==== Systematic approaches to debugging
==== Learning from mistakes and improving code quality

=== Summary and Further Resources

TODO

0 comments on commit e26eb1e

Please sign in to comment.