For AI agents: the complete documentation index is available at https://docs.ovhcloud.com/fr/llms.txt, the full documentation bundle is available at https://docs.ovhcloud.com/fr/llms-full.txt, and this page is available as Markdown at https://docs.ovhcloud.com/fr/guides/manage-and-operate/observability/logs-data-platform/logging-ldp.md.

Envoyer des logs avec une bibliothèque de logs - Python 3.x - logging-ldp

Voir en Markdown

Envoyez les logs de vos applications Python 3.x vers Logs Data Platform avec logging-ldp.

Objectif

Ce guide vous montre comment envoyer vos logs vers Logs Data Platform en utilisant Python 3.x.

logging-ldp est conçu comme un formatter et un handler de journalisation haute performance permettant d'envoyer des entrées de log vers Logs Data Platform.

Ce package inclut :

  • un handler TCP/TLS pour envoyer des entrées de log via TCP avec prise en charge de TLS.
  • un formatter pour convertir un enregistrement de log au format GELF(1.1).
  • une fonctionnalité pour s'assurer que les champs respectent les conventions de nommage LDP.

Prérequis

Pour suivre ce guide, vous aurez besoin de :

En pratique

Installation

Via pip

Vous pouvez utiliser pip pour installer logging-ldp ; veillez à utiliser la dernière version :

$ pip3 install --upgrade pip
[...]
Successfully installed pip-<version>
$ pip3 install --upgrade logging-ldp
[...]
Successfully installed logging-ldp-<version> setuptools-18.3.1

Via les sources

logging-ldp est disponible sur le dépôt GitHub d'OVH et peut être installé manuellement :

$ git clone git@github.com:ovh/python-logging-ldp.git
Cloning into 'python-logging-ldp'...
remote: Counting objects: 58, done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 58 (delta 26), reused 0 (delta 0)
Receiving objects: 100% (58/58), 9.62 KiB | 0 bytes/s, done.
Resolving deltas: 100% (26/26), done.
Checking connectivity... done.

$ cd python-logging-ldp
$ python3 setup.py install
[...]
Using /usr/lib/python3.x/site-packages
Finished processing dependencies for logging-ldp==<version>

Comment envoyer des logs

L'exemple suivant montre comment envoyer un log vers un input TCP Graylog :

import logging
from logging_ldp.formatters import LDPGELFFormatter
from logging_ldp.handlers import LDPGELFTCPSocketHandler

def setup_logging():
    handler = LDPGELFTCPSocketHandler(hostname="gra1.logs.ovh.com")
    handler.setFormatter(LDPGELFFormatter(token="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"))
    logging.getLogger().addHandler(handler)
    logging.getLogger().setLevel(logging.INFO)

if __name__ == '__main__':
    setup_logging()

    logging.info("Test !")

Envoyer des métadonnées statiques supplémentaires

Pour ajouter automatiquement des métadonnées à tous vos logs, vous pouvez implémenter un schéma alternatif :

import logging
from marshmallow import fields
from logging_ldp.formatters import LDPGELFFormatter
from logging_ldp.handlers import LDPGELFTCPSocketHandler
from logging_ldp.schemas import LDPSchema

def setup_logging():
    # Load you config there
    config = dict(name="myapp", version="0.0.1")

    # Define a custom Schema
    class MyApp(LDPSchema):
        app_name = fields.Constant(config['name'])
        app_version = fields.Constant(config['version'])

    handler = LDPGELFTCPSocketHandler(hostname="gra1.logs.ovh.com")
    handler.setFormatter(LDPGELFFormatter(token="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", schema=MyApp))
    logging.getLogger().addHandler(handler)
    logging.getLogger().setLevel(logging.INFO)

if __name__ == '__main__':
    setup_logging()

    logging.info("Test !")

L'entrée de log envoyée à Graylog ressemblera à ceci :

{
  "_app_name": "myapp",
  "_app_version": "0.0.1",
  "_X-OVH-TOKEN": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "file": "test_thread.py",
  "host": "cdumay-desk",
  "level": 6,
  "line": 36,
  "short_message": "Test !",
  "timestamp": 1556036745.6493497,
  "version": "1.1"
}

Remarque : le résultat n'est présenté « pretty printed » que pour la documentation.

Envoyer des métadonnées intermittentes supplémentaires

Pour définir des métadonnées occasionnelles, vous pouvez définir un schéma avec des sous-éléments imbriqués (Nested) :

import logging
from marshmallow import Schema, fields
from logging_ldp.formatters import LDPGELFFormatter
from logging_ldp.handlers import LDPGELFTCPSocketHandler
from logging_ldp.schemas import LDPSchema

# Define a sub-schema
class User(Schema):
    name = fields.String(required=True)
    age = fields.Integer()

# Définir un schéma personnalisé à appliquer aux entrées de log
class AccountInfo(LDPSchema):
    user = fields.Nested(User, required=True)
    manager = fields.Nested(User)

def setup_logging():
    handler = LDPGELFTCPSocketHandler(hostname="gra1.logs.ovh.com")
    handler.setFormatter(LDPGELFFormatter(
        token="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        schema=AccountInfo
    ))
    logging.getLogger().addHandler(handler)
    logging.getLogger().setLevel(logging.INFO)

if __name__ == '__main__':
    setup_logging()

    current_user = dict(name="John Doe")
    boss = dict(name="Roger Smith", age=51)
    logging.info("User has logged", extra=dict(user=current_user, manager=boss))

L'entrée de log envoyée sera :

{
  "_manager_age_int": 51,
  "_manager_name": "Roger Smith",
  "_user_name": "John Doe",
  "_X-OVH-TOKEN": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "file": "test_thread.py",
  "host": "cdumay-desk",
  "level": 6,
  "line": 40,
  "short_message": "User has logged",
  "timestamp": 1556037587.4444475,
  "version": "1.1"
}

Comme on peut le constater :

  • Les objets sont aplatis en dictionnaires : manager.name devient manager_name.
  • Les champs sont typés selon la convention de nommage LDP : manager.age devient manager_age_int.
  • Les valeurs nulles ne sont pas envoyées : user.age.
  • Vous pouvez définir required=True pour rendre une métadonnée obligatoire, ou default=xxx pour ajouter une donnée automatiquement.

Aller plus loin

Cette page vous a-t-elle aidé ?