Scala์—์„œ ์ถ”์  ์ด๋ฒคํŠธ ๋‚ด๋ณด๋‚ด๊ธฐยถ

Snowflake Telemetry API ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ com.snowflake.telemetry.Telemetry ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Scala๋กœ ์ž‘์„ฑ๋œ ํ•จ์ˆ˜ ๋˜๋Š” ํ”„๋กœ์‹œ์ € ์ฒ˜๋ฆฌ๊ธฐ์—์„œ ์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Telemetry ํด๋ž˜์Šค๋Š” Snowflake์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ 

Snowflake ์›๊ฒฉ ๋ถ„์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ ๋˜๋Š” ํ”„๋กœ์‹œ์ €์˜ ์‹คํ–‰ ํ™˜๊ฒฝ์— ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Snowflake ์›๊ฒฉ ๋ถ„์„ ํŒจํ‚ค์ง€ ์ข…์†์„ฑ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Maven์œผ๋กœ ์ฝ”๋“œ๋ฅผ ํŒจํ‚ค์ง•ํ•  ๋•Œ Telemetry ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์›๊ฒฉ ๋ถ„์„ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก Java ๋ฐ Scala ํ™˜๊ฒฝ ์„ค์ •ํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์—์„œ SELECT ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์ €์žฅ๋œ ์ถ”์  ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ถ”์  ๋ฐ์ดํ„ฐ ๋ณด๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฐธ๊ณ 

์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•  ์ง€์นจ์€ ์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ผ๋ฐ˜ ์ง€์นจ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Snowflake์—์„œ ๋กœ๊น… ์„ค์ • ๋ฐ ๋ฉ”์‹œ์ง€ ๊ฒ€์ƒ‰์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ์ •๋ณด๋Š” ํ•จ์ˆ˜์™€ ํ”„๋กœ์‹œ์ €์˜ ์ถ”์  ์ด๋ฒคํŠธ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฝ”๋“œ์—์„œ ๋กœ๊น…ํ•˜๊ธฐ ์ „์— ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์›๊ฒฉ ๋ถ„์„ API์— ๋Œ€ํ•œ ์ง€์› ์ถ”๊ฐ€ํ•˜๊ธฐยถ

Telemetry ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ์—์„œ ์˜คํ”ˆ ์†Œ์Šค Snowflake ์›๊ฒฉ ๋ถ„์„ ํŒจํ‚ค์ง€ ๋ฅผ ๊ฐ€์šฉ์„ฑ ์žˆ๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • CREATE PROCEDURE ๋˜๋Š” CREATE FUNCTION ๋ฌธ์˜ PACKAGES ์ ˆ์— com.snowflake:telemetry ํŒจํ‚ค์ง€๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. PACKAGES ์ ˆ์€ ํฌํ•จ๋œ Snowflake ์›๊ฒฉ ๋ถ„์„ API๋ฅผ ์ฝ”๋“œ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

    ๋‹ค์Œ ์˜ˆ์ œ์˜ ์ฝ”๋“œ์—์„œ๋Š” PACKAGES ์ ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ๋ถ„์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ Snowpark ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Scala๋กœ ์ž‘์„ฑ๋œ ์ €์žฅ ํ”„๋กœ์‹œ์ €์— ํ•„์š”ํ•จ โ€“ ์ž์„ธํ•œ ๋‚ด์šฉ์€ SQL์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ๋œ ์ €์žฅ ํ”„๋กœ์‹œ์ €์— ๋Œ€ํ•œ Scala ์ฒ˜๋ฆฌ๊ธฐ ์ž‘์„ฑํ•˜๊ธฐ ์ฐธ์กฐ)๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

    CREATE OR REPLACE PROCEDURE myproc(...)
      RETURNS ...
      LANGUAGE SCALA
      ...
      PACKAGES = ('com.snowflake:snowpark:latest', 'com.snowflake:telemetry:latest')
      ...
    
    Copy
  • ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ์—์„œ com.snowflake.telemetry ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    import com.snowflake.telemetry.Telemetry
    
    Copy

์ถ”์  ์ด๋ฒคํŠธ ์ถ”๊ฐ€ํ•˜๊ธฐยถ

Telemetry.addEvent ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์ด๋ฒคํŠธ ์ด๋ฆ„์„ ์ „๋‹ฌํ•˜์—ฌ ์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ์ ์œผ๋กœ ํŠน์„ฑ(ํ‚ค-๊ฐ’ ํŽ˜์–ด)์„ ์ด๋ฒคํŠธ์™€ ์—ฐ๊ฒฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

addEvent ๋ฉ”์„œ๋“œ์—๋Š” ๋‹ค์Œ ์„œ๋ช…์ด ์žˆ์Šต๋‹ˆ๋‹ค.

public static void addEvent(String name)
public static void addEvent(String name, Attributes attributes)
Copy

๋‹ค์Œ ์˜ˆ์ œ์˜ ์ฝ”๋“œ๋Š” testEvent ๋ผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฒคํŠธ์— key ๋ฐ result ๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ํŠน์„ฑ๊ณผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

// Adding an event without attributes.
Telemetry.addEvent("testEvent")

// Adding an event with attributes.
Attributes eventAttributes = Attributes.of(
  AttributeKey.stringKey("key"), "run",
  AttributeKey.longKey("result"), Long.valueOf(123))
Telemetry.addEvent("testEventWithAttributes", eventAttributes)
Copy

์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์— ๋‘ ๊ฐœ์˜ ํ–‰์ด ์ƒ๊ธฐ๋Š”๋ฐ, RECORD ์—ด์˜ ๊ฐ’์ด ๊ฐ๊ฐ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

{
  "name": "testEvent"
}
Copy
{
  "name": "testEventWithAttributes"
}
Copy

testEventWithAttributes ์ด๋ฒคํŠธ ํ–‰์˜ RECORD_ATTRIBUTES ์—ด์— ๋‹ค์Œ ํŠน์„ฑ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

{
  "key": "run",
  "result": 123
}
Copy

๋ฒ”์œ„ ํŠน์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐยถ

Telemetry.setSpanAttribute ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฒ”์œ„์™€ ์—ฐ๊ฒฐ๋œ ํŠน์„ฑ(ํ‚ค-๊ฐ’ ํŽ˜์–ด)์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

setSpanAttribute ๋ฉ”์„œ๋“œ์—๋Š” ๋‹ค์Œ ์„œ๋ช…์ด ์žˆ์Šต๋‹ˆ๋‹ค.

public static void setSpanAttribute(String key, boolean value)
public static void setSpanAttribute(String key, long value)
public static void setSpanAttribute(String key, double value)
public static void setSpanAttribute(String key, String value)
Copy

๋ฒ”์œ„์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Snowflake๊ฐ€ ์ถ”์  ์ด๋ฒคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ• ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋‹ค์Œ ์˜ˆ์ œ์˜ ์ฝ”๋“œ๋Š” 4๊ฐ€์ง€ ํŠน์„ฑ์„ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

// Setting span attributes.
Telemetry.setSpanAttribute("example.boolean", true)
Telemetry.setSpanAttribute("example.long", 2L)
Telemetry.setSpanAttribute("example.double", 2.5)
Telemetry.setSpanAttribute("example.string", "testAttribute")
Copy

์ด๋Ÿฌํ•œ ํŠน์„ฑ์„ ์„ค์ •ํ•˜๋ฉด ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์˜ RECORD_ATTRIBUTES ์—ด์— ๋‹ค์Œ ๋‚ด์šฉ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

{
  "example.boolean": true,
  "example.long": 2,
  "example.double": 2.5,
  "example.string": "testAttribute"
}
Copy

์‚ฌ์šฉ์ž ์ง€์ • ๋ฒ”์œ„ ์ถ”๊ฐ€ํ•˜๊ธฐยถ

Snowflake์—์„œ ์ƒ์„ฑ๋œ ๊ธฐ๋ณธ ๋ฒ”์œ„์™€ ๋ณ„๋„๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฒ”์œ„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๋ฒ”์œ„์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ถ”์ ์— ์‚ฌ์šฉ์ž ์ง€์ • ๋ฒ”์œ„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋‹ค์Œ ์˜ˆ์ œ์˜ ์ฝ”๋“œ๋Š” OpenTelemetry API ๋ฐ OpenTelemetry context propagation API ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ my.span ๋ฒ”์œ„๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ƒˆ ๋ฒ”์œ„์— ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด ์ฝ”๋“œ๋Š” ๋ฒ”์œ„๋ฅผ ์ข…๋ฃŒํ•˜์—ฌ ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์— ํ•ด๋‹น ๋ฒ”์œ„์˜ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ์บก์ฒ˜๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ Span.end ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๊ฐ€ ์บก์ฒ˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION testScalaUserSpans(x VARCHAR) RETURNS VARCHAR
  LANGUAGE SCALA
  RUNTIME_VERSION = 2.12
  PACKAGES = ('com.snowflake:telemetry:latest')
  HANDLER = 'TestScalaClass.run'
  AS
  $$
  class TestScalaClass {
    import com.snowflake.telemetry.Telemetry
    import io.opentelemetry.api.GlobalOpenTelemetry
    import io.opentelemetry.api.trace.Tracer
    import io.opentelemetry.api.trace.Span
    import io.opentelemetry.context.Scope

    def run(x: String): String = {
      val tracer: Tracer = GlobalOpenTelemetry.getTracerProvider().get("my.tracer")
      val span: Span = tracer.spanBuilder("my.span").startSpan()
      span.addEvent("test event from scala")
      span.end()
      return x
    }
  }
  $$;
Copy

์˜ˆยถ

์ €์žฅ ํ”„๋กœ์‹œ์ € ์˜ˆ์ œยถ

CREATE OR REPLACE PROCEDURE do_tracing()
  RETURNS STRING
  LANGUAGE SCALA
  RUNTIME_VERSION = '2.12'
  PACKAGES=('com.snowflake:snowpark:latest', 'com.snowflake:telemetry:latest')
  HANDLER = 'ProcedureHandler.run'
  AS
  $$
  import com.snowflake.snowpark_java.Session
  import com.snowflake.telemetry.Telemetry
  import io.opentelemetry.api.common.AttributeKey
  import io.opentelemetry.api.common.Attributes

  class ProcedureHandler {

    def run(session: Session): String = {

      // Set span attribute.
      Telemetry.setSpanAttribute("example.proc.do_tracing", "begin")

      // Add an event without attributes.
      Telemetry.addEvent("run_method_start")

      // Add an event with attributes.
      val eventAttributes: Attributes = Attributes.of(
        AttributeKey.stringKey("example.method.name"), "run")
      Telemetry.addEvent("event_with_attributes", eventAttributes)

      // Set span attribute.
      Telemetry.setSpanAttribute("example.proc.do_tracing", "complete")

      return "SUCCESS"
    }
  }
  $$;
Copy