Emitting Trace Events in Java

You can use the com.snowflake.telemetry.Telemetry class in the Telemetry API library to emit trace events from a function or procedure handler written in Java. The Telemetry class is included with Snowflake.

Note

Using the Snowflake Telemetry Library adds other libraries to your function or procedure’s execution environment. For more information, refer to Snowflake Telemetry Package Dependencies.

For information on including the Telemetry library when packaging your code with Maven, refer to Setting Up Your Java and Scala Environment to Use the Telemetry Class.

You can access stored trace event data by executing a SELECT command on the event table. For more information, refer to Accessing Trace Data.

Note

For guidelines to keep in mind when adding trace events, refer to General Guidelines for Adding Trace Events.

For general information about setting up logging and retrieving messages in Snowflake, refer to Logging Messages from Functions and Procedures.

Before logging from code, you must:

  • Set up an event table to collect messages logged from handler code.

    For more information, refer to Setting up an Event Table.

  • Be sure you have the trace level set so that the data you want are stored in the event table.

    For more information, refer to Setting trace level.

Adding Support for the Telemetry API

To use Telemetry methods, you must make the Snowflake Telemetry library, which is included with Snowflake, available to your handler code.

  • In the PACKAGES clause in your CREATE PROCEDURE or CREATE FUNCTION statement, include the com.snowflake:telemetry package. The PACKAGES clause makes the included Snowflake Telemetry API available to your code.

    Code in the following example uses the PACKAGES clause to reference the Telemetry library as well as the Snowpark library (which is required for stored procedures written in Java – for more information, refer to Writing stored procedures in Java).

    CREATE OR REPLACE PROCEDURE MYPROC(...)
      RETURNS ...
      LANGUAGE JAVA
      ...
      PACKAGES = ('com.snowflake:snowpark:latest', 'com.snowflake:telemetry:latest')
      ...
    
    Copy
  • Import the com.snowflake.telemetry package in your Java handler code.

    import com.snowflake.telemetry.Telemetry;
    
    Copy

Adding Trace Events

You can add trace events by calling the Telemetry.addEvent method, passing a name for the event. You can also optionally associate attributes – key-value pairs – with an event.

The addEvent method has the following signatures:

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

Code in the following example adds an event called testEvent, associating with the event two attributes: key and 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

Adding these events results in two rows in the event table, each with a different value in the RECORD column:

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

The testEventWithAttributes event row includes the following attributes in the row’s RECORD_ATTRIBUTES column:

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

Adding Span Attributes

You can set attributes – key-value pairs – associated with spans by calling the Telemetry.setSpanAttribute method.

The setSpanAttribute method has the following signatures:

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

For details on spans, see How Snowflake represents trace events.

Code in the following example creates four attributes and sets their values:

// 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

Setting these attributes results in the following in the event table’s RECORD_ATTRIBUTES column:

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

Java Examples

Stored Procedure Example

CREATE OR REPLACE PROCEDURE do_tracing()
RETURNS STRING
LANGUAGE JAVA
RUNTIME_VERSION = '11'
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;

public class ProcedureHandler {

  public String run(Session session) {

    // 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.
    Attributes eventAttributes = Attributes.of(
      AttributeKey.stringKey("example.method.name"), "run",
      AttributeKey.longKey("example.long"), Long.valueOf(123));
    Telemetry.addEvent("event_with_attributes", eventAttributes);

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

    return "SUCCESS";
  }
}
$$;
Copy

UDF Example

CREATE OR REPLACE FUNCTION add_two_numbers(A FLOAT, B FLOAT) RETURNS FLOAT
LANGUAGE JAVA
PACKAGES=('com.snowflake:telemetry:latest')
HANDLER = 'ScalarFunctionHandler.run'
AS
$$
import com.snowflake.telemetry.Telemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;

class ScalarFunctionHandler {

  public static Double run(Double d0, Double d1) {

    // Set span attribute.
    Telemetry.setSpanAttribute("example.func.add_two_numbers", "begin");

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

    // Add an event with attributes.
    Attributes eventAttributes = Attributes.of(
      AttributeKey.stringKey("example.method.name"), "run",
      AttributeKey.longKey("example.long"), Long.valueOf(123));
    Telemetry.addEvent("event_with_attributes", eventAttributes);

    Double response = d0 == null || d1 == null ? null : (d0 + d1);

    // Set span attribute.
    Telemetry.setSpanAttribute("example.func.add_two_numbers.response", response);
    Telemetry.setSpanAttribute("example.func.add_two_numbers", "complete");

    return response;
  }
}
$$;
Copy

UDTF Example

CREATE OR REPLACE FUNCTION digits_of_number(x int)
RETURNS TABLE(result int)
LANGUAGE JAVA
PACKAGES=('com.snowflake:telemetry:latest')
HANDLER = 'TableFunctionHandler'
AS
$$
import com.snowflake.telemetry.Telemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import java.util.stream.Stream;

public class TableFunctionHandler {

  public TableFunctionHandler() {
    // Set span attribute.
    Telemetry.setSpanAttribute("example.func.digits_of_number", "begin");
  }

  static class OutputRow {
    public int result;

    public OutputRow(int result) {
      this.result = result;
    }
  }

  public static Class getOutputClass() {
    return OutputRow.class;
  }

  public Stream<OutputRow> process(int input) {

    // Add an event with attributes.
    Attributes eventAttributes = Attributes.of(
      AttributeKey.longKey("example.received.value"), Long.valueOf(input));
    Telemetry.addEvent("digits_of_number", eventAttributes);

    Stream.Builder<OutputRow> stream = Stream.builder();
    while (input > 0) {

      stream.add(new OutputRow(input %10));
      input /= 10;
    }

    // Set span attribute.
    Telemetry.setSpanAttribute("example.func.digits_of_number", "complete");

    return stream.build();
  }
}
$$;
Copy