Repository navigation
DLPX-99899 connstat-stats.sh: replace stdbuf -oL with mawk -W interactive - #131
Conversation
…tive stdbuf -oL works by overriding libc stdio buffer settings via LD_PRELOAD. mawk 1.3.4 manages its own output buffers and calls write() directly on the pipe file descriptor — it never routes through the C stdio FILE* that stdbuf's preloaded library intercepts. The result is stdbuf -oL is silently ignored and mawk's output stays buffered until process exit. Since PR #128 switched to a single long-running connstat (no -c exit), mawk never exits, the buffer never flushes, and Telegraf receives zero tcp_stats data on any engine where /usr/bin/awk resolves to mawk — which is every stock Ubuntu 24.04 engine (mawk is Priority: required and the default alternative for /usr/bin/awk). PR #128 was validated only on dhruv5.dlpxdc.co, which had gawk installed as the awk alternative. gawk uses libc stdio and does honour stdbuf -oL, so the test passed there while every standard engine was silently broken. Fix: replace stdbuf -oL awk with mawk -W interactive. The -W interactive flag is mawk's own mechanism for per-line flushing — it forces mawk to flush its output buffer after every print, regardless of libc. Also correct the script comment, which incorrectly claimed stdbuf -oL works. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The narrow buffering fix preserves the existing output contract, with reported live validation and no blocking findings.
No open issues 🎉
What changed in this PR
Restores streaming TCP metrics to Telegraf on engines using mawk, addressing the buffering regression introduced in PR #128.
Changes:
- Replaces
stdbuf -oL awkwithmawk -W interactive. - Updates buffering comments without changing aggregation, timestamps, or CSV formatting.
| File | Description |
|---|---|
telegraf/connstat-stats.sh |
Enables mawk-native output flushing and updates explanatory comments. |
Review effort: Balanced
prakashsurya
left a comment
There was a problem hiding this comment.
Approving. The change is right and I reproduced it independently: under mawk 1.3.4 (the engine's version) the develop script prints nothing, and this PR's script streams correctly aggregated lines every interval. One thing to correct before merge: the description, the commit message and the new script comment all give the wrong cause, and the repo will keep that explanation.
The cause is mawk's input buffering, not its output. When mawk reads a pipe, it keeps calling read() until it has filled a 256 KB buffer (or hits EOF), and runs no print or fflush() before then. connstat writes only a few KB per interval and never exits, so nothing ever comes out. stdbuf -oL does take effect on mawk's stdout; it just can't help, because mawk never gets as far as writing. -W interactive fixes it because it switches stdin to line-by-line reads (it also unbuffers stdout). See man mawk: "sets unbuffered writes to stdout and line buffered reads from stdin".
Each of these takes a few seconds to check with strace:
# 1. Default mawk, fflush() after every print: reads keep filling the 256 KB buffer, and nothing is written
$ (while :; do echo a,b; sleep 1; done) | strace -e trace=read,write mawk -F, '{print; fflush()}' >/dev/null
read(0, "a,b\n", 262144) = 4
read(0, "a,b\n", 262140) = 4
read(0, "a,b\n", 262136) = 4
# 2. -W interactive: each line is read, then written straight away
$ (while :; do echo a,b; sleep 1; done) | strace -e trace=read,write mawk -W interactive -F, '{print}' >/dev/null
read(0, "a,b\n", 4096) = 4
write(1, "a,b", 3) = 3
write(1, "\n", 1) = 1
# 3. stdbuf -oL does change mawk's stdout: one write per line, versus a single write without it
$ strace -f -e trace=write stdbuf -oL mawk 'BEGIN{print "a"; print "b"}' >/dev/null
write(1, "a\n", 2) = 2
write(1, "b\n", 2) = 2
$ strace -e trace=write mawk 'BEGIN{print "a"; print "b"}' >/dev/null
write(1, "a\nb\n", 4) = 4
Number 3 is the one that rules out "mawk bypasses libc stdio, so LD_PRELOAD can't reach it". It also explains the engine result in DLPX-99899, where {print; fflush()} gave 0 lines.
Requested before merge:
- The script comment: the suggestion inline below.
- The commit message and PR description: say mawk block-fills its stdin buffer, rather than "bypasses libc stdio" or "forces a flush after every print".
Optional:
debian/controldoesn't listmawk. It isPriority: requiredbut notEssential, so adding it toDepends:would document the hard dependency.- The two
fflush()calls (L57, L85) now do nothing, since-W interactivealready unbuffers stdout. They're harmless, so keep or drop them.
Also checked, no issues:
- Real Telegraf (1.40.2, the
[[inputs.execd]]block fromtelegraf.base, with a stubconnstat): this PR wrote a point every interval with the right tags, fields and timestamps. The old script under mawk wrote 0. - Output unchanged: on the same input, the PR's script prints exactly what the old one does under gawk,
/etc/serviceslookups included. - Clean shutdown: stopping Telegraf leaves no
connstatormawkbehind. - Other collectors: none has the same bug. The rest use
egrep --line-bufferedor call commands directly.
Review on PR #131 clarified that mawk's problem is input-side block buffering, not output-side libc-stdio bypass. Reviewer verified with strace that: - mawk fills a 256 KB stdin buffer before processing any record - stdbuf -oL does take effect on mawk's stdout; it just cannot help because mawk never gets as far as writing - -W interactive fixes it by switching stdin to line-by-line reads (and also unbuffers stdout) Changes: - Update the script comment to describe the input-side cause. - Use /usr/bin/mawk full path to match /usr/bin/connstat style. - Drop the two fflush() calls — -W interactive already unbuffers stdout, so they are no-ops under the chosen fix. - Add mawk to debian/control Depends — mawk is Priority: required on Ubuntu 24.04 so already present, but declaring the hard runtime dependency documents the requirement. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review and the independent strace repro — much appreciated. Addressed in commit 4b14f5a (second commit on this branch):
End-to-end verified on both engines before pushing (telegraf restarted, waited 5 min, queried InfluxDB):
Note: the correction is captured in 4b14f5a's commit message, but the original 47b3907 commit message and the PR description above still carry the earlier (output-side) explanation. Happy to update the PR description now — let me know if you'd prefer that, or if the second-commit record is sufficient for the squash-merge. |
Background
PR #128 (DLPX-98742) rewrote
connstat-stats.shto use a single long-runningconnstatprocess piped throughstdbuf -oL awk, replacing the previousconnstat -c 2loop. The goal was to eliminate the 20 s batch-delivery latency and produce a continuous per-line stream to Telegraf'sexecdinput.The PR comment stated that
stdbuf -oLforces line-buffered stdout onawk. That claim is correct for gawk but insufficient for mawk, the defaultawkon every stock Ubuntu 24.04 engine — because the real problem is on the input side, not the output side.Problem
mawk 1.3.4block-reads its stdin: it keeps callingread()to fill a 256 KB input buffer before processing any record.stdbuf -oLdoes take effect on mawk's stdout (verified withstracebelow); it just can't help in this pipeline, because mawk never gets as far as writing.fflush()has the same limitation.connstatwrites only a few KB per 10 s interval and never exits (-cremoved in PR #128), so mawk's input buffer never fills, EOF never arrives, and Telegraf'sexecdinput receives zerotcp_statsdata — indefinitely, with no error logged on either side.strace evidence (credit: @prakashsurya during code review):
Case #3 rules out "mawk bypasses libc stdio" — stdbuf can reach mawk's stdout, it just doesn't matter when mawk is stuck in a
read()loop filling an input buffer that never fills.Why PR #128 Appeared to Work
PR #128 was validated exclusively on
dhruv5.dlpxdc.co(2026.5.0.0), which hadgawkinstalled as theawkalternative (/usr/bin/awk → /usr/bin/gawk).gawkreads stdin line by line and emits each record immediately — the pipeline streams correctly regardless ofstdbuf.On a stock Ubuntu 24.04 engine,
mawkis the only awk installed (Priority: required) and is the default alternative (/usr/bin/awk → /usr/bin/mawk). On those engines, PR #128 silently broketcp_statscollection entirely from the moment it landed.Fix
Replace
stdbuf -oL awkwith/usr/bin/mawk -W interactive.-W interactiveis mawk's native flag that switches stdin to line-buffered reads (and also unbuffers stdout). It works regardless of libc orLD_PRELOAD.Additional changes in commit 4b14f5a (in response to code review):
fflush()calls — redundant under-W interactive.mawktodebian/controlDepends:— mawk isPriority: requiredon Ubuntu 24.04 so already present, but this records the hard runtime dependency explicitly.Test Plan
Root cause reproduction
Tested on two engines: one where the bug was masked and one where it was visible.
dlpx-dev.dlpxdc.co —
awk → gawk(non-standard, same configuration as dhruv5 in PR #128):connstat … | stdbuf -oL mawk …connstat … | mawk -W interactive …connstat … | stdbuf -oL gawk …dlpx-qa-develop-qar-233997-766f97e2.dlpxdc.co (Azure) —
awk → mawk(standard configuration):connstat … | stdbuf -oL awk …(current script)connstat … | mawk -W interactive …(fix)Live InfluxDB verification
Deployed the final script (post commit 4b14f5a) to both engines, restarted Telegraf, waited 5 min, queried the
defaultbucket fortcp_stats:tcp_statspoints (last 5 min)dlpx-dev.dlpxdc.codlpx-qa-develop-qar-233997-766f97e2.dlpxdc.coAll 10 fields present on both:
connections,cwnd,inbytes,outbytes,retranssegs,rtt,rwnd,suna,swnd,unsent. Prior to the fix: 0 rows in InfluxDB on the Azure engine. Removing thefflush()calls did not break streaming —-W interactivehandles output flushing on its own.Portability validation — official Ubuntu 24.04 base image
Output:
On a completely unmodified
ubuntu:24.04image with no extras installed:mawkisPriority: required— guaranteed present on every Ubuntu system; cannot be removed without breakingapt/usr/bin/awk → mawkis the default alternative (gawk is not installed in the base image)mawk -W interactiveworks correctlyThis confirms the fix is correct and portable across all current Delphix engine variants (AWS, Azure, GCP) running Ubuntu 24.04.
Related
dlpx-qa-gatePR #9177 (engine_flux_templates_positive.py::test_tcp_stats_written_for_live_connections) isknown_failurewith DLPX-99899 and should be unblocked by this fixGenerated with Claude Code