diff --git a/graph.py b/graph.py index 52ca5e2..4129257 100755 --- a/graph.py +++ b/graph.py @@ -74,14 +74,14 @@ def g(command): # Plot a single column of values from data.txt -def plot(ylabel, title, name, column): +def plot(ylabel, title, session, column): g(f"set ylabel '{ylabel}'") g(f"set title '{title}'") - g(f"plot '{name}.txt' using 1:{column}:{column} title 'cpu' with boxes palette") + g(f"plot '{session}.txt' using 1:{column}:{column} title 'cpu' with boxes palette") # Read additional information from 'data.txt' comments -def read_comments(name): +def read_comments(session): global START_DATE global END_DATE global AVERAGE_LOAD @@ -95,7 +95,7 @@ def read_comments(name): global CPU_NAME global DURATION - with open(f"{name}.txt", "r") as f: + with open(f"{session}.txt", "r") as f: for line in f: value = None @@ -156,18 +156,34 @@ def read_comments(name): AVERAGE_LOAD = value -try: - if os.environ["SARGRAPH_OUTPUT_TYPE"] == "svg": - OUTPUT_TYPE="svg" - OUTPUT_EXT="svg" -except: - pass +def graph(session, fname='plot.png'): + global OUTPUT_TYPE + global OUTPUT_EXT + global labels -def graph(name): global gnuplot - read_comments(name) + labels = [] + + if "SARGRAPH_OUTPUT_TYPE" in os.environ: + if os.environ["SARGRAPH_OUTPUT_TYPE"] == "svg": + OUTPUT_TYPE="svg" + OUTPUT_EXT="svg" + elif fname.lower().endswith('.svg'): + OUTPUT_TYPE="svg" + OUTPUT_EXT="svg" + elif fname.lower().endswith('.png'): + # Otherwise leave the default png + pass + else: + print("Error: unknown graph extension.") + sys.exit(1) + + # Leave just the base name + fname = fname[:-4] + + read_comments(session) gnuplot = run_process("gnuplot", stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -203,7 +219,7 @@ def graph(name): g(f"set terminal {OUTPUT_TYPE} size 1200,800 background '#222222' font 'Courier-New,8'") - g(f"set output '{name}.{OUTPUT_EXT}'") + g(f"set output '{fname}.{OUTPUT_EXT}'") g(f"set multiplot layout {NUMBER_OF_PLOTS},1 title \"\\n\\n\\n\"") @@ -231,9 +247,9 @@ def graph(name): g("set object rectangle from graph 0, graph 0 to graph 2, graph 2 behind fillcolor rgb '#111111' fillstyle solid noborder") g(f"set object rectangle from '{START_DATE.replace(' ', '-')}', 0 to '{END_DATE.replace(' ', '-')}', 100 behind fillcolor rgb '#000000' fillstyle solid noborder") - plot("cpu % load (user)", f"cpu load (average = {AVERAGE_LOAD:.2f} %)", name, 2) - plot("ram % usage", f"ram usage (max = {MAX_USED_RAM:.2f} GB)", name, 3) - plot(f"{NAME_FS}'", f"{NAME_FS} usage (max = {MAX_USED_FS:.2f} MB)", name, 4) + plot("cpu % load (user)", f"cpu load (average = {AVERAGE_LOAD:.2f} %)", session, 2) + plot("ram % usage", f"ram usage (max = {MAX_USED_RAM:.2f} GB)", session, 3) + plot(f"{NAME_FS}'", f"{NAME_FS} usage (max = {MAX_USED_FS:.2f} MB)", session, 4) g("unset multiplot") g("unset output") diff --git a/sargraph.py b/sargraph.py index 0783e35..e23a56c 100755 --- a/sargraph.py +++ b/sargraph.py @@ -79,7 +79,10 @@ elif cmd[0] == "stop": except: print("Warning: cannot find pid.") gpid = -1 - p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", "q\n"]) + if len(cmd) >= 2 and cmd[1] == "none": + p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", "command:b\n"]) + else: + p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", "command:q\n"]) while p.poll() is None: time.sleep(0.1) if gpid == -1: @@ -89,9 +92,6 @@ elif cmd[0] == "stop": #print("Waiting for pid %d" % gpid) while pid_running(gpid): time.sleep(0.25) - - import graph - graph.graph(sid) elif cmd[0] == "label": # Check if the label name was provided if len(cmd) < 2: @@ -100,12 +100,24 @@ elif cmd[0] == "label": label = cmd[1] print(f"Adding label '{label}' to sargraph session '{sid}'.") - p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", f"{label}\n"]) + p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", f"label:{label}\n"]) + while p.poll() is None: + time.sleep(0.1) +elif cmd[0] == 'save': + print(f"Saving graph from session '{sid}'.") + if len(cmd) < 2: + fname = '' + else: + fname = cmd[1] + p = subprocess.Popen(["screen", "-S", sid, "-X", "stuff", f"command:s:{fname}\n"]) while p.poll() is None: time.sleep(0.1) elif cmd[0] == 'plot': - # TODO: plot the result - pass + import graph + if len(cmd) < 2: + graph.graph(sid) + else: + graph.graph(sid, cmd[1]) else: print(f"Error: Unknown command '{cmd[0]}'") sys.exit(1) diff --git a/watch.py b/watch.py index c304f44..632ef30 100755 --- a/watch.py +++ b/watch.py @@ -68,7 +68,7 @@ def read_table(f): # Initialize 'data.txt' where the data is dumped -def initialize(name, machine): +def initialize(session, machine): global TOTAL_RAM with open("/proc/meminfo") as f: @@ -87,7 +87,7 @@ def initialize(name, machine): cpu_name = line.replace("\n", "").split(": ")[1] break - with open(f"{name}.txt", "w") as f: + with open(f"{session}.txt", "w") as f: print(f"# pid: {os.getpid()}", f"machine: {uname}", f"cpu count: {cpus}", @@ -96,7 +96,7 @@ def initialize(name, machine): # Add a summary comment to 'data.txt' -def summarize(name): +def summarize(session): average_load = TOTAL_LOAD / float(SAMPLE_NUMBER) max_used_ram = MAX_USED_RAM / 1024.0 / 1024.0 max_used_fs = MAX_USED_FS / 1024.0 @@ -105,7 +105,7 @@ def summarize(name): edt = datetime.datetime.strptime(END_DATE, '%Y-%m-%d %H:%M:%S') delta_t = ((edt - sdt).total_seconds()) / 60.0 - with open(f"{name}.txt", "a") as f: + with open(f"{session}.txt", "a") as f: print(f"# total ram: {TOTAL_RAM:.2f} GB", f"total disk space: {TOTAL_FS:.2f} GB", f"max ram used: {max_used_ram:.2f} GB", @@ -117,7 +117,7 @@ def summarize(name): # Run sar and gather data from it -def watch(name, fsdev): +def watch(session, fsdev): global SAMPLE_NUMBER global START_DATE global END_DATE @@ -131,12 +131,15 @@ def watch(name, fsdev): global die + # Was a graph alreay produced by save command from sargraph? + dont_plot = False + my_env = os.environ my_env["S_TIME_FORMAT"] = "ISO" p = run_process("sar", "-F", "-u", "-r", "1", stdout=subprocess.PIPE, env=my_env) machine = p.stdout.readline().decode() - initialize(name, machine) + initialize(session, machine) p.stdout.readline() signal.signal(signal.SIGTERM, kill_handler) @@ -151,13 +154,32 @@ def watch(name, fsdev): now = datetime.datetime.now() if sys.stdin in rlist: label_line = sys.stdin.readline().replace("\n", "") - if label_line == "q": - die = 1 - break - - with open(f"{name}.txt", "a") as f: - timestamp = now.strftime("%Y-%m-%d-%H:%M:%S") - print(f"# {timestamp} label: {label_line}", file=f) + if label_line.startswith("command:"): + label_line = label_line[len("command:"):] + if label_line == "q": + die = 1 + break + elif label_line.startswith("s:"): + label_line = label_line[len("s:"):] + + dont_plot = True + + if label_line != "none": + import graph + summarize(session) + if not label_line: + graph.graph(session) + else: + graph.graph(session, label_line) + elif label_line == "b": + dont_plot = True + die = 1 + break + elif label_line.startswith('label:'): + label_line = label_line[len('label:'):] + with open(f"{session}.txt", "a") as f: + timestamp = now.strftime("%Y-%m-%d-%H:%M:%S") + print(f"# {timestamp} label: {label_line}", file=f) if (p.stdout not in rlist): continue @@ -200,7 +222,7 @@ def watch(name, fsdev): END_DATE = date + " " + daytime timestamp = date + "-" + daytime - with open(f"{name}.txt", "a") as f: + with open(f"{session}.txt", "a") as f: print(timestamp, cpu_data['%user'][0], ram_data['%memused'][0], @@ -214,4 +236,8 @@ def watch(name, fsdev): time.sleep(1) sys.exit(0) - summarize(name) + summarize(session) + + if not dont_plot: + import graph + graph.graph(session)