You can log messages from a function or procedure handler written in Scala by using the SLF4J API. When you’ve
set up an event table to store log entries, Snowflake stores log
entries generated by your handler code in the table.
You can use the SLF4J API included with the Snowflake Telemetry library included on Snowflake. To do so, include the following
value in the PACKAGES clause when you create the function or procedure: com.snowflake:telemetry:latest.
Using the Snowflake Telemetry Library adds other libraries to your function or procedure’s execution environment. For more information,
see Snowflake telemetry package dependencies.
Note
SLF4J does not support logging messages at the FATAL level. For handlers written in Java or Scala, the FATAL level is
treated as the ERROR level.
For example, if you set the LOG_LEVEL parameter to FATAL, ERROR-level messages from a Java or Scala
handler are ingested.
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, call methods of the slf4j fluent API, such as Logger.atInfo and Logger.atError. Use these
methods to set key-value pairs in the log entry. Each returns an org.slf4j.spi.LoggingEventBuilder, which you can use to set the
log message.
Code in the following example logs a message “Logging with attributes” to the event table’s VALUE column. It also adds a custom
attribute to the RECORD_ATTRIBUTES column.
CREATE OR REPLACEPROCEDURE do_logging_scala()RETURNSVARCHARLANGUAGESCALARUNTIME_VERSION='2.12'PACKAGES=('com.snowflake:telemetry:latest','com.snowflake:snowpark_2.12:latest')HANDLER='ScalaLoggingHandler.doThings'AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Sessionclass ScalaLoggingHandler {private val logger: Logger = LoggerFactory.getLogger(getClass)
def doThings(session: Session):String={
logger.atInfo().addKeyValue("custom1","value1").setMessage("Logging with attributes").log();return"SUCCESS"}}
$$;
CREATE OR REPLACEPROCEDURE do_logging_scala()RETURNSVARCHARLANGUAGESCALARUNTIME_VERSION='2.13'PACKAGES=('com.snowflake:telemetry:latest','com.snowflake:snowpark_2.13:latest')HANDLER='ScalaLoggingHandler.doThings'AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Sessionclass ScalaLoggingHandler {private val logger: Logger = LoggerFactory.getLogger(getClass)
def doThings(session: Session):String={
logger.atInfo().addKeyValue("custom1","value1").setMessage("Logging with attributes").log();return"SUCCESS"}}
$$;
Output of this Logger.atInfo call appears in the event table as follows. Note that the RECORD_ATTRIBUTES column will include
attributes that Snowflake adds automatically.
Code in the following example imports references the Snowflake Telemetry library and from it gets a logger. It logs a message at the
INFO level. It also logs an error for an exception.
For more information about the methods you can use to log at specific levels, see SLF4J methods.
CREATE OR REPLACEPROCEDURE do_logging()RETURNSVARCHARLANGUAGESCALARUNTIME_VERSION='2.12'PACKAGES=('com.snowflake:snowpark_2.12:latest','com.snowflake:telemetry:latest')HANDLER='ScalaLoggingHandler.doThings'AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Sessionclass ScalaLoggingHandler {private val logger: Logger = LoggerFactory.getLogger(getClass)
logger.info("Logging from within the Scala constructor.")
def doThings(session: Session):String={
logger.info("Logging from Scala method start.")
try {
throwException
} catch {case e: Exception => logger.error("Logging an error from Scala handler: "+ e.getMessage())return"ERROR"}return"SUCCESS"}// Simulate a thrown exceptionto catch.@throws(classOf[Exception])private def throwException ={
throw new Exception("Something went wrong.")}}
$$
;
CREATE OR REPLACEPROCEDURE do_logging()RETURNSVARCHARLANGUAGESCALARUNTIME_VERSION='2.13'PACKAGES=('com.snowflake:snowpark_2.13:latest','com.snowflake:telemetry:latest')HANDLER='ScalaLoggingHandler.doThings'AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Sessionclass ScalaLoggingHandler {private val logger: Logger = LoggerFactory.getLogger(getClass)
logger.info("Logging from within the Scala constructor.")
def doThings(session: Session):String={
logger.info("Logging from Scala method start.")
try {
throwException
} catch {case e: Exception => logger.error("Logging an error from Scala handler: "+ e.getMessage())return"ERROR"}return"SUCCESS"}// Simulate a thrown exceptionto catch.@throws(classOf[Exception])private def throwException ={
throw new 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.
Code in the following example queries the event table where the log messages are stored. The query reports on the severity and message of
each log entry from the handler class.
SET event_table_name='my_db.public.my_event_table';SELECTRECORD['severity_text']ASSEVERITY,VALUEASMESSAGEFROMIDENTIFIER($event_table_name)WHERESCOPE['name']='ScalaLoggingHandler'ANDRECORD_TYPE='LOG';
The preceding example generates the following output.
---------------------------------------------------------------------------
| SEVERITY | MESSAGE |
---------------------------------------------------------------------------
| "INFO" | "Logging from within the Scala constructor." |
---------------------------------------------------------------------------
| "INFO" | "Logging from Scala method start." |
---------------------------------------------------------------------------
| "ERROR" | "Logging an error from Scala handler: Something went wrong." |
---------------------------------------------------------------------------