Scala์์ ๋ฉ์์ง ๋ก๊น ํ๊ธฐยถ
SLF4J API ๋ฅผ ์ฌ์ฉํ์ฌ Scala๋ก ์์ฑ๋ ํจ์ ๋๋ ํ๋ก์์ ์ฒ๋ฆฌ๊ธฐ์ ๋ฉ์์ง๋ฅผ ๋ก๊น ํ ์ ์์ต๋๋ค. ๋ก๊ทธ ํญ๋ชฉ์ ์ ์ฅํ๋๋ก ์ด๋ฒคํธ ํ ์ด๋ธ์ ์ค์ ํ๋ฉด Snowflake๊ฐ ์ฒ๋ฆฌ๊ธฐ ์ฝ๋์์ ์์ฑ๋ ๋ก๊ทธ ํญ๋ชฉ์ ํ ์ด๋ธ์ ์ ์ฅํฉ๋๋ค.
Snowflake์ ํฌํจ๋ Snowflake ์๊ฒฉ ๋ถ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ ๊ณต๋๋ SLF4J API ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ ค๋ฉด ํจ์๋ ํ๋ก์์ ๋ฅผ ๋ง๋ค ๋ PACKAGES ์ ์ com.snowflake:telemetry:latest
๊ฐ์ ํฌํจํ์ญ์์ค.
Maven์ผ๋ก ์ฝ๋๋ฅผ ํจํค์งํ ๋ Telemetry ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํฌํจํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์๊ฒฉ ๋ถ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋๋ก Java ๋ฐ Scala ํ๊ฒฝ ์ค์ ํ๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ฐธ๊ณ
Snowflake ์๊ฒฉ ๋ถ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ํจ์ ๋๋ ํ๋ก์์ ์ ์คํ ํ๊ฒฝ์ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ Snowflake ์๊ฒฉ ๋ถ์ ํจํค์ง ์ข ์์ฑ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ฐธ๊ณ
SLF4J๋ FATAL
์์ค์์ ๋ฉ์์ง ๋ก๊น
์ ์ง์ํ์ง ์์ต๋๋ค. Java ๋๋ Scala๋ก ์์ฑ๋ ์ฒ๋ฆฌ๊ธฐ์ ๊ฒฝ์ฐ FATAL
์์ค์ ERROR
์์ค์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด LOG_LEVEL
๋งค๊ฐ ๋ณ์๋ฅผ FATAL
๋ก ์ค์ ํ๋ฉด Java ๋๋ Scala ์ฒ๋ฆฌ๊ธฐ์ ERROR
์์ค ๋ฉ์์ง๊ฐ ์์ง๋ฉ๋๋ค.
Snowflake์์ ๋ก๊น ์ค์ ๋ฐ ๋ฉ์์ง ๊ฒ์์ ๋ํ ์ผ๋ฐ์ ์ธ ์ ๋ณด๋ ํจ์ ๋ฐ ํ๋ก์์ ์ ๋ฉ์์ง ๋ก๊น ํ๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ฝ๋์์ ๋ก๊น ํ๊ธฐ ์ ์ ๋ค์์ ์ํํด์ผ ํฉ๋๋ค.
์ฒ๋ฆฌ๊ธฐ ์ฝ๋์์ ๋ก๊น ๋ ๋ฉ์์ง๋ฅผ ์์งํ๋๋ก ์ด๋ฒคํธ ํ ์ด๋ธ์ ์ค์ ํฉ๋๋ค.
์์ธํ ๋ด์ฉ์ ์ด๋ฒคํธ ํ ์ด๋ธ ๊ฐ์ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ํ๋ ๋ฉ์์ง๊ฐ ์ด๋ฒคํธ ํ ์ด๋ธ์ ์ ์ฅ๋๋๋ก ๋ก๊น ์์ค์ ์ค์ ํ๋์ง ํ์ธํฉ๋๋ค.
์์ธํ ๋ด์ฉ์ ๋ก๊น , ๋ฉํธ๋ฆญ ๋ฐ ์ถ์ ์ ์ํ ์์ค ์ค์ ํ๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ฌ์ฉ์ ์ง์ ํน์ฑ ์ถ๊ฐํ๊ธฐยถ
๋ก๊ทธ ํญ๋ชฉ์ ์์ฑํ ๋ ํค-๊ฐ ํ์ด๋ก ์ฌ์ฉ์ ๊ณ ์ ์ ํน์ฑ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. Snowflake๋ ์ด๋ฌํ ์ฌ์ฉ์ ์ง์ ํน์ฑ์ ์ด๋ฒคํธ ํ ์ด๋ธ์ RECORD_ATTRIBUTES ์ด ์ ์ ์ฅํฉ๋๋ค.
์ฌ์ฉ์ ์ง์ ํน์ฑ์ ์ถ๊ฐํ๋ ค๋ฉด Logger.atInfo
๋ฐ Logger.atError
๊ฐ์ slf4j fluent API์ ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ ํญ๋ชฉ์ ํค-๊ฐ ํ์ด๋ฅผ ์ค์ ํฉ๋๋ค. ๊ฐ๊ฐ์ ๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ค์ ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ org.slf4j.spi.LoggingEventBuilder ๋ฅผ ๋ฐํํฉ๋๋ค.
๋ค์ ์์ ์ ์ฝ๋๋ ์ด๋ฒคํธ ํ ์ด๋ธ์ VALUE ์ด์ โํน์ฑ ํฌํจ ๊ธฐ๋กโ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํฉ๋๋ค. ๋ํ RECORD_ATTRIBUTES ์ด์ ์ฌ์ฉ์ ์ง์ ํน์ฑ์ ์ถ๊ฐํฉ๋๋ค.
CREATE OR REPLACE PROCEDURE do_logging_scala()
RETURNS VARCHAR
LANGUAGE SCALA
RUNTIME_VERSION = '2.12'
PACKAGES=('com.snowflake:telemetry:latest', 'com.snowflake:snowpark:latest')
HANDLER = 'ScalaLoggingHandler.doThings'
AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Session
class 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"
}
}
$$;
์ด Logger.atInfo
ํธ์ถ์ ์ถ๋ ฅ์ ์ด๋ฒคํธ ํ
์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ด ํ์๋ฉ๋๋ค. RECORD_ATTRIBUTES ์ด์๋ Snowflake๊ฐ ์๋์ผ๋ก ์ถ๊ฐํ๋ ํน์ฑ์ด ํฌํจ๋ฉ๋๋ค.
------------------------------------------------------------------
| VALUE | RECORD_ATTRIBUTES |
------------------------------------------------------------------
| "Logging with attributes" | { |
| | "custom1": "value1", |
| | "thread.name": "Thread-5" |
| | } |
------------------------------------------------------------------
Scala์ ์ยถ
๋ค์ ์์ ๊ฐ์ ธ์ค๊ธฐ์ ์ฝ๋๋ Snowflake ์๊ฒฉ ๋ถ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐธ์กฐํ๊ณ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ก๊ฑฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. INFO
์์ค์์ ๋ฉ์์ง๋ฅผ ๋ก๊น
ํฉ๋๋ค. ๋ํ ์์ธ์ ๋ํ ์ค๋ฅ๋ฅผ ๋ก๊น
ํฉ๋๋ค.
ํน์ ์์ค์์ ๋ก๊น ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ฉ์๋์ ๋ํ ์์ธํ ๋ด์ฉ์ SLF4J ๋ฉ์๋ ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
CREATE OR REPLACE PROCEDURE do_logging()
RETURNS VARCHAR
LANGUAGE SCALA
RUNTIME_VERSION = '2.12'
PACKAGES=('com.snowflake:snowpark:latest', 'com.snowflake:telemetry:latest')
HANDLER = 'ScalaLoggingHandler.doThings'
AS
$$
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.snowflake.snowpark.Session
class 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 exception to catch.
@throws(classOf[Exception])
private def throwException = {
throw new Exception("Something went wrong.")
}
}
$$
;
์ด๋ฒคํธ ํ ์ด๋ธ์์ SELECT ๋ช ๋ น์ ์คํํ์ฌ ๋ก๊ทธ ๋ฉ์์ง์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ ๋ก๊ทธ ๋ฉ์์ง ๋ณด๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
๋ค์ ์์ ์ ์ฝ๋๋ ๋ก๊ทธ ๋ฉ์์ง๊ฐ ์ ์ฅ๋ ์ด๋ฒคํธ ํ ์ด๋ธ์ ์ฟผ๋ฆฌํฉ๋๋ค. ์ด ์ฟผ๋ฆฌ๋ ์ฒ๋ฆฌ๊ธฐ ํด๋์ค์์ ๊ฐ ๋ก๊ทธ ํญ๋ชฉ์ ์ฌ๊ฐ๋์ ๋ฉ์์ง์ ๋ํด ๋ณด๊ณ ํฉ๋๋ค.
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'] = 'ScalaLoggingHandler'
AND RECORD_TYPE = 'LOG';
์์ ์์ ์์๋ ๋ค์ ์ถ๋ ฅ์ ์์ฑํฉ๋๋ค.
---------------------------------------------------------------------------
| 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." |
---------------------------------------------------------------------------