2013-01-10 15 views
8

का एक स्टैक ट्रेस प्राप्त करें मेरे पास एक स्क्रिप्ट है जो हर रात एक क्रॉन नौकरी से चलती है। हाल ही में, यह स्क्रिप्ट में कई मिनटों के बाद पूरी तरह से ठंडा हो गया है, और मैं यह नहीं समझ सकता कि क्यों। यदि यह जावा था, तो मैं बस kill -3 PID चला सकता था और यह stdout में थ्रेड डंप मुद्रित करेगा। क्या PHP में कोई समकक्ष है, जहां मैं चल रहे PHP स्क्रिप्ट पर वर्तमान स्टैक ट्रेस (और आदर्श मेमोरी जानकारी) का डंप प्राप्त कर सकता हूं?एक लटका PHP स्क्रिप्ट

+0

सरल समाधान, अपने कोड में कुछ लॉगिंग स्टेटमेंट फेंकें और देखें कि निष्पादन में वे कहां रुकते हैं। – Sammitch

उत्तर

7

सबसे अच्छी बात यह है कि आप configure के दौरान स्वयं PHP को संकलित कर सकते हैं।

$ gdb -p $PHP_PID 
(gdb) bt  # Get a system-level stacktrace, might already give some info 
(gdb) source /path/to/php-src/.gdbinit # Load some useful macros 
(gdb) dump_bt executor_globals.current_execute_data 
      # Macro from PHP's .gbinit giving PHP stack trace 
      # If you for whatever reason are using a thread-safe PHP build you have to do this: 
(gdb) ____executor_globals 
(gdb) dump_bt $eg.current_execute_data 

और फिर डिबग आगे :-)

नोट इस आपके पास काम करने के लिए है कि: प्रक्रिया तो अभी भी लटकी हुई है तो आप इन चरणों का उपयोग कर एक PHP स्तरीय स्टैकट्रेस पाने के लिए gdb और कुछ मैक्रो का उपयोग कर सकते हैं प्रतीक जानकारी के साथ एक PHP बाइनरी रखने के लिए, --enable-debug यह सुनिश्चित करता है कि।

+0

हाय। क्या PHP चर के मौजूदा मानों को उसी तरह मुद्रित करना संभव है? – shark555

+1

मेरे सिर के शीर्ष से: dump_ht execor_globals.active_symbol_table (उपयोग करने के लिए चर के नाम को सत्यापित करने के लिए: lxr.php.net या अपने स्थानीय PHP स्रोत पेड़ पर जाएं और execor_globals परिभाषा की जांच करें) – johannes

+0

मैं pthreads एक्सटेंशन का उपयोग कर रहा हूं (php multithreading) और इसके लिए काम करने के लिए मुझे सबसे पहले सेट_ट्स (अन्यथा ____executor_globals क्रैश) का उपयोग करना था, 'tsrm_ls' तर्क मान स्टैक फ्रेम में दिखाई देने वाले – 2072

2

हां। आप debug_backtrace के साथ बैकट्रैक प्राप्त कर सकते हैं। इसके अलावा आपको memory_get_usage की आवश्यकता हो सकती है।

+2

मेरी समस्या यह है कि मुझे नहीं पता कि यह कहां लटक रहा है। अगर मैंने किया, तो यह आसान समाधान होगा। –

1

एक PHP स्क्रिप्ट को टाइमटाउट होना चाहिए यदि यह अधिकतम रनटाइम से अधिक हो। निश्चित रूप से यह आपके लिए समस्या का समाधान करेगा; बस इसे तोड़ने के लिए प्रतीक्षा करें, और आपका स्टैक ट्रेस है।

मुझे लगता है कि यह संभव है कि आपके पास आपके कोड (या php.ini) में कुछ है जो इसे तोड़ने से रोकने के लिए अधिकतम रनटाइम शून्य पर सेट करता है। यदि आपको वह मिल गया है, तो इससे छुटकारा पाएं (या डिफ़ॉल्ट रूप से बहुत छोटा होने पर इसे बहुत बड़े टाइमआउट पर सेट करें)।

आप इसे xDebug या इसी तरह के टूल के साथ चलाने का प्रयास भी कर सकते हैं, जो आपको एक प्रोफाइलर ट्रेस देगा जो आपको प्रोग्राम का कॉल पेड़ देगा, और आपको अपने आईडीई में कोड के माध्यम से कदम उठाने की अनुमति देगा, तो आप देख सकते हैं कि क्या हो रहा है; यदि वहां एक अनंत लूप है, तो आपको उससे बहुत जल्दी पहचानने में सक्षम होना चाहिए।

+0

यह एक लंबी चल रही स्क्रिप्ट है। कुछ बार इसमें कई घंटे लग सकते हैं। मैं नियमित रूप से उस राशि के लिए टाइमआउट रीसेट करता हूं जो चल रहे फ़ंक्शन के लिए उचित है, लेकिन यह किसी भी तरह मेरी समस्या को नहीं पकड़ता है। –

2

मैंने देखा है कि pcntl_signal का उपयोग कर एक संभावित समाधान है। मैं इसे अपने आप प्रयास नहीं किया है, तो आप कुछ नमूना कोड यहाँ पा सकते हैं:

https://secure.phabricator.com/D7797

function __phutil_signal_handler__($signal_number) { 
    $e = new Exception(); 
    $pid = getmypid(); 
    // Some phabricator daemons may not be attached to a terminal. 
    Filesystem::writeFile(
    sys_get_temp_dir().'/phabricator_backtrace_'.$pid, 
    $e->getTraceAsString()); 
} 

if (function_exists('pcntl_signal')) { 
    pcntl_signal(SIGHUP, '__phutil_signal_handler__'); 
} 
+0

यह * काम * कर सकता है अगर आप '--debug नहीं जोड़ सकते कॉन्फ़िगर स्क्रिप्ट के लिए सक्षम 'ध्वज। लेकिन मुझे नहीं लगता कि आप डिबगिंग के इस स्तर को कर रहे होंगे यदि आप कॉन्फ़िगरेशन ऑगमेंट्स के साथ भी नहीं खेल सके। –

1

बशर्ते आप PHP स्थापित के लिए gdb और डिबगिंग प्रतीकों है, तो आप एक पूर्ण पीएचपी पश्व-अनुरेखन मिल सकती है।

डिबगिंग प्रतीकों को स्थापित करने की विधि डिस्ट्रो से distro में भिन्न हो सकती है। उदाहरण के लिए अमेज़ॅन लिनक्स पर मैंने rpm -qa | grep php56-common भाग लिया और परिणाम debuginfo-install पर पास कर दिया। ध्यान दें कि मानक पैकेज मैनेजर का उपयोग कर डिबगिंग प्रतीकों को स्थापित करने से वांछित परिणाम नहीं मिल सकते हैं - अमेज़ॅन लिनक्स पर मुझे yum install php56-debuginfo चलाते समय PHP के एक अलग संस्करण के लिए डीबगिंग प्रतीक मिल गए और gdb को यह पसंद नहीं आया।

यदि आपके पास है तो आपको बैकट्रैक प्राप्त करने के लिए चलने की प्रक्रिया की भी आवश्यकता नहीं है। आप kill -ABRT $pid कर सकते हैं और बाद में कोर डंप का निरीक्षण कर सकते हैं।

फिर आप gdb -p $pid या gdb /usr/bin/php $path_to_core_dump के साथ कोर डंप के साथ चल रहे प्रक्रिया को डीबग करना प्रारंभ कर सकते हैं।

टाइपिंग bt आपको एक सी स्टैक ट्रेस देगा। यह कभी-कभी आपको गलत होने का संकेत देने के लिए पर्याप्त होगा। सुनिश्चित करें कि डीबगिंग प्रतीक सही ढंग से स्थापित हैं; bt को PHP स्रोत कोड में फ़ाइल नाम और रेखा संख्याओं पर इंगित करना चाहिए।

अब p executor_globals.current_execute_data आज़माएं। इसे $1 = (struct _zend_execute_data *) 0x7f3a9bcb12d0 जैसे कुछ प्रिंट करना चाहिए। यदि ऐसा है, तो इसका मतलब है कि जीडीबी PHP के आंतरिक जांच कर सकता है।

थोड़ा पायथन स्क्रीप्टिंग का उपयोग करके आप एक पूर्ण PHP बैकट्रैक उत्पन्न कर सकते हैं। python-interactive लिखें और फिर इस छोटे से स्क्रिप्ट सम्मिलित करें:

def bt(o): 
    if o == 0: return 
    print "%s:%d" % (o["op_array"]["filename"].string(), o["opline"]["lineno"]) 
    bt(o["prev_execute_data"]) 

bt(gdb.parse_and_eval("executor_globals.current_execute_data")) 

ध्यान दें कि यह विधि पीएचपी के आंतरिक भागों पर निर्भर है, तो यह पहले या बाद के संस्करणों पर काम न करे। मैंने php 5.6.14 के साथ ऐसा किया। इस विधि का लाभ यह है कि यह दोनों चल रही प्रक्रियाओं और कोर डंप दोनों के लिए काम करता है, साथ ही आपको PHP को पुन: संकलित करने या अपनी PHP स्क्रिप्ट को पुनरारंभ करने की आवश्यकता नहीं है। के बाद आप gdb और डिबगिंग प्रतीकों को इंस्टॉल भी कर सकते हैं, आपको एक लटकती प्रक्रिया मिलती है।

संबंधित मुद्दे