diff --git a/dmoj/urls.py b/dmoj/urls.py
index 72e81cb..01bbbd9 100644
--- a/dmoj/urls.py
+++ b/dmoj/urls.py
@@ -1069,6 +1069,26 @@ urlpatterns = [
internal.InternalProblem.as_view(),
name="internal_problem",
),
+ url(
+ r"^request_time$",
+ internal.InternalRequestTime.as_view(),
+ name="internal_request_time",
+ ),
+ url(
+ r"^request_time_detail$",
+ internal.InternalRequestTimeDetail.as_view(),
+ name="internal_request_time_detail",
+ ),
+ url(
+ r"^internal_slow_request$",
+ internal.InternalSlowRequest.as_view(),
+ name="internal_slow_request",
+ ),
+ url(
+ r"^internal_slow_request_detail$",
+ internal.InternalSlowRequestDetail.as_view(),
+ name="internal_slow_request_detail",
+ ),
]
),
),
diff --git a/judge/middleware.py b/judge/middleware.py
index b86731d..ccd1547 100644
--- a/judge/middleware.py
+++ b/judge/middleware.py
@@ -1,5 +1,8 @@
import time
import logging
+import random
+import json
+from datetime import datetime
from django.conf import settings
from django.http import HttpResponseRedirect, Http404
@@ -148,17 +151,23 @@ class SlowRequestMiddleware(object):
self.get_response = get_response
def __call__(self, request):
- logger = logging.getLogger("judge.slow_request")
+ logger = logging.getLogger("judge.request_time")
+ logger_slow = logging.getLogger("judge.slow_request")
start_time = time.time()
response = self.get_response(request)
response_time = time.time() - start_time
+ url_name = resolve(request.path).url_name
+
+ message = {
+ "url_name": url_name,
+ "response_time": response_time * 1000,
+ "profile": request.user.username,
+ "date": datetime.now().strftime("%Y/%m/%d"),
+ "url": request.build_absolute_uri(),
+ "method": request.method,
+ }
if response_time > 9:
- message = {
- "message": "Slow request",
- "url": request.build_absolute_uri(),
- "response_time": response_time * 1000,
- "method": request.method,
- "profile": request.profile,
- }
- logger.info(message)
+ logger_slow.info(json.dumps(message))
+ if random.random() < 0.1:
+ logger.info(json.dumps(message))
return response
diff --git a/judge/views/internal.py b/judge/views/internal.py
index 45f9249..7c8e6f2 100644
--- a/judge/views/internal.py
+++ b/judge/views/internal.py
@@ -1,16 +1,27 @@
+import logging
+import json
+
from django.views.generic import ListView
from django.utils.translation import gettext as _, gettext_lazy
from django.db.models import Count
from django.http import HttpResponseForbidden
+from django.urls import reverse
from judge.utils.diggpaginator import DiggPaginator
from judge.models import VolunteerProblemVote, Problem
-class InternalProblem(ListView):
+class InternalView(object):
+ def get(self, request, *args, **kwargs):
+ if request.user.is_superuser:
+ return super(InternalView, self).get(request, *args, **kwargs)
+ return HttpResponseForbidden()
+
+
+class InternalProblem(ListView, InternalView):
model = Problem
title = _("Internal problems")
- template_name = "internal/base.html"
+ template_name = "internal/problem.html"
paginate_by = 100
context_object_name = "problems"
@@ -44,7 +55,87 @@ class InternalProblem(ListView):
return context
- def get(self, request, *args, **kwargs):
- if request.user.is_superuser:
- return super(InternalProblem, self).get(request, *args, **kwargs)
- return HttpResponseForbidden()
+
+class RequestTimeMixin(object):
+ def get_requests_data(self):
+ logger = logging.getLogger(self.log_name)
+ log_filename = logger.handlers[0].baseFilename
+ requests = []
+
+ with open(log_filename, "r") as f:
+ for line in f:
+ try:
+ info = json.loads(line)
+ requests.append(info)
+ except:
+ continue
+ return requests
+
+
+class InternalRequestTime(ListView, InternalView, RequestTimeMixin):
+ title = _("Request times")
+ template_name = "internal/request_time.html"
+ context_object_name = "pages"
+ log_name = "judge.request_time"
+ detail_url_name = "internal_request_time_detail"
+ page_type = "request_time"
+
+ def get_queryset(self):
+ requests = self.get_requests_data()
+ table = {}
+ for r in requests:
+ url_name = r["url_name"]
+ if url_name not in table:
+ table[url_name] = {
+ "time": 0,
+ "count": 0,
+ "url_name": url_name,
+ "pattern": reverse(url_name) if url_name else None,
+ }
+ old_sum = table[url_name]["time"] * table[url_name]["count"]
+ table[url_name]["count"] += 1
+ table[url_name]["time"] = (old_sum + float(r["response_time"])) / table[
+ url_name
+ ]["count"]
+ order = self.request.GET.get("order", "time")
+ return sorted(table.values(), key=lambda x: x[order], reverse=True)
+
+ def get_context_data(self, **kwargs):
+ context = super(InternalRequestTime, self).get_context_data(**kwargs)
+ context["page_type"] = self.page_type
+ context["title"] = self.title
+ context["current_path"] = self.request.path
+ context["detail_path"] = reverse(self.detail_url_name)
+ return context
+
+
+class InternalRequestTimeDetail(InternalRequestTime):
+ template_name = "internal/request_time_detail.html"
+ context_object_name = "requests"
+
+ def get_queryset(self):
+ url_name = self.request.GET.get("url_name", None)
+ if not url_name:
+ return HttpResponseForbidden()
+ if url_name == "None":
+ url_name = None
+ self.title = url_name
+ requests = self.get_requests_data()
+ filtered_requests = [r for r in requests if r["url_name"] == url_name]
+ order = self.request.GET.get("order", "response_time")
+ return sorted(filtered_requests, key=lambda x: x[order], reverse=True)[:200]
+
+ def get_context_data(self, **kwargs):
+ context = super(InternalRequestTimeDetail, self).get_context_data(**kwargs)
+ context["url_name"] = self.request.GET.get("url_name", None)
+ return context
+
+
+class InternalSlowRequest(InternalRequestTime):
+ log_name = "judge.slow_request"
+ detail_url_name = "internal_slow_request_detail"
+ page_type = "slow_request"
+
+
+class InternalSlowRequestDetail(InternalRequestTimeDetail):
+ log_name = "judge.slow_request"
diff --git a/templates/internal/left-sidebar.html b/templates/internal/left-sidebar.html
new file mode 100644
index 0000000..64788be
--- /dev/null
+++ b/templates/internal/left-sidebar.html
@@ -0,0 +1,5 @@
+
diff --git a/templates/internal/base.html b/templates/internal/problem.html
similarity index 94%
rename from templates/internal/base.html
rename to templates/internal/problem.html
index 1df34d8..eebb02c 100644
--- a/templates/internal/base.html
+++ b/templates/internal/problem.html
@@ -25,9 +25,7 @@
{% endblock %}
{% block left_sidebar %}
-
+ {% include "internal/left-sidebar.html" %}
{% endblock %}
{% block middle_content %}
diff --git a/templates/internal/request_time.html b/templates/internal/request_time.html
new file mode 100644
index 0000000..ce3118a
--- /dev/null
+++ b/templates/internal/request_time.html
@@ -0,0 +1,28 @@
+{% extends "two-column-content.html" %}
+
+{% block left_sidebar %}
+ {% include "internal/left-sidebar.html" %}
+{% endblock %}
+
+{% block middle_content %}
+
+
+
+ URL Name |
+ Pattern |
+ Time (ms) |
+ Count |
+
+
+
+ {% for page in pages %}
+
+ {{page['url_name']}} |
+ {{page['pattern']}} |
+ {{page['time'] | floatformat(2)}} |
+ {{page['count']}} |
+
+ {% endfor %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/templates/internal/request_time_detail.html b/templates/internal/request_time_detail.html
new file mode 100644
index 0000000..5e3c3bd
--- /dev/null
+++ b/templates/internal/request_time_detail.html
@@ -0,0 +1,36 @@
+{% extends "two-column-content.html" %}
+
+{% block left_sidebar %}
+ {% include "internal/left-sidebar.html" %}
+{% endblock %}
+
+{% block middle_content %}
+
+
+
+ Profile |
+ URL |
+ Method |
+ Time (ms) |
+ Date |
+
+
+
+ {% for request in requests %}
+
+
+ {% if request['profile'] %}
+ {{request['profile']}}
+ {% else %}
+ None
+ {% endif %}
+ |
+ {{request['url']}} |
+ {{request['method']}} |
+ {{request['response_time'] | floatformat(2)}} |
+ {{request['date']}} |
+
+ {% endfor %}
+
+
+{% endblock %}
\ No newline at end of file