Skip to content

Cria projeto inicial para acomodar gerenciador de logs, cálculo de métricas de acesso e api sushi - #1

Merged
gitnnolabs merged 40 commits into
scieloorg:mainfrom
pitangainnovare:main
May 6, 2024
Merged

Cria projeto inicial para acomodar gerenciador de logs, cálculo de métricas de acesso e api sushi#1
gitnnolabs merged 40 commits into
scieloorg:mainfrom
pitangainnovare:main

Conversation

@pitangainnovare

@pitangainnovarepitangainnovare commented Apr 8, 2024

Copy link
Copy Markdown
Contributor

O que esse PR faz?

Este PR cria, inicialmente, uma estrutura baseada nos templates scms (core, upload, entre outros) para acomodar, numa única app, as funcionalidades de:

  1. Gerente de logs de acesso
  2. Cálculo de métricas COUNTER
  3. Disponibilização de relatórios de acesso SUSHI

Este PR abarca a construção inicial do projeto, com os apps de rastreamento de erros (tracker), execução de tarefas assíncronas (Celery), modelagem de gerente de logs (log_manager) e indexação de dados (Solr).

Por onde a revisão poderia começar?

Sugere-se revisar por commits. A partir do commit 682519d códigos novos, de fato, são adicionados ao projeto. Antes dele, alguns trechos aproveitados dos projetos core e upload são maioria - ainda assim, sugere-se também analisar os arquivos de configuração do projeto (config) e requirements.

Como este poderia ser testado manualmente?

Pode-se seguir os seguintes passos para construir e rodar a aplicação, estando na raiz do projeto:

  1. make build compose=local.yml
  2. make django_makemigrations
  3. make django_migrate
  4. make django_createsuperuser
  5. make up

Após o quinto passo, a aplicação deverá estar funcional e acessível por meio da url http://0.0.0.0:8009/admin

  1. Acesse a url http://0.0.0.0:8009/admin/
  2. Entre com as credenciais do superusuário
  3. Observe que há, no menu principal, um item chamado Log Manager, que, quando acionado, lista os cinco items seguintes: Application Configuration, Collection Configuration, Log File Dates, Log File e Log Processed Row.

Para testar a aplicação, é preciso realizar algumas adições de conteúdo, como ter uma lista de coleções e configurações associadas à aplicação e às coleções. Os passos 9 a 11 ilustram como fazer isso:

  1. Adicione coleções acessando o django shell e aproveitando-se da task da app collections
# Entre no django shell
make django_shell
# Carregue as coleções
from collection import tasks
tasks.task_load_collections(username="NOME-DO-SUPERUSER")
  1. Crie configurações para diretório de suplementos, suplementos de mapa de geolocalizações, arquivos de bots COUNTER, e extensões de log suportadas, como mostra a imagem

image

  1. Crie uma configuração de coleção para indicar qual é o diretório de arquivos de logs, como mostra a imagem seguinte

image

  1. Copie alguns arquivos de log para o diretório indicado no passo 11 (obtenha esses arquivos no servidor Matomo ou contato o autor deste PR)

image

  1. Adicione period_tasks para fazer download dos insumos de bots COUNTER e de mapa de geolocalizações (informe o parâmetro username: "SEU_NOME_DE_USUARIO" no campo keyword arguments, além dos parâmetros "url_robots" e "url_mmdb", como mostra a imagem e dicionário seguintes)

image

{
"username": "SEU_NOME_DE_USUARIO", "url_robots": "https://raw.githubusercontent.com/atmire/COUNTER-Robots/master/COUNTER_Robots_list.json", "url_mmdb": "https://download.db-ip.com/free/dbip-city-lite-2024-03.mmdb.gz",
}
  1. Entre no django_shell e execute a task discover_logs, como indicado (acesse o shell por meio de make django_shell). Também é possível configurar periodic_task, bastando acrescentar o username no campo keyword arguments.
fromlog_managerimporttasks# descubra novos logstasks.task_discover(collection_acron2="wi", username="SEU_NOME_DE_USUARIO")
# confira os logs na tela Log Files

image

  1. Valide e prorocesse logs
fromlog_managerimporttasks# valide logs para mudar o status de "CREATED" para "QUEUE" (ou "INVALIDATED")tasks.task_validate_logs(collection_acron2="wi", user_id=1)
# processo os logs em QUEUEtasks.task_parse_logs(collection_acron2="wi", username="SEU_NOME_DE_USUARIO")
# confira os resultados na tela Log Processed Row

image

  1. O último passo é indexar os dados no Solr. Faça
make django_bash
python manage.py update_index
  1. Confira os resultados no Solr

image

Algum cenário de contexto que queira dar?

N/A

Screenshots

N/A

Quais são tickets relevantes?

N/A

Referências

N/A

@gitnnolabs

gitnnolabs commented Apr 26, 2024 via email

Copy link
Copy Markdown
Contributor

Comment threadtracker/tasks.py
User = get_user_model()


def _get_user(request, username=None, user_id=None):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilizar a funcao '_get_user' que esta localizado em core/utils/utils.py e apagar esta

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essa app foi extraída do repositório core. Fiz alguns ajustes para padronizar com o sugerido. Obrigado.

Comment threadtracker/models.py
...


class EventReportDeleteEventsError(Exception):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talvez seja melhor colocar essas execeções em um arquivo excepetions.py

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concordo.

@@ -0,0 +1,24 @@
from rest_framework import serializers

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esses modulos de APi vao ser utilizados?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não no contexto da app core e sim em uma app nova (sushi).

Comment threadcollection/tasks.py

@celery_app.task(bind=True)
def task_load_collections(self, user_id=None, username=None):
if user_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilizar funcao '_get_user'

Comment threadlog_manager/models.py

@classmethod
def get(cls, config_type, sorting_field='-version_number'):
return cls.objects.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alterar o nome do método para de acordo com o função. Ou alterar a query para cls.objects.get(config_type=config_type)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preciso que seja filter. Mudarei o nome.

Comment threadlog_manager/models.py
@classmethod
def create(cls, user, config_type, value, is_enabled=True, version_number=None):
try:
last_config = cls.objects.filter(config_type=config_type).order_by('-version_number').first()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Com esse trecho de código, não acontecerá a exceção 'cls.DoesNotExist'.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdade, só ocorre com get. Obrigado. Corrigi.

Comment threadlog_manager/models.py
base_form_class = CoreAdminModelForm

panels = [
FieldPanel('collection'),

@samuelveigarangelsamuelveigarangelMay 2, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilizar AutocompletePanel.

fromwagtailautocomplete.edit_handlersimportAutocompletePanelpanels= [
AutocompletePanel("collection")
]

Comment threadlog_manager/models.py

@classmethod
def get(cls, collection_acron2, config_type, is_enabled=True):
return cls.objects.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilizar get.

@pitangainnovarepitangainnovareMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não devp, pois aqui posso obter mais de um elemento (como num outro caso já citado). Mudei o nome do método para ser mais claro. Obrigado.

Comment threadlog_manager/models.py

panel = [
FieldPanel('date'),
FieldPanel('log_file')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutocompletePanel

Comment threadlog_manager/models.py
@classmethod
def create(cls, user, collection, path, stat_result, hash, status=None):
try:
obj = cls.objects.get(hash=hash)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cls.get(hash=hash)

Comment threadlog_manager/models.py
FieldPanel('path'),
FieldPanel('stat_result'),
FieldPanel('status'),
FieldPanel('collection'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutocompletePanel

"date",
"log_file__collection",
)
search_fields = ()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correto?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sim, ficará vazio por enquanto.

Comment threadlog_manager/models.py
base_form_class = CoreAdminModelForm

panels = [
FieldPanel('log_file'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutocompletePanel

Comment threadlog_manager/tasks.py
"""
col = Collection.objects.get(acron2=collection_acron2)

col_configs_dirs = models.CollectionConfig.get(

@samuelveigarangelsamuelveigarangelMay 2, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No método de classe CollectionConfig.get(), ao mudar de filter() para get(), esse trecho de código ficaria com mais clareza e garantiria que trataremos a ausência do objeto esperado de forma explícita

try:
col_configs_dirs=models.CollectionConfig.get(
collection_acron2=collection_acron2, config_type=choices.COLLECTION_CONFIG_TYPE_DIRECTORY_LOGS,
is_enabled=is_enabled,
)
exceptmodels.CollectionConfig.DoesNotExist:
raiseexceptions.UndefinedCollectionConfigError('ERROR. Please, add a Collection Config for the Logs Directory.')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ou então utilizar filter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exato. A confusão esteve em nomear como "get" um elemento que usa filter. Corrigi o nome e creio ter ficado mais claro.

Comment threadlog_manager/utils.py


def temporal_reference_to_datetime(text):
text = text.lower()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colocar esta linha dentro do if para evitar erros de NoneType

Comment threadlog_manager/tasks.py
Returns:
None.
"""
if username:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utilizar '_get_user'

Comment threadlog_manager/tasks.py


@celery_app.task(bind=True, name=_('Create Log File'))
def task_create_log_file(self, collection, path, user_id=None, username=None):

@samuelveigarangelsamuelveigarangelMay 2, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

celery precisa serializar os argumentos para envia-los ao workers. Então, seria interessante voce passar algum identificador de collection para você obter ele dentro da task e assim passar o objeto collection para o método create()

Comment threadlog_manager/tasks.py

@celery_app.task(bind=True, name=_('Validate Log'), timelimit=-1)
def task_validate_log(self, log_file_hash, user_id=None, username=None):
if username:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utilizar '_get_user'

Comment threadlog_manager/tasks.py
Returns:
None.
"""
if username:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilizar '_get_user'

Comment threadlog_manager/tasks.py

@celery_app.task(bind=True, name=_('Download Supplies'))
def task_download_supplies(self, url_robots, url_mmdb, user_id=None, username=None):
if user_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utilizar '_get_user'

Comment threadrequirements/base.txt

# Django
# ------------------------------------------------------------------------------
django==4.2.7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Atualizar django e wagtail para versões mais recente

Comment threadlocal.yml
context: .
dockerfile: ./compose/local/django/Dockerfile
image: scielo_core_local_django
container_name: scielo_core_local_django

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mudar nome dos containers tanto em local.yml como em production.yml.
Sugestão: scielo_usage_local...

Comment threadlog_manager/tasks.py
@@ -78,3 +78,32 @@ def task_discover(self, collection_acron2, is_enabled=True, temporal_reference=N

if not (temporal_reference or from_date) or file_ctime > obj_from_date:
task_create_log_file(col, file_path, user_id, username)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task_create_log_file.apply_async(args=(collection_acron2, file_path, user_id, username))

@gitnnolabs

Copy link
Copy Markdown
Contributor

@pitangainnovare solicitei para o @samuelveigarangel realizar a validação! Assim que possível por gentileza, verifique a possibilidade dos ajustes solicitado pelo @samuelveigarangel

@gitnnolabs

Copy link
Copy Markdown
Contributor

Pessoal irei aprovar esse PR para que tenhamos um ambiente de homologação.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@pitangainnovare@gitnnolabs@samuelveigarangel@rafaelpezzuto