作为调试过程的重要步骤,仔细查找时间和进程是必须的。
script经常使用scriptreplay,我想知道是否存在用于操作结果文件的工具。
script
scriptreplay
示例(来自如何分析 bash shell 脚本启动缓慢?):
script -t script.log 2>script.tim -c 'bash -x -c " for ((i=3;i--;));do sleep .1;done for ((i=2;i--;)) ;do tar -cf /tmp/test.tar -C / bin gzip /tmp/test.tar rm /tmp/test.tar.gz done "'
然后有两个文件:
-rw-r--r-- 1 user user 472 Sep 25 10:44 script.log -rw-r--r-- 1 user user 213 Sep 25 10:44 script.tim
我可以通过以下方式重演该脚本:
scriptreplay --timing script.tim --typescript script.log 10
作为执行时间除数,10使重放速度提高 10 倍,或者
10
scriptreplay --timing script.tim --typescript script.log .1
使重播速度变慢 10 倍。
我想知道是否存在类似的工具:
好吧,从那里开始:
cut -d \ -f1 <script.tim | xargs | tr \ + | bc 3.616809
将输出总体执行时间,或者如果有太多行:
cut -d \ -f1 <script.tim | xargs | tr \ + | bc | xargs | tr \ + | bc 3.616809
和
cut -d \ -f2 <script.tim | xargs | tr \ + | bc 366 sed '1d;$d' script.log |wc -c 367
检查整体脚本输出大小。(sed删除日志的第一行和最后一行,其中包含:Script started on Wed Sep 25 14:40:20 2019和Script done on Wed Sep 25 14:40:23 2019。)
sed
Script started on Wed Sep 25 14:40:20 2019
Script done on Wed Sep 25 14:40:23 2019
然后,计算某个时间的日志大小(指针):
perl -e 'my ($l,$t,$p)=(0,0,0); # line totTime pos open FH,"<".$ARGV[0] || die; while (<FH>) { my ($d,$n)=split" "; # duration numBytes $l++; $t+=$d; $p+=$n; $t>=${ARGV[1]} && do { print $l." ".$p."\n"; exit 0; }; };' script.tim 1.2 12 216
TimingFile( head -n 12) 中的第 12 行和 TypeScript 文件 () 中的字节位置 216 head -c 216。
head -n 12
head -c 216
或者如果我正在搜索*某个字符串的*运行时间:
grep -ob 'tar.*test' script.log 217:tar -cf /tmp/test 320:tar -cf /tmp/test perl -e 'my ($l,$t,$p)=(0,0,0);open FH,"<".$ARGV[0] || die;while (<FH>) { my ($d,$n)=split" ";$l++;$t+=$d;$p+=$n;$p>=${ARGV[1]} && do { print $l." ".$p."\n";exit 0;};};' script.tim 217 17 228 head -n 17 script.tim | cut -d \ -f1 | xargs | tr \ + | bc 1.091276
寻找更轻松的东西…
使用 Python 来简化你的分析可以更轻松地操作 script.log 和 script.tim 文件。我们可以编写一个 Python 脚本来动态显示重播过程的执行时间和日志大小,甚至可以添加键盘控制来暂停和跳过步骤。下面是一个可以帮助你执行这些任务的基本脚本。对于更复杂的交互式界面(如 Ncurses),也可以扩展。
script.log
script.tim
import time import sys def parse_timing_file(timing_file): with open(timing_file, 'r') as f: timings = [] for line in f: duration, bytes_count = line.split() timings.append((float(duration), int(bytes_count))) return timings def parse_log_file(log_file): with open(log_file, 'r') as f: log = f.read() return log def replay_script(timing_file, log_file, speed_factor=1.0): timings = parse_timing_file(timing_file) log = parse_log_file(log_file) pointer = 0 # Log file pointer start_time = time.time() for duration, byte_count in timings: # Adjust duration according to speed factor time.sleep(duration / speed_factor) # Print log output up to the current byte position sys.stdout.write(log[pointer:pointer + byte_count]) sys.stdout.flush() # Update pointer to the new position pointer += byte_count print(f"\nReplay finished in {time.time() - start_time:.2f} seconds (speed factor: {speed_factor})") # Example usage timing_file = "script.tim" log_file = "script.log" speed_factor = 10 # Adjust speed as needed replay_script(timing_file, log_file, speed_factor)
parse_timing_file
parse_log_file
replay_script
sys.stdout.write
speed_factor
0.1
可以考虑使用 curses 模块来实现更交互式的界面,如暂停和快进控制。以下是如何在 Python 中引入基本交互控制的示例:
curses
import curses import time def interactive_replay(timing_file, log_file, speed_factor=1.0): timings = parse_timing_file(timing_file) log = parse_log_file(log_file) def main(stdscr): pointer = 0 pause = False replay_speed = speed_factor stdscr.nodelay(1) # Non-blocking input stdscr.clear() stdscr.addstr(0, 0, "Press 'p' to pause/play, 'q' to quit, '+' to speed up, '-' to slow down") for duration, byte_count in timings: # Handle keyboard input key = stdscr.getch() if key == ord('q'): break # Quit the replay elif key == ord('p'): pause = not pause # Toggle pause elif key == ord('+'): replay_speed *= 1.5 # Speed up elif key == ord('-'): replay_speed /= 1.5 # Slow down if pause: time.sleep(0.1) continue # Adjust timing according to replay speed time.sleep(duration / replay_speed) # Print log content stdscr.addstr(1, 0, log[pointer:pointer + byte_count]) stdscr.clrtoeol() stdscr.refresh() pointer += byte_count curses.wrapper(main) # Run the interactive replay interactive_replay(timing_file, log_file, speed_factor)
'p'
'q'
'+'
'-'
可以进一步扩展脚本,使其具有更多的功能,例如: - 跳到特定时间:允许用户输入时间戳并直接跳转到对应的输出位置。 - 查找功能:实现搜索功能以在回放中找到特定文本或模式。 - 进度条:显示整个回放过程的进度条或剩余时间。