Aller au contenu principal

Configurez les clients OpenTelemetry (OTLP) pour envoyer des données à Unity Catalog

info

Bêta

Cette fonctionnalité est en Bêta.

Zerobus Ingest inclut un endpoint OpenTelemetry Protocol (OTLP). Vous pouvez envoyer des traces, des logs et des métriques directement dans les tables Delta Unity Catalog en utilisant les SDK et collecteurs OpenTelemetry standard, sans bibliothèques personnalisées. Cette page couvre la récupération de votre endpoint, la création de tables cibles, la configuration d'un Service Principal et l'envoi de vos premières données de télémétrie.

Obtenez votre endpoint Zerobus Ingest et votre URL de Workspace

L'URL de l'Endpoint suit ce modèle :

  • URL du workspace : https://<databricks-instance>.cloud.databricks.com
  • Endpoint du serveur : <workspace-id>.zerobus.<region>.cloud.databricks.com

Par exemple :

  • URL du workspace : https://dbc-a1b2c3d4-e5f6.cloud.databricks.com
  • Endpoint du serveur : 1234567890123456.zerobus.us-west-2.cloud.databricks.com

Pour plus de détails sur la recherche de votre ID de workspace, URL et région, consultez Obtenez votre URL de workspace et votre endpoint Zerobus Ingest.

Créer des tables cibles dans Unity Catalog

Vous devez créer les tables Delta cibles avant d'envoyer les données. Chaque type de signal (traces, Logs, métriques) nécessite sa propre table avec un schéma spécifique.

Prérequis :

Pour configurer vos tables :

  1. Remplacez <catalog>.<schema>.<prefix> par votre catalogue, votre schéma et le préfixe de nom de table souhaité.
  2. Remplacez <service-principal-uuid> par l'ID d'application (UUID) de votre service principal. Pour le trouver, accédez à l' tab Configurations du service principal dans votre Databricks workspace.
  3. Exécutez le script dans Databricks SQL.

Tableau des portées

La table des spans stocke les données de trace distribuées, y compris le timing, le statut et les attributs pour chaque span.

SQL
CREATE TABLE <catalog>.<schema>.<prefix>_otel_spans (
record_id STRING,
time TIMESTAMP,
date DATE,
service_name STRING,
trace_id STRING,
span_id STRING,
trace_state STRING,
parent_span_id STRING,
flags INT,
name STRING,
kind STRING,
start_time_unix_nano LONG,
end_time_unix_nano LONG,
attributes VARIANT,
dropped_attributes_count INT,
events ARRAY<STRUCT<
time_unix_nano: LONG,
name: STRING,
attributes: VARIANT,
dropped_attributes_count: INT
>>,
dropped_events_count INT,
links ARRAY<STRUCT<
trace_id: STRING,
span_id: STRING,
trace_state: STRING,
attributes: VARIANT,
dropped_attributes_count: INT,
flags: INT
>>,
dropped_links_count INT,
status STRUCT<
message: STRING,
code: STRING
>,
resource STRUCT<
attributes: VARIANT,
dropped_attributes_count: INT
>,
resource_schema_url STRING,
instrumentation_scope STRUCT<
name: STRING,
version: STRING,
attributes: VARIANT,
dropped_attributes_count: INT
>,
span_schema_url STRING
) USING DELTA
CLUSTER BY (time, service_name, trace_id)
TBLPROPERTIES (
'otel.schemaVersion' = 'v2',
'delta.checkpointPolicy' = 'classic',
'delta.enableVariantShredding' = 'true', -- optional
'delta.feature.variantShredding-preview' = 'supported', -- optional
'delta.feature.variantType-preview' = 'supported' -- optional
);

Table des logs

La table des Logs stocke les enregistrements de logs structurés, y compris la gravité, le corps et les attributs des Ressources.

SQL
CREATE TABLE <catalog>.<schema>.<prefix>_otel_logs (
record_id STRING,
time TIMESTAMP,
date DATE,
service_name STRING,
event_name STRING,
trace_id STRING,
span_id STRING,
time_unix_nano LONG,
observed_time_unix_nano LONG,
severity_number STRING,
severity_text STRING,
body VARIANT,
attributes VARIANT,
dropped_attributes_count INT,
flags INT,
resource STRUCT<
attributes: VARIANT,
dropped_attributes_count: INT
>,
resource_schema_url STRING,
instrumentation_scope STRUCT<
name: STRING,
version: STRING,
attributes: VARIANT,
dropped_attributes_count: INT
>,
log_schema_url STRING
) USING DELTA
CLUSTER BY (time, service_name)
TBLPROPERTIES (
'otel.schemaVersion' = 'v2',
'delta.checkpointPolicy' = 'classic',
'delta.enableVariantShredding' = 'true', -- optional
'delta.feature.variantShredding-preview' = 'supported', -- optional
'delta.feature.variantType-preview' = 'supported' -- optional
);

Table des métriques

Le tableau de métriques stocke les mesures de jauge, de somme et d'histogramme, ainsi que leurs attributs de ressource et d'étendue d'instrumentation associés.

SQL
CREATE TABLE <catalog>.<schema>.<prefix>_otel_metrics (
record_id STRING,
time TIMESTAMP,
date DATE,
service_name STRING,
start_time_unix_nano LONG,
time_unix_nano LONG,
name STRING,
description STRING,
unit STRING,
metric_type STRING,
gauge STRUCT<
value: DOUBLE,
exemplars: ARRAY<STRUCT<
time_unix_nano: LONG,
value: DOUBLE,
span_id: STRING,
trace_id: STRING,
filtered_attributes: VARIANT
>>,
attributes: VARIANT,
flags: INT
>,
sum STRUCT<
value: DOUBLE,
exemplars: ARRAY<STRUCT<
time_unix_nano: LONG,
value: DOUBLE,
span_id: STRING,
trace_id: STRING,
filtered_attributes: VARIANT
>>,
attributes: VARIANT,
flags: INT,
aggregation_temporality: STRING,
is_monotonic: BOOLEAN
>,
histogram STRUCT<
count: LONG,
sum: DOUBLE,
bucket_counts: ARRAY<LONG>,
explicit_bounds: ARRAY<DOUBLE>,
exemplars: ARRAY<STRUCT<
time_unix_nano: LONG,
value: DOUBLE,
span_id: STRING,
trace_id: STRING,
filtered_attributes: VARIANT
>>,
attributes: VARIANT,
flags: INT,
min: DOUBLE,
max: DOUBLE,
aggregation_temporality: STRING
>,
exponential_histogram STRUCT<
attributes: VARIANT,
count: LONG,
sum: DOUBLE,
scale: INT,
zero_count: LONG,
positive_bucket: STRUCT<
offset: INT,
bucket_counts: ARRAY<LONG>
>,
negative_bucket: STRUCT<
offset: INT,
bucket_counts: ARRAY<LONG>
>,
flags: INT,
exemplars: ARRAY<STRUCT<
time_unix_nano: LONG,
value: DOUBLE,
span_id: STRING,
trace_id: STRING,
filtered_attributes: VARIANT
>>,
min: DOUBLE,
max: DOUBLE,
zero_threshold: DOUBLE,
aggregation_temporality: STRING
>,
summary STRUCT<
count: LONG,
sum: DOUBLE,
quantile_values: ARRAY<STRUCT<
quantile: DOUBLE,
value: DOUBLE
>>,
attributes: VARIANT,
flags: INT
>,
metadata VARIANT,
resource STRUCT<
attributes: VARIANT,
dropped_attributes_count: INT
>,
resource_schema_url STRING,
instrumentation_scope STRUCT<
name: STRING,
version: STRING,
attributes: VARIANT,
dropped_attributes_count: INT
>,
metric_schema_url STRING
) USING DELTA
CLUSTER BY (time, service_name)
TBLPROPERTIES (
'otel.schemaVersion' = 'v2',
'delta.checkpointPolicy' = 'classic',
'delta.enableVariantShredding' = 'true', -- optional
'delta.feature.variantShredding-preview' = 'supported', -- optional
'delta.feature.variantType-preview' = 'supported' -- optional
);

Créez un Service Principal et accordez des autorisations

Configurez un Service Principal avec des identifiants OAuth et accordez-lui l’accès à vos tables. Pour plus d'informations sur la configuration d'un Service Principal, consultez Autoriser l'accès du Service Principal à Databricks avec OAuth.

Accordez au Service Principal l'accès au catalogue, au schéma et à chaque table. L'octroi de ALL PRIVILEGES n'est pas suffisant. Vous devez explicitement accorder MODIFY et SELECT sur chaque table.

SQL
GRANT USE CATALOG ON CATALOG <catalog> TO `<service-principal-uuid>`;
GRANT USE SCHEMA ON SCHEMA <catalog>.<schema> TO `<service-principal-uuid>`;
GRANT MODIFY, SELECT ON TABLE <catalog>.<schema>.<prefix>_otel_spans TO `<service-principal-uuid>`;
GRANT MODIFY, SELECT ON TABLE <catalog>.<schema>.<prefix>_otel_logs TO `<service-principal-uuid>`;
GRANT MODIFY, SELECT ON TABLE <catalog>.<schema>.<prefix>_otel_metrics TO `<service-principal-uuid>`;

Configurez votre exportateur

Les exemples suivants utilisent l'instrumentation sans code OpenTelemetry pour collecter et transmettre automatiquement les traces, les logs et les métriques à Zerobus Ingest sans aucune modification de code apportée à votre application. Vous pouvez également utiliser d'autres exportateurs compatibles OTLP qui prennent en charge gRPC et les en-têtes de métadonnées personnalisés.

En-têtes requis

Toutes les requêtes OTLP doivent inclure les en-têtes de métadonnées suivants :

  • x-databricks-zerobus-table-name: Le nom de table Unity Catalog entièrement qualifié au format <catalog>.<schema>.<table>. Chaque requête cible une seule table.
  • Authorization: jeton porteur OAuth généré à partir des informations d'identification du Service Principal.

Pour générer un jeton de porteur statique à partir de vos identifiants de Service Principal, consultez Autoriser l'accès de Service Principal à Databricks avec OAuth. Les jetons statiques expirent après une heure. Pour les applications de longue durée, consultez OpenTelemetry Collector avec refresh automatique du jeton.

Configuration des variables

Définissez ces variables avant d'exécuter l'un ou l'autre exemple :

Variable

Exemple

DATABRICKS_CLIENT_ID

abc123-... (ID d’application du Service Principal)

DATABRICKS_CLIENT_SECRET

dose1234...

WORKSPACE_URL

my-workspace.cloud.databricks.com

WORKSPACE_ID

1234567890123456

REGION

us-west-2

CATALOG

my_catalog

SCHEMA

my_schema

TABLE_PREFIX

my_prefix

Variable

Exemple

DATABRICKS_CLIENT_ID

abc123-... (ID d’application du Service Principal)

DATABRICKS_CLIENT_SECRET

dose1234...

WORKSPACE_URL

my-workspace.cloud.databricks.com

WORKSPACE_ID

1234567890123456

REGION

us-west-2

CATALOG

my_catalog

SCHEMA

my_schema

TABLE_PREFIX

my_prefix

Vous pouvez définir ces variables comme variables d'environnement à l'aide de Bash. Par exemple :

Bash
export DATABRICKS_CLIENT_ID="<your-client-id>"
export DATABRICKS_CLIENT_SECRET="<your-client-secret>"

Quick start avec un jeton statique

L'exemple suivant utilise un jeton porteur statique pour chaque type de signal (traces, logs, métriques). Avant d'exécuter cet exemple, générez des jetons à partir de vos informations d'identification de service principal. Consultez Autoriser l'accès du Service Principal à Databricks avec OAuth.

Utilisez cette approche pour les pipelines de courte durée ou ad hoc où la gestion du refresh des jetons n'est pas un problème. Les jetons OAuth statiques expirent après une heure et ne conviennent pas aux processus de longue durée. Pour les charges de travail de production, utilisez plutôt le OpenTelemetry Collector avec automatic token refresh.

Vous devez générer un jeton distinct pour chaque type de signal. Dans la charge utile authorization_details, remplacez $TABLE_NAME par le nom complet de la table pour chaque signal, tel que ${TABLE_PREFIX}_otel_spans, ${TABLE_PREFIX}_otel_logs et ${TABLE_PREFIX}_otel_metrics.

Bash
authorization_details=$(cat <<EOF
[{
"type": "unity_catalog_privileges",
"privileges": ["USE CATALOG"],
"object_type": "CATALOG",
"object_full_path": "$CATALOG"
},
{
"type": "unity_catalog_privileges",
"privileges": ["USE SCHEMA"],
"object_type": "SCHEMA",
"object_full_path": "$CATALOG.$SCHEMA"
},
{
"type": "unity_catalog_privileges",
"privileges": ["SELECT", "MODIFY"],
"object_type": "TABLE",
"object_full_path": "$CATALOG.$SCHEMA.$TABLE_NAME"
}]
EOF
)

curl -X POST \
-u "$DATABRICKS_CLIENT_ID:$DATABRICKS_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=all-apis" \
-d "resource=api://databricks/workspaces/$WORKSPACE_ID/zerobusDirectWriteApi" \
--data-urlencode "authorization_details=$authorization_details" \
"https://$WORKSPACE_URL/oidc/v1/token"

Enregistrez les trois jetons d'accès renvoyés comme TOKEN_SPANS, TOKEN_LOGS et TOKEN_METRICS avant d'installer les packages d'auto-instrumentation. Ensuite, exécutez votre application :

Bash
OTEL_SERVICE_NAME="my-service" \
OTEL_EXPORTER_OTLP_PROTOCOL="grpc" \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://${WORKSPACE_ID}.zerobus.${REGION}.cloud.databricks.com:443" \
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="https://${WORKSPACE_ID}.zerobus.${REGION}.cloud.databricks.com:443" \
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="https://${WORKSPACE_ID}.zerobus.${REGION}.cloud.databricks.com:443" \
OTEL_EXPORTER_OTLP_TRACES_HEADERS="authorization=Bearer ${TOKEN_SPANS},x-databricks-zerobus-table-name=${CATALOG}.${SCHEMA}.${TABLE_PREFIX}_otel_spans" \
OTEL_EXPORTER_OTLP_LOGS_HEADERS="authorization=Bearer ${TOKEN_LOGS},x-databricks-zerobus-table-name=${CATALOG}.${SCHEMA}.${TABLE_PREFIX}_otel_logs" \
OTEL_EXPORTER_OTLP_METRICS_HEADERS="authorization=Bearer ${TOKEN_METRICS},x-databricks-zerobus-table-name=${CATALOG}.${SCHEMA}.${TABLE_PREFIX}_otel_metrics" \
OTEL_TRACES_EXPORTER="otlp" \
OTEL_METRICS_EXPORTER="otlp" \
OTEL_LOGS_EXPORTER="otlp" \
opentelemetry-instrument python my_app.py

Collecteur OpenTelemetry avec automatic token refresh des jetons

Les jetons OAuth Databricks expirent après une heure. Plutôt que de gérer le token refresh dans le code de votre application, déployez un collecteur OpenTelemetry comme proxy entre votre application et Zerobus Ingest. Le collecteur utilise oauth2clientauthextension pour émettre un jeton à partir de vos informations d'identification de Service Principal au Startup et le refresh automatiquement avant son expiration.

Il s'agit de l'approche recommandée pour les charges de travail de longue durée et de production. Contrairement à l'approche par jeton statique, le Collecteur gère l'acquisition et le refresh des jetons OAuth automatiquement — votre code d'application ne nécessite aucune modification.

Le Collecteur se situe entre votre application et Zerobus Ingest. Votre application envoie du OTLP simple au Collecteur sur localhost:4317 sans authentification. Le Collecteur ajoute le jeton OAuth et l'en-tête de table à chaque requête et le transmet à l'endpoint Zerobus Ingest.

Configuration du collecteur

Créez un fichier collector.yaml pour configurer votre collecteur :

YAML
extensions:
oauth2client/spans:
client_id: ${env:DATABRICKS_CLIENT_ID}
client_secret: ${env:DATABRICKS_CLIENT_SECRET}
token_url: https://${env:WORKSPACE_URL}/oidc/v1/token
scopes: ['all-apis']
endpoint_params:
resource: 'api://databricks/workspaces/${env:WORKSPACE_ID}/zerobusDirectWriteApi'
authorization_details:
- '[{"type":"unity_catalog_privileges","privileges":["USE CATALOG"],"object_type":"CATALOG","object_full_path":"${env:CATALOG}"},{"type":"unity_catalog_privileges","privileges":["USE SCHEMA"],"object_type":"SCHEMA","object_full_path":"${env:CATALOG}.${env:SCHEMA}"},{"type":"unity_catalog_privileges","privileges":["SELECT","MODIFY"],"object_type":"TABLE","object_full_path":"${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_spans"}]'

oauth2client/logs:
client_id: ${env:DATABRICKS_CLIENT_ID}
client_secret: ${env:DATABRICKS_CLIENT_SECRET}
token_url: https://${env:WORKSPACE_URL}/oidc/v1/token
scopes: ['all-apis']
endpoint_params:
resource: 'api://databricks/workspaces/${env:WORKSPACE_ID}/zerobusDirectWriteApi'
authorization_details:
- '[{"type":"unity_catalog_privileges","privileges":["USE CATALOG"],"object_type":"CATALOG","object_full_path":"${env:CATALOG}"},{"type":"unity_catalog_privileges","privileges":["USE SCHEMA"],"object_type":"SCHEMA","object_full_path":"${env:CATALOG}.${env:SCHEMA}"},{"type":"unity_catalog_privileges","privileges":["SELECT","MODIFY"],"object_type":"TABLE","object_full_path":"${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_logs"}]'

oauth2client/metrics:
client_id: ${env:DATABRICKS_CLIENT_ID}
client_secret: ${env:DATABRICKS_CLIENT_SECRET}
token_url: https://${env:WORKSPACE_URL}/oidc/v1/token
scopes: ['all-apis']
endpoint_params:
resource: 'api://databricks/workspaces/${env:WORKSPACE_ID}/zerobusDirectWriteApi'
authorization_details:
- '[{"type":"unity_catalog_privileges","privileges":["USE CATALOG"],"object_type":"CATALOG","object_full_path":"${env:CATALOG}"},{"type":"unity_catalog_privileges","privileges":["USE SCHEMA"],"object_type":"SCHEMA","object_full_path":"${env:CATALOG}.${env:SCHEMA}"},{"type":"unity_catalog_privileges","privileges":["SELECT","MODIFY"],"object_type":"TABLE","object_full_path":"${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_metrics"}]'

exporters:
otlp/spans:
endpoint: ${env:WORKSPACE_ID}.zerobus.${env:REGION}.cloud.databricks.com:443
auth:
authenticator: oauth2client/spans
headers:
x-databricks-zerobus-table-name: '${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_spans'

otlp/logs:
endpoint: ${env:WORKSPACE_ID}.zerobus.${env:REGION}.cloud.databricks.com:443
auth:
authenticator: oauth2client/logs
headers:
x-databricks-zerobus-table-name: '${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_logs'

otlp/metrics:
endpoint: ${env:WORKSPACE_ID}.zerobus.${env:REGION}.cloud.databricks.com:443
auth:
authenticator: oauth2client/metrics
headers:
x-databricks-zerobus-table-name: '${env:CATALOG}.${env:SCHEMA}.${env:TABLE_PREFIX}_otel_metrics'

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317

processors:
batch:
timeout: 5s # adjust as needed
send_batch_size: 10 # adjust as needed

service:
extensions: [oauth2client/spans, oauth2client/logs, oauth2client/metrics]
pipelines:
traces:
receivers: [otlp] # adjust as needed
processors: [batch]
exporters: [otlp/spans]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlp/logs]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp/metrics]

Ensuite, exécutez le collecteur :

Bash
./otelcol-contrib --config collector.yaml

Instrumentez votre application

Définissez les variables requises avant d'exécuter cet exemple de code. Ensuite, installez les packages d'auto-instrumentation et exécutez votre application.

Bash
OTEL_SERVICE_NAME=my-service \
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=otlp \
OTEL_LOGS_EXPORTER=otlp \
opentelemetry-instrument python my_app.py

Ressources supplémentaires