Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions plot_mem_usage_live.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from src.dockerstats import *

ds = DockerStats("data.csv")

ds.plot_category_live('MEM Usage')
11 changes: 6 additions & 5 deletions scripts/generate_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

# Using linux date
# For mac - brew install coreutils ; echo "alias date=gdate" >> ~/.bash_profile
runtime="30 minutes"
runtime="24 hours"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I were to work on it, I would put some of the value like the runtime or sleep time as variables 🤔
But I don't mind as is.

endtime=$(date -ud "$runtime" +%s)
echo "Collecting docker stats for ${runtime} or until cancelled..."

# while true
while [[ $(date -u +%s) -le ${endtime} ]]
do docker stats --no-stream --format "table {{.Name}};{{.CPUPerc}};{{.MemPerc}};{{.MemUsage}};{{.NetIO}};{{.BlockIO}};{{.PIDs}}" > dockerstats
tail -n +2 dockerstats | awk -v date=";$(date +%T)" '{print $0, date}' >> data.csv
sleep 5
tail -n +2 dockerstats | awk -v date=";$(date -u +'%Y-%m-%dT%H:%M:%SZ')" '{print $0, date}' >> data.csv
sleep 1
done

cat data.csv
rm -rf dockerstats
echo "Finished after ${runtime} see data.csv"
rm -rf dockerstats
40 changes: 33 additions & 7 deletions src/dockerstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.animation import FuncAnimation

from src import setup_plot

Expand All @@ -12,7 +13,12 @@ class DockerStats:
__category = ["CPU %", "MEM %", "NET INPUT", "NET OUTPUT", "BLOCK INPUT", "BLOCK OUTPUT"]

def __init__(self, data_path):
self.df = pd.read_csv(data_path, delimiter=";", names=DockerStats.__header_list)
setup_plot()
self.data_path = data_path
self.load_data()

def load_data(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it's separated to be able to load the data asynchronously?

self.df = pd.read_csv(self.data_path, delimiter=";", names=DockerStats.__header_list)
self.df["CPU %"] = self.df["CPU %"].apply(self.__percentage_to_float())
self.df["MEM %"] = self.df["MEM %"].apply(self.__percentage_to_float())
self.df["MEM Usage"] = self.df["MEM Usage"].apply(lambda value: self.__take_usage(value))
Expand All @@ -25,25 +31,45 @@ def __init__(self, data_path):
self.df["MEM Usage"] = self.df["MEM Usage"].apply(lambda x: self.__to_float_mb(x))
self.df.drop(["NET IO", "BLOCK IO"], inplace=True, axis=1)
self.df["DATE"] = pd.to_datetime(self.df["DATE"])
setup_plot()

def plot_category(self, category, size=(10, 5)):
fig, ax = plt.subplots(figsize=size)
def prep_fix_and_ax(self, size):
self.fig, self.ax = plt.subplots(figsize=size)

# Leave more space for the legend
plt.subplots_adjust(right=0.7)

def plot_category(self, category, size=(10, 5)):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you have an example of how you used the new methods ? (For the Readme)

self.prep_fix_and_ax(size=size)
self._do_plot_category(category=category)
plt.show()

def plot_category_live(self, category, size=(10, 5), update_interval_ms=10000):

self.prep_fix_and_ax(size=size)
self._do_plot_category(category=category)

def _update(_):
# In lieu of something clever that updates the data in each of `self.ax.get_lines()`
# instead just clear and re-plot the whole thing which is fine for slow refresh rates
self.load_data()
self.ax.clear()
self._do_plot_category(category=category)

animation = FuncAnimation(self.fig, _update, interval=update_interval_ms, cache_frame_data=False)
plt.show()


def _do_plot_category(self, category):
names = self.df["NAME"].unique()
self.df.reset_index().groupby('NAME').plot(x='DATE', y=category, ax=ax)
self.df.reset_index().groupby('NAME').plot(x='DATE', y=category, ax=self.ax, marker="+")

# groupby sorts the names so this is necessary too in order for the legend to be in the right order
names.sort()
plt.legend(names, title='apps', bbox_to_anchor=(1.05, 1), loc='upper left')

plt.ylabel(self.__category_label(category))
plt.xlabel('Time')

plt.show()
plt.grid(alpha=0.5)

def plot_category_all(self):
for category in self.__category:
Expand Down