From 83b20643d26e95da8cd0a20c0011267797164d81 Mon Sep 17 00:00:00 2001 From: havk Date: Sun, 13 Jun 2021 20:39:45 +0200 Subject: [PATCH] Add hits to chart data (#141) * Add hits to chart data * Hide legend Co-authored-by: R. Miles McCain --- shynet/core/models.py | 128 +++++++++++------- .../dashboard/includes/service_overview.html | 4 +- .../dashboard/includes/time_chart.html | 39 +++--- .../templates/dashboard/pages/service.html | 2 +- 4 files changed, 104 insertions(+), 69 deletions(-) diff --git a/shynet/core/models.py b/shynet/core/models.py index 5d6f5a7..f19cbaa 100644 --- a/shynet/core/models.py +++ b/shynet/core/models.py @@ -198,6 +198,36 @@ class Service(models.Model): avg_hits_per_session = hit_count / session_count if session_count > 0 else None + avg_session_duration = self._get_avg_session_duration(sessions, session_count) + + chart_data, chart_tooltip_format, chart_granularity = self._get_chart_data( + sessions, hits, start_time, end_time, tz_now + ) + return { + "currently_online": currently_online, + "session_count": session_count, + "hit_count": hit_count, + "has_hits": has_hits, + "bounce_rate_pct": bounce_count * 100 / session_count + if session_count > 0 + else None, + "avg_session_duration": avg_session_duration, + "avg_load_time": avg_load_time, + "avg_hits_per_session": avg_hits_per_session, + "locations": locations, + "referrers": referrers, + "countries": countries, + "operating_systems": operating_systems, + "browsers": browsers, + "devices": devices, + "device_types": device_types, + "chart_data": chart_data, + "chart_tooltip_format": chart_tooltip_format, + "chart_granularity": chart_granularity, + "online": True, + } + + def _get_avg_session_duration(self, sessions, session_count): try: avg_session_duration = sessions.annotate( duration=models.F("last_seen") - models.F("start_time") @@ -212,68 +242,72 @@ class Service(models.Model): if session_count == 0: avg_session_duration = None + return avg_session_duration + + def _get_chart_data(self, sessions, hits, start_time, end_time, tz_now): # Show hourly chart for date ranges of 3 days or less, otherwise daily chart if (end_time - start_time).days < 3: - session_chart_tooltip_format = "MM/dd HH:mm" - session_chart_granularity = "hourly" - session_chart_data = { - k["hour"]: k["count"] - for k in sessions.annotate(hour=TruncHour("start_time")) + chart_tooltip_format = "MM/dd HH:mm" + chart_granularity = "hourly" + sessions_per_hour = ( + sessions.annotate(hour=TruncHour("start_time")) .values("hour") .annotate(count=models.Count("uuid")) .order_by("hour") + ) + chart_data = { + k["hour"]: {"sessions": k["count"]} for k in sessions_per_hour } - for hour_offset in range(int((end_time - start_time).total_seconds() / 3600) + 1): - hour = (start_time + timezone.timedelta(hours=hour_offset)) - if hour not in session_chart_data: - session_chart_data[hour] = 0 if hour <= tz_now else None + hits_per_hour = ( + hits.annotate(hour=TruncHour("start_time")) + .values("hour") + .annotate(count=models.Count("id")) + .order_by("hour") + ) + for k in hits_per_hour: + if k["hour"] not in chart_data: + chart_data[k["hour"]] = {"hits": k["count"], "sessions": 0} + else: + chart_data[k["hour"]]["hits"] = k["count"] + + hours_range = range(int((end_time - start_time).total_seconds() / 3600) + 1) + for hour_offset in hours_range: + hour = start_time + timezone.timedelta(hours=hour_offset) + if hour not in chart_data and hour <= tz_now: + chart_data[hour] = {"sessions": 0, "hits": 0} else: - session_chart_tooltip_format = "MMM d" - session_chart_granularity = "daily" - session_chart_data = { - k["date"]: k["count"] - for k in sessions.annotate(date=TruncDate("start_time")) + chart_tooltip_format = "MMM d" + chart_granularity = "daily" + sessions_per_day = ( + sessions.annotate(date=TruncDate("start_time")) .values("date") .annotate(count=models.Count("uuid")) .order_by("date") - } + ) + chart_data = {k["date"]: {"sessions": k["count"]} for k in sessions_per_day} + hits_per_day = ( + hits.annotate(date=TruncDate("start_time")) + .values("date") + .annotate(count=models.Count("id")) + .order_by("date") + ) + for k in hits_per_day: + chart_data[k["date"]]["hits"] = k["count"] + for day_offset in range((end_time - start_time).days + 1): day = (start_time + timezone.timedelta(days=day_offset)).date() - if day not in session_chart_data: - session_chart_data[day] = 0 if day <= tz_now.date() else None + if day not in chart_data and day <= tz_now.date(): + chart_data[day] = {"sessions": 0, "hits": 0} - return { - "currently_online": currently_online, - "session_count": session_count, - "hit_count": hit_count, - "has_hits": has_hits, - "avg_hits_per_session": hit_count / (max(session_count, 1)), - "bounce_rate_pct": bounce_count * 100 / session_count - if session_count > 0 - else None, - "avg_session_duration": avg_session_duration, - "avg_load_time": avg_load_time, - "avg_hits_per_session": avg_hits_per_session, - "locations": locations, - "referrers": referrers, - "countries": countries, - "operating_systems": operating_systems, - "browsers": browsers, - "devices": devices, - "device_types": device_types, - "session_chart_data": json.dumps( - [ - {"x": str(key), "y": value} - for key, value in sorted( - session_chart_data.items(), key=lambda k: k[0] - ) - ] - ), - "session_chart_tooltip_format": session_chart_tooltip_format, - "session_chart_granularity": session_chart_granularity, - "online": True, + chart_data = sorted(chart_data.items(), key=lambda k: k[0]) + chart_data = { + 'sessions': [v['sessions'] for k, v in chart_data], + 'hits': [v['hits'] for k, v in chart_data], + 'labels': [str(k) for k, v in chart_data], } + return chart_data, chart_tooltip_format, chart_granularity + def get_absolute_url(self): return reverse( "dashboard:service", diff --git a/shynet/dashboard/templates/dashboard/includes/service_overview.html b/shynet/dashboard/templates/dashboard/includes/service_overview.html index 1720413..29feae5 100644 --- a/shynet/dashboard/templates/dashboard/includes/service_overview.html +++ b/shynet/dashboard/templates/dashboard/includes/service_overview.html @@ -51,7 +51,7 @@
- {% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data sparkline=True height=100 name=object.uuid tooltip_format=stats.session_chart_tooltip_format granularity=stats.session_chart_granularity %} + {% include 'dashboard/includes/time_chart.html' with data=stats.chart_data sparkline=True height=100 name=object.uuid tooltip_format=stats.chart_tooltip_format granularity=stats.chart_granularity %}
{% endwith %} - \ No newline at end of file + diff --git a/shynet/dashboard/templates/dashboard/includes/time_chart.html b/shynet/dashboard/templates/dashboard/includes/time_chart.html index 22542a9..554bfa6 100644 --- a/shynet/dashboard/templates/dashboard/includes/time_chart.html +++ b/shynet/dashboard/templates/dashboard/includes/time_chart.html @@ -5,12 +5,14 @@ enabled: false }, tooltip: { - shared: false, + shared: true, x: { format: '{{tooltip_format|default:"MMM d"}}', }, }, - colors: ["#805AD5"], + legend: { + show: false, + }, chart: { zoom: { enabled: false, @@ -18,7 +20,7 @@ toolbar: { show: false, }, - type: 'area', + type: 'line', height: {{height|default:"200"}}, offsetY: -1, animations: { @@ -27,20 +29,10 @@ sparkline: { enabled: {% if sparkline %}true{% else %}false{% endif %}, }, - fill: { - type: 'gradient', - gradient: { - shadeIntensity: 1, - inverseColors: false, - opacityFrom: 0.8, - opacityTo: 0, - stops: [0, 75, 100] - }, - }, {% if granularity == "daily" and click_zoom %} events: { markerClick: function(event, chartContext, { seriesIndex, dataPointIndex, w: {config}}) { - const day = config.series[seriesIndex].data[dataPointIndex].x + const day = config.labels[dataPointIndex] window.location.href = `?startDate=${day}&endDate=${day}` }, }, @@ -79,13 +71,22 @@ }, }, stroke: { - width: 1.5, + width: 2, + curve: 'smooth', }, series: [{ - name: "{{unit|default:'Sessions'}}", - data: {{data|safe}} - }] + name: "Hits", + type: 'area', + color: "#ddd6fe", + data: {{data.hits|safe}} + }, { + name: "Sessions", + type: 'line', + color: "#805AD5", + data: {{data.sessions|safe}} + }], + labels: {{data.labels|safe}} }; var triggerMatchesChart = new ApexCharts(document.querySelector("#chart{{name|default:'Main'}}"), triggerMatchesChartOptions); triggerMatchesChart.render(); - \ No newline at end of file + diff --git a/shynet/dashboard/templates/dashboard/pages/service.html b/shynet/dashboard/templates/dashboard/pages/service.html index d249755..18fd5d8 100644 --- a/shynet/dashboard/templates/dashboard/pages/service.html +++ b/shynet/dashboard/templates/dashboard/pages/service.html @@ -94,7 +94,7 @@ {% endwith %}
- {% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data tooltip_format=stats.session_chart_tooltip_format granularity=stats.session_chart_granularity click_zoom=True %} + {% include 'dashboard/includes/time_chart.html' with data=stats.chart_data tooltip_format=stats.chart_tooltip_format granularity=stats.chart_granularity click_zoom=True %}
{% endif %}