The SDP init scripts p4d_base, p4broker_base, and p4p_base include
built-in support for running a service under strace at startup. This
provides a repeatable, low-friction way to capture syscall traces for
diagnostic purposes without modifying any init script or configuration file.
Note:
strace -fon a busy server generates large output volumes and adds measurable overhead. This feature is intended for short-term diagnostic use only — not for permanent production deployment.
The init scripts automatically select one of two modes based on whether the service is managed by systemd or started directly (non-systemd).
When a service is managed by systemd, strace is interposed between the init
script and the service binary:
systemd → p4d_N_init → strace ... p4d $P4D_FLAGS
strace runs the service binary as its own child process. Every syscall is
captured from the very first instruction — nothing from startup is missed.
This is ideal for diagnosing issues that occur during early startup (e.g.
replication thread initialization on a replica).
Trade-off: Because strace is the parent process, the service cannot be
stopped independently from strace. Stop the service normally
(systemctl stop p4d_N) to terminate both.
When a service is started directly (without systemd), the init script starts
the service normally and then attaches strace using strace -p <pid> once
the service process ID is known.
Trade-off: Syscalls that occur between process start and the moment the PID is discovered (typically a second or less) are not captured. For services where startup-phase syscalls are important, use systemd wrap mode.
strace runs as a completely independent background process. It can be
stopped at any time without affecting the running service.
All strace-related files live in $LOGS and incorporate the service name
(e.g. p4d_1, p4broker_1, p4p_1) so that multiple instances on the same
host never collide.
The strace output log also includes a timestamp (generated at the moment strace starts) so successive runs do not overwrite each other.
| File | Purpose |
|---|---|
$LOGS/.strace.<ServiceName> |
Marker file — create this to enable strace |
$LOGS/.strace.<ServiceName>.pid |
PID of the running strace process (attach mode only) |
$LOGS/strace.<ServiceName>.<YYYYMMDD_HHMMSS>.log |
strace output |
For p4d instance 1 on a host where $LOGS is /p4/1/logs:
/p4/1/logs/.strace.p4d_1 ← marker file (you create this)
/p4/1/logs/.strace.p4d_1.pid ← strace PID (attach mode only)
/p4/1/logs/strace.p4d_1.20260627_143022.log ← strace output
For a p4broker on the same instance:
/p4/1/logs/.strace.p4broker_1
/p4/1/logs/.strace.p4broker_1.pid
/p4/1/logs/strace.p4broker_1.20260627_143055.log
A p4broker started with a non-default config tag (e.g. mytag) uses
p4broker_1_mytag as the service name.
With systemd (wrap mode — recommended for startup diagnosis):
# 1. Create the marker file (empty = use default flags: -f -tt)
touch /p4/N/logs/.strace.p4d_N
# 2. (Re)start the service
sudo systemctl restart p4d_N
# 3. Confirm strace is running (the service log will show the strace log path)
grep strace /p4/N/logs/p4d_init.log | tail -5
Without systemd (attach mode):
touch /p4/N/logs/.strace.p4d_N
/p4/N/bin/p4d_N_init start
# Confirm strace is running
cat /p4/N/logs/.strace.p4d_N.pid
ps -p $(cat /p4/N/logs/.strace.p4d_N.pid)
touch /p4/N/logs/.strace.p4broker_N
sudo systemctl restart p4broker_N # systemd (wrap mode)
# or
/p4/N/bin/p4broker_N_init start # non-systemd (attach mode)
touch /p4/N/logs/.strace.p4p_N
sudo systemctl restart p4p_N # systemd (wrap mode)
# or
/p4/N/bin/p4p_N_init start # non-systemd (attach mode)
Attach mode only. Because strace runs as a separate background process
in attach mode, it can be killed independently at any time. The service
continues running normally.
# Generic form:
kill $(cat /p4/N/logs/.strace.<ServiceName>.pid)
# Examples:
kill $(cat /p4/1/logs/.strace.p4d_1.pid)
kill $(cat /p4/1/logs/.strace.p4broker_1.pid)
kill $(cat /p4/1/logs/.strace.p4p_1.pid)
The init script also calls stop_strace_if_running automatically when the
service is stopped via the init script, cleaning up the PID file.
Note: In attach mode,
stracealso exits automatically when its target process dies, so no explicit cleanup is needed if the service itself stops.
Wrap mode: strace is the parent process. The only way to stop it is to
stop the service normally (e.g. systemctl stop p4d_N). Killing strace
directly will also stop the service.
Remove the marker file before restarting the service:
rm /p4/N/logs/.strace.p4d_N
sudo systemctl restart p4d_N
By default, strace is invoked with -f -tt (follow forks, include timestamps
with microsecond resolution). To use different flags, write them to the marker
file on a single line before starting the service:
# Trace only network-related syscalls:
echo '-f -e trace=network' > /p4/1/logs/.strace.p4d_1
# Trace file-related syscalls with string lengths up to 256 bytes:
echo '-f -s 256 -e trace=file' > /p4/1/logs/.strace.p4d_1
# Default (empty file):
touch /p4/1/logs/.strace.p4d_1
The flags in the marker file replace the defaults entirely, so include
-f explicitly if you want fork-following.
The exact log file path (including the timestamp) is recorded in the service
init log (p4d_init.log, p4broker_init.log, or p4p_init.log) at the
moment strace starts.
# Find the strace log path for the most recent run:
grep 'strace' /p4/1/logs/p4d_init.log | grep 'output:'
# Follow the trace in real time (strace writes line-buffered with -tt):
tail -f /p4/1/logs/strace.p4d_1.20260627_143022.log
# Count syscalls by name:
sort /p4/1/logs/strace.p4d_1.20260627_143022.log | uniq -c | sort -rn | head -20
The shared library /p4/common/lib/strace.lib is sourced by all three init
scripts. It provides three functions:
| Function | Purpose |
|---|---|
run_service_under_strace <binary> [args...] |
Wrap mode: run service as strace child |
attach_strace_if_requested <pid_cmd> |
Attach mode: attach strace to running service |
stop_strace_if_running |
Stop background strace and remove PID file |
Mode is selected automatically based on $UseSystemd:
$UseSystemd == 1 → wrap mode (run_service_under_strace)
$UseSystemd == 0 → attach mode (attach_strace_if_requested ... & disown)
UseSystemd is set to 1 when a systemd unit file for the service exists and
is active (detected at script startup via systemctl).
The ServiceName variable (e.g. p4d_1) is derived from the service binary
name (e.g. ${P4DBIN##*/}) and is set unconditionally before any systemd
detection, so strace file naming works correctly on both systemd and
non-systemd hosts.
In non-systemd operation, the service binary forks immediately and daemonizes.
Using strace binary args (wrap mode) in this case would cause strace to
block indefinitely tracking the daemon, holding the init script open. The
attach approach is better suited here: the init script exits normally, and
strace attaches in a separate background process.
With systemd, the init script is already meant to block (the service runs in
the foreground as ExecStart). Replacing binary args with
strace ... binary args is a natural fit — no additional complexity is
introduced, and systemd manages the strace process as the service.
# Using strace with SDP-Managed Services
## Overview
The SDP init scripts `p4d_base`, `p4broker_base`, and `p4p_base` include
built-in support for running a service under `strace` at startup. This
provides a repeatable, low-friction way to capture syscall traces for
diagnostic purposes without modifying any init script or configuration file.
> **Note:** `strace -f` on a busy server generates large output volumes and
> adds measurable overhead. This feature is intended for short-term diagnostic
> use only — not for permanent production deployment.
---
## Two strace Modes
The init scripts automatically select one of two modes based on whether the
service is managed by **systemd** or started **directly** (non-systemd).
### Wrap Mode (systemd — complete capture)
When a service is managed by systemd, `strace` is interposed between the init
script and the service binary:
```
systemd → p4d_N_init → strace ... p4d $P4D_FLAGS
```
`strace` runs the service binary as its own child process. Every syscall is
captured from the very first instruction — nothing from startup is missed.
This is ideal for diagnosing issues that occur during early startup (e.g.
replication thread initialization on a replica).
**Trade-off:** Because `strace` is the parent process, the service cannot be
stopped independently from `strace`. Stop the service normally
(`systemctl stop p4d_N`) to terminate both.
### Attach Mode (non-systemd — best effort)
When a service is started directly (without systemd), the init script starts
the service normally and then attaches `strace` using `strace -p <pid>` once
the service process ID is known.
**Trade-off:** Syscalls that occur between process start and the moment the
PID is discovered (typically a second or less) are **not captured**. For
services where startup-phase syscalls are important, use systemd wrap mode.
`strace` runs as a completely independent background process. It can be
stopped at any time without affecting the running service.
---
## File Naming Convention
All strace-related files live in `$LOGS` and incorporate the **service name**
(e.g. `p4d_1`, `p4broker_1`, `p4p_1`) so that multiple instances on the same
host never collide.
The strace output log also includes a **timestamp** (generated at the moment
strace starts) so successive runs do not overwrite each other.
| File | Purpose |
|------|---------|
| `$LOGS/.strace.<ServiceName>` | Marker file — create this to enable strace |
| `$LOGS/.strace.<ServiceName>.pid` | PID of the running strace process (attach mode only) |
| `$LOGS/strace.<ServiceName>.<YYYYMMDD_HHMMSS>.log` | strace output |
For p4d instance `1` on a host where `$LOGS` is `/p4/1/logs`:
```
/p4/1/logs/.strace.p4d_1 ← marker file (you create this)
/p4/1/logs/.strace.p4d_1.pid ← strace PID (attach mode only)
/p4/1/logs/strace.p4d_1.20260627_143022.log ← strace output
```
For a p4broker on the same instance:
```
/p4/1/logs/.strace.p4broker_1
/p4/1/logs/.strace.p4broker_1.pid
/p4/1/logs/strace.p4broker_1.20260627_143055.log
```
A p4broker started with a non-default config tag (e.g. `mytag`) uses
`p4broker_1_mytag` as the service name.
---
## Enabling strace — Step by Step
### p4d (P4 Server)
**With systemd (wrap mode — recommended for startup diagnosis):**
```bash
# 1. Create the marker file (empty = use default flags: -f -tt)
touch /p4/N/logs/.strace.p4d_N
# 2. (Re)start the service
sudo systemctl restart p4d_N
# 3. Confirm strace is running (the service log will show the strace log path)
grep strace /p4/N/logs/p4d_init.log | tail -5
```
**Without systemd (attach mode):**
```bash
touch /p4/N/logs/.strace.p4d_N
/p4/N/bin/p4d_N_init start
# Confirm strace is running
cat /p4/N/logs/.strace.p4d_N.pid
ps -p $(cat /p4/N/logs/.strace.p4d_N.pid)
```
### p4broker (P4 Broker)
```bash
touch /p4/N/logs/.strace.p4broker_N
sudo systemctl restart p4broker_N # systemd (wrap mode)
# or
/p4/N/bin/p4broker_N_init start # non-systemd (attach mode)
```
### p4p (P4 Proxy)
```bash
touch /p4/N/logs/.strace.p4p_N
sudo systemctl restart p4p_N # systemd (wrap mode)
# or
/p4/N/bin/p4p_N_init start # non-systemd (attach mode)
```
---
## Stopping strace Without Affecting the Service
**Attach mode only.** Because `strace` runs as a separate background process
in attach mode, it can be killed independently at any time. The service
continues running normally.
```bash
# Generic form:
kill $(cat /p4/N/logs/.strace.<ServiceName>.pid)
# Examples:
kill $(cat /p4/1/logs/.strace.p4d_1.pid)
kill $(cat /p4/1/logs/.strace.p4broker_1.pid)
kill $(cat /p4/1/logs/.strace.p4p_1.pid)
```
The init script also calls `stop_strace_if_running` automatically when the
service is stopped via the init script, cleaning up the PID file.
> **Note:** In attach mode, `strace` also exits automatically when its target
> process dies, so no explicit cleanup is needed if the service itself stops.
**Wrap mode:** `strace` is the parent process. The only way to stop it is to
stop the service normally (e.g. `systemctl stop p4d_N`). Killing strace
directly will also stop the service.
---
## Preventing strace from Running on Next Restart
Remove the marker file before restarting the service:
```bash
rm /p4/N/logs/.strace.p4d_N
sudo systemctl restart p4d_N
```
---
## Custom strace Flags
By default, strace is invoked with `-f -tt` (follow forks, include timestamps
with microsecond resolution). To use different flags, write them to the marker
file on a single line before starting the service:
```bash
# Trace only network-related syscalls:
echo '-f -e trace=network' > /p4/1/logs/.strace.p4d_1
# Trace file-related syscalls with string lengths up to 256 bytes:
echo '-f -s 256 -e trace=file' > /p4/1/logs/.strace.p4d_1
# Default (empty file):
touch /p4/1/logs/.strace.p4d_1
```
The flags in the marker file **replace** the defaults entirely, so include
`-f` explicitly if you want fork-following.
---
## Viewing the Output
The exact log file path (including the timestamp) is recorded in the service
init log (`p4d_init.log`, `p4broker_init.log`, or `p4p_init.log`) at the
moment strace starts.
```bash
# Find the strace log path for the most recent run:
grep 'strace' /p4/1/logs/p4d_init.log | grep 'output:'
# Follow the trace in real time (strace writes line-buffered with -tt):
tail -f /p4/1/logs/strace.p4d_1.20260627_143022.log
# Count syscalls by name:
sort /p4/1/logs/strace.p4d_1.20260627_143022.log | uniq -c | sort -rn | head -20
```
---
## Implementation Notes
### Shared Library
The shared library `/p4/common/lib/strace.lib` is sourced by all three init
scripts. It provides three functions:
| Function | Purpose |
|----------|---------|
| `run_service_under_strace <binary> [args...]` | Wrap mode: run service as strace child |
| `attach_strace_if_requested <pid_cmd>` | Attach mode: attach strace to running service |
| `stop_strace_if_running` | Stop background strace and remove PID file |
### Mode Selection
Mode is selected automatically based on `$UseSystemd`:
```
$UseSystemd == 1 → wrap mode (run_service_under_strace)
$UseSystemd == 0 → attach mode (attach_strace_if_requested ... & disown)
```
`UseSystemd` is set to `1` when a systemd unit file for the service exists and
is active (detected at script startup via `systemctl`).
### ServiceName
The `ServiceName` variable (e.g. `p4d_1`) is derived from the service binary
name (e.g. `${P4DBIN##*/}`) and is set unconditionally before any systemd
detection, so strace file naming works correctly on both systemd and
non-systemd hosts.
### Why Not Always Use Wrap Mode?
In non-systemd operation, the service binary forks immediately and daemonizes.
Using `strace binary args` (wrap mode) in this case would cause strace to
block indefinitely tracking the daemon, holding the init script open. The
attach approach is better suited here: the init script exits normally, and
strace attaches in a separate background process.
With systemd, the init script is already meant to block (the service runs in
the foreground as `ExecStart`). Replacing `binary args` with
`strace ... binary args` is a natural fit — no additional complexity is
introduced, and systemd manages the `strace` process as the service.
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 33433 | Claude (AI Agent by Anthropic) |
Copy Up from //p4-sdp/dev into //p4-sdp/main. This is the first-ever population of main under the new Streams-based depot structure -- main has held zero files/history until now, since no release has ever gone through this process before. 463 files, covering the entire 2026.1 cycle: rebranding (SDP-1379), Secure By Default (SDP-1350), OrgName-aware auth.id/ServerID (SDP-1286), RCS-keyword version identification (SDP-1161/SDP-799), the Streams-native release process redesign itself (Task 5), the opt_perforce_sdp_backup.sh false-error fix, the P4D 2026.1 test-suite targeting, refreshed P4*.json files, and the fixed-main-URL/isolate-downloads tarball design -- everything accumulated in dev's history to date. Isolated paths (ai_dev_support/, Version, doc/*.html, doc/*.pdf, doc/gen/*.man.txt, doc/gen/sdp_install.cfg, Unsupported/doc/*.html, Unsupported/doc/*.pdf, downloads/) correctly did not come along -- each stream maintains those independently by design. Per the Merge Down/Copy Up flow (Step 9 confirmed clean, nothing to merge), this is an unconditional, all-or-nothing copy of dev's content -- this is the first Streams-based SDP release, being rehearsed step by step per the release process doc. Agent: Claude Code, Model: Claude Sonnet 5 (claude-sonnet-5), operating as bot_Claude_Anthropic. |
||
| //p4-sdp/dev/doc/Using_strace_for_SDP_Services.md | |||||
| #2 | 33409 | Claude (AI Agent by Anthropic) |
Copy Up from //p4-sdp/dev_rebrand into //p4-sdp/dev. This is the first promotion of dev_rebrand's work into dev since dev_rebrand was created (2025-05-24) -- 303 files, covering the entire 2026.1 rebranding effort (SDP-1379), the Secure By Default adaptation (SDP-1350), OrgName-aware auth.id/ServerID (SDP-1286), RCS-keyword version identification (SDP-1161/SDP-799), and the Streams-native release process redesign (Task 5) done this session, plus everything else accumulated in dev_rebrand's history before this session. Per the Merge Down/Copy Up flow, this is intentionally a full, unconditional blast-replace of dev's content from dev_rebrand -- all selectivity/care happened in the preceding Merge Down (dev -> dev_rebrand, changes 33407-33408), which absorbed Robert Cowham's independent dev-side work first so nothing of his is lost by this Copy Up. Two files are worth calling out since they might look alarming in isolation: - tools/mdcu.sh is deleted -- intentional, retired this session in favor of the two direct Streams commands now documented in doc/ReleaseProcessOverview.md. - tools/ReleaseProcessOverview.md is deleted -- this is a stale relic of a file move dev_rebrand made back in 2025-05-24 (tools/ -> doc/) that was never previously propagated to dev; the current, fully-rewritten doc/ReleaseProcessOverview.md is added/updated correctly by this same changelist. |
||
| #1 | 32990 | C. Thomas Tyler |
p4 merge -b SDP_Classic_to_Streams p4 resolve -as All files resolved automatically. The "real" merge work comes in the coming Merge Down from dev->dev_rebrand. |
||
| //guest/perforce_software/sdp/dev/doc/Using_strace_for_SDP_Services.md | |||||
| #1 | 32904 | C. Thomas Tyler |
strace support for p4d, p4broker, and p4p SDP init scripts Added diagnostic strace feature to p4d_base, p4broker_base, and p4p_base. When a file $LOGS/.strace.<ServiceName> exists at start time, strace is enabled using one of two modes selected automatically: - Wrap mode (systemd): strace runs the service binary as its child process, capturing every syscall from the very first instruction. Ideal for diagnosing startup-phase issues (e.g. replica startup threads). - Attach mode (non-systemd): strace attaches to the already-running service after startup using strace -p <pid>. Best effort -- early startup syscalls may be missed. Strace output goes to $LOGS/strace.<ServiceName>.<YYYYMMDD_HHMMSS>.log; in attach mode the strace PID is also recorded in $LOGS/.strace.<ServiceName>.pid. Shared functions live in a new library: /p4/common/lib/strace.lib Also added startup/shutdown logging to p4broker_base and p4p_base, which previously had no init logging. Added documentation: doc/Using_strace_for_SDP_Services.md Fixes SDP-1365 (Feature): Add strace support to p4*_base init scripts, with docs. #review-32858 @tom_tyler @robert_cowham |
||