Skip to content

Commit

Permalink
Merge pull request #170 from flask-dashboard/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
FlyingBird95 committed Jun 15, 2018
2 parents e63e11a + 2d5685b commit 74eb58e
Show file tree
Hide file tree
Showing 76 changed files with 963 additions and 411 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The Flask Monitoring Dashboard is an extension that offers four main functionali
The dashboard is automatically added to your existing Flask application.
You can view the results by default using the default endpoint (this can be configured to another route):

[/dashboard](http://localhost:5000/dashboard)
[/dashboard](http://localhost:5000/dashboard)

For more advanced documentation, take a look at the information on [this site](http://flask-monitoringdashboard.readthedocs.io/en/latest/functionality.html).

Expand Down
6 changes: 5 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ Unreleased
----------
Changed

-
- Implemented a Sunburst visualization of the Grouped Profiler

- Improved test coverage

- Improved python-doc


v2.0.0
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.0",
"version": "2.0.1",
"author": "Patrick Vogel, Thijs Klooster & Bogdan Petre",
"email": "patrickvogel@live.nl"
}
19 changes: 15 additions & 4 deletions flask_monitoringdashboard/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
"""
Core files for the Flask Monitoring Dashboard
Core files for the Flask Monitoring Dashboard. It contains the following packages:
- config handles the configuration-file
- forms handles generating and processing WTF-forms
- plot handles the plotly library
- profiler handles profiling requests
It also contains the following files
- auth.py handles authentication
- forms.py are used for generating WTF_Forms
- measurements.py contains a number of wrappers
- outlier.py contains outlier information
- colors.py handles color-hash
- group_by.py handles the group_by functionality
- info_box.py handles the generation of information box, one for each graph
- measurements.py contains a number of wrappers, one for each monitoring level
- rules.py includes a function that retrieves all rules of the entire Flask
application, or for a specific endpoint.
- timezone: handles utc-timezone <==> local-timezone
- utils: for other functions
"""
16 changes: 8 additions & 8 deletions flask_monitoringdashboard/core/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

def admin_secure(func):
"""
When the user is not logged into the system, the user is requested to the login page.
There are two types of user-modes:
- admin: Can be visited with this wrapper.
- guest: Cannot be visited with this wrapper.
When the user is not logged into the system, the user is requested to the login page.
There are two types of user-modes:
- admin: Can be visited with this wrapper.
- guest: Cannot be visited with this wrapper.
:param func: the endpoint to be wrapped.
"""

Expand All @@ -24,10 +24,10 @@ def wrapper(*args, **kwargs):

def secure(func):
"""
When the user is not logged into the system, the user is requested to the login page.
There are two types of user-modes:
- admin: Can be visited with this wrapper.
- guest: Can be visited with this wrapper.
When the user is not logged into the system, the user is requested to the login page.
There are two types of user-modes:
- admin: Can be visited with this wrapper.
- guest: Can be visited with this wrapper.
:param func: the endpoint to be wrapped.
"""

Expand Down
6 changes: 4 additions & 2 deletions flask_monitoringdashboard/core/group_by.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@


def recursive_group_by(argument):
""" Returns the result of the given argument. The result is computed as:
"""
Returns the result of the given argument. The result is computed as:
- If the argument is a primitive (i.e. str, bool, int, ...) return its value.
- If the argument is a function, call the function.
- If the argument is iterable (i.e. list or tuple), compute the result by iterating over the argument
Return type is always a string"""
Return type is always a string
"""

if type(argument) in PRIMITIVES:
return str(argument)
Expand Down
8 changes: 4 additions & 4 deletions flask_monitoringdashboard/core/measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def init_measurement():


def add_decorator(endpoint):
"""
Adds a wrapper to an endpoint in the app, depending on the monitor level.
:param endpoint: Endpoint object to be monitored
"""
fun = user_app.view_functions[endpoint.name]
if endpoint.monitor_level == 0:
add_wrapper0(endpoint, fun)
Expand All @@ -48,7 +52,6 @@ def wrapper(*args, **kwargs):

wrapper.original = fun
user_app.view_functions[endpoint.name] = wrapper
return wrapper


def add_wrapper1(endpoint, fun):
Expand All @@ -62,7 +65,6 @@ def wrapper(*args, **kwargs):

wrapper.original = fun
user_app.view_functions[endpoint.name] = wrapper
return wrapper


def add_wrapper2(endpoint, fun):
Expand All @@ -77,7 +79,6 @@ def wrapper(*args, **kwargs):

wrapper.original = fun
user_app.view_functions[endpoint.name] = wrapper
return wrapper


def add_wrapper3(endpoint, fun):
Expand All @@ -92,4 +93,3 @@ def wrapper(*args, **kwargs):

wrapper.original = fun
user_app.view_functions[endpoint.name] = wrapper
return wrapper
52 changes: 0 additions & 52 deletions flask_monitoringdashboard/core/outlier.py

This file was deleted.

13 changes: 10 additions & 3 deletions flask_monitoringdashboard/core/profiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@


def start_thread_last_requested(endpoint):
""" Starts a thread that updates the last_requested time in the database"""
BaseProfiler(endpoint.id).start()
"""
Starts a thread that updates the last_requested time in the database.
:param endpoint: Endpoint object
"""
BaseProfiler(endpoint).start()


def start_performance_thread(endpoint, duration):
""" Starts a thread that updates performance, utilization and last_requested in the databse. """
"""
Starts a thread that updates performance, utilization and last_requested in the database.
:param endpoint: Endpoint object
:param duration: duration of the request
"""
ip = request.environ['REMOTE_ADDR']
PerformanceProfiler(endpoint, ip, duration).start()

Expand Down
5 changes: 2 additions & 3 deletions flask_monitoringdashboard/core/profiler/baseProfiler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import datetime
import threading

from flask_monitoringdashboard.database import session_scope
Expand All @@ -12,9 +11,9 @@ class BaseProfiler(threading.Thread):
"""

def __init__(self, endpoint):
threading.Thread.__init__(self)
self._endpoint = endpoint
threading.Thread.__init__(self)

def run(self):
with session_scope() as db_session:
update_last_accessed(db_session, endpoint=self._endpoint)
update_last_accessed(db_session, endpoint_name=self._endpoint.name)
9 changes: 3 additions & 6 deletions flask_monitoringdashboard/core/profiler/outlierProfiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from flask_monitoringdashboard import config
from flask_monitoringdashboard.database import session_scope
from flask_monitoringdashboard.database.outlier import add_outlier
from flask_monitoringdashboard.database.request import get_avg_execution_time
from flask_monitoringdashboard.database.request import get_avg_duration


class OutlierProfiler(threading.Thread):
Expand All @@ -31,17 +31,14 @@ def __init__(self, current_thread, endpoint):
def run(self):
# sleep for average * ODC ms
with session_scope() as db_session:
average = get_avg_execution_time(db_session, self._endpoint.id) * config.outlier_detection_constant
average = get_avg_duration(db_session, self._endpoint.id) * config.outlier_detection_constant
time.sleep(average / 1000)
if not self._stopped:
stack_list = []
frame = sys._current_frames()[self._current_thread]
in_endpoint_code = False
# filename, line number, function name, source code line
for fn, ln, fun, line in traceback.extract_stack(frame):
# fn: filename
# ln: line number
# fun: function name
# text: source code line
if self._endpoint.name == fun:
in_endpoint_code = True
if in_endpoint_code:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ def __init__(self, endpoint, ip, duration):
def run(self):
with session_scope() as db_session:
update_last_accessed(db_session, endpoint_name=self._endpoint.name)
print("mao")
add_request(db_session, duration=self._duration, endpoint_id=self._endpoint.id, ip=self._ip)
11 changes: 5 additions & 6 deletions flask_monitoringdashboard/core/profiler/stacktraceProfiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,8 @@ def run(self):
frame = sys._current_frames()[self._thread_to_monitor]
in_endpoint_code = False
self._path_hash.set_path('')

# filename, line number, function name, source code line
for fn, ln, fun, line in traceback.extract_stack(frame):
# fn: filename
# ln: line number
# fun: function name
# line: source code line
if self._endpoint.name == fun:
in_endpoint_code = True
if in_endpoint_code:
Expand Down Expand Up @@ -103,7 +99,10 @@ def insert_lines_db(self, db_session, request_id):

def get_funcheader(self):
lines_returned = []
fun = user_app.view_functions[self._endpoint.name]
try:
fun = user_app.view_functions[self._endpoint.name]
except AttributeError:
fun = None
if hasattr(fun, 'original'):
original = fun.original
fn = inspect.getfile(original)
Expand Down
2 changes: 1 addition & 1 deletion flask_monitoringdashboard/core/profiler/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def order_histogram(items, path=''):
Finds the order of self._text_dict and assigns this order to self._lines_body
:param items: list of key, value. Obtained by histogram.items()
:param path: used to filter the results
:return: The items, but sorted
:return The items, but sorted
"""
sorted_list = []
indent = PathHash.get_indent(path) + 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import division
from numpy import std

from flask_monitoringdashboard.views.details.profiler import get_body
Expand Down Expand Up @@ -41,4 +42,3 @@ def percentage(self):
@property
def average(self):
return self.sum / self.hits

18 changes: 4 additions & 14 deletions flask_monitoringdashboard/core/profiler/util/pathHash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,16 @@ class PathHash(object):
def __init__(self):
self._string_hash = StringHash()
self._current_path = ''
self._last_fn = None
self._last_ln = None

def set_path(self, path):
self._current_path = path
self._last_fn = None
self._last_ln = None

def get_path(self, fn, ln):
"""
:param fn: String with the filename
:param ln: line number
:param text: String with the text on the given line.
:return: Encoded path name.
"""
if self._last_fn == fn and self._last_ln == ln:
return self._current_path
self._last_fn = fn
self._last_ln = ln
self._current_path = self.append(fn, ln)
return self._current_path

Expand All @@ -48,7 +39,6 @@ def append(self, fn, ln):
Concatenate the current_path with the new path.
:param fn: filename
:param ln: line number
:param text: String with the text on the given line.
:return: The new current_path
"""
if self._current_path:
Expand All @@ -75,13 +65,14 @@ def _decode(self, string):
return self._string_hash.unhash(int(hash)), int(ln)

@staticmethod
def get_indent(string):
def get_indent(path):
"""
Compute the amount of callers given a path.
:param path: the path from the root to the statement
:return: an integer
"""
if string:
return len(string.split(STRING_SPLIT))
if path:
return len(path.split(STRING_SPLIT))
return 0

def get_code(self, path):
Expand Down Expand Up @@ -111,6 +102,5 @@ def get_stacklines_path(self, stack_lines, index):
while index >= 0 and stack_lines[index].indent != current_indent - 1:
index -= 1
for code_line in reversed(path):
# self._current_path = self.append(code_line.filename, code_line.line_number, code_line.code)
self._current_path = self.append(code_line.filename, self._string_hash.hash(code_line.code))
return self._current_path
5 changes: 4 additions & 1 deletion flask_monitoringdashboard/core/profiler/util/stringHash.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Class used for hashing the paths.
"""


class StringHash(object):
Expand Down Expand Up @@ -34,4 +37,4 @@ def unhash(self, hash):
if v == hash:
return k

ValueError('Value not possible to unhash: {}'.format(hash))
raise ValueError('Value not possible to unhash: {}'.format(hash))

0 comments on commit 74eb58e

Please sign in to comment.