-
Notifications
You must be signed in to change notification settings - Fork 12
Log Guide [PT BR]
O sistema de log é usado para coletar informações importantes sobre o perfil dos usuários do Amadeus, possibilitando conhecer quais partes são mais acessadas e quanto tempo são gasto nelas, entre outras coisas. Com essas informações nós somos capazes de melhorar o aprendizado dos estudantes dando à ele direções (dicas) para aumentar suas notas.
Para ser capaz de usar o sistema de log você precisará importar no arquivo views.py do seu app os seguintes pacotes:
- LogMixin de core.mixins: usado para ativar o sistema de log em Class-Based Views;
- log_decorator de core.decorators: usado para ativar o sistema de log em Function-Based Views;
- log_decorator_ajax de core.decorators: usado para ativar o sistema de log em Function-Based Views que são ativados por componentes ajax como accordion ou collapse no caso de você precisar armazenar quanto tempo o usuário passou com aquele componente aberto;
- Log from core.models: usado caso você necessite armazenar o tempo gasto pelo usuário na página;
-
Class-Based Views:
-
Primeiro você precisa fazer sua classe extender LogMixin:
class MyView(..., LogMixin,...):
-
Fazendo isso os seguintes atributos ficaram disponíveis para a sua classe:
- log_action - Uma string que indica qual foi a ação do usuário (Padrão em inglês) (Ex.: viewed, create, update...)
- log_resource - Uma string que indica qual foi o recurso (i.e. setor do app) ao qual o usuário realizou a ação (Ex.: forum, course, topic...)
- log_component - Uma string que indica qual foi o app ao qual o usuário realizou a ação (O nome da app)
- log_context - Um dicionário que armazena toda informação relevante sobre o contexto do recurso, como todo o caminho para chegar até ele, e informações específicas do recurso.
Em código:
class MyView(..., LogMixin,...): log_action = "" log_resource = "" log_component = "" log_context = {} #outros atributos
Obs.: O atributo log_context deve ser explicitamente declarado na sessão de atributos da classe para ser acessado nos métodos da classe para populá-lo. Para seu preenchimento você pode usar qualquer método da Class-Based View (form_valid, dispatch, get_success_url) desde que você tenha toda a informação necessária nele. Em código:
class MyView(..., LogMixin,...): #definicoes de atributos e outros metodos def get_success_url(self): #alguma rotina/definicoes self.log_context['key'] = value #possivelmente mais informacoes de log_context #outras rotinas/definicoes do metodo
Obs².: Toda informação colocada no log_context deve serializável para json (É recomendável usar apenas strings)
-
Com esses atributos preenchidos você precisará chamar em um dos seus métodos (o mesmo que você usou para preencher o log_context) a seguinte função:
super(ClassViewName, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
Essa função recebe como parâmetro todos os atributos de log que estão disponíveis através da adição do LogMixin e o usuário que fez a requisição. É importante garantir que o usuário não seja um usuário anônimo o que pode ser feito pela adição do LoginRequiredMixin (Veja a documentação do Django para mais informações).
-
Para armazenar o tempo gasto pelo usuário naquele recurso você precisa:
- Adicionar isso em seu log_context:
self.log_context['timestamp_start'] = str(int(time.time()))
- Adicionar essa linha depois de chamar a função createLog:
self.request.session['log_id'] = Log.objects.latest('id').id
-
Aqui está um exemplo completo de como ficaria o código:
import time from django.shortcuts import render, get_object_or_404 from django.core.urlresolvers import reverse, reverse_lazy from core.models import Log from core.mixins import LogMixin from .forms import ForumForm from .models import Forum class CreateForumView(LoginRequiredMixin, generic.edit.CreateView, LogMixin): log_component = "forum" log_action = "create" log_resource = "forum" log_context = {} login_url = reverse_lazy("core:home") redirect_field_name = 'next' template_name = 'forum/forum_form.html' form_class = ForumForm def get_success_url(self): self.success_url = reverse('course:forum:render_forum', args = (self.object.id, )) #Nesse caso 'Forum' tem uma relacao com 'topic' (Voce precisa acessar um topic para alcancar o forum) #Entao informacao sobre o topic do forum é fornecida ao log_context self.log_context['forum_id'] = self.object.id self.log_context['forum_name'] = self.object.name self.log_context['topic_id'] = self.object.topic.id self.log_context['topic_name'] = self.object.topic.name self.log_context['topic_slug'] = self.object.topic.slug super(CreateForumView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context) return self.success_url class ForumDetailView(LoginRequiredMixin, LogMixin, generic.DetailView): log_component = "forum" log_action = "viewed" log_resource = "forum" log_context = {} login_url = reverse_lazy("core:home") redirect_field_name = 'next' model = Forum template_name = 'forum/forum_view.html' context_object_name = 'forum' def dispatch(self, *args, **kwargs): forum = get_object_or_404(Forum, slug = self.kwargs.get('slug')) #Nesse caso 'Forum' tem uma relacao com 'topic' (Voce precisa acessar um topic para alcancar o forum) #Entao informacao sobre o topic do forum é fornecida ao log_context self.log_context['forum_id'] = forum.id self.log_context['forum_name'] = forum.name self.log_context['topic_id'] = forum.topic.id self.log_context['topic_name'] = forum.topic.name self.log_context['topic_slug'] = forum.topic.slug self.log_context['timestamp_start'] = str(int(time.time())) super(ForumDetailView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context) self.request.session['log_id'] = Log.objects.latest('id').id return super(ForumDetailView, self).dispatch(*args, **kwargs) def get_context_data(self, **kwargs): context = super(ForumDetailView, self).get_context_data(**kwargs) forum = get_object_or_404(Forum, slug = self.kwargs.get('slug')) context['forum'] = forum return context
-
-
Function-Based Views:
-
Para ter o sistema de log funcionando com function-based views tudo que você precisa fazer é adicionar o seguinte decorator:
@log_decorator("", "", "")
Nele, o primeiro parâmetro se refere ao log_component; o segundo ao log_action; e o terceiro ao log_resource;
Obs.: Para preencher o log_context tudo que você precisa é, no corpo da sua função, adicioná-lo ao parâmetro "log_context" do request. Em código:
log_context = {} log_context['course_id'] = course.id log_context['course_name'] = course.name log_context['course_slug'] = course.slug log_context['course_category_id'] = course.category.id log_context['course_category_name'] = course.category.name request.log_context = log_context
O código completo seria algo como isso:
#imports e outras funcoes @log_decorator("course", "subscribe", "course") def subscribe_course(request, slug): course = get_object_or_404(Course, slug = slug) course.students.add(request.user) log_context = {} log_context['course_id'] = course.id log_context['course_name'] = course.name log_context['course_slug'] = course.slug log_context['course_category_id'] = course.category.id log_context['course_category_name'] = course.category.name request.log_context = log_context return JsonResponse({"status": "ok", "message": _("Successfully subscribed to the course!")})
-
Se você quiser armazenar o tempo gasto pelo usuário você precisará mudar o decorator para:
Obs.: Isso é recomendado para requisições ajax, se esse não for o caso você deveria considerar usar Class-Based Views.@log_decorator_ajax("", "", "")
Obs.: Os parâmetros são os mesmos de log_decorator.
Somado a isso você precisará adicionar em seu log_context:
log_context['timestamp_start'] = str(int(time.time())) log_context['timestamp_end'] = "-1"
E pegar o último id de log generado para passar para o response:
log_id = Log.objects.latest('id').id response = JsonResponse({"message": "ok", "log_id": log_id})
O código completo seria algo similiar a isso:
@log_decorator_ajax("courses", "viewed", "topic") def topic_log(request, topic): topic = get_object_or_404(Topic, id = topic) log_context = {} log_context['topic_id'] = topic.id log_context['topic_name'] = topic.name log_context['topic_slug'] = topic.slug log_context['subject_id'] = topic.subject.id log_context['subject_name'] = topic.subject.name log_context['subject_slug'] = topic.subject.slug log_context['timestamp_start'] = str(int(time.time())) log_context['timestamp_end'] = "-1" request.log_context = log_context log_id = Log.objects.latest('id').id response = JsonResponse({"message": "ok", "log_id": log_id}) return response
-