288 lines
9.6 KiB
Markdown
288 lines
9.6 KiB
Markdown
# Debugging Tips
|
|
|
|
Sometimes things don't work the way they should. Here are some tips on debugging issues out
|
|
in production.
|
|
|
|
## Starting a Rails console session
|
|
|
|
Troubleshooting and debugging your GitLab instance often requires a
|
|
[Rails console](https://guides.rubyonrails.org/command_line.html#rails-console).
|
|
See also:
|
|
|
|
- [GitLab Rails Console Cheat Sheet](gitlab_rails_cheat_sheet.md).
|
|
- [Navigating GitLab via Rails console](navigating_gitlab_via_rails_console.md).
|
|
|
|
**For Omnibus installations**
|
|
|
|
```shell
|
|
sudo gitlab-rails console
|
|
```
|
|
|
|
**For installations from source**
|
|
|
|
```shell
|
|
sudo -u git -H bundle exec rails console -e production
|
|
```
|
|
|
|
Kubernetes: the console is in the task-runner pod, refer to our [Kubernetes cheat sheet](kubernetes_cheat_sheet.md#gitlab-specific-kubernetes-information) for details.
|
|
|
|
### Enabling Active Record logging
|
|
|
|
You can enable output of Active Record debug logging in the Rails console
|
|
session by running:
|
|
|
|
```ruby
|
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
```
|
|
|
|
This will show information about database queries triggered by any Ruby code
|
|
you may run in the console. To turn off logging again, run:
|
|
|
|
```ruby
|
|
ActiveRecord::Base.logger = nil
|
|
```
|
|
|
|
### Disabling database statement timeout
|
|
|
|
You can disable the PostgreSQL statement timeout for the current Rails console
|
|
session by running:
|
|
|
|
```ruby
|
|
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
|
|
```
|
|
|
|
Note that this change only affects the current Rails console session and will
|
|
not be persisted in the GitLab production environment or in the next Rails
|
|
console session.
|
|
|
|
### Output Rails console session history
|
|
|
|
If you'd like to output your Rails console command history in a format that's
|
|
easy to copy and save for future reference, you can run:
|
|
|
|
```ruby
|
|
puts Readline::HISTORY.to_a
|
|
```
|
|
|
|
## Using the Rails runner
|
|
|
|
If you need to run some Ruby code in the context of your GitLab production
|
|
environment, you can do so using the [Rails runner](https://guides.rubyonrails.org/command_line.html#rails-runner). When executing a script file, the script must be accessible by the `git` user.
|
|
|
|
**For Omnibus installations**
|
|
|
|
```shell
|
|
sudo gitlab-rails runner "RAILS_COMMAND"
|
|
|
|
# Example with a two-line Ruby script
|
|
sudo gitlab-rails runner "user = User.first; puts user.username"
|
|
|
|
# Example with a ruby script file (make sure to use the full path)
|
|
sudo gitlab-rails runner /path/to/script.rb
|
|
```
|
|
|
|
**For installations from source**
|
|
|
|
```shell
|
|
sudo -u git -H bundle exec rails runner -e production "RAILS_COMMAND"
|
|
|
|
# Example with a two-line Ruby script
|
|
sudo -u git -H bundle exec rails runner -e production "user = User.first; puts user.username"
|
|
|
|
# Example with a ruby script file (make sure to use the full path)
|
|
sudo -u git -H bundle exec rails runner -e production /path/to/script.rb
|
|
```
|
|
|
|
## Mail not working
|
|
|
|
A common problem is that mails are not being sent for some reason. Suppose you configured
|
|
an SMTP server, but you're not seeing mail delivered. Here's how to check the settings:
|
|
|
|
1. Run a [Rails console](#starting-a-rails-console-session).
|
|
|
|
1. Look at the ActionMailer `delivery_method` to make sure it matches what you
|
|
intended. If you configured SMTP, it should say `:smtp`. If you're using
|
|
Sendmail, it should say `:sendmail`:
|
|
|
|
```ruby
|
|
irb(main):001:0> ActionMailer::Base.delivery_method
|
|
=> :smtp
|
|
```
|
|
|
|
1. If you're using SMTP, check the mail settings:
|
|
|
|
```ruby
|
|
irb(main):002:0> ActionMailer::Base.smtp_settings
|
|
=> {:address=>"localhost", :port=>25, :domain=>"localhost.localdomain", :user_name=>nil, :password=>nil, :authentication=>nil, :enable_starttls_auto=>true}
|
|
```
|
|
|
|
In the example above, the SMTP server is configured for the local machine. If this is intended, you may need to check your local mail
|
|
logs (e.g. `/var/log/mail.log`) for more details.
|
|
|
|
1. Send a test message via the console.
|
|
|
|
```ruby
|
|
irb(main):003:0> Notify.test_email('youremail@email.com', 'Hello World', 'This is a test message').deliver_now
|
|
```
|
|
|
|
If you do not receive an e-mail and/or see an error message, then check
|
|
your mail server settings.
|
|
|
|
## Advanced Issues
|
|
|
|
For more advanced issues, `gdb` is a must-have tool for debugging issues.
|
|
|
|
### The GNU Project Debugger (gdb)
|
|
|
|
To install on Ubuntu/Debian:
|
|
|
|
```shell
|
|
sudo apt-get install gdb
|
|
```
|
|
|
|
On CentOS:
|
|
|
|
```shell
|
|
sudo yum install gdb
|
|
```
|
|
|
|
### rbtrace
|
|
|
|
GitLab 11.2 ships with [rbtrace](https://github.com/tmm1/rbtrace), which
|
|
allows you to trace Ruby code, view all running threads, take memory dumps,
|
|
and more. However, this is not enabled by default. To enable it, define the
|
|
`ENABLE_RBTRACE` variable to the environment. For example, in Omnibus:
|
|
|
|
```ruby
|
|
gitlab_rails['env'] = {"ENABLE_RBTRACE" => "1"}
|
|
```
|
|
|
|
Then reconfigure the system and restart Unicorn and Sidekiq. To run this
|
|
in Omnibus, run as root:
|
|
|
|
```ruby
|
|
/opt/gitlab/embedded/bin/ruby /opt/gitlab/embedded/bin/rbtrace
|
|
```
|
|
|
|
## Common Problems
|
|
|
|
Many of the tips to diagnose issues below apply to many different situations. We'll use one
|
|
concrete example to illustrate what you can do to learn what is going wrong.
|
|
|
|
### 502 Gateway Timeout after Unicorn spins at 100% CPU
|
|
|
|
This error occurs when the Web server times out (default: 60 s) after not
|
|
hearing back from the Unicorn worker. If the CPU spins to 100% while this in
|
|
progress, there may be something taking longer than it should.
|
|
|
|
To fix this issue, we first need to figure out what is happening. The
|
|
following tips are only recommended if you do NOT mind users being affected by
|
|
downtime. Otherwise skip to the next section.
|
|
|
|
1. Load the problematic URL
|
|
1. Run `sudo gdb -p <PID>` to attach to the Unicorn process.
|
|
1. In the gdb window, type:
|
|
|
|
```plaintext
|
|
call (void) rb_backtrace()
|
|
```
|
|
|
|
1. This forces the process to generate a Ruby backtrace. Check
|
|
`/var/log/gitlab/unicorn/unicorn_stderr.log` for the backtrace. For example, you may see:
|
|
|
|
```plaintext
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:33:in `block in start'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:33:in `loop'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:36:in `block (2 levels) in start'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:44:in `sample'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `sample_objects'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `each_with_object'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `each'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:69:in `block in sample_objects'
|
|
from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:69:in `name'
|
|
```
|
|
|
|
1. To see the current threads, run:
|
|
|
|
```plaintext
|
|
thread apply all bt
|
|
```
|
|
|
|
1. Once you're done debugging with `gdb`, be sure to detach from the process and exit:
|
|
|
|
```plaintext
|
|
detach
|
|
exit
|
|
```
|
|
|
|
Note that if the Unicorn process terminates before you are able to run these
|
|
commands, gdb will report an error. To buy more time, you can always raise the
|
|
Unicorn timeout. For omnibus users, you can edit `/etc/gitlab/gitlab.rb` and
|
|
increase it from 60 seconds to 300:
|
|
|
|
```ruby
|
|
unicorn['worker_timeout'] = 300
|
|
```
|
|
|
|
For source installations, edit `config/unicorn.rb`.
|
|
|
|
[Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
|
|
|
|
#### Troubleshooting without affecting other users
|
|
|
|
The previous section attached to a running Unicorn process, and this may have
|
|
undesirable effects for users trying to access GitLab during this time. If you
|
|
are concerned about affecting others during a production system, you can run a
|
|
separate Rails process to debug the issue:
|
|
|
|
1. Log in to your GitLab account.
|
|
1. Copy the URL that is causing problems (e.g. `https://gitlab.com/ABC`).
|
|
1. Create a Personal Access Token for your user (Profile Settings -> Access Tokens).
|
|
1. Bring up the [GitLab Rails console.](#starting-a-rails-console-session)
|
|
1. At the Rails console, run:
|
|
|
|
```ruby
|
|
app.get '<URL FROM STEP 2>/?private_token=<TOKEN FROM STEP 3>'
|
|
```
|
|
|
|
For example:
|
|
|
|
```ruby
|
|
app.get 'https://gitlab.com/gitlab-org/gitlab-foss/-/issues/1?private_token=123456'
|
|
```
|
|
|
|
1. In a new window, run `top`. It should show this Ruby process using 100% CPU. Write down the PID.
|
|
1. Follow step 2 from the previous section on using gdb.
|
|
|
|
### GitLab: API is not accessible
|
|
|
|
This often occurs when GitLab Shell attempts to request authorization via the
|
|
internal API (e.g., `http://localhost:8080/api/v4/internal/allowed`), and
|
|
something in the check fails. There are many reasons why this may happen:
|
|
|
|
1. Timeout connecting to a database (e.g., PostgreSQL or Redis)
|
|
1. Error in Git hooks or push rules
|
|
1. Error accessing the repository (e.g., stale NFS handles)
|
|
|
|
To diagnose this problem, try to reproduce the problem and then see if there
|
|
is a Unicorn worker that is spinning via `top`. Try to use the `gdb`
|
|
techniques above. In addition, using `strace` may help isolate issues:
|
|
|
|
```shell
|
|
strace -ttTfyyy -s 1024 -p <PID of unicorn worker> -o /tmp/unicorn.txt
|
|
```
|
|
|
|
If you cannot isolate which Unicorn worker is the issue, try to run `strace`
|
|
on all the Unicorn workers to see where the `/internal/allowed` endpoint gets
|
|
stuck:
|
|
|
|
```shell
|
|
ps auwx | grep unicorn | awk '{ print " -p " $2}' | xargs strace -ttTfyyy -s 1024 -o /tmp/unicorn.txt
|
|
```
|
|
|
|
The output in `/tmp/unicorn.txt` may help diagnose the root cause.
|
|
|
|
## More information
|
|
|
|
- [Debugging Stuck Ruby Processes](https://blog.newrelic.com/engineering/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9/)
|
|
- [Cheatsheet of using gdb and Ruby processes](gdb-stuck-ruby.txt)
|