Ausgeben von Ablaufverfolgungsereignissen in Java

Sie können die com.snowflake.telemetry.Telemetry-Klasse in der Snowflake Telemetrie-API-Bibliothek verwenden, um Ereignisse von einer in Java geschriebenen Funktions- oder Prozedur-Handler auszugeben. Die Klasse Telemetry wird von Snowflake bereitgestellt.

Bemerkung

Durch Verwendung der Snowflake-Telemetrie-Bibliothek werden der Ausführungsumgebung Ihrer Funktion oder Prozedur weitere Bibliotheken hinzugefügt. Weitere Informationen dazu finden Sie unter Abhängigkeiten des Snowflake-Telemetriepaketen.

Weitere Informationen zum Einbinden der Telemetrie-Bibliothek beim Packen Ihres Codes mit Maven finden Sie unter Einrichten Ihrer Java- und Scala-Umgebung für die Verwendung der Telemetrie-Klasse.

Sie können auf die gespeicherten Daten zu den Ablaufverfolgungsereignissen zugreifen, indem Sie einen SELECT-Befehl auf der Ereignistabelle ausführen. Weitere Informationen dazu finden Sie unter Ablaufverfolgung anzeigen.

Bemerkung

Richtlinien, die beim Hinzufügen von Ablaufverfolgungsereignissen berücksichtigt werden sollten, finden Sie unter Allgemeine Richtlinien für das Hinzufügen von Ablaufverfolgungsereignissen.

Allgemeine Informationen zur Einstellung der Protokollierung und zum Abrufen von Meldungen in Snowflake finden Sie unter Protokollierung von Meldungen aus Funktionen und Prozeduren.

Bevor Sie die Protokollierung für Code nutzen können, müssen Sie Folgendes tun:

Hinzufügen von Unterstützung für die Telemetrie-API

Um Telemetry-Methoden verwenden zu können, müssen Sie die Snowflake-Telemetrie-Bibliothek, die in Snowflake enthalten ist, Ihrem Handler-Code zur Verfügung stellen.

  • Fügen Sie in der PACKAGES-Klausel Ihrer CREATE PROCEDURE- oder CREATE FUNCTION-Anweisung das Paket com.snowflake:telemetry ein. Die PACKAGES-Klausel stellt die darin enthaltene Snowflake-Telemetrie-API für Ihren Code zur Verfügung.

    Der Code im folgenden Beispiel verwendet die PACKAGES-Klausel, um sowohl auf die Telemetrie-Bibliothek als auch auf die Snowpark-Bibliothek zu verweisen (die für in Java geschriebene Prozeduren erforderlich ist. Weitere Informationen finden Sie unter Schreiben von gespeicherten Prozeduren in Java).

    CREATE OR REPLACE PROCEDURE MYPROC(...)
      RETURNS ...
      LANGUAGE JAVA
      ...
      PACKAGES = ('com.snowflake:snowpark:latest', 'com.snowflake:telemetry:latest')
      ...
    
    Copy
  • Importieren Sie das Paket com.snowflake.telemetry in Ihren Java-Handler-Code.

    import com.snowflake.telemetry.Telemetry;
    
    Copy

Hinzufügen von Ablaufverfolgungsereignissen

Sie können Ablaufverfolgungsereignisse hinzufügen, indem Sie die Methode Telemetry.addEvent aufrufen und einen Namen für das Ereignis übergeben. Sie können einem Ereignis optional auch Attribute (Schlüssel-Wert-Paare) zuordnen.

Die Methode addEvent hat die folgenden Signaturen:

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

Der Code im folgenden Beispiel fügt ein Ereignis mit dem Namen testEvent hinzu und ordnet diesem zwei Attribute zu: key und 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

Das Hinzufügen dieser Ereignisse führt zu zwei Zeilen in der Ereignistabelle, die jeweils einen anderen Wert in der Spalte RECORD haben:

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

Die Ereigniszeile testEventWithAttributes enthält in der Spalte RECORD_ATTRIBUTES die folgenden Attribute:

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

Hinzufügen von Bereichsattributen

Durch Aufruf der Methode Telemetry.setSpanAttribute können Sie Attribute (Schlüssel-Wert-Paare) festlegen, die bestimmten Bereichen (Spans) zugeordnet sind.

Die Methode setSpanAttribute hat die folgenden Signaturen:

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

Weitere Informationen zu Bereichen (Spans) finden Sie unter Darstellung von Ablaufverfolgungsereignissen in Snowflake.

Der Code im folgenden Beispiel erstellt vier Attribute und legt deren Werte fest:

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

Das Einstellen dieser Attribute führt in der Spalte RECORD_ATTRIBUTES der Ereignistabelle zu folgendem Ergebnis:

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

Hinzufügen benutzerdefinierter Bereiche (Spans)

Bemerkung

Die Unterstützung für benutzerdefinierte Zeiträume ist ein Vorschau-Feature, das für alle Konten verfügbar ist.

Sie können benutzerdefinierte Bereiche (Spans) hinzufügen, die sich von dem von Snowflake erstellten Standardbereich unterscheiden. Weitere Informationen zu benutzerdefinierten Bereichen (Spans) finden Sie unter Hinzufügen von benutzerdefinierten Bereichen zu einer Ablaufverfolgung.

Der Code im folgenden Beispiel verwendet die Kontextweitergabe OpenTelemetry API und OpenTelemetry API, um einen neuen Bereich (Span) my.span zu erstellen. Es fügt dann dem neuen Bereich (Span) ein Ereignis mit Attributen hinzu. Schließlich beendet der Code den Bereich (Span), damit die Ereignisdaten des Bereichs in der Ereignistabelle erfasst werden. Wenn der Code nicht die Span.end-Methode aufruft, werden die Daten nicht in der Ereignistabelle erfasst.

CREATE OR REPLACE FUNCTION customSpansJavaExample() RETURNS STRING
LANGUAGE JAVA
PACKAGES = ('com.snowflake:telemetry:latest')
HANDLER = 'MyJavaClass.run'
as
$$
  import com.snowflake.telemetry.Telemetry;
  import io.opentelemetry.api.common.AttributeKey;
  import io.opentelemetry.api.common.Attributes;
  import io.opentelemetry.api.GlobalOpenTelemetry;
  import io.opentelemetry.api.trace.Tracer;
  import io.opentelemetry.api.trace.Span;
  import io.opentelemetry.context.Scope;

  class MyJavaClass {
    public static String run() {
      Tracer tracer = GlobalOpenTelemetry.getTracerProvider().get("my.tracer");
      Span span = tracer.spanBuilder("my.span").startSpan();
      try (Scope scope = span.makeCurrent()) {
        // Do processing, adding events that will be captured in a my.span.

        // Add an event with attributes.
        Attributes eventAttributes = Attributes.of(
          AttributeKey.stringKey("key"), "run",
          AttributeKey.longKey("result"), Long.valueOf(123));

        span.addEvent("testEventWithAttributes", eventAttributes);
        span.setAttribute("testAttribute", "value");

      } finally {
        span.end();
      }
      return "success";
    }
  }
$$;
Copy

Java-Beispiele

Beispiel einer gespeicherten Prozedur

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

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

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