Index: core/admin_templates/logs/system_logs/system_log_edit.tpl =================================================================== --- core/admin_templates/logs/system_logs/system_log_edit.tpl +++ core/admin_templates/logs/system_logs/system_log_edit.tpl @@ -69,8 +69,8 @@ padding-left: 25px; } - .log_backtrace div { - margin: 4px 0; + .log_backtrace div.expandable-area { + margin: 4px 0 8px 0; } </style> @@ -84,13 +84,27 @@ </inp2:m_RenderElement> </inp2:m_DefineElement> -<inp2:m_DefineElement name="backtrace_element"> +<inp2:m_DefineElement name="backtrace_element" expandable=""> <li> <inp2:m_if check="m_Param" name="has_args"> - <a href="#" title="<inp2:m_Phrase name='hint:la_LogBacktraceFunction' html_escape='1'/>" trace_index="<inp2:m_Param name='index'/>"><inp2:m_Phrase name="la_LogBacktraceFunction"/>:</a> <inp2:m_Param name="file_info"/> + <inp2:m_SetParam expandable="1"/> + <inp2:m_elseif check="m_Param" name="has_code_fragment"/> + <inp2:m_SetParam expandable="1"/> + </inp2:m_if> + + <inp2:m_if check="m_Param" name="expandable"> + <a href="#" class="expandable" title="<inp2:m_Phrase name='hint:la_LogBacktraceFunction' html_escape='1'/>" trace_index="<inp2:m_Param name='index'/>"><inp2:m_Phrase name="la_LogBacktraceFunction"/>:</a> <inp2:m_Param name="file_info"/> - <div class="highlight-area" style="display: none;" id="trace_args_<inp2:m_Param name='index'/>"> - <inp2:m_Param name="args"/> + <div style="display: none;" class="expandable-area"> + <inp2:m_if check="m_Param" name="has_args"> + <inp2:m_Phrase name="la_text_Arguments"/>: + <div class="highlight-area"><inp2:m_Param name="args"/></div> + </inp2:m_if> + + <inp2:m_if check="m_Param" name="has_code_fragment"> + <a href="#" class="expandable"><inp2:m_Phrase name="la_btn_ToggleCode"/></a> + <div class="highlight-area expandable-area" style="display: none;"><inp2:m_Param name="code_fragment"/></div> + </inp2:m_if> </div> <inp2:m_else/> <inp2:m_Phrase name="la_LogBacktraceFunction"/>: <inp2:m_Param name="file_info"/> @@ -155,7 +169,7 @@ <inp2:m_RenderElement design="form_row" prefix="system-log" field="LogBacktrace"> <td class="control-cell" valign="top"> <ol class="log_backtrace"> - <inp2:$prefix_PrintBacktrace render_as="backtrace_element" include_args="1"/> + <inp2:$prefix_PrintBacktrace render_as="backtrace_element" include_args="1" include_code_fragment="1"/> </ol> </td> </inp2:m_RenderElement> @@ -183,10 +197,10 @@ <script type="text/javascript"> $(document).ready(function () { - $('a', '.log_backtrace').click(function () { - $('#trace_args_' + $(this).attr('trace_index')).toggle(); + $('.log_backtrace').on('click', 'a.expandable', function ($e) { + $(this).siblings('.expandable-area:first').toggle(); - return false; + $e.preventDefault(); }); }); </script> Index: core/install/english.lang =================================================================== --- core/install/english.lang +++ core/install/english.lang @@ -60,6 +60,7 @@ <PHRASE Label="la_btn_SetValue" Module="Core" Type="1">U2V0IFZhbHVl</PHRASE> <PHRASE Label="la_btn_ShowStructure" Module="Core" Type="1">U2hvdyBTdHJ1Y3R1cmU=</PHRASE> <PHRASE Label="la_btn_Synchronize" Module="Core" Type="1">U3luY2hyb25pemU=</PHRASE> + <PHRASE Label="la_btn_ToggleCode" Module="Core" Type="1">VG9nZ2xlIENvZGUuLi4=</PHRASE> <PHRASE Label="la_btn_Unselect" Module="Core" Type="1">VW5zZWxlY3Q=</PHRASE> <PHRASE Label="la_btn_Up" Module="Core" Type="1">VXA=</PHRASE> <PHRASE Label="la_btn_UseDraft" Module="Core" Type="1">VXNl</PHRASE> @@ -1327,6 +1328,7 @@ <PHRASE Label="la_Text_Admin" Module="Core" Type="1">QWRtaW4=</PHRASE> <PHRASE Label="la_text_advanced" Module="Core" Type="1">QWR2YW5jZWQ=</PHRASE> <PHRASE Label="la_Text_All" Module="Core" Type="1">QWxs</PHRASE> + <PHRASE Label="la_text_Arguments" Module="Core" Type="1">QXJndW1lbnRz</PHRASE> <PHRASE Label="la_text_AutoRefresh" Module="Core" Type="1">QXV0by1SZWZyZXNo</PHRASE> <PHRASE Label="la_Text_BackupComplete" Module="Core" Type="1">QmFjayB1cCBoYXMgYmVlbiBjb21wbGV0ZWQuIFRoZSBiYWNrdXAgZmlsZSBpczo=</PHRASE> <PHRASE Label="la_Text_backup_access" Module="Core" Type="1">SW4tUG9ydGFsIGRvZXMgbm90IGhhdmUgYWNjZXNzIHRvIHdyaXRlIHRvIHRoaXMgZGlyZWN0b3J5</PHRASE> Index: core/kernel/utility/logger.php =================================================================== --- core/kernel/utility/logger.php +++ core/kernel/utility/logger.php @@ -521,6 +521,8 @@ if ( isset($trace_info['args']) ) { $trace[$trace_index]['args'] = $this->_implodeObjects($trace_info['args']); } + + $trace[$trace_index]['code_fragment'] = $this->getCodeFragment($trace_info); } $this->_logRecord['LogBacktrace'] = serialize($this->_removeObjectsFromTrace($trace)); @@ -529,6 +531,43 @@ } /** + * Returns a code fragment. + * + * @param array $trace_info Trace info. + * + * @return string + */ + protected function getCodeFragment(array $trace_info) + { + $line = $trace_info['line']; + $from_line = max(1, $line - 10); + $to_line = $line + 10; + + // Prefix example: ">>> 5. " or " 5. ". + $prefix_length = 4 + strlen($to_line) + 2; + + $cmd_parts = array( + 'sed', + '-n', + escapeshellarg($from_line . ',' . $to_line . 'p'), + escapeshellarg($trace_info['file']), + ); + $command = implode(' ', $cmd_parts); + + $ret = array(); + $code_fragment = preg_replace('/(\r\n|\n|\r)$/', '', shell_exec($command), 1); + + foreach ( explode("\n", $code_fragment) as $line_offset => $code_fragment_part ) { + $line_number = $from_line + $line_offset; + $line_indicator = $line_number == $line ? '>>> ' : ' '; + + $ret[] = str_pad($line_indicator . $line_number . '.', $prefix_length) . $code_fragment_part; + } + + return implode("\n", $ret); + } + + /** * Remove objects from trace, since before PHP 5.2.5 there wasn't possible to remove them initially * * @param Array $trace Index: core/units/logs/system_logs/system_log_tp.php =================================================================== --- core/units/logs/system_logs/system_log_tp.php +++ core/units/logs/system_logs/system_log_tp.php @@ -118,6 +118,7 @@ $ret = ''; $trace = unserialize($value); $include_args = isset($params['include_args']) ? $params['include_args'] : false; + $include_code_fragment = isset($params['include_code_fragment']) ? $params['include_code_fragment'] : false; $strip_tags = isset($params['strip_tags']) ? $params['strip_tags'] : false; $block_params = $this->prepareTagParams($params); @@ -139,11 +140,21 @@ } $block_params['has_args'] = isset($trace_info['args']); + $block_params['has_code_fragment'] = isset($trace_info['code_fragment']); if ( $include_args ) { $block_params['args'] = $block_params['has_args'] ? $this->highlightString(print_r($trace_info['args'], true)) : ''; } + if ( $include_code_fragment ) { + if ( $block_params['has_code_fragment'] ) { + $block_params['code_fragment'] = $this->highlightString($trace_info['code_fragment']); + } + else { + $block_params['code_fragment'] = ''; + } + } + $ret .= $this->Application->ParseBlock($block_params); }