-
Notifications
You must be signed in to change notification settings - Fork 10
Suprime envio de erros por email e adiciona registro opcional de logs no OpenSearch (com infra de dev e índices por ambiente) #1432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0e556b3
72cf71c
4dda20f
1bc0532
6d63626
3abcea3
9fe8765
7db098f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,307 @@ | ||||||
| """ | ||||||
| Custom logging handlers for the SciELO Content Manager. | ||||||
|
|
||||||
| This module provides an OpenSearch logging handler that ships log records | ||||||
| to an OpenSearch cluster. It is intentionally tolerant of failures: any | ||||||
| error while contacting OpenSearch is suppressed (and reported to | ||||||
| ``sys.stderr`` via ``logging.Handler.handleError``) so that logging never | ||||||
| disrupts the application. | ||||||
|
|
||||||
| Activation is controlled by the project's ``LOGGING`` configuration; when | ||||||
| OpenSearch is not enabled, loggers fall back to the console handler. | ||||||
|
|
||||||
| Usage from application code | ||||||
| --------------------------- | ||||||
|
|
||||||
| The handler is wired in ``config/settings/*.py`` and attached to the root | ||||||
| and ``django`` loggers automatically when enabled, so application code | ||||||
| just uses the standard :mod:`logging` API. Both plain messages and | ||||||
| structured fields are supported: | ||||||
|
|
||||||
| .. code-block:: python | ||||||
|
|
||||||
| import logging | ||||||
|
|
||||||
| logger = logging.getLogger(__name__) | ||||||
|
|
||||||
| # Plain message — indexed with the default fields (@timestamp, level, | ||||||
| # logger, message, module, func_name, line_no, host, service, | ||||||
| # environment, ...). | ||||||
| logger.info("user logged in") | ||||||
|
|
||||||
| # Message with positional arguments (Python's standard interpolation). | ||||||
| logger.warning("slow query took %.2fs on table=%s", 1.23, "article") | ||||||
|
|
||||||
| # Structured/contextual fields via ``extra={...}``. Any keys passed in | ||||||
| # ``extra`` that are not standard ``LogRecord`` attributes are added | ||||||
| # as top-level fields on the OpenSearch document, which makes them | ||||||
| # filterable in dashboards (e.g. by ``user_id`` or ``request_id``). | ||||||
| logger.info( | ||||||
| "imported article", | ||||||
| extra={ | ||||||
| "user_id": user.id, | ||||||
| "article_pid": article.pid, | ||||||
| "request_id": request_id, | ||||||
| "duration_ms": duration_ms, | ||||||
| }, | ||||||
| ) | ||||||
|
|
||||||
| # Exceptions are captured automatically with a full traceback when | ||||||
| # ``exc_info=True`` (or when using ``logger.exception(...)`` inside | ||||||
| # an ``except`` block). | ||||||
| try: | ||||||
| do_something() | ||||||
| except Exception: | ||||||
| logger.exception( | ||||||
| "import failed", | ||||||
| extra={"article_pid": pid, "stage": "xml_parse"}, | ||||||
| ) | ||||||
|
|
||||||
| The ``service`` and ``environment`` fields (configured globally via | ||||||
| ``OPENSEARCH_LOGGING_ENVIRONMENT`` in settings) are merged into every | ||||||
| document, so each environment writes to a clearly identified, separate | ||||||
| index (e.g. ``core-logs-prod-YYYY.MM.DD`` vs ``core-logs-dev-YYYY.MM.DD``) | ||||||
| and also carries the ``environment`` field inside the document itself. | ||||||
| """ | ||||||
| from __future__ import annotations | ||||||
|
|
||||||
| import atexit | ||||||
| import logging | ||||||
| import os | ||||||
| import queue | ||||||
| import socket | ||||||
| import threading | ||||||
| from datetime import datetime, timezone | ||||||
| from typing import Any, Iterable, Optional | ||||||
|
|
||||||
|
|
||||||
| class OpenSearchLogHandler(logging.Handler): | ||||||
| """A non-blocking logging handler that ships records to OpenSearch. | ||||||
|
|
||||||
| Records are placed on an in-memory queue and shipped by a background | ||||||
| daemon thread using ``opensearch-py``. The handler never raises: | ||||||
| connection or indexing errors are routed through | ||||||
| :meth:`logging.Handler.handleError` so the application is never | ||||||
| impacted by logging failures. | ||||||
|
|
||||||
| Parameters | ||||||
| ---------- | ||||||
| hosts: | ||||||
| Iterable of hosts (strings such as ``"https://os.example.org:9200"`` | ||||||
| or dicts accepted by :class:`opensearchpy.OpenSearch`). When empty | ||||||
| or ``None`` the handler is a no-op. | ||||||
| index: | ||||||
| Index name (or index name prefix when ``index_date_format`` is | ||||||
| set) used to store the log documents. | ||||||
| index_date_format: | ||||||
| Optional ``strftime`` format string. When set, the daily/monthly | ||||||
| index name is built as | ||||||
| ``f"{index}-{datetime.now(timezone.utc):format}"``. | ||||||
| http_auth: | ||||||
| Optional ``(user, password)`` tuple used for basic auth. | ||||||
| use_ssl: | ||||||
| Whether to use HTTPS (default ``True``). | ||||||
| verify_certs: | ||||||
| Whether to verify TLS certificates (default ``True``). | ||||||
| extra_fields: | ||||||
| Optional mapping merged into every log document (useful for | ||||||
| environment / service tags). | ||||||
| queue_size: | ||||||
| Maximum number of buffered records. Older records are dropped | ||||||
|
||||||
| Maximum number of buffered records. Older records are dropped | |
| Maximum number of buffered records. New records are dropped |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adicione exemplos de como utilizar essa classe para registra logs no código.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Adicione exemplos de como utilizar essa classe para registra logs no código.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feito em 1bc0532. Adicionei uma seção "Usage from application code" no docstring de
config/logging_handlers.pycom exemplos cobrindo: mensagem simples (logger.info(...)), interpolação com argumentos (logger.warning("took %.2fs", x)), campos estruturados viaextra={"user_id": ..., "request_id": ...}(promovidos automaticamente para top-level no documento OpenSearch), e captura de exceções comlogger.exception(..., extra={...}).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Já implementado em 1bc0532. Veja o docstring do módulo
config/logging_handlers.py— seção "Usage from application code" cobre: mensagem simples (logger.info(...)), interpolação posicional (logger.warning("took %.2fs on %s", x, table)), campos estruturados viaextra={"user_id": ..., "request_id": ...}(promovidos automaticamente para top-level), e captura de exceções comlogger.exception("...", extra={...}).