ฉันจะล็อก stdout ของกระบวนการที่เริ่มต้นโดย start-stop-daemon ได้อย่างไร


120

ฉันใช้สคริปต์ init เพื่อเรียกใช้กระบวนการง่ายๆซึ่งเริ่มต้นด้วย:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS

กระบวนการที่เรียกว่า $ DAEMON มักจะพิมพ์ข้อมูลบันทึกไปยังเอาต์พุตมาตรฐาน เท่าที่ฉันสามารถบอกได้ว่าข้อมูลนี้ไม่ได้ถูกเก็บไว้ที่ใดก็ได้

ฉันต้องการเขียนหรือต่อท้าย stdout ของ $ DAEMON ในไฟล์ที่ไหนสักแห่ง

ทางออกเดียวที่ฉันรู้คือบอก start-stop-daemon ให้เรียกใช้ shellscript แทน $ DAEMON โดยตรง จากนั้นสคริปต์จะเรียก $ DAEMON และเขียนลงในไฟล์บันทึก แต่นั่นต้องใช้สคริปต์พิเศษซึ่งเช่นเดียวกับการปรับเปลี่ยน daemon เองดูเหมือนจะเป็นวิธีที่ผิดในการแก้ปัญหาทั่วไปดังกล่าว

คำตอบ:


127

หากต้องการขยายคำตอบของ ypocat เนื่องจากจะไม่ให้ฉันแสดงความคิดเห็น:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
 --make-pidfile --pidfile $PIDFILE --background       \
 --startas /bin/bash -- -c "exec $DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1"

การใช้execเพื่อรัน daemon อนุญาตให้หยุดหยุดกระบวนการลูกได้อย่างถูกต้องแทนที่จะเป็นเพียง bash parent

การใช้--startasแทน--execเพื่อให้แน่ใจว่ากระบวนการจะถูกตรวจพบโดย pid ของมันอย่างถูกต้องและจะไม่เริ่มต้น daemon หลายอินสแตนซ์อย่างผิดพลาดหากการเริ่มต้นถูกเรียกหลายครั้ง มิฉะนั้น start-stop-daemon จะมองหากระบวนการ a / bin / bash และละเว้นกระบวนการลูกจริงที่รัน daemon


2
นี่เป็นวิธีแก้ปัญหาที่ดีกว่า @ypocat เป็นหลักเนื่องจากการปิด daemon อีกครั้งโดยแทนที่--startด้วยการ--stopใช้งานจริง
aef

ฉันลองเรียกใช้คำสั่งนี้จาก rc.local แทน init.d ... ดูเหมือนจะไม่ได้รับผลลัพธ์แบบเดียวกัน อย่างไรก็ตามเมื่อเรียกใช้จากเชลล์ผ่าน SSH มันใช้งานได้อย่างมีเสน่ห์!
nemo

1
จะมีstart-stop-daemon --test (...)หน้าตาเป็นอย่างไร?
อับดุล

2
@MattClimbs จะเขียนทับไฟล์ทุกครั้งหลังเริ่มต้น ใช้>>แทน>การต่อท้าย
Meow

2
ก่อนที่คุณจะออกนอกลู่นอกทาง (เช่นฉัน) เพราะบันทึกของคุณว่างเปล่าโปรดทราบว่านี่เป็นบัฟเฟอร์ คุณสามารถใช้ "exec stdbuf -oL -eL $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1" เพื่อบังคับให้เอาต์พุตล้างแต่ละบรรทัด (จากblog.lanyonm.org/articles/2015/01/11/… )
piers7

47

คุณต้องทำ:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec /bin/bash -- -c "$DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1"

นอกจากนี้หากคุณใช้--chuidหรือ--userตรวจสอบให้แน่ใจว่าผู้ใช้สามารถเขียนถึง/var/logหรือที่มีอยู่/var/log/some.logได้ วิธีที่ดีที่สุดคือให้ผู้ใช้รายนั้นเป็นเจ้าของ/var/log/subdir/แม้ว่า


1
เยี่ยมมากขอบคุณ ypocat วันนี้เช่นเดียวกับการบันทึกบันทึกฉันต้องเรียกใช้สคริปต์ที่ไม่ใช่ไบนารีซึ่ง --exec ไม่อนุญาต แต่เคล็ดลับของคุณใช้ได้ผล!
joeytwiddle

8
ด้านเสีย ... การหยุดบริการฆ่าทุบตี แต่ไม่ใช่กระบวนการเด็กเริ่มต้นทุบตี! (ในกรณีของฉัน DAEMON = กาแฟ)
joeytwiddle

1
ฉันแก้ไขสิ่งนั้นโดยการฆ่ากระบวนการย่อยทั้งหมดของกระบวนการทุบตีที่ด้านบนของ do_stop bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
joeytwiddle

5
สิ่งที่ควรรู้และpkillวิธีแก้ไขด้วย สงสัยว่า... -c "exec $DAEMON..."(การเพิ่ม "exec") จะทำอย่างไร ตอนนี้ไม่มีในจานเลยลองไม่ได้
youurayy

12
@ypocat ฉันตรวจสอบแล้วว่าใช้ได้กับ -c "exec $ DAEMON ... " ซึ่งหมายความว่าไม่จำเป็นต้องแฮ็ก pkill
overthink

40

ดูเหมือนว่าคุณควรจะสามารถใช้--no-closeพารามิเตอร์ได้ในขณะนี้เมื่อเริ่มstart-stop-daemonจับเอาต์พุต daemon คุณลักษณะใหม่นี้มีอยู่ในdpkgแพ็คเกจตั้งแต่เวอร์ชัน 1.16.5 บน Debian:

เพิ่มตัวเลือก --no-close ใหม่เพื่อปิดใช้งานการปิด fds บน --background

สิ่งนี้ช่วยให้ผู้เรียกดูข้อความกระบวนการเพื่อจุดประสงค์ในการดีบักหรือสามารถเปลี่ยนทิศทางตัวบอกไฟล์ไปยังล็อกไฟล์ syslog หรือสิ่งที่คล้ายกัน


8
มันน่าเสียดายที่ไม่มีใน Ubuntu 12.04 :(
Leon Radley

ฉันดูเหมือนจะไม่ได้ - ไม่ใกล้จะทำงาน ... ผลลัพธ์ยังคงไปที่เชลล์ที่ฉันกำลังเรียกใช้สคริปต์ init.d จาก :(
stantonk

+1 ทำงานได้อย่างสมบูรณ์แบบบน Debian บีบด้วยบริการ node.js ที่ถูก daemonized
พูด

2
@stantonk คุณไพพ์ stdout / stderr ไปยังไฟล์หรือไม่? บรรทัดคำสั่งที่สมบูรณ์มีลักษณะดังนี้ และตรวจสอบให้แน่ใจว่าสามารถเขียนไฟล์บันทึกโดยผู้ใช้ $ USER: start-stop-daemon --start --chuid $ USER --pidfile $ PIDFILE --background --no-close --make-pidfile --exec $ DAEMON - $ DAEMONARGS >> /var/log/xxxxx.log 2> & 1
nharrer

1
นี้ไม่สามารถใช้ได้กับ start-stop-daemonopenrc อย่างไรก็ตามเวอร์ชัน openrc มี-1และ-2ตัวเลือกในการเปลี่ยนเส้นทาง stdout และ stderr ตามลำดับ
little-dude

14

ด้วย openrc (ซึ่งเป็นค่าเริ่มต้นใน gentoo หรือ alpine linux เป็นต้น) start-stop-daemonมีตัวเลือก-1และ-2:

-1, --stdout เปลี่ยนเส้นทาง stdout ไปยังไฟล์

-2, --stderr เปลี่ยนเส้นทาง stderr ไปยังไฟล์

ดังนั้นคุณสามารถเขียน:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS -1 $LOGFILE -2 $LOGFILE

9

ไม่ยากเกินไปที่จะจับเอาท์พุทของ daemon และบันทึกลงในไฟล์:

start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas $DAEMON --no-close \
  -- $DAEMON_ARGS >> $LOGFILE 2>&1

logrotateแต่วิธีนี้อาจจะก่อให้เกิดผลลัพธ์สำหรับ

อาจจะดีกว่าถ้าจับเอาท์พุทไปที่ syslog ในDebianสิ่งนี้จะตรงกับพฤติกรรมของบริการ systemd ความพยายามที่ตรงไปตรงมาต่อไปนี้ในการเขียนตัวอย่างข้างต้นใหม่นั้นไม่ถูกต้องเนื่องจากทิ้งไว้เบื้องหลังสองกระบวนการพาเรนต์น้อย ("zombie") (คนตัดไม้และภูต) หลังจากหยุด daemon เนื่องจากstart-stop-daemonยกเลิกเฉพาะลูกของมัน แต่ไม่ใช่ลูกหลานทั้งหมด:

## Do not use this!
start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas /bin/sh \
  -- -c """exec $DAEMON $DAEMON_ARGS | /usr/bin/logger --tag $NAME"""

เพื่อให้การทำงานเราต้องห่อหุ้มที่สิ้นสุดเด็กเมื่อได้รับจากSIGTERM start-stop-daemonมีบางส่วน:

Duende :
start-stop-daemon --start --background \
  --pidfile $PIDFILE \
  --startas /usr/sbin/duende \
  -- --pid $PIDFILE --chroot=/ --uid 65534 --ident $NAME \
  /bin/su --login $DAEMON_USER --shell /bin/sh --command """exec ${DAEMON} $DAEMON_ARGS"""

หมายเหตุ: เป็นผู้ใช้uid=65534nobody

ข้อดี : ใช้งานได้และค่อนข้างง่าย
จุดด้อย : 4 กระบวนการ (หัวหน้างานduende, ทางแยกที่มีสิทธิ์ลดลง (คนตัดไม้) suและดีมอนเอง); บังคับ--chroot; หาก daemon ยุติทันที (เช่นคำสั่งไม่ถูกต้อง) ให้status_of_proc -p $PIDFILE "$DAEMON" "$NAME"รายงานว่าเริ่มต้นสำเร็จ

ภูต :
start-stop-daemon --start --pidfile $PIDFILE \
  --startas /usr/bin/daemon \
  -- --noconfig --name $NAME --stderr=syslog.info --stdout=syslog.info \
  -- /bin/su --login $DAEMON_USER --shell /bin/sh --command """exec $DAEMON $DAEMON_ARGS"""

จุดเด่น : 3 กระบวนการ (หัวหน้างานdaemon, suและภูตเอง)
จุดด้อย : ยากต่อการจัดการ$PIDFILEเนื่องจากตัวเลือกบรรทัดคำสั่งของdaemon ที่สับสน หาก daemon ยุติทันที (เช่นคำสั่งไม่ถูกต้อง) ให้status_of_proc -p $PIDFILE "$DAEMON" "$NAME"รายงานว่าเริ่มต้นสำเร็จ

pipexec ( ผู้ชนะ ):

start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas /usr/bin/pipexec -- -k \
   -- [ D $DAEMON $DAEMON_ARGS ] [ L /usr/bin/logger --tag $NAME ] '{D:2>D:1}' '{D:1>L:0}'

จุดเด่น : 3 กระบวนการ (หัวหน้างานpipexec, loggerและภูตตัวเอง); ถ้า daemon ยุติทันที (เช่นคำสั่งไม่ถูกต้อง) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"รายงานความล้มเหลวอย่างถูกต้อง
จุดด้อย : ไม่มี

นี่คือผู้ชนะ - วิธีแก้ปัญหาที่ง่ายและเรียบร้อยซึ่งดูเหมือนว่าจะทำงานได้ดี


7

โดยปกติจะstart-stop-daemonปิดตัวอธิบายไฟล์มาตรฐานเมื่อทำงานในพื้นหลัง จากหน้าคนของstart-stop-daemon:

-C, --no-close
อย่าปิดตัวอธิบายไฟล์ใด ๆ เมื่อบังคับให้ daemon เข้าสู่พื้นหลัง ใช้สำหรับวัตถุประสงค์ในการดีบักเพื่อดูผลลัพธ์ของกระบวนการหรือเพื่อเปลี่ยนทิศทางตัวบอกไฟล์เพื่อบันทึกผลลัพธ์ของกระบวนการ เกี่ยวข้องเฉพาะเมื่อใช้ --background

อันนี้ใช้ได้กับฉัน:

    start-stop-daemon -b -C -o -c \ 
         $DAEMON_USER -S -x $DAEMON > $DAEMON_LOG 2>&1

4

การอ้างถึงรายชื่อผู้รับจดหมายเก่า:

https://lists.ubuntu.com/archives/ubuntu-uk/2005-June/000037.html

วิธีง่ายๆ - และหากคุณต้องการใช้ start-stop-daemon วิธีเดียวก็คือการสร้างสคริปต์ขนาดเล็กที่มี:

#!/bin/sh
exec /home/boinc/boinc/boinc > /home/boinc/log/boinc.log

จากนั้นใช้สคริปต์นั้นเป็นอาร์กิวเมนต์เพื่อ start-stop-daemon

บางทีคำถามที่แท้จริงก็คือจำเป็นต้องใช้ start-stop-daemon ตั้งแต่แรกหรือไม่?


3

ฉันไม่แน่ใจว่า "$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1" จะเคยปิด file descriptor สำหรับล็อกไฟล์หรือไม่ ... ซึ่งหมายความว่าถ้า daemon ของคุณทำงานตลอดไปฉันไม่แน่ใจ logrotate นั้นหรือกลไกอื่น ๆ ในการล้างพื้นที่ดิสก์จะทำงานได้ เนื่องจากเป็น> แทน >> คำสั่งที่แนะนำจะตัดบันทึกที่มีอยู่เมื่อรีสตาร์ท หากคุณต้องการดูสาเหตุที่ภูตขัดข้องและรีสตาร์ทโดยอัตโนมัตินั่นอาจไม่เป็นประโยชน์มากนัก

อีกทางเลือกหนึ่งอาจเป็น "$ DAEMON | คนตัดไม้" คนตัดไม้เป็นคำสั่งที่จะเข้าสู่ระบบ syslog (/ var / log / messages) ถ้าคุณต้องการ stderr ด้วยฉันคิดว่าคุณสามารถใช้ "$ DAEMON 1> & 2 | คนตัดไม้"


คุณถูกต้องโดย>>ทั่วไปการใช้จะเหมาะสมกว่าสำหรับภูตแม้ว่าจะบอกเป็นนัยว่าตอนนี้คุณควรสร้างกฎ logrotate แล้วก็ตาม!
joeytwiddle

สำหรับพื้นที่ดิสก์วิธีการตัดทอนไฟล์จะได้รับพื้นที่คืนทันที (อย่างน้อยก็ภายใต้ระบบไฟล์ภายนอก) แต่ระวังวิธีการที่ลบไฟล์ที่ยังคงถูกเขียนถึง: พื้นที่จะไม่ถูกเรียกคืนจนกว่าที่จับจะถูกปล่อยออกมาและคุณจะไม่พบโหนดไฟล์เพื่อตัดทอนด้วยตนเองอีกต่อไป!
joeytwiddle

@joeytwiddle ส่วนหนึ่งของประเด็นของฉันที่นี่คือมีสถานการณ์ที่ logrotate จะล้มเหลวในการหมุนบันทึกหากไม่เคยปิดที่จับไฟล์
nairbv

--no-close ... | loggerไม่ทำงานสำหรับฉัน (Debian 7.3, start-stop-daemon 1.16.12) สคริปต์ start-stop-daemon ไม่กลับมาแม้ว่า / var / log / messages จะถูกเติม :-) 1>&2ฉันพยายามมันมีและไม่มี
hgoebl

hgoebl คุณต้องมีนิพจน์ "cmd | logger" ในเครื่องหมายคำพูดดังนั้นล่ามจะรู้ว่าเป็น "cmd" ที่คุณกำลังส่งไปยังคนตัดไม้ไม่ใช่นิพจน์ start-stop-daemon
Wexxor

2

สมมติว่ามันเป็นการทุบตี (แม้ว่ากระสุนอื่น ๆ บางตัวอาจอนุญาตเช่นกัน) บรรทัด:

exec >>/tmp/myDaemon.log

จะส่งเอาต์พุตมาตรฐานในอนาคตทั้งหมดไปยังไฟล์นั้น นั่นเป็นเพราะการexecไม่มีชื่อโปรแกรมจะทำให้เวทมนตร์เปลี่ยนเส้นทางได้ จากbashหน้าคน:

หากไม่ได้ระบุคำสั่งการเปลี่ยนเส้นทางใด ๆ จะมีผลในเชลล์ปัจจุบัน

การจัดการไฟล์ดังกล่าวเป็นอีกปัญหาหนึ่งของหลักสูตร


คุณช่วยอธิบายได้ไหมว่าควรวางบรรทัดนี้ไว้ที่ใด หลังจากstart-stop-daemonบรรทัดที่คำถามเริ่มต้นกล่าวถึง?
อับดุล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.