Linux Troubleshooting and Diagnostics Questions
In depth troubleshooting and diagnostic techniques for complex Linux issues at the system and kernel level. Includes advanced use of strace, ltrace, perf, ftrace, and reading proc and sys filesystems, root cause analysis of memory leaks and resource exhaustion, diagnosing intermittent failures and I O bottlenecks, log analysis, service debugging, containerized environment troubleshooting, and strategies for progressive isolation, replication, and remediation of production incidents. Senior level expectations include understanding kernel interactions, tracing user space to kernel transitions, and designing observability approaches to prevent recurrence.
Sample Answer
Sample Answer
package main
import (
"bufio"
"context"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"syscall"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
minorRate = prometheus.NewGauge(prometheus.GaugeOpts{Name: "proc_minor_faults_per_second", Help: "Per-second minor page faults"})
majorRate = prometheus.NewGauge(prometheus.GaugeOpts{Name: "proc_major_faults_per_second", Help: "Per-second major page faults"})
rssDelta = prometheus.NewGauge(prometheus.GaugeOpts{Name: "proc_rss_delta_bytes_per_second", Help: "RSS delta bytes per second"})
)
func init() {
prometheus.MustRegister(minorRate, majorRate, rssDelta)
}
type sample struct {
minflt, majflt uint64
rssPages int64
startTime uint64
at time.Time
}
func readProcStat(pid int) (sample, error) {
path := fmt.Sprintf("/proc/%d/stat", pid)
f, err := os.Open(path)
if err != nil { return sample{}, err }
defer f.Close()
scanner := bufio.NewScanner(f)
scanner.Scan()
line := scanner.Text()
// extract comm exactly: find first '(' and last ')'
l := strings.Index(line, "(")
r := strings.LastIndex(line, ")")
if l < 0 || r < 0 || r <= l { return sample{}, fmt.Errorf("unexpected stat format") }
// after ) there is a space then the rest fields
rest := strings.TrimSpace(line[r+1:])
parts := strings.Fields(rest)
// fields after comm: state (1), ppid(2), ... minflt is field 9 after comm? We map positions per proc man:
// According to proc(5): after comm: state(1), ppid(2), pgrp(3), session(4), tty_nr(5), tpgid(6), flags(7),
// minflt(8), cminflt(9), majflt(10), cmajflt(11), utime(12) ... rss is field 20 after comm.
// So indices (0-based) in parts: minflt -> 7, majflt -> 9, rss -> 19, starttime -> 21
if len(parts) < 22 { return sample{}, fmt.Errorf("stat fields too short") }
minflt, _ := strconv.ParseUint(parts[7], 10, 64)
majflt, _ := strconv.ParseUint(parts[9], 10, 64)
rssPages, _ := strconv.ParseInt(parts[19], 10, 64)
startt, _ := strconv.ParseUint(parts[21], 10, 64)
return sample{minflt: minflt, majflt: majflt, rssPages: rssPages, startTime: startt, at: time.Now()}, nil
}
func monitor(ctx context.Context, pid int) {
var prev *sample
pageSize := int64(syscall.Getpagesize())
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
// initial sample
s, err := readProcStat(pid)
if err != nil { return }
prev = &s
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
cur, err := readProcStat(pid)
if err != nil {
// process may have exited; reset metrics to 0 and continue waiting for revive
minorRate.Set(0); majorRate.Set(0); rssDelta.Set(0)
// attempt to re-open next tick
prev = nil
continue
}
// check starttime for PID reuse
if prev != nil && cur.startTime != prev.startTime {
// PID reused: reset baseline
prev = &cur
minorRate.Set(0); majorRate.Set(0); rssDelta.Set(0)
continue
}
if prev == nil {
prev = &cur
continue
}
dt := cur.at.Sub(prev.at).Seconds()
if dt <= 0 { prev = &cur; continue }
minorRate.Set(float64(cur.minflt - prev.minflt) / dt)
majorRate.Set(float64(cur.majflt - prev.majflt) / dt)
rssBytesDelta := float64((cur.rssPages - prev.rssPages) * pageSize)
rssDelta.Set(rssBytesDelta / dt)
prev = &cur
}
}
}
func main() {
pid := 12345 // replace or pass as arg
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go monitor(ctx, pid)
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":9000", nil)
}Sample Answer
Sample Answer
# show system vs user
top -b -n1 -o %CPU
# per-cpu breakdown (system time)
mpstat -P ALL 1 3
pidstat -ut 1 1 # user/system per pidps -eo pid,ppid,cmd,%cpu,%mem,stime,etime --sort=-%cpu | head
# or for containers
cat /proc/<pid>/cgroup# strace short sample (low overhead if short)
strace -c -p <pid> -t -f -qq -o /tmp/strace.out sleep 5
# or use perf syscall counts
sudo perf stat -e syscalls:sys_enter_* -p <pid> sleep 5# system-wide sample profile (symbols)
sudo perf record -F 99 -a -g -- sleep 10
sudo perf report --stdio --call-graph
# per-pid
sudo perf record -F 99 -p <pid> -g -- sleep 10
sudo perf report --stdio# interrupts
cat /proc/interrupts
# softirq activity
watch -n1 cat /proc/softirqs# sockets of process
ss -pan | grep <pid>
# netstat counters
sudo ethtool -S eth0
# per-protocol perf events
sudo perf record -e net:netif_receive_skb -a -- sleep 10# vfs and IO stats
iostat -xz 1 3
sudo blktrace -d /dev/sdX -o - | blkparse -i -
# dentry/inode stats
cat /proc/sys/vm/vfs_cache_pressure
# see blocked tasks
sudo perf probe -x /boot/vmlinux --list # set probes if needed# enable function_graph for pid
sudo bash -c 'echo function_graph > /sys/kernel/debug/tracing/current_tracer'
sudo bash -c "echo <pid> > /sys/kernel/debug/tracing/set_ftrace_pid"
sudo bash -c 'echo 1 > /sys/kernel/debug/tracing/tracing_on'
# run workload briefly, then dump
sudo cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt
# reset
sudo bash -c 'echo 0 > /sys/kernel/debug/tracing/tracing_on'# kernel and config
uname -a
cat /proc/version
sysctl -a > /tmp/sysctl.txt
# process specific
cat /proc/<pid>/stack
cat /proc/<pid>/status
# open files
sudo ls -l /proc/<pid>/fdsudo perf script > /tmp/perf.script
# if addresses appear, use addr2line or /proc/kallsyms
addr2line -e /boot/vmlinux-$(uname -r) <hex-address>Sample Answer
Unlock Full Question Bank
Get access to hundreds of Linux Troubleshooting and Diagnostics interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.