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 intoscieloorg: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 intoscieloorg:mainfrom
pitangainnovare:main

Conversation

@pitangainnovare
Copy link
Contributor

@pitangainnovare pitangainnovare commented Apr 8, 2024

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.
from log_manager import tasks

# descubra novos logs
tasks.task_discover(collection_acron2="wi", username="SEU_NOME_DE_USUARIO")

# confira os logs na tela Log Files

image

  1. Valide e prorocesse logs
from log_manager import tasks

# 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 QUEUE
tasks.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
Copy link
Contributor

gitnnolabs commented Apr 26, 2024 via email

User = get_user_model()


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

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
Contributor Author

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.

...


class EventReportDeleteEventsError(Exception):

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
Contributor Author

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

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
Contributor Author

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).


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

Choose a reason for hiding this comment

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

Utilizar funcao '_get_user'


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

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
Contributor Author

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.

@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()

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
Contributor Author

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.

base_form_class = CoreAdminModelForm

panels = [
FieldPanel('collection'),
Copy link

@samuelveigarangel samuelveigarangel May 2, 2024

Choose a reason for hiding this comment

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

Utilizar AutocompletePanel.

from wagtailautocomplete.edit_handlers import AutocompletePanel
panels = [
     AutocompletePanel("collection")
]


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

Choose a reason for hiding this comment

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

Utilizar get.

Copy link
Contributor Author

@pitangainnovare pitangainnovare May 9, 2024

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.


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

Choose a reason for hiding this comment

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

AutocompletePanel

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

Choose a reason for hiding this comment

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

cls.get(hash=hash)

FieldPanel('path'),
FieldPanel('stat_result'),
FieldPanel('status'),
FieldPanel('collection'),

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 = ()

Choose a reason for hiding this comment

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

Correto?

Copy link
Contributor Author

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.

base_form_class = CoreAdminModelForm

panels = [
FieldPanel('log_file'),

Choose a reason for hiding this comment

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

AutocompletePanel

"""
col = Collection.objects.get(acron2=collection_acron2)

col_configs_dirs = models.CollectionConfig.get(
Copy link

@samuelveigarangel samuelveigarangel May 2, 2024

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,
    )
except models.CollectionConfig.DoesNotExist:
        raise exceptions.UndefinedCollectionConfigError('ERROR. Please, add a Collection Config for the Logs Directory.')

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
Contributor Author

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.



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

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

Returns:
None.
"""
if username:

Choose a reason for hiding this comment

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

utilizar '_get_user'



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

@samuelveigarangel samuelveigarangel May 2, 2024

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()


@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:

Choose a reason for hiding this comment

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

utilizar '_get_user'

Returns:
None.
"""
if username:

Choose a reason for hiding this comment

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

Utilizar '_get_user'


@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:

Choose a reason for hiding this comment

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

utilizar '_get_user'


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

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

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

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...

@@ -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)

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
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
Contributor

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

@gitnnolabs gitnnolabs merged commit 00bb1d7 into scieloorg:main May 6, 2024
pitangainnovare added a commit that referenced this pull request May 10, 2024
Aplica correções sugeridas pela revisão realizada no Pull Request #1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants