Journalisation des messages en Python

Vous pouvez enregistrer les messages d’une fonction ou d’un gestionnaire de procédure écrit en Python en utilisant la journalisation, le module de journalisation de la bibliothèque standard de Python. Lorsque vous avez configuré une table d’événements pour stocker les entrées de journal, Snowflake stocke les entrées de journal générées par votre code de gestionnaire dans la table.

Pour plus d’informations sur les niveaux de journalisation pris en charge par Python, voir la documentation sur les niveaux de journalisation. Notez que Snowflake traite deux des niveaux de journalisation de Python d’une manière particulière :

  • Le niveau CRITICAL de Python sera traité comme FATAL.

  • Le niveau NOTSET de Python sera traité comme TRACE.

Pour des informations générales sur la configuration de la journalisation et la récupération des messages dans Snowflake, voir Enregistrement de messages à partir de fonctions et de procédures.

Avant de journaliser à partir d’un code, vous devez :

Remplacement des niveaux de seuil de journalisation avec Python

Vous pouvez utiliser le code du gestionnaire Python pour remplacer les niveaux de seuil de journalisation qui ont été définis avec SQL. Lorsque vous définissez le niveau de journalisation avec Python, les entrées de journalisation utiliseront les niveaux de journalisation définis par Python.

En définissant des niveaux de journalisation en Python, vous pouvez effectuer les opérations suivantes :

  • Remplacer le seuil défini pour la session Snowflake ou pour des objets tels que la procédure ou l’UDF.

  • Définir des seuils pour des paquets Python spécifiés.

    Par exemple, vous pouvez utiliser le nom du journaliseur que vous avez défini (et qui est stocké dans la table d’événements) pour définir un seuil pour ce journaliseur avec Python.

Le code Python de l’exemple suivant définit le niveau de journalisation pour le paquet session Snowpark pour DEBUG.

session_logger = logging.getLogger('snowflake.snowpark.session')
session_logger.setLevel(logging.DEBUG)
Copy

Utilisation du nom du journaliseur pour définir le niveau de journalisation

Vous pouvez utiliser le nom du journaliseur enregistré dans la table d’événements pour définir un seuil pour les entrées de journalisation de ce journaliseur. Cela peut s’avérer utile lorsque vous souhaitez définir le seuil d’un journaliseur de manière à ce qu’il filtre les entrées d’enregistrement indésirables dépassant un certain niveau.

Pour ce faire, vous devez d’abord interroger la table d’événements pour découvrir le nom du journaliseur associé aux entrées pour lesquelles vous souhaitez capturer un niveau de journalisation différent. Ensuite, en utilisant le nom du journaliseur, vous définissez le niveau de journalisation au seuil que vous souhaitez.

Le code de l’exemple suivant demande des entrées de journal, en incluant le nom du journaliseur dans les données renvoyées. Vous pouvez obtenir le nom comme valeur de la colonne de portée.

SET event_table_name='my_db.public.my_event_table';

SELECT
  TIMESTAMP as time,
  RECORD['severity_text'] as log_level,
  SCOPE['name'] as logger_name,
  VALUE as message
FROM
  IDENTIFIER($event_table_name)
WHERE
  RECORD_TYPE = 'LOG';
Copy

Cette requête peut renvoyer de nombreuses entrées provenant de plusieurs journaliseurs. Si, après avoir examiné les résultats, vous décidez que vous obtenez de nombreux messages INFO que vous ne souhaitez pas recevoir du journaliseur numpy, vous pouvez utiliser Python pour définir le seuil de ce journaliseur afin de capturer les entrées de journal au niveau ERROR et au-dessus.

numpy_logger = logging.getLogger('numpy_logs')
numpy_logger.setLevel(logging.ERROR)
Copy

Pour en savoir plus sur l’interrogation de la table d’événements, voir Affichage des messages de journalisation.

Ajout d’attributs personnalisés

Lorsque vous créez une entrée de journal, vous pouvez ajouter vos propres attributs dans des paires clé-valeur. Snowflake enregistre ces attributs personnalisés dans la colonne RECORD_ATTRIBUTES de la table des événements.

Pour ajouter des attributs personnalisés lors de l’appel de l’une des fonctions de niveau de journalisation — y compris logger.info, logger.error, et ainsi de suite — ajoutez un argument de mot-clé extra, définissant la valeur de l’argument sur les paires clé-valeur à enregistrer en tant qu’attributs personnalisés.

Le code de l’exemple suivant enregistre un message « Logging with attributes » dans la colonne VALUE de la table des événements. Cela ajoute également deux attributs personnalisés à la colonne RECORD_ATTRIBUTES.

CREATE OR REPLACE PROCEDURE do_logging_python()
RETURNS VARCHAR
LANGUAGE PYTHON
PACKAGES = ('snowflake-snowpark-python')
RUNTIME_VERSION = 3.9
HANDLER = 'do_things'
AS $$
import logging

logger = logging.getLogger("python_logger")

def do_things(session):

  logger.info("Logging with attributes in SP", extra = {'custom1': 'value1', 'custom2': 'value2'})

  return "SUCCESS"
$$;
Copy

La sortie de l’appel logger.info apparaît dans la table des événements comme suit. Notez que la colonne RECORD_ATTRIBUTES comprendra les attributs que Snowflake ajoute automatiquement.

---------------------------------------------------------------------
| VALUE                        | RECORD_ATTRIBUTES                  |
---------------------------------------------------------------------
| "Logging with attributes in" | {                                  |
|                              |   "code.filepath": "_udf_code.py", |
|                              |   "code.function": "do_things",    |
|                              |   "code.lineno": 10,               |
|                              |   "custom1": "value1",             |
|                              |   "custom2": "value2"              |
|                              | }                                  |
---------------------------------------------------------------------

Exemples Python

Les sections suivantes fournissent des exemples d’ajout de la prise en charge de la journalisation à partir du code Python.

Exemple de procédure stockée

Le code de l’exemple suivant importe le module logging, obtient un enregistreur et enregistre un message au niveau INFO.

Pour plus d’informations sur les niveaux de journalisation pris en charge par Python, voir la documentation sur les niveaux de journalisation.

CREATE OR REPLACE PROCEDURE do_logging()
RETURNS VARCHAR
LANGUAGE PYTHON
PACKAGES=('snowflake-snowpark-python')
RUNTIME_VERSION = 3.9
HANDLER='do_things'
AS $$
import logging

logger = logging.getLogger("python_logger")
logger.info("Logging from Python module.")

def do_things(session):
  logger.info("Logging from Python function start.")

  try:
    throw_exception()
  except Exception:
    logger.error("Logging an error from Python handler: ")
    return "ERROR"

  return "SUCCESS"

def throw_exception():
  raise Exception("Something went wrong.")

$$;
Copy

Vous pouvez accéder aux messages du journal en exécutant une commande SELECT sur la table d’événements. Pour plus d’informations, voir Affichage des messages de journalisation.

Le code de l’exemple suivant interroge la table d’événements dans laquelle sont stockés les messages du journal. La requête indique la gravité et le message de chaque entrée de journal de la classe du gestionnaire.

SET event_table_name='my_db.public.my_event_table';

SELECT
  RECORD['severity_text'] AS SEVERITY,
  VALUE AS MESSAGE
FROM
  IDENTIFIER($event_table_name)
WHERE
  SCOPE['name'] = 'python_logger'
  AND RECORD_TYPE = 'LOG';
Copy

L’exemple précédent génère la sortie suivante.

---------------------------------------------------------------------------
| SEVERITY | MESSAGE                                                      |
---------------------------------------------------------------------------
| "INFO"   | "Logging from Python module."                                |
---------------------------------------------------------------------------
| "INFO"   | "Logging from Python function start."                        |
---------------------------------------------------------------------------
| "ERROR"  | "Logging an error from Python handler."                      |
---------------------------------------------------------------------------

Exemples Streamlit

Le code de l’exemple suivant importe le module logging, obtient un enregistreur et enregistre un message au niveau INFO.

Pour plus d’informations sur les niveaux de journalisation pris en charge par Python, voir la documentation sur les niveaux de journalisation.

import streamlit as st
import logging

logger = logging.getLogger('app_logger')

st.title("Streamlit logging example")

hifives_val = st.slider("Number of high-fives", min_value=0, max_value=90, value=60)

if st.button("Submit"):
    logger.info(f"Submitted with high-fives: {hifives_val}")
Copy