Add render
This commit is contained in:
parent
15d979e9c6
commit
ff76f43e14
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
stats.json
|
stats.json
|
||||||
|
venv
|
||||||
|
mem_usage.png
|
||||||
|
24
README.md
24
README.md
@ -31,4 +31,26 @@ the crontab line redirect the outputs into `/dev/null`. Can also be a path to a
|
|||||||
Display stats
|
Display stats
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
To be done...
|
This steps permit to generate a render from a stats file (generated by the script
|
||||||
|
called by the crontab, see stats export section).
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
Need python3 with venv module
|
||||||
|
|
||||||
|
sudo apt install python3 python3-venv
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
Go in [display](display) folder
|
||||||
|
|
||||||
|
cd display
|
||||||
|
|
||||||
|
Then to generate a png, just run (install is automatically done if needed)
|
||||||
|
./render_stats.sh stats.json
|
||||||
|
|
||||||
|
It is also possible to see a web version fo the render :
|
||||||
|
./render_stats.sh stats.json -w
|
||||||
|
|
||||||
|
**Note:** if the stats file is in a remote server, one can use `scp` to get it:
|
||||||
|
scp alban@eunuque.caracals.org:/path/to/docker-stats-histo/stats.json .
|
||||||
|
72
display/render.py
Normal file
72
display/render.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import pygal
|
||||||
|
|
||||||
|
|
||||||
|
PNG_OUTPUT = 'mem_usage.png'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=("Render for docker stats memory usage")
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument('stats', type=str, help="Path to stats file")
|
||||||
|
parser.add_argument('--web', '-w', action='store_true',
|
||||||
|
help="Render in web browser instead of svg")
|
||||||
|
args = parser.parse_args()
|
||||||
|
return args.stats, args.web
|
||||||
|
|
||||||
|
|
||||||
|
def name_from_field(field: str) -> str :
|
||||||
|
if field.startswith("onlyoffice-"):
|
||||||
|
return "onlyoffice"
|
||||||
|
return field.split("_")[0]
|
||||||
|
|
||||||
|
def main():
|
||||||
|
stats_fn, web_render = parse_args()
|
||||||
|
data = load_data(stats_fn)
|
||||||
|
|
||||||
|
render(data, web_render)
|
||||||
|
|
||||||
|
|
||||||
|
def load_data(stats_fn: str):
|
||||||
|
with open(stats_fn) as stats_f:
|
||||||
|
data = json.load(stats_f)
|
||||||
|
|
||||||
|
data_dict = {name_from_field(field): [0]*len(data) for field in data[0]}
|
||||||
|
print("Found", len(data), "points")
|
||||||
|
|
||||||
|
|
||||||
|
for t_i, stat in enumerate(data):
|
||||||
|
for field in stat:
|
||||||
|
if field == "date": # date
|
||||||
|
data_dict[field][t_i] = datetime.strptime(stat[field], "%Y-%m-%dT%H:%M:%S%z")
|
||||||
|
else: # float
|
||||||
|
value = stat[field].split(" ")[0]
|
||||||
|
value = value.replace("MiB", "e3")
|
||||||
|
data_dict[name_from_field(field)][t_i] += float(value) / 1000 # values are in MiB
|
||||||
|
return data_dict
|
||||||
|
|
||||||
|
|
||||||
|
def render(data: dict, web_render:bool=False):
|
||||||
|
bar_chart = pygal.StackedBar(height=400)
|
||||||
|
bar_chart.x_labels = data["date"]
|
||||||
|
for k in data:
|
||||||
|
if k == "date":
|
||||||
|
continue
|
||||||
|
#if "db" in k or "database" in k or "mysql" in k or "mongo" in k or "postgre" in k:
|
||||||
|
# continue
|
||||||
|
bar_chart.add(k, data[k])
|
||||||
|
|
||||||
|
if web_render:
|
||||||
|
bar_chart.render_in_browser()
|
||||||
|
else:
|
||||||
|
bar_chart.render_to_png(PNG_OUTPUT)
|
||||||
|
print("Image generated in:", PNG_OUTPUT)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
51
display/render_stats.sh
Executable file
51
display/render_stats.sh
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
|
||||||
|
# Need to replace last line of file from "}," to "}]"
|
||||||
|
# To avoid modify original file, use temporary file
|
||||||
|
TMP_FILE=stats_tmp.json
|
||||||
|
VENV=venv
|
||||||
|
|
||||||
|
if [[ $# -ne 1 ]] && [[ $# -ne 2 ]]; then
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $0 STATS_FILE [-w] "
|
||||||
|
echo ""
|
||||||
|
echo "Params:"
|
||||||
|
echo " - stats_file: path to stats file"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " - w: do rende1r using web browser"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATS_FILE=$1
|
||||||
|
OPT=""
|
||||||
|
if [[ $# -eq 2 ]]; then
|
||||||
|
OPT=${OPT}" -w"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pip install -----------------------------------------------------------------
|
||||||
|
if [ ! -d ${VENV} ]; then
|
||||||
|
echo "Installing python environment in ${VENV}..."
|
||||||
|
python3 -m venv ${VENV}
|
||||||
|
. ${VENV}/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
echo "Python environment installed..."
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
. ${VENV}/bin/activate
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Render ----------------------------------------------------------------------
|
||||||
|
sed -e '$s/},/}]/' ${STATS_FILE} > ${TMP_FILE}
|
||||||
|
|
||||||
|
# Update last line
|
||||||
|
# Generate render
|
||||||
|
python render.py ${TMP_FILE} ${OPT}
|
||||||
|
|
||||||
|
rm ${TMP_FILE}
|
||||||
|
|
||||||
|
deactivate
|
10
display/requirements.txt
Normal file
10
display/requirements.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
pygal
|
||||||
|
|
||||||
|
|
||||||
|
# For pygal web render
|
||||||
|
lxml
|
||||||
|
tinycss
|
||||||
|
cssselect
|
||||||
|
cairosvg
|
Loading…
Reference in New Issue
Block a user