Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'release/v0.8.5'

  • Loading branch information...
commit 930f33bfe9526cc7b917853da473a358ec5fc071 2 parents 8cb8aba + 6479ad3
@robhudson authored
View
22 NEWS
@@ -1,6 +1,28 @@
News for django-debug-toolbar
=============================
+0.8.5 (2011 Apr 25)
+-------------------
+
+* Ensure if we're overriding the urlconf that we're resetting handler404/500.
+
+* Updated middleware logic to avoid work if content-type isn't right.
+
+* Change .load() calls to GET to avoid CSRF protection.
+
+* Updated SQL panel to match Django's which now includes logging.
+
+* Added basic multi-db support.
+
+* Some HTML validation fixes.
+
+* Added support for `executemany`. Thanks to postal2600.
+
+* Added support for LogBook. Thanks to Vincent Driessen.
+
+* Added clean_params method to DatabaseStatTracker to scrub non-unicode
+ data for displaying on the sql panel. Thanks to Matthew J Morrison
+
0.8.4 (2010 Nov 8)
------------------
View
2  README.rst
@@ -16,7 +16,7 @@ Currently, the following panels have been written and are working:
- Templates and context used, and their template paths
- SQL queries including time to execute and links to EXPLAIN each query
- List of signals, their args and receivers
-- Logging output via Python's built-in logging module
+- Logging output via Python's built-in logging, or via the `logbook <http://logbook.pocoo.org>`_ module
There is also one Django management command currently:
View
2  debug_toolbar/__init__.py
@@ -1,2 +1,2 @@
-VERSION = (0, 8, 4)
+VERSION = (0, 8, 5)
__version__ = '.'.join(map(str, VERSION))
View
6 debug_toolbar/media/debug_toolbar/css/toolbar.css
@@ -394,3 +394,9 @@
#djDebug .highlight .nv { color:#333 } /* Name.Variable */
#djDebug .highlight .s2 { color:#333 } /* Literal.String.Double */
#djDebug .highlight .cp { color:#333 } /* Comment.Preproc */
+
+@media print {
+ #djDebug {
+ display: none;
+ }
+}
View
2  debug_toolbar/media/debug_toolbar/css/toolbar.min.css
@@ -1 +1 @@
-#djDebug{color:#000;background:#FFF;}#djDebug,#djDebug div,#djDebug span,#djDebug applet,#djDebug object,#djDebug iframe,#djDebug h1,#djDebug h2,#djDebug h3,#djDebug h4,#djDebug h5,#djDebug h6,#djDebug p,#djDebug blockquote,#djDebug pre,#djDebug a,#djDebug abbr,#djDebug acronym,#djDebug address,#djDebug big,#djDebug cite,#djDebug code,#djDebug del,#djDebug dfn,#djDebug em,#djDebug font,#djDebug img,#djDebug ins,#djDebug kbd,#djDebug q,#djDebug s,#djDebug samp,#djDebug small,#djDebug strike,#djDebug strong,#djDebug sub,#djDebug sup,#djDebug tt,#djDebug var,#djDebug b,#djDebug u,#djDebug i,#djDebug center,#djDebug dl,#djDebug dt,#djDebug dd,#djDebug ol,#djDebug ul,#djDebug li,#djDebug fieldset,#djDebug form,#djDebug label,#djDebug legend,#djDebug table,#djDebug caption,#djDebug tbody,#djDebug tfoot,#djDebug thead,#djDebug tr,#djDebug th,#djDebug td{margin:0;padding:0;border:0;outline:0;font-size:12px;line-height:1.5em;color:#000;vertical-align:baseline;background:transparent;font-family:sans-serif;text-align:left;}#djDebug #djDebugToolbar{background:#111;width:200px;z-index:100000000;position:fixed;top:0;bottom:0;right:0;opacity:.9;}#djDebug #djDebugToolbar small{color:#999;}#djDebug #djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebug #djDebugToolbar li{border-bottom:1px solid #222;color:#fff;display:block;font-weight:bold;float:none;margin:0;padding:0;position:relative;width:auto;}#djDebug #djDebugToolbar li>a,#djDebug #djDebugToolbar li>div.contentless{font-weight:normal;font-style:normal;text-decoration:none;display:block;font-size:16px;padding:10px 10px 5px 25px;color:#fff;}#djDebug #djDebugToolbar li a:hover{color:#111;background-color:#ffc;}#djDebug #djDebugToolbar li.active{background-image:url(../img/indicator.png);background-repeat:no-repeat;background-position:left center;background-color:#333;padding-left:10px;}#djDebug #djDebugToolbar li.active a:hover{color:#b36a60;background-color:transparent;}#djDebug #djDebugToolbar li small{font-size:12px;color:#999;font-style:normal;text-decoration:none;font-variant:small-caps;}#djDebug #djDebugToolbarHandle{position:fixed;background:#fff;border:1px solid #111;top:30px;right:0;z-index:100000000;opacity:.75;}#djDebug a#djShowToolBarButton{display:block;height:75px;width:30px;border-right:none;border-bottom:4px solid #fff;border-top:4px solid #fff;border-left:4px solid #fff;color:#fff;font-size:10px;font-weight:bold;text-decoration:none;text-align:center;text-indent:-999999px;background:#000 url(../img/djdt_vertical.png) no-repeat left center;opacity:.5;}#djDebug a#djShowToolBarButton:hover{background-color:#111;padding-right:6px;border-top-color:#FFE761;border-left-color:#FFE761;border-bottom-color:#FFE761;opacity:1.0;}#djDebug code{display:block;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;white-space:pre;overflow:auto;}#djDebug tr.djDebugOdd{background-color:#f5f5f5;}#djDebug .panelContent{display:none;position:fixed;margin:0;top:0;right:200px;bottom:0;left:0;background-color:#eee;color:#666;z-index:100000000;}#djDebug .panelContent>div{border-bottom:1px solid #ddd;}#djDebug .djDebugPanelTitle{position:absolute;background-color:#ffc;color:#666;padding-left:20px;top:0;right:0;left:0;height:50px;}#djDebug .djDebugPanelTitle code{display:inline;font-size:inherit;}#djDebug .djDebugPanelContent{position:absolute;top:50px;right:0;bottom:0;left:0;height:auto;padding:0 0 0 20px;}#djDebug .djDebugPanelContent .scroll{height:100%;overflow:auto;display:block;padding:0 10px 0 0;}#djDebug h3{font-size:24px;font-weight:normal;line-height:50px;}#djDebug h4{font-size:20px;font-weight:bold;margin-top:.8em;}#djDebug .panelContent table{border:1px solid #ccc;border-collapse:collapse;width:100%;background-color:#fff;display:block;margin-top:.8em;overflow:auto;}#djDebug .panelContent tbody td,#djDebug .panelContent tbody th{vertical-align:top;padding:2px 3px;}#djDebug .panelContent thead th{padding:1px 6px 1px 3px;text-align:left;font-weight:bold;font-size:14px;}#djDebug .panelContent tbody th{width:12em;text-align:right;color:#666;padding-right:.5em;}#djDebug .djTemplateHideContextDiv{background-color:#fff;}#djDebug .panelContent .djDebugClose{text-indent:-9999999px;display:block;position:absolute;top:4px;right:15px;height:40px;width:40px;background:url(../img/close.png) no-repeat center center;}#djDebug .panelContent .djDebugClose:hover{background-image:url(../img/close_hover.png);}#djDebug .panelContent .djDebugClose.djDebugBack{background-image:url(../img/back.png);}#djDebug .panelContent .djDebugClose.djDebugBack:hover{background-image:url(../img/back_hover.png);}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dt{margin-top:.75em;}#djDebug .panelContent dd{margin-left:10px;}#djDebug a.toggleTemplate{padding:4px;background-color:#bbb;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.toggleTemplate:hover{padding:4px;background-color:#444;color:#ffe761;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.djTemplateShowContext,#djDebug a.djTemplateShowContext span.toggleArrow{color:#999;}#djDebug a.djTemplateShowContext:hover,#djDebug a.djTemplateShowContext:hover span.toggleArrow{color:#000;cursor:pointer;}#djDebug .djDebugSqlWrap{position:relative;}#djDebug .djDebugSql{z-index:100000002;}#djDebug .djSQLHideStacktraceDiv tbody th{text-align:left;}#djDebug .djSqlExplain td{white-space:pre;}#djDebug span.djDebugLineChart{background-color:#777;height:3px;position:absolute;bottom:0;top:0;left:0;display:block;z-index:1000000001;}#djDebug span.djDebugLineChartWarning{background-color:#900;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#000;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#000;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#000;font-weight:bold;}#djDebug .highlight .s{color:#333;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#000;font-weight:bold;}#djDebug .highlight .na{color:#333;}#djDebug .highlight .nt{color:#000;font-weight:bold;}#djDebug .highlight .nv{color:#333;}#djDebug .highlight .s2{color:#333;}#djDebug .highlight .cp{color:#333;}
+#djDebug{color:#000;background:#FFF;}#djDebug,#djDebug div,#djDebug span,#djDebug applet,#djDebug object,#djDebug iframe,#djDebug h1,#djDebug h2,#djDebug h3,#djDebug h4,#djDebug h5,#djDebug h6,#djDebug p,#djDebug blockquote,#djDebug pre,#djDebug a,#djDebug abbr,#djDebug acronym,#djDebug address,#djDebug big,#djDebug cite,#djDebug code,#djDebug del,#djDebug dfn,#djDebug em,#djDebug font,#djDebug img,#djDebug ins,#djDebug kbd,#djDebug q,#djDebug s,#djDebug samp,#djDebug small,#djDebug strike,#djDebug strong,#djDebug sub,#djDebug sup,#djDebug tt,#djDebug var,#djDebug b,#djDebug u,#djDebug i,#djDebug center,#djDebug dl,#djDebug dt,#djDebug dd,#djDebug ol,#djDebug ul,#djDebug li,#djDebug fieldset,#djDebug form,#djDebug label,#djDebug legend,#djDebug table,#djDebug caption,#djDebug tbody,#djDebug tfoot,#djDebug thead,#djDebug tr,#djDebug th,#djDebug td{margin:0;padding:0;border:0;outline:0;font-size:12px;line-height:1.5em;color:#000;vertical-align:baseline;background:transparent;font-family:sans-serif;text-align:left;}#djDebug #djDebugToolbar{background:#111;width:200px;z-index:100000000;position:fixed;top:0;bottom:0;right:0;opacity:.9;}#djDebug #djDebugToolbar small{color:#999;}#djDebug #djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebug #djDebugToolbar li{border-bottom:1px solid #222;color:#fff;display:block;font-weight:bold;float:none;margin:0;padding:0;position:relative;width:auto;}#djDebug #djDebugToolbar li>a,#djDebug #djDebugToolbar li>div.contentless{font-weight:normal;font-style:normal;text-decoration:none;display:block;font-size:16px;padding:10px 10px 5px 25px;color:#fff;}#djDebug #djDebugToolbar li a:hover{color:#111;background-color:#ffc;}#djDebug #djDebugToolbar li.active{background-image:url(../img/indicator.png);background-repeat:no-repeat;background-position:left center;background-color:#333;padding-left:10px;}#djDebug #djDebugToolbar li.active a:hover{color:#b36a60;background-color:transparent;}#djDebug #djDebugToolbar li small{font-size:12px;color:#999;font-style:normal;text-decoration:none;font-variant:small-caps;}#djDebug #djDebugToolbarHandle{position:fixed;background:#fff;border:1px solid #111;top:30px;right:0;z-index:100000000;opacity:.75;}#djDebug a#djShowToolBarButton{display:block;height:75px;width:30px;border-right:none;border-bottom:4px solid #fff;border-top:4px solid #fff;border-left:4px solid #fff;color:#fff;font-size:10px;font-weight:bold;text-decoration:none;text-align:center;text-indent:-999999px;background:#000 url(../img/djdt_vertical.png) no-repeat left center;opacity:.5;}#djDebug a#djShowToolBarButton:hover{background-color:#111;padding-right:6px;border-top-color:#FFE761;border-left-color:#FFE761;border-bottom-color:#FFE761;opacity:1.0;}#djDebug code{display:block;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;white-space:pre;overflow:auto;}#djDebug tr.djDebugOdd{background-color:#f5f5f5;}#djDebug .panelContent{display:none;position:fixed;margin:0;top:0;right:200px;bottom:0;left:0;background-color:#eee;color:#666;z-index:100000000;}#djDebug .panelContent>div{border-bottom:1px solid #ddd;}#djDebug .djDebugPanelTitle{position:absolute;background-color:#ffc;color:#666;padding-left:20px;top:0;right:0;left:0;height:50px;}#djDebug .djDebugPanelTitle code{display:inline;font-size:inherit;}#djDebug .djDebugPanelContent{position:absolute;top:50px;right:0;bottom:0;left:0;height:auto;padding:0 0 0 20px;}#djDebug .djDebugPanelContent .scroll{height:100%;overflow:auto;display:block;padding:0 10px 0 0;}#djDebug h3{font-size:24px;font-weight:normal;line-height:50px;}#djDebug h4{font-size:20px;font-weight:bold;margin-top:.8em;}#djDebug .panelContent table{border:1px solid #ccc;border-collapse:collapse;width:100%;background-color:#fff;display:block;margin-top:.8em;overflow:auto;}#djDebug .panelContent tbody td,#djDebug .panelContent tbody th{vertical-align:top;padding:2px 3px;}#djDebug .panelContent thead th{padding:1px 6px 1px 3px;text-align:left;font-weight:bold;font-size:14px;}#djDebug .panelContent tbody th{width:12em;text-align:right;color:#666;padding-right:.5em;}#djDebug .djTemplateHideContextDiv{background-color:#fff;}#djDebug .panelContent .djDebugClose{text-indent:-9999999px;display:block;position:absolute;top:4px;right:15px;height:40px;width:40px;background:url(../img/close.png) no-repeat center center;}#djDebug .panelContent .djDebugClose:hover{background-image:url(../img/close_hover.png);}#djDebug .panelContent .djDebugClose.djDebugBack{background-image:url(../img/back.png);}#djDebug .panelContent .djDebugClose.djDebugBack:hover{background-image:url(../img/back_hover.png);}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dt{margin-top:.75em;}#djDebug .panelContent dd{margin-left:10px;}#djDebug a.toggleTemplate{padding:4px;background-color:#bbb;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.toggleTemplate:hover{padding:4px;background-color:#444;color:#ffe761;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.djTemplateShowContext,#djDebug a.djTemplateShowContext span.toggleArrow{color:#999;}#djDebug a.djTemplateShowContext:hover,#djDebug a.djTemplateShowContext:hover span.toggleArrow{color:#000;cursor:pointer;}#djDebug .djDebugSqlWrap{position:relative;}#djDebug .djDebugSql{z-index:100000002;}#djDebug .djSQLHideStacktraceDiv tbody th{text-align:left;}#djDebug .djSqlExplain td{white-space:pre;}#djDebug span.djDebugLineChart{background-color:#777;height:3px;position:absolute;bottom:0;top:0;left:0;display:block;z-index:1000000001;}#djDebug span.djDebugLineChartWarning{background-color:#900;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#000;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#000;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#000;font-weight:bold;}#djDebug .highlight .s{color:#333;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#000;font-weight:bold;}#djDebug .highlight .na{color:#333;}#djDebug .highlight .nt{color:#000;font-weight:bold;}#djDebug .highlight .nv{color:#333;}#djDebug .highlight .s2{color:#333;}#djDebug .highlight .cp{color:#333;}@media print{#djDebug{display:none;}}
View
6 debug_toolbar/media/debug_toolbar/js/toolbar.js
@@ -44,7 +44,11 @@
return false;
});
$('#djDebug a.remoteCall').click(function() {
- $('#djDebugWindow').load(this.href, {}, function() {
+ $('#djDebugWindow').load(this.href, function(response, status, xhr) {
+ if (status == "error") {
+ var message = '<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+xhr.status+': '+xhr.statusText+'</h3></div>';
+ $('#djDebugWindow').html(message);
+ }
$('#djDebugWindow a.djDebugBack').click(function() {
$(this).parent().parent().hide();
return false;
View
2  debug_toolbar/media/debug_toolbar/js/toolbar.min.js
@@ -1 +1 @@
-(function(g,a,b,i){var f,h;var e=false;if(!(f=g.jQuery)||b>f.fn.jquery||i(f)){var c=a.createElement("script");c.type="text/javascript";c.src=DEBUG_TOOLBAR_MEDIA_URL+"js/jquery.js";c.onload=c.onreadystatechange=function(){if(!e&&(!(h=this.readyState)||h=="loaded"||h=="complete")){i((f=g.jQuery).noConflict(1),e=true);f(c).remove()}};a.documentElement.childNodes[0].appendChild(c)}})(window,document,"1.3",function(b,a){b.cookie=function(f,n,q){if(typeof n!="undefined"){q=q||{};if(n===null){n="";q.expires=-1}var j="";if(q.expires&&(typeof q.expires=="number"||q.expires.toUTCString)){var k;if(typeof q.expires=="number"){k=new Date();k.setTime(k.getTime()+(q.expires*24*60*60*1000))}else{k=q.expires}j="; expires="+k.toUTCString()}var p=q.path?"; path="+(q.path):"";var l=q.domain?"; domain="+(q.domain):"";var e=q.secure?"; secure":"";document.cookie=[f,"=",encodeURIComponent(n),j,p,l,e].join("")}else{var h=null;if(document.cookie&&document.cookie!=""){var o=document.cookie.split(";");for(var m=0;m<o.length;m++){var g=b.trim(o[m]);if(g.substring(0,f.length+1)==(f+"=")){h=decodeURIComponent(g.substring(f.length+1));break}}}return h}};b("head").append('<link rel="stylesheet" href="'+DEBUG_TOOLBAR_MEDIA_URL+'css/toolbar.min.css" type="text/css" />');var d="djdt";var c={init:function(){b("#djDebug").show();var e=null;b("#djDebugPanelList li a").click(function(){if(!this.className){return false}e=b("#djDebug #"+this.className);if(e.is(":visible")){b(document).trigger("close.djDebug");b(this).parent().removeClass("active")}else{b(".panelContent").hide();e.show();b("#djDebugToolbar li").removeClass("active");b(this).parent().addClass("active")}return false});b("#djDebug a.djDebugClose").click(function(){b(document).trigger("close.djDebug");b("#djDebugToolbar li").removeClass("active");return false});b("#djDebug a.remoteCall").click(function(){b("#djDebugWindow").load(this.href,{},function(){b("#djDebugWindow a.djDebugBack").click(function(){b(this).parent().parent().hide();return false})});b("#djDebugWindow").show();return false});b("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){c.toggle_arrow(b(this).children(".toggleArrow"));c.toggle_content(b(this).parent().next());return false});b("#djDebugSQLPanel a.djSQLShowStacktrace").click(function(){c.toggle_content(b(".djSQLHideStacktraceDiv",b(this).parents("tr")));return false});b("#djHideToolBarButton").click(function(){c.hide_toolbar(true);return false});b("#djShowToolBarButton").click(function(){c.show_toolbar();return false});b(document).bind("close.djDebug",function(){if(b("#djDebugWindow").is(":visible")){b("#djDebugWindow").hide();return}if(b(".panelContent").is(":visible")){b(".panelContent").hide();return}if(b("#djDebugToolbar").is(":visible")){c.hide_toolbar(true);return}});if(b.cookie(d)){c.hide_toolbar(false)}else{c.show_toolbar(false)}},toggle_content:function(e){if(e.is(":visible")){e.hide()}else{e.show()}},close:function(){b(document).trigger("close.djDebug");return false},hide_toolbar:function(e){b("#djDebugWindow").hide();b(".panelContent").hide();b("#djDebugToolbar li").removeClass("active");b("#djDebugToolbar").hide("fast");b("#djDebugToolbarHandle").show();b(document).unbind("keydown.djDebug");if(e){b.cookie(d,"hide",{path:"/",expires:10})}},show_toolbar:function(e){b(document).bind("keydown.djDebug",function(f){if(f.keyCode==27){c.close()}});b("#djDebugToolbarHandle").hide();if(e){b("#djDebugToolbar").show("fast")}else{b("#djDebugToolbar").show()}b.cookie(d,null,{path:"/",expires:-1})},toggle_arrow:function(f){var e=String.fromCharCode(9654);var g=String.fromCharCode(9660);f.html(f.html()==e?g:e)}};b(document).ready(function(){c.init()})});
+(function(g,a,b,i){var f,h;var e=false;if(!(f=g.jQuery)||b>f.fn.jquery||i(f)){var c=a.createElement("script");c.type="text/javascript";c.src=DEBUG_TOOLBAR_MEDIA_URL+"js/jquery.js";c.onload=c.onreadystatechange=function(){if(!e&&(!(h=this.readyState)||h=="loaded"||h=="complete")){i((f=g.jQuery).noConflict(1),e=true);f(c).remove()}};a.documentElement.childNodes[0].appendChild(c)}})(window,document,"1.3",function(b,a){b.cookie=function(f,n,q){if(typeof n!="undefined"){q=q||{};if(n===null){n="";q.expires=-1}var j="";if(q.expires&&(typeof q.expires=="number"||q.expires.toUTCString)){var k;if(typeof q.expires=="number"){k=new Date();k.setTime(k.getTime()+(q.expires*24*60*60*1000))}else{k=q.expires}j="; expires="+k.toUTCString()}var p=q.path?"; path="+(q.path):"";var l=q.domain?"; domain="+(q.domain):"";var e=q.secure?"; secure":"";document.cookie=[f,"=",encodeURIComponent(n),j,p,l,e].join("")}else{var h=null;if(document.cookie&&document.cookie!=""){var o=document.cookie.split(";");for(var m=0;m<o.length;m++){var g=b.trim(o[m]);if(g.substring(0,f.length+1)==(f+"=")){h=decodeURIComponent(g.substring(f.length+1));break}}}return h}};b("head").append('<link rel="stylesheet" href="'+DEBUG_TOOLBAR_MEDIA_URL+'css/toolbar.min.css" type="text/css" />');var d="djdt";var c={init:function(){b("#djDebug").show();var e=null;b("#djDebugPanelList li a").click(function(){if(!this.className){return false}e=b("#djDebug #"+this.className);if(e.is(":visible")){b(document).trigger("close.djDebug");b(this).parent().removeClass("active")}else{b(".panelContent").hide();e.show();b("#djDebugToolbar li").removeClass("active");b(this).parent().addClass("active")}return false});b("#djDebug a.djDebugClose").click(function(){b(document).trigger("close.djDebug");b("#djDebugToolbar li").removeClass("active");return false});b("#djDebug a.remoteCall").click(function(){b("#djDebugWindow").load(this.href,function(g,f,i){if(f=="error"){var h='<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+i.status+": "+i.statusText+"</h3></div>";b("#djDebugWindow").html(h)}b("#djDebugWindow a.djDebugBack").click(function(){b(this).parent().parent().hide();return false})});b("#djDebugWindow").show();return false});b("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){c.toggle_arrow(b(this).children(".toggleArrow"));c.toggle_content(b(this).parent().next());return false});b("#djDebugSQLPanel a.djSQLShowStacktrace").click(function(){c.toggle_content(b(".djSQLHideStacktraceDiv",b(this).parents("tr")));return false});b("#djHideToolBarButton").click(function(){c.hide_toolbar(true);return false});b("#djShowToolBarButton").click(function(){c.show_toolbar();return false});b(document).bind("close.djDebug",function(){if(b("#djDebugWindow").is(":visible")){b("#djDebugWindow").hide();return}if(b(".panelContent").is(":visible")){b(".panelContent").hide();return}if(b("#djDebugToolbar").is(":visible")){c.hide_toolbar(true);return}});if(b.cookie(d)){c.hide_toolbar(false)}else{c.show_toolbar(false)}},toggle_content:function(e){if(e.is(":visible")){e.hide()}else{e.show()}},close:function(){b(document).trigger("close.djDebug");return false},hide_toolbar:function(e){b("#djDebugWindow").hide();b(".panelContent").hide();b("#djDebugToolbar li").removeClass("active");b("#djDebugToolbar").hide("fast");b("#djDebugToolbarHandle").show();b(document).unbind("keydown.djDebug");if(e){b.cookie(d,"hide",{path:"/",expires:10})}},show_toolbar:function(e){b(document).bind("keydown.djDebug",function(f){if(f.keyCode==27){c.close()}});b("#djDebugToolbarHandle").hide();if(e){b("#djDebugToolbar").show("fast")}else{b("#djDebugToolbar").show()}b.cookie(d,null,{path:"/",expires:-1})},toggle_arrow:function(f){var e=String.fromCharCode(9654);var g=String.fromCharCode(9660);f.html(f.html()==e?g:e)}};b(document).ready(function(){c.init()})});
View
16 debug_toolbar/middleware.py
@@ -67,10 +67,14 @@ def _show_toolbar(self, request):
def process_request(self, request):
if self.show_toolbar(request):
if self.override_url:
- original_urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
+ original_urlconf = __import__(getattr(request, 'urlconf', settings.ROOT_URLCONF), {}, {}, ['*'])
debug_toolbar.urls.urlpatterns += patterns('',
('', include(original_urlconf)),
)
+ if hasattr(original_urlconf, 'handler404'):
+ debug_toolbar.urls.handler404 = original_urlconf.handler404
+ if hasattr(original_urlconf, 'handler500'):
+ debug_toolbar.urls.handler500 = original_urlconf.handler500
self.override_url = False
request.urlconf = 'debug_toolbar.urls'
@@ -96,15 +100,15 @@ def process_response(self, request, response):
{'redirect_to': redirect_to}
)
response.cookies = cookies
- if response.status_code == 200:
- for panel in self.debug_toolbars[request].panels:
- panel.process_response(request, response)
+ if response.status_code == 200 and 'gzip' not in response.get('Content-Encoding', ''):
if response['Content-Type'].split(';')[0] in _HTML_TYPES:
+ for panel in self.debug_toolbars[request].panels:
+ panel.process_response(request, response)
response.content = replace_insensitive(
smart_unicode(response.content),
self.tag,
smart_unicode(self.debug_toolbars[request].render_toolbar() + self.tag))
- if response.get('Content-Length', None):
- response['Content-Length'] = len(response.content)
+ if response.get('Content-Length', None):
+ response['Content-Length'] = len(response.content)
del self.debug_toolbars[request]
return response
View
83 debug_toolbar/panels/logger.py
@@ -8,16 +8,21 @@
from django.utils.translation import ugettext_lazy as _
from debug_toolbar.panels import DebugPanel
-class ThreadTrackingHandler(logging.Handler):
+
+class LogCollector(object):
def __init__(self):
if threading is None:
raise NotImplementedError("threading module is not available, \
the logging panel cannot be used without it")
- logging.Handler.__init__(self)
self.records = {} # a dictionary that maps threads to log records
- def emit(self, record):
- self.get_records().append(record)
+ def add_record(self, record, thread=None):
+ # Avoid logging SQL queries since they are already in the SQL panel
+ # TODO: Make this check whether SQL panel is enabled
+ if record.get('channel', '') == 'django.db.backends':
+ return
+
+ self.get_records(thread).append(record)
def get_records(self, thread=None):
"""
@@ -36,20 +41,67 @@ def clear_records(self, thread=None):
if thread in self.records:
del self.records[thread]
-handler = ThreadTrackingHandler()
+
+class ThreadTrackingHandler(logging.Handler):
+ def __init__(self, collector):
+ logging.Handler.__init__(self)
+ self.collector = collector
+
+ def emit(self, record):
+ record = {
+ 'message': record.getMessage(),
+ 'time': datetime.datetime.fromtimestamp(record.created),
+ 'level': record.levelname,
+ 'file': record.pathname,
+ 'line': record.lineno,
+ 'channel': record.name,
+ }
+ self.collector.add_record(record)
+
+
+collector = LogCollector()
+logging_handler = ThreadTrackingHandler(collector)
logging.root.setLevel(logging.NOTSET)
-logging.root.addHandler(handler)
+logging.root.addHandler(logging_handler) # register with logging
+
+try:
+ import logbook
+ logbook_supported = True
+except ImportError:
+ # logbook support is optional, so fail silently
+ logbook_supported = False
+
+if logbook_supported:
+ class LogbookThreadTrackingHandler(logbook.handlers.Handler):
+ def __init__(self, collector):
+ logbook.handlers.Handler.__init__(self, bubble=True)
+ self.collector = collector
+
+ def emit(self, record):
+ record = {
+ 'message': record.message,
+ 'time': record.time,
+ 'level': record.level_name,
+ 'file': record.filename,
+ 'line': record.lineno,
+ 'channel': record.channel,
+ }
+ self.collector.add_record(record)
+
+
+ logbook_handler = LogbookThreadTrackingHandler(collector)
+ logbook_handler.push_application() # register with logbook
class LoggingPanel(DebugPanel):
name = 'Logging'
has_content = True
def process_request(self, request):
- handler.clear_records()
+ collector.clear_records()
def get_and_delete(self):
- records = handler.get_records()
- handler.clear_records()
+ records = collector.get_records()
+ collector.clear_records()
return records
def nav_title(self):
@@ -57,7 +109,7 @@ def nav_title(self):
def nav_subtitle(self):
# FIXME l10n: use ngettext
- return "%s message%s" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's')
+ return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's')
def title(self):
return _('Log Messages')
@@ -66,16 +118,7 @@ def url(self):
return ''
def content(self):
- records = []
- for record in self.get_and_delete():
- records.append({
- 'message': record.getMessage(),
- 'time': datetime.datetime.fromtimestamp(record.created),
- 'level': record.levelname,
- 'file': record.pathname,
- 'line': record.lineno,
- })
-
+ records = self.get_and_delete()
context = self.context.copy()
context.update({'records': records})
View
108 debug_toolbar/panels/sql.py
@@ -6,14 +6,29 @@
import django
from django.conf import settings
-from django.db import connection
+try:
+ from django.db import connections
+except ImportError:
+ # Compatibility with Django < 1.2
+ from django.db import connection
+ connections = {'default': connection}
+ connection.alias = 'default'
+
from django.db.backends import util
from django.views.debug import linebreak_iter
from django.template import Node
from django.template.loader import render_to_string
from django.utils import simplejson
-from django.utils.encoding import force_unicode
+from django.utils.encoding import force_unicode, DjangoUnicodeDecodeError
from django.utils.hashcompat import sha_constructor
+try:
+ from django.utils.log import getLogger
+ logger = getLogger('django.db.backends')
+ has_logger = True
+except ImportError:
+ # Compatibility with Django < 1.2
+ has_logger = False
+
from django.utils.translation import ugettext_lazy as _
from debug_toolbar.panels import DebugPanel
@@ -85,12 +100,73 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
Replacement for CursorDebugWrapper which stores additional information
in `connection.queries`.
"""
+ def clean_params(self, params):
+ clean_params = ()
+ for x in params:
+ try:
+ force_unicode(x, strings_only=True)
+ except DjangoUnicodeDecodeError:
+ clean_params += ("<non unicode object>", )
+ else:
+ clean_params += (x, )
+ return clean_params
+
def execute(self, sql, params=()):
start = datetime.now()
try:
return self.cursor.execute(sql, params)
finally:
stop = datetime.now()
+ params = self.clean_params(params)
+ duration = ms_from_timedelta(stop - start)
+ stacktrace = tidy_stacktrace(traceback.extract_stack())
+ _params = ''
+ try:
+ _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params])
+ except TypeError:
+ pass # object not JSON serializable
+
+ template_info = None
+ cur_frame = sys._getframe().f_back
+ try:
+ while cur_frame is not None:
+ if cur_frame.f_code.co_name == 'render':
+ node = cur_frame.f_locals['self']
+ if isinstance(node, Node):
+ template_info = get_template_info(node.source)
+ break
+ cur_frame = cur_frame.f_back
+ except:
+ pass
+ del cur_frame
+
+ # Logging was added in Django 1.3
+ if has_logger:
+ logger.debug('(%.3f) %s; args=%s' % (duration, sql, params),
+ extra={'duration':duration, 'sql':sql, 'params':params}
+ )
+
+ # We keep `sql` to maintain backwards compatibility
+ self.db.queries.append({
+ 'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
+ 'duration': duration,
+ 'raw_sql': sql,
+ 'params': _params,
+ 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(),
+ 'stacktrace': stacktrace,
+ 'start_time': start,
+ 'stop_time': stop,
+ 'is_slow': (duration > SQL_WARNING_THRESHOLD),
+ 'is_select': sql.lower().strip().startswith('select'),
+ 'template_info': template_info,
+ })
+
+ def executemany(self, sql, params=()):
+ start = datetime.now()
+ try:
+ return self.cursor.executemany(sql, params)
+ finally:
+ stop = datetime.now()
duration = ms_from_timedelta(stop - start)
stacktrace = tidy_stacktrace(traceback.extract_stack())
_params = ''
@@ -113,6 +189,11 @@ def execute(self, sql, params=()):
pass
del cur_frame
+ if has_logger:
+ logger.debug('(%.3f) %s; args=%s' % (duration, sql, params),
+ extra={'duration':duration, 'sql':sql, 'params':params}
+ )
+
# We keep `sql` to maintain backwards compatibility
self.db.queries.append({
'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
@@ -139,16 +220,27 @@ class SQLDebugPanel(DebugPanel):
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
- self._offset = len(connection.queries)
+ self._offset = dict((conn, len(connections[conn].queries)) for conn in connections)
self._sql_time = 0
self._queries = []
+ self._databases = {}
def nav_title(self):
return _('SQL')
def nav_subtitle(self):
- self._queries = connection.queries[self._offset:]
- self._sql_time = sum([q['duration'] for q in self._queries])
+ self._queries = []
+ self._databases = {}
+ for alias in connections:
+ db_queries = connections[alias].queries[self._offset[alias]:]
+ self._databases[alias] = {
+ 'time_spent': sum(q['duration'] for q in db_queries),
+ 'queries': len(db_queries),
+ }
+ self._queries.extend([(alias, q) for q in db_queries])
+
+ self._queries.sort(key=lambda x: x[1]['start_time'])
+ self._sql_time = sum([d['time_spent'] for d in self._databases.itervalues()])
num_queries = len(self._queries)
# TODO l10n: use ngettext
return "%d %s in %.2fms" % (
@@ -165,7 +257,8 @@ def url(self):
def content(self):
width_ratio_tally = 0
- for query in self._queries:
+ for alias, query in self._queries:
+ query['alias'] = alias
query['sql'] = reformat_sql(query['sql'])
try:
query['width_ratio'] = (query['duration'] / self._sql_time) * 100
@@ -176,7 +269,8 @@ def content(self):
context = self.context.copy()
context.update({
- 'queries': self._queries,
+ 'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']),
+ 'queries': [q for a, q in self._queries],
'sql_time': self._sql_time,
'is_mysql': settings.DATABASE_ENGINE == 'mysql',
})
View
1  debug_toolbar/templates/debug_toolbar/base.html
@@ -1,5 +1,4 @@
{% load i18n %}
-<style type="text/css">@media print { #djDebug {display:none;}}</style>
<script type="text/javascript">
// <![CDATA[
var DEBUG_TOOLBAR_MEDIA_URL = "{{ DEBUG_TOOLBAR_MEDIA_URL }}";
View
2  debug_toolbar/templates/debug_toolbar/panels/logger.html
@@ -5,6 +5,7 @@
<tr>
<th>{% trans "Level" %}</th>
<th>{% trans "Time" %}</th>
+ <th>{% trans "Channel" %}</th>
<th>{% trans "Message" %}</th>
<th>{% trans "Location" %}</th>
</tr>
@@ -14,6 +15,7 @@
<tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ record.level }}</td>
<td>{{ record.time|date:"h:i:s m/d/Y" }}</td>
+ <td>{{ record.channel|default:"-" }}</td>
<td>{{ record.message }}</td>
<td>{{ record.file }}:{{ record.line }}</td>
</tr>
View
2  debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -5,6 +5,7 @@
<th>{% trans "Time" %}&nbsp;(ms)</th>
<th>{% trans "Action" %}</th>
<th>{% trans 'Stacktrace' %}</th>
+ <th>{% trans 'Alias' %}</th>
<th>{% trans 'Query' %}</th>
</tr>
</thead>
@@ -28,6 +29,7 @@
<div class="djSQLShowStacktraceDiv"><a class="djSQLShowStacktrace" href="#">Toggle Stacktrace</a></div>
{% endif %}
</td>
+ <td>{{ query.alias }}</td>
<td class="syntax">
<div class="djDebugSqlWrap">
<div class="djDebugSql">{{ query.sql|safe }}</div>
Please sign in to comment.
Something went wrong with that request. Please try again.