在 Python 中记录消息日志

You can log messages from a function or procedure handler written in Python by using logging (https://docs.python.org/library/logging.html), the logging module in Python’s standard library. When you’ve set up an event table to store log entries, Snowflake stores log entries generated by your handler code in the table.

For more information about logging levels supported by Python, see the logging levels documentation (https://docs.python.org/3/library/logging.html#levels). Note that Snowflake treats two of the Python logging levels in a particular way:

  • The Python CRITICAL level will be treated as FATAL.
  • The Python NOTSET level will be treated as TRACE.

For general information about setting up logging and retrieving messages in Snowflake, see Logging messages from functions and procedures.

通过代码记录之前,您必须:

使用 Python 替换日志阈值级别

You can use Python handler code to override the log threshold levels that have been log level set with SQL. When you set the log level with Python, log entries will use the logging levels defined by Python (https://docs.python.org/3/library/logging.html#levels).

通过使用 Python 设置日志级别,您可执行以下操作:

  • 替换为 Snowflake 会话或对象(如过程或 UDF)设置的阈值。

  • 将阈值范围限定为指定的 Python 包。

    For example, you can use the logger name you set (and which is stored in the event table) to set a threshold for that logger with Python.

Python code in the following example sets the log level for the Snowpark session package to DEBUG.

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

使用记录器名称设置日志记录级别

您可以使用事件表中记录的记录器名称为该记录器中的日志条目设置阈值。当您想要设置记录器的阈值,使它过滤掉高于特定级别的不需要的日志条目时,此操作可能会很有用。

为此,您首先需要查询事件表,找出与要获取不同日志记录级别的条目相关的记录器名称。然后,使用该记录器名称将日志级别设置为所需的阈值。

Code in the following example queries for log entries, including the logger name in the returned data. You can get the name as the value of the Scope column.

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';

This query might return many entries from several loggers. If, after looking through the results, you decide that you’re getting many INFO messages that you don’t want from the numpy logger, you can use Python to set that logger’s threshold to capture log entries at the ERROR level and above.

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

For more about querying the event table, see Viewing log messages.

添加自定义属性

When you create a log entry, you can add your own attributes in key-value pairs. Snowflake saves these custom attributes to the event table’s RECORD_ATTRIBUTES column.

To add custom attributes when calling one of the logging level functions — including logger.info, logger.error, and so on — add an extra keyword argument, setting the argument’s value to the key-value pairs to record as custom attributes.

以下示例中的代码将消息“Logging with attributes”记录到事件表的 VALUE 列中。它还向 RECORD_ATTRIBUTES 列添加了两个自定义属性。

CREATE OR REPLACE PROCEDURE do_logging_python()
RETURNS VARCHAR
LANGUAGE PYTHON
PACKAGES = ('snowflake-snowpark-python')
RUNTIME_VERSION = 3.12
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"
$$;

Output of the logger.info call appears in the event table as follows. Note that the RECORD_ATTRIBUTES column will include attributes that Snowflake adds automatically.

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

Python 示例

以下各节提供了从 Python 代码中为日志记录添加支持的示例。

存储过程示例

Code in the following example imports the logging module, gets a logger, and logs a message at the INFO level.

For more information about logging levels supported by Python, see the logging levels documentation (https://docs.python.org/3/library/logging.html#levels).

CREATE OR REPLACE PROCEDURE do_logging()
RETURNS VARCHAR
LANGUAGE PYTHON
PACKAGES=('snowflake-snowpark-python')
RUNTIME_VERSION = 3.12
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.")

$$;

You can access log messages by executing a SELECT command on the event table. For more information, see Viewing log messages.

以下示例中的代码查询存储日志消息的事件表。该查询报告处理程序类中每个日志条目的严重性和消息。

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';

前面的示例生成以下输出。

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

Streamlit 示例

Code in the following example imports the logging module, gets a logger, and logs a message at the INFO level.

For more information about logging levels supported by Python, see the logging levels documentation (https://docs.python.org/3/library/logging.html#levels).

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}")