Page MenuHomePhabricator
Paste P15857

plot-docker-stats.py
ActivePublic

Authored by JMeybohm on May 7 2021, 1:05 PM.
Tags
None
Referenced Files
F34449190: plot-docker-stats.py
May 10 2021, 2:25 PM
F34445119: plot-docker-stats.py
May 7 2021, 1:05 PM
Subscribers
None
#!/bin/env python3
import argparse
import json
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
def calculate_CPU_usage(record):
"""Return the used CPU delta (in ms) and CPU usage in percent since last tick"""
cpu_percent = 0.0
cpu_delta = (
record["cpu_stats"]["cpu_usage"]["total_usage"]
- record["precpu_stats"]["cpu_usage"]["total_usage"]
)
system_delta = (
record["cpu_stats"]["system_cpu_usage"]
- record["precpu_stats"]["system_cpu_usage"]
)
cpu_count = record["cpu_stats"]["online_cpus"]
if system_delta > 0 and cpu_delta > 0:
cpu_percent = (cpu_delta / system_delta) * cpu_count * 100
if cpu_delta > 0:
cpu_delta = cpu_delta / 1000000
return (cpu_delta, cpu_percent)
def read_json(fileobj):
j = []
first_line = True
for record in fileobj:
# Skip the first line it does not have previous recordings
if first_line:
first_line = False
continue
try:
record = json.loads(record)
except json.decoder.JSONDecodeError:
# probably last line not completely flushed
continue
cpu_delta, cpu_percent = calculate_CPU_usage(record)
tick = dict(read=record["read"])
tick["cpu_delta"] = cpu_delta
tick["cpu_percent"] = cpu_percent
# Calculate the time (in ms) the container was throttled since last tick
tick["cpu_throttled_ms"] = (
record["cpu_stats"]["throttling_data"]["throttled_time"]
- record["precpu_stats"]["throttling_data"]["throttled_time"]
) / 1000000
j.append(tick)
return j
def plot(df, title="foo", output=None):
fig = make_subplots(
rows=2, cols=1, shared_xaxes=True, subplot_titles=("CPU %", "CPU (trottled) ms")
)
fig.add_trace(
go.Scatter(x=df["read"], y=df["cpu_percent"], name="CPU %"),
row=1,
col=1,
)
fig.add_trace(
go.Scatter(x=df["read"], y=df["cpu_delta"], name="CPU ms"),
row=2,
col=1,
)
fig.add_trace(
go.Scatter(x=df["read"], y=df["cpu_throttled_ms"], name="throttled ms"),
row=2,
col=1,
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="%", range=[0, 100], row=1, col=1)
fig.update_yaxes(title_text="ms", row=2, col=1)
fig.update_layout(title_text=title)
if output is None:
fig.show()
else:
fig.write_html(output)
if __name__ == "__main__":
"""
Generate the input file with something like:
curl -s --unix-socket /var/run/docker.sock \
"http://localhost/containers/${CONTAINER_ID}/stats?stream=1" |
jq -c '{read: .read, cpu_stats: .cpu_stats, precpu_stats: .precpu_stats}'
"""
parser = argparse.ArgumentParser(description="Plot docker stats CPU usage data")
parser.add_argument("input", type=argparse.FileType("r"))
parser.add_argument("--out", type=argparse.FileType("w"), required=False)
args = parser.parse_args()
j = read_json(args.input)
df = pd.DataFrame.from_dict(j)
plot(df, args.input.name, args.out)