Skip to content

Commit

Permalink
Merge pull request #176 from flask-dashboard/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
FlyingBird95 committed Jun 21, 2018
2 parents 94e7462 + 854df35 commit 40d8c37
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 63 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Unreleased
----------
Changed

- Fixed Issue #174

- Fixed issue with profiler not going into code

- Implemented a Sunburst visualization of the Grouped Profiler

- Improved test coverage
Expand Down
7 changes: 4 additions & 3 deletions docs/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ There are two migrations that you have to do, before you can use version 2.0.0.
We have created a script for you that can achieve this. It migrates the data in the existing
database into a new database, without removing the existing database.

You can find `the migration script here`_.

.. _`the migration script here`: https://github.com/flask-dashboard/Flask-MonitoringDashboard/tree/master/flask_monitoringdashboard/migrate_v1_to_v2.py

If you want to run this script, you need to be aware of the following:

- If you already have version 1.X.X of the Flask-MonitoringDashboard installed, first update to
Expand All @@ -28,9 +32,6 @@ There are two migrations that you have to do, before you can use version 2.0.0.

- Once you have migrated your database, you have to update the database location in your configuration-file.

- You can find `the migration script here`_.

.. _`the migration script here`: https://github.com/flask-dashboard/Flask-MonitoringDashboard/tree/master/flask_monitoringdashboard/migrate_v1_to_v2.py

2. **Migrate the configuration file**: You also have to update the configuration file completely, since we've
re factored this to make it more clear. The main difference is that several properties have been re factored
Expand Down
2 changes: 1 addition & 1 deletion flask_monitoringdashboard/constants.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "2.0.2",
"version": "2.0.3",
"author": "Patrick Vogel, Thijs Klooster & Bogdan Petre",
"email": "patrickvogel@live.nl"
}
5 changes: 4 additions & 1 deletion flask_monitoringdashboard/core/profiler/outlierProfiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ def run(self):
time.sleep(average / 1000)
if not self._stopped:
stack_list = []
frame = sys._current_frames()[self._current_thread]
try:
frame = sys._current_frames()[self._current_thread]
except KeyError:
return
in_endpoint_code = False
# filename, line number, function name, source code line
for fn, ln, fun, line in traceback.extract_stack(frame):
Expand Down
11 changes: 10 additions & 1 deletion flask_monitoringdashboard/core/profiler/stacktraceProfiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
from flask_monitoringdashboard.database.stack_line import add_stack_line


FILENAME = 'flask_monitoringdashboard/core/measurement.py'
FILENAME_LEN = len(FILENAME)

class StacktraceProfiler(threading.Thread):
"""
Used for profiling the performance per line code.
Expand Down Expand Up @@ -46,7 +49,11 @@ def run(self):
duration = newcurrent_time - current_time
current_time = newcurrent_time

frame = sys._current_frames()[self._thread_to_monitor]
try:
frame = sys._current_frames()[self._thread_to_monitor]
except KeyError:
print("key error")
continue
in_endpoint_code = False
self._path_hash.set_path('')
# filename, line number, function name, source code line
Expand All @@ -56,6 +63,8 @@ def run(self):
if in_endpoint_code:
key = (self._path_hash.get_path(fn, ln), fun, line)
self._histogram[key] += duration
if len(fn) > FILENAME_LEN and fn[-FILENAME_LEN:] == FILENAME and fun == "wrapper":
in_endpoint_code = True
if in_endpoint_code:
self._total += duration

Expand Down
5 changes: 3 additions & 2 deletions flask_monitoringdashboard/database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from sqlalchemy import Column, Integer, String, DateTime, create_engine, Float, Boolean, TEXT, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.orm import sessionmaker, relationship, scoped_session

from flask_monitoringdashboard import config
from flask_monitoringdashboard.core.group_by import get_group_by
Expand Down Expand Up @@ -172,7 +172,8 @@ def session_scope():
:return: the session for accessing the database
"""
session = DBSession()
session_obj = scoped_session(DBSession)
session = session_obj()
try:
yield session
session.commit()
Expand Down
27 changes: 26 additions & 1 deletion flask_monitoringdashboard/database/stack_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from sqlalchemy import desc, distinct
from sqlalchemy.orm import joinedload

from flask_monitoringdashboard.database import StackLine, Request
from flask_monitoringdashboard.database import StackLine, Request, CodeLine
from flask_monitoringdashboard.database.code_line import get_code_line


Expand Down Expand Up @@ -49,6 +49,31 @@ def get_profiled_requests(db_session, endpoint_id, offset, per_page):
return result


def get_profiled_requests_filtered(db_session, endpoint_id, code_line="g()", offset=0, per_page=10):
"""
Gets the requests of an endpoint containing a particular stack line,
sorted by request time, together with the stack lines.
:param db_session: session for the database
:param endpoint_id: filter profiled requests on this endpoint
:param code_line: line of code to filter on
:param offset: number of items to skip
:param per_page: number of items to return
:return list of Request objects. Each Request contains a list of StackLine objects. Each StackLine object
contains a Code object.
"""
result = db_session.query(Request).filter(Request.endpoint_id == endpoint_id).\
join(StackLine, Request.stack_lines).join(CodeLine, StackLine.code). \
options(joinedload(Request.stack_lines).joinedload(StackLine.code)). \
filter(CodeLine.code == code_line). \
order_by(desc(Request.id)).offset(offset).limit(per_page)
result = result.all()
print(len(result))
for r in result:
print(r.id)
for sl in r.stack_lines:
print(sl.code.code)


def get_grouped_profiled_requests(db_session, endpoint_id):
"""
Gets the grouped stack lines of all requests of an endpoint.
Expand Down
70 changes: 57 additions & 13 deletions flask_monitoringdashboard/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This file can be executed for developing purposes.
It is not used when the flask_monitoring_dashboard is attached to an existing flask application.
"""
import random

from flask import Flask

Expand All @@ -13,29 +14,72 @@ def create_app():
app = Flask(__name__)

dashboard.config.outlier_detection_constant = 0
dashboard.config.database_name = 'sqlite:///flask_monitoring_dashboard_v10.db'
# dashboard.config.database_name = 'sqlite:///flask_monitoring_dashboard_v10.db'
dashboard.config.database_name = 'sqlite:////home/bogdan/databases/flask-dashboard-2.0.db'
dashboard.config.version = '3.1'
dashboard.bind(app)

def f(i=5):
if i == 0:
time.sleep(1)
else:
f(i-1)

def g():
def f():
time.sleep(2)
time.sleep(1)

@app.route('/endpoint')
def endpoint():
if random.randint(0, 1):
f()
else:
g()
f()
return 'Ok'

@app.route('/endpoint1')
def endpoint1():
f()
return 'Ok'

@app.route('/endpoint2')
def endpoint2():
f()
return 'Ok'

@app.route('/endpoint3')
def endpoint3():
f()
return 'Ok'

@app.route('/endpoint4')
def endpoint4():
f()
return 'Ok'

@app.route('/endpoint5')
def endpoint5():
f()
return 'Ok'

@app.route('/endpoint6')
def endpoint6():
f()
return 'Ok'

@app.route('/endpoint7')
def endpoint7():
f()
return 'Ok'

@app.route('/endpoint8')
def endpoint8():
f()
return 'Ok'

@app.route('/endpoint9')
def endpoint9():
f()
return 'Ok'

@app.route('/endpoint10')
def endpoint10():
f()
return 'Ok'

return app


if __name__ == '__main__':
create_app().run(debug=True)
create_app().run(debug=True, threaded=True)
6 changes: 4 additions & 2 deletions flask_monitoringdashboard/migrate_v1_to_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

# OLD_DB_URL = 'dialect+driver://username:password@host:port/old_db'
# NEW_DB_URL = 'dialect+driver://username:password@host:port/new_db'
OLD_DB_URL = 'mysql+pymysql://root:admin@localhost/migration1'
NEW_DB_URL = 'mysql+pymysql://root:admin@localhost/migration2'
OLD_DB_URL = 'sqlite:////home/bogdan/databases/flask-dashboard.db'
NEW_DB_URL = 'sqlite:////home/bogdan/databases/flask-dashboard-2.0.db'
# OLD_DB_URL = 'mysql+pymysql://root:admin@localhost/migration1'
# NEW_DB_URL = 'mysql+pymysql://root:admin@localhost/migration2'


TABLES = ["rules", "functionCalls", "outliers", "tests", "testRun"]
Expand Down
42 changes: 4 additions & 38 deletions flask_monitoringdashboard/static/js/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Configure tooltips for collapsed side navigation
$('.navbar-sidenav [data-toggle="tooltip"]').tooltip({
template: '<div class="tooltip navbar-sidenav-tooltip" role="tooltip" style="pointer-events: none;"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
})
});
// Toggle the side navigation
$("#sidenavToggler").click(function (e) {
e.preventDefault();
Expand Down Expand Up @@ -33,7 +33,7 @@
}
});
// Configure tooltips globally
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="tooltip"]').tooltip();
// Smooth scrolling using jQuery easing
$(document).on('click', 'a.scroll-to-top', function (event) {
var $anchor = $(this);
Expand All @@ -43,45 +43,11 @@
event.preventDefault();
});

// update to hide everying of hide-tag
// update to hide of every hide-tag
$("hide").text("");

// update the duration of every html-time tag
$("time").text(function(i, ms){
// ms is a float or int
//ms = Math.round(parseFloat(ms) / 10) * 10;
ms = Math.round( parseFloat(ms) * 10) / 10;
var s = ms / 1000;
var min = Math.floor(s / 60);
var hr = Math.floor(s / 3600);
var day = Math.floor(hr / 24);
var value = "";
if (ms < 100.5){
value = ms + " ms";
} else if (ms < 999.5){
value = Math.round(ms) + " ms";
} else if (s < 60){
s = Math.round(ms / 100) / 10;
value = s + " sec";
} else if (hr == 0){
s = Math.round(s % 60);
value = min + " min";
if (s > 0){
value += ", " + s + " sec";
}
} else if (day == 0){
value = hr + " hr";
min = Math.round(min % 60);
if (min > 0){
value += ", " + min + " min";
}
} else {
value = day + " d";
hr = Math.round(hr % 24);
if (hr > 0){
value += ", " + hr + " hr";
}
}
return value;
return format_time(ms);
});
})(jQuery);
38 changes: 38 additions & 0 deletions flask_monitoringdashboard/static/js/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

function format_time(time){
// ms is a float or int
//ms = Math.round(parseFloat(ms) / 10) * 10;
var ms = Math.round(parseFloat(time) * 10) / 10;
var s = ms / 1000;
var min = Math.floor(s / 60);
var hr = Math.floor(s / 3600);
var day = Math.floor(hr / 24);
var value = "";
if (ms < 100.5) {
value = ms + " ms";
} else if (ms < 999.5) {
value = Math.round(ms) + " ms";
} else if (s < 60) {
s = Math.round(ms / 100) / 10;
value = s + " sec";
} else if (hr === 0) {
s = Math.round(s % 60);
value = min + " min";
if (s > 0) {
value += ", " + s + " sec";
}
} else if (day === 0) {
value = hr + " hr";
min = Math.round(min % 60);
if (min > 0) {
value += ", " + min + " min";
}
} else {
value = day + " d";
hr = Math.round(hr % 24);
if (hr > 0) {
value += ", " + hr + " hr";
}
}
return value;
}
1 change: 1 addition & 0 deletions flask_monitoringdashboard/templates/fmd_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<link href="{{ url_for('dashboard.static', filename='css/custom.css') }}" rel="stylesheet">
<link rel="shortcut icon" href="{{ url_for('dashboard.static', filename='img/favicon.ico') }}" />

<script src="{{ url_for('dashboard.static', filename='js/util.js') }}"></script>
{% block head %}
{% endblock %}
</head>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@

{% block script %}
<script type="text/javascript">
$('#dataTable').DataTable().order([[4, "desc"]]).draw();
$('#dataTable').DataTable({
"createdRow": function( row, data, dataIndex ) {
$(row).find("time").text(function (i, ms) {
return format_time(ms);
});
}
}).order([[4, "desc"]]).draw();

$.get( "https://pypi.org/pypi/Flask-MonitoringDashboard/json", function( data ) {

Expand Down

0 comments on commit 40d8c37

Please sign in to comment.