Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified Log Level Syntax and Clean up to enable Multiple Logger Objects #46

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
38 changes: 36 additions & 2 deletions cvlog/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,38 @@
from .log import image, edges, threshold, hough_circles, hough_lines, contours, keypoints
from .logger import Logger
from .config import Level, Mode, set_mode, set_level, set_path, set_rotate_log

__all__ = ['image', 'edges', 'threshold', 'hough_circles', 'hough_lines', 'contours', 'keypoints', 'Level', 'Mode', 'set_mode', 'set_level', 'set_path', 'set_rotate_log']
__all__ = ['Logger', 'image', 'edges', 'threshold', 'hough_circles', 'hough_lines', 'contours', 'keypoints', 'Level', 'Mode', 'set_mode', 'set_level', 'set_path', 'set_rotate_log']

root = Logger()
info = root.info
error = root.error
trace = root.trace
Logger.root = root

def getLogger(name=None):
if name is None:
return root


# LEGACY SUPPORT

def image(level, image, **options):
getattr(root, level.name.lower()).image(image, **options)

def edges(level, image, **options):
getattr(root, level.name.lower()).edges(image, **options)

def threshold(level, image, **options):
getattr(root, level.name.lower()).threshold(image, **options)

def hough_circles(level, lines, image, **options):
getattr(root, level.name.lower()).hough_circles(lines, image, **options)

def hough_lines(level, circles, image, **options):
getattr(root, level.name.lower()).hough_lines(circles, image, **options)

def contours(level, contours, image, index=-1, **options):
getattr(root, level.name.lower()).contours(contours, image, index, **options)

def keypoints(level, kp, image, **options):
getattr(root, level.name.lower()).keypoints(kp, image, **options)
15 changes: 9 additions & 6 deletions cvlog/html_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,27 @@ def __init__(self):
self.__no_data = False
self.__rotate_log()

def log_image(self, level, log_type, img_data, msg):
def log_image(self, level, logger_name, log_type, img_data, msg):
data = ''.join(['<img src="data:image/png;base64, ', img_data, '"/>'])
self.__append_log_item(level, log_type, data, msg)
self.__append_log_item(level, logger_name, log_type, data, msg)

def __append_log_item(self, level, log_type, log_detail, msg):
def __append_log_item(self, level, logger_name, log_type, log_detail, msg):
template = '<div class="log-item" id="'
template += self.__unique_id() + '" onclick="show_data(this.id)"'
short_stack, data = self.__get_log_info()
data['level'] = level
data['log_type'] = log_type
data['logger_name'] = logger_name
data['msg'] = msg
template += "data='" + json.dumps(data) + "' logdata = '" + log_detail + "'>"
template += '<div class="log-type">' + log_type + '</div>'
template += '<h3 class="tvme">' + data['time_stamp']
template += '<span class="level ' + level.lower() + '">' + data['level'] + '</span></h3>'
template += '<p class="line">' + re.sub(r'^/', '', short_stack) + '</p>'
template += '<div class="info-row"><div class="log-type">' + log_type + '</div>'
template += '<div class="logger-name">' + str(logger_name or '') + '</div></div>'
if msg is not None:
template += '<p class="description">' + msg + '</p>'
template += '<p class="line">' + re.sub(r'^/', '', short_stack) + '</p></div>'
template += '</div>'
self.__try_append([template])

def __append(self, html_text_seq):
Expand Down Expand Up @@ -67,7 +70,7 @@ def __create_file(self):
if not os.path.exists(dir_path):
os.makedirs(dir_path)
with open(self.__file_path(), 'w') as html:
html.writelines(['<html>', ht.STYLE, ht.SCRIPT, ht.CONTENT_START, ht.NO_DATA_CONTENT, ht.CONTENT_END])
html.writelines(['<html lang="en">', ht.STYLE, ht.SCRIPT, ht.CONTENT_START, ht.NO_DATA_CONTENT, ht.CONTENT_END])
self.__no_data = True

def __rotate_log(self):
Expand Down
6 changes: 3 additions & 3 deletions cvlog/html_template.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CONTENT_START = '<body><div class="log-menu"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACYUlEQVRYhc2XP2jWQBjGf+/Hx2eQCiJOgiLiIB2kOIiDiHQQERfnLn4grrqIopODCKKDjrq4WBFpRfEfOgkqFQQ3cXBwcPgQaRW0ltrmcciFxjPJXeKH+EBILnf33u8uT95cjBJJ6gBHgD6wGei5qk6hWVpyfg0cM7P3ZXGjJKkn6ZHaa07S3tjxrATgHHDaFd8BD4F5N8Nld04LXVJgDXAcWO3uLQCHzOxxm9nPuZm8kJQ06HvNW4kfkg6E+nW88jZgrbu+ZGYLDfhnvXICTIUgfIBi2Q8Y0lLJvRxifyxAUWlNXSxADnFH0nhTgKqAVfpZU5cAdyWNNQFoqpBfRoDbvrGHCXCfLBF9AD4CA+ATv3tpK7C9MoKkscJrtGtYZJIOF+LuKdYNcwXq9LKqohvqKakLnAU2kQHnR5nSwjELnDGzb9QYug4gfw13s5Kam+oVMEnNKx1cAWAGuE62AjHtIZvxZ+CJK7cHcOm4HzlwY/0rE1YqxoQJcJlsYxJqvwRMmdnVoQEAO4GjsQGBUcAHaOWB/PHMABcpN6G/LVsEHkRhRgAAYGaLwIkmQZvovzZhB0DSCHAT2FJoX5cJITPjAJgws0FbgFw7gIMR7XyNAuNkmfCvAJ4DJ4GNDQG+ANPuuvJRBx+BmaXAhYaDR6vOhMM0aOVE/UGKCWP9EAHiYklKJH11O5dnknrhXsGYHUm3XMxlSRuK9WW/ZueBU674FrgHfGdlUxHaruer2gVWAfvI0jnApJlNhIgTSU/b/5tW6o2kdf54f6yAg+iSfYD6ZAmorSHzhHQDuGJm836DXyc+jBXxLgUYAAAAAElFTkSuQmCC" alt=""> </div><div class="log-detail"> <div id="log-detail"><div id="log_type" class="log-type"></div> <h2 id="ld_title"></h2> <h3 id="ld_head1"></h3> <div><pre id="description"></pre></div> <div id="ld_log_data"></div><h3 id="ld_head2"></h3> <div><pre id="stack_trace"></pre></div></div></div><div class="log-list"> <h1 class="title"> Logs</h1>'
CONTENT_START = '<body><div class="log-menu"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACYUlEQVRYhc2XP2jWQBjGf+/Hx2eQCiJOgiLiIB2kOIiDiHQQERfnLn4grrqIopODCKKDjrq4WBFpRfEfOgkqFQQ3cXBwcPgQaRW0ltrmcciFxjPJXeKH+EBILnf33u8uT95cjBJJ6gBHgD6wGei5qk6hWVpyfg0cM7P3ZXGjJKkn6ZHaa07S3tjxrATgHHDaFd8BD4F5N8Nld04LXVJgDXAcWO3uLQCHzOxxm9nPuZm8kJQ06HvNW4kfkg6E+nW88jZgrbu+ZGYLDfhnvXICTIUgfIBi2Q8Y0lLJvRxifyxAUWlNXSxADnFH0nhTgKqAVfpZU5cAdyWNNQFoqpBfRoDbvrGHCXCfLBF9AD4CA+ATv3tpK7C9MoKkscJrtGtYZJIOF+LuKdYNcwXq9LKqohvqKakLnAU2kQHnR5nSwjELnDGzb9QYug4gfw13s5Kam+oVMEnNKx1cAWAGuE62AjHtIZvxZ+CJK7cHcOm4HzlwY/0rE1YqxoQJcJlsYxJqvwRMmdnVoQEAO4GjsQGBUcAHaOWB/PHMABcpN6G/LVsEHkRhRgAAYGaLwIkmQZvovzZhB0DSCHAT2FJoX5cJITPjAJgws0FbgFw7gIMR7XyNAuNkmfCvAJ4DJ4GNDQG+ANPuuvJRBx+BmaXAhYaDR6vOhMM0aOVE/UGKCWP9EAHiYklKJH11O5dnknrhXsGYHUm3XMxlSRuK9WW/ZueBU674FrgHfGdlUxHaruer2gVWAfvI0jnApJlNhIgTSU/b/5tW6o2kdf54f6yAg+iSfYD6ZAmorSHzhHQDuGJm836DXyc+jBXxLgUYAAAAAElFTkSuQmCC" alt=""> </div><div class="log-detail"> <div id="log-detail"> <h2 id="ld_title"></h2><div class="info-row"><div id="log_type" class="log-type"></div><div id="logger-name" class="logger-name"></div></div><h3 id="ld_head1"></h3> <div id="description"></div> <div id="ld_log_data"></div><h3 id="ld_head2"></h3> <div><pre id="stack_trace"></pre></div></div></div><div class="log-list"> <h1 class="title"> Logs</h1>'
CONTENT_END = '</div></body></html>'
NO_DATA_CONTENT = '<div id="no-data">No data logged</div>'
SCRIPT = '<script>var selected_id; function show_data(id){var menu=document.getElementById(id); data=JSON.parse(menu.getAttribute("data")); document.getElementById("ld_title").innerHTML=data["time_stamp"]; document.getElementById("log_type").innerHTML=data["log_type"]; if(data["msg"]){ document.getElementById("description").innerHTML=data["msg"];} else {document.getElementById("description").innerHTML=""; } document.getElementById("ld_head2").innerHTML="Stack Trace:"; document.getElementById("stack_trace").innerHTML=data["long_stack"]; document.getElementById("ld_log_data").innerHTML=menu.getAttribute("logdata"); document.getElementById("ld_head1").innerHTML="Log Detail:"; if(selected_id && selected_id !=id){var prev=document.getElementById(selected_id); prev.className="log-item"}menu.className="log-item selected"; selected_id=id}</script>'
STYLE = '<style>body{width: 100%; height: 100%; margin: 0px; font-family:Arial, Helvetica, sans-serif;}.log-menu{height: 100%;width: 3%;float: left;background-color: #32324a;text-align: center;}.log-menu>img{height: 25px; padding-top: 25px;}.log-list{width:30%;height: 100%;float: left; background-color: #f3f3f3; overflow: scroll;}.log-detail{width:67%;height: 100%;float: right; overflow: scroll;}.log-detail>div{padding: 30px 15px;height: 100%;}h2{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif;font-size: 19px;font-style: normal;font-variant: normal;font-weight: 700;line-height: 20px; color: #333;}.log-item{padding: 5px 15px;border-bottom: 1px solid #ddd; margin-left: 10px;}.title{padding: 5px 20px;}.show{display: block;}.hide{display: none;}.log-detail img{max-width:100%; margin-top: 10px; border: 1px solid #888;}.stack{font-style: italic; margin-bottom: 10px;}.selected{margin-left: 6px;background-color: white;border-top-left-radius: 10px;border-bottom-left-radius: 10px;box-shadow: -2px 2px 4px #ddd;border-bottom: none;}h1{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif; font-size: 25px; font-style: normal; font-variant: normal; font-weight: 700; line-height: 26.4px;}h3{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: 700; line-height: 15.4px; margin:0px;}p{font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; line-height: 20px; margin:0px;}span.level{color: #fff; padding: 2px 12px;float: right; margin: -5px 0px;border-radius: 5px; font-size: 11px;}.info{background-color: #039BE5;}.trace{background-color: #757575;}.error{background-color: #e53935;}pre{font-size: 13px;line-height: 1.3em;padding: 0px;text-align: justify;width: 100%;padding-left: 5px;white-space: pre-wrap;background: #fafafa;}#no-data{margin: 10px;border: 1px solid transparent;padding: 5px;border-radius: 5px;background: #FFE082;color: #555;} .log-type{ margin: 3px 0px;text-transform: uppercase;font-size: 12px;color: darkcyan; font-weight:bold} .line{font-family: monospace;font-size: 13px; white-space: nowrap;overflow: hidden;text-overflow: ellipsis;direction: rtl;} #ld_head1{margin-bottom: 10px;font-size: 15px;} #ld_head2{margin-top: 25px;font-size: 15px;} p.description{padding: 5px;font-family: monospace;font-size: 13px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}</style>'
SCRIPT = '<script>var selected_id; function show_data(id){var menu=document.getElementById(id); data=JSON.parse(menu.getAttribute("data")); document.getElementById("ld_title").innerHTML=data["time_stamp"]; document.getElementById("log_type").innerHTML=data["log_type"]; if(data["logger_name"]){ document.getElementById("logger-name").innerHTML=data["logger_name"];} else {document.getElementById("logger-name").innerHTML=""; } if(data["msg"]){ document.getElementById("description").innerHTML=data["msg"];} else {document.getElementById("description").innerHTML=""; } document.getElementById("ld_head2").innerHTML="Stack Trace:"; document.getElementById("stack_trace").innerHTML=data["long_stack"]; document.getElementById("ld_log_data").innerHTML=menu.getAttribute("logdata"); document.getElementById("ld_head1").innerHTML="Log Detail:"; if(selected_id && selected_id !=id){var prev=document.getElementById(selected_id); prev.className="log-item"}menu.className="log-item selected"; selected_id=id}</script>'
STYLE = '<style>body{width: 100%; height: 100%; margin: 0px; font-family:Arial, Helvetica, sans-serif;}.info-row{display: inline-block;width:100%}.log-menu{height: 100%;width: 3%;float: left;background-color: #32324a;text-align: center;}.log-menu>img{height: 25px; padding-top: 25px;}.log-list{width:30%;height: 100%;float: left; background-color: #f3f3f3; overflow: scroll;}.log-detail{width:67%;height: 100%;float: right; overflow: scroll;}.log-detail>div{padding: 30px 15px;height: 100%;}h2{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif;font-size: 19px;font-style: normal;font-variant: normal;font-weight: 700;line-height: 20px; color: #333;}.log-item{padding: 5px 15px;border-bottom: 1px solid #ddd; margin-left: 10px;}.title{padding: 5px 20px;}.show{display: block;}.hide{display: none;}.log-detail img{max-width:100%; margin-top: 10px; border: 1px solid #888;}.stack{font-style: italic; margin-bottom: 10px;}.selected{margin-left: 6px;background-color: white;border-top-left-radius: 10px;border-bottom-left-radius: 10px;box-shadow: -2px 2px 4px #ddd;border-bottom: none;}h1{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif; font-size: 25px; font-style: normal; font-variant: normal; font-weight: 700; line-height: 26.4px;}h3{font-family: Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: 700; line-height: 15.4px; margin:2px 0px;}p{font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; line-height: 20px; margin:0px;}span.level{color: #fff; padding: 2px 12px;float: right; margin: -2px 0px;border-radius: 5px; font-size: 11px;}.info{background-color: #039BE5;}.trace{background-color: #757575;}.error{background-color: #e53935;}pre{font-size: 13px;margin-bottom: 20px;line-height: 1.3em;padding: 0px;text-align: justify;width: 100%;padding-left: 5px;white-space: pre-wrap;background: #fafafa;}#no-data{margin: 10px;border: 1px solid transparent;padding: 5px;border-radius: 5px;background: #FFE082;color: #555;} .logger-name{float: right;max-width:65%;color: #525363;margin: 3px 0px;text-transform: uppercase;font-size: 12px;margin-top: 3px;overflow: hidden;text-overflow: ellipsis;font-weight: bold} .log-type{ float: left;margin: 3px;text-transform: uppercase;font-size: 12px;color: darkcyan; font-weight:bold;text-align: right;} .line{font-family: monospace;font-size: 13px; white-space: nowrap;overflow: hidden;text-overflow: ellipsis;direction: rtl;} #ld_head1{margin: 15px 0px;font-size: 15px;} #ld_head2{margin-top: 25px;font-size: 15px;} p.description{padding: 3px 5px;font-size: 14px;font-style: italic;white-space: nowrap;overflow: hidden;text-overflow: ellipsis; color:#666;}</style>'
87 changes: 0 additions & 87 deletions cvlog/log.py

This file was deleted.

96 changes: 96 additions & 0 deletions cvlog/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import cv2
import os
import cvlog.html_logger as hl
import base64
import numpy as np
from cvlog.config import Config, Mode, Level

class Logger:
root = None

def __init__(self, name=None):
self.error = BaseLogger(Level.ERROR, name)
self.info = BaseLogger(Level.INFO, name)
self.trace = BaseLogger(Level.TRACE, name)

class BaseLogger:
root = None

def __init__(self, level=None, name=None):
self.__name = name
self.__level = level
self.__html_logger = hl.HtmlLogger()

def image(self, image, **options):
self.__image('image', image, options)

def edges(self, image, **options):
self.__image('edges', image, options)

def threshold(self, image, **options):
self.__image('threshold', image, options)

def hough_lines(self, lines, cv_image, **options):
debug_image = cv_image.copy()
for line in lines:
(x1, y1), (x2, y2) = self.__find_line_pts(line)
cv2.line(debug_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
self.__image('hough lines', debug_image, options)

def hough_circles(self, circles, cv_image, **options):
debug_image = cv_image.copy()
if circles is not None:
_a, b, _c = circles.shape
for i in range(b):
x, y, r = circles[0][i]
cv2.circle(debug_image, (x, y), r, (0, 0, 255), 2)
cv2.circle(debug_image, (x, y), 2, (0, 255, 0), 2) # center
self.__image('hough circles', debug_image, options)

def contours(self, contours, cv_image, index=-1, **options):
debug_image = cv_image.copy()
cv2.drawContours(debug_image, contours, index, (0, 255, 0), 2)
self.__image('contours', debug_image, options)

def keypoints(self, kp, cv_image, **options):
debug_image = cv_image.copy()
cv2.drawKeypoints(debug_image, kp, debug_image, (0, 255, 0), flags=options.get('flags', 0))
self.__image('key points', debug_image, options)

def __find_line_pts(self, line):
r, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * r
y0 = b * r
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
return (x1, y1), (x2, y2)

def __image(self, log_type, image, options):
if image is None:
return
if Config().curent_level().value < self.__level.value:
return
if Config().curent_mode() == Mode.DEBUG:
self.show_image(self.__level.name, log_type, image, options)
elif Config().curent_mode() == Mode.LOG:
self.__log_image(self.__level.name, log_type, image, options)

def __log_image(self, level, log_type, img, options):
retval, buffer = cv2.imencode('.png', img)
if not retval:
return None
msg = options.get('msg', None)
self.__html_logger.log_image(level, self.__name, log_type, base64.b64encode(buffer).decode(), msg)

def show_image(self, title, log_type, img, options):
cv2.namedWindow('window', cv2.WINDOW_NORMAL)
cv2.setWindowTitle('window', title + ':' + log_type)
cv2.imshow('window', img)
value = cv2.waitKey(0)
if value == 27:
os._exit(1)
return value
Loading