Crate opentelemetry_application_insights

Source
Expand description

An Azure Application Insights exporter implementation for OpenTelemetry Rust.

Disclaimer: This is not an official Microsoft product.

§Usage

§Trace

This requires the trace (enabled by default) and opentelemetry-http/reqwest features.

use opentelemetry::{global, trace::Tracer};
use opentelemetry_sdk::trace::SdkTracerProvider;

fn main() {
    let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap();
    let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string(
        connection_string,
        reqwest::blocking::Client::new(),
    )
    .expect("valid connection string");
    let tracer_provider = SdkTracerProvider::builder()
        .with_batch_exporter(exporter)
        .build();
    global::set_tracer_provider(tracer_provider.clone());

    let tracer = global::tracer("example");
    tracer.in_span("main", |_cx| {});

    tracer_provider.shutdown().unwrap();
}

§Logs

This requires the logs (enabled by default) and opentelemetry-http/reqwest features.

use log::{Level, info};
use opentelemetry_appender_log::OpenTelemetryLogBridge;
use opentelemetry_sdk::logs::SdkLoggerProvider;

fn main() {
    // Setup exporter
    let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap();
    let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string(
        connection_string,
        reqwest::blocking::Client::new(),
    )
    .expect("valid connection string");
    let logger_provider = SdkLoggerProvider::builder()
        .with_batch_exporter(exporter)
        .build();
    let otel_log_appender = OpenTelemetryLogBridge::new(&logger_provider);
    log::set_boxed_logger(Box::new(otel_log_appender)).unwrap();
    log::set_max_level(Level::Info.to_level_filter());

    // Log
    let fruit = "apple";
    let price = 2.99;
    info!("{fruit} costs {price}");

    // Export remaining logs before exiting
    logger_provider.shutdown().unwrap();
}

§Metrics

This requires the metrics (enabled by default) and opentelemetry-http/reqwest features.

use opentelemetry::global;
use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider};
use std::time::Duration;

fn main() {
    // Setup exporter
    let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap();
    let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string(
        connection_string,
        reqwest::blocking::Client::new(),
    )
    .expect("valid connection string");
    let reader = PeriodicReader::builder(exporter).build();
    let meter_provider = SdkMeterProvider::builder().with_reader(reader).build();
    global::set_meter_provider(meter_provider.clone());

    // Record value
    let meter = global::meter("example");
    let histogram = meter.f64_histogram("pi").build();
    histogram.record(3.14, &[]);

    // Simulate work, during which metrics will periodically be reported.
    std::thread::sleep(Duration::from_secs(300));

    meter_provider.shutdown().unwrap();
}

§Live Metrics

This requires the live-metrics feature and the experimental async runtime span processor API behind the opentelemetry_sdk/experimental_trace_batch_span_processor_with_async_runtime feature.

Enable live metrics collection: https://learn.microsoft.com/en-us/azure/azure-monitor/app/live-stream.

Metrics are based on traces. See attribute mapping below for how traces are mapped to requests, dependencies and exceptions and how they are deemed “successful” or not.

To configure role, instance, and machine name provide service.name, service.instance.id, and host.name resource attributes respectively in the resource.

Sample telemetry is not supported, yet.

use opentelemetry::{global, trace::Tracer};
use opentelemetry_sdk::trace::SdkTracerProvider;

#[tokio::main]
async fn main() {
    let connection_string = std::env::var("APPLICATIONINSIGHTS_CONNECTION_STRING").unwrap();
    let exporter = opentelemetry_application_insights::Exporter::new_from_connection_string(
        connection_string,
        reqwest::blocking::Client::new(),
    )
    .expect("valid connection string");
    let tracer_provider = SdkTracerProvider::builder()
        .with_span_processor(opentelemetry_sdk::trace::span_processor_with_async_runtime::BatchSpanProcessor::builder(exporter.clone(), opentelemetry_sdk::runtime::Tokio).build())
        .with_span_processor(opentelemetry_application_insights::LiveMetricsSpanProcessor::new(exporter, opentelemetry_sdk::runtime::Tokio))
        .build();
    global::set_tracer_provider(tracer_provider.clone());

    // ... send traces ...

    tracer_provider.shutdown().unwrap();
}

§Async runtimes and HTTP clients

In order to support different async runtimes, the exporter requires you to specify an HTTP client that works with your chosen runtime. The opentelemetry-http crate comes with support for:

  • reqwest: enable the opentelemetry-http/reqwest feature and configure the exporter with either with_client(reqwest::Client::new()) or with_client(reqwest::blocking::Client::new()).
  • and more…

Alternatively you can bring any other HTTP client by implementing the HttpClient trait.

Map async/sync clients with the appropriate builder methods:

  • Sync clients with {SdkTracerProvider,SdkLoggerProvider}.with_batch_exporter/PeriodicReader::builder. If you’re already in an async context when creating the client, you might need to create it using std::thread::spawn(reqwest::blocking::Client::new).join().unwrap().
  • Async clients with the corresponding experimental async APIs. Or with the pipeline API and build_batch/install_batch.

§Attribute mapping

OpenTelemetry and Application Insights are using different terminology. This crate tries its best to map OpenTelemetry fields to their correct Application Insights pendant.

§Resource

Resource and instrumentation library attributes map to the following fields for spans, events and metrics (the mapping tries to follow the OpenTelemetry semantic conventions for resource).

OpenTelemetry attribute keyApplication Insights field
service.namespace + service.nameContext: Cloud role (ai.cloud.role)
k8s.deployment.nameContext: Cloud role (ai.cloud.role)
k8s.replicaset.nameContext: Cloud role (ai.cloud.role)
k8s.statefulset.nameContext: Cloud role (ai.cloud.role)
k8s.job.nameContext: Cloud role (ai.cloud.role)
k8s.cronjob.nameContext: Cloud role (ai.cloud.role)
k8s.daemonset.nameContext: Cloud role (ai.cloud.role)
k8s.pod.nameContext: Cloud role instance (ai.cloud.roleInstance)
service.instance.idContext: Cloud role instance (ai.cloud.roleInstance)
device.idContext: Device id (ai.device.id)
device.model.nameContext: Device model (ai.device.model)
service.versionContext: Application version (ai.application.ver)
telemetry.sdk.name + telemetry.sdk.versionContext: Internal SDK version (ai.internal.sdkVersion)
ai.*Context: AppInsights Tag (ai.*)

If service.name is the default (i.e. starts with “unknown_service:”), the Kubernetes based values take precedence.

§Spans

The OpenTelemetry SpanKind determines the Application Insights telemetry type:

OpenTelemetry SpanKindApplication Insights telemetry type
CLIENT, PRODUCER, INTERNALDependency
SERVER, CONSUMERRequest

The Span’s status determines the Success field of a Dependency or Request. Success is false if the status Error; otherwise true.

The following of the Span’s attributes map to special fields in Application Insights (the mapping tries to follow the OpenTelemetry semantic conventions for trace).

Note: for INTERNAL Spans the Dependency Type is always "InProc".

OpenTelemetry attribute keyApplication Insights field
user.idContext: Authenticated user id (ai.user.authUserId)
SpanKind::Server + http.request.method + http.routeContext: Operation Name (ai.operation.name)
ai.*Context: AppInsights Tag (ai.*)
url.fullDependency Data
db.query.textDependency Data
http.request.header.hostDependency Target
server.address + server.portDependency Target
network.peer.address + network.peer.portDependency Target
db.namespaceDependency Target
http.response.status_codeDependency Result code
db.system.nameDependency Type
messaging.systemDependency Type
rpc.systemDependency Type
"HTTP" if any http. attribute existsDependency Type
"DB" if any db. attribute existsDependency Type
url.fullRequest Url
url.scheme + http.request.header.host + url.path + url.queryRequest Url
url.scheme + server.address + server.port + url.path + url.queryRequest Url
client.addressRequest Source
network.peer.addressRequest Source
http.response.status_codeRequest Response code

All other attributes are directly converted to custom properties.

For Requests the attributes http.request.method and http.route override the Name.

§Deprecated attributes

The following deprecated attributes also work:

AttributeDeprecated attribute
user.idenduser.id
db.namespacedb.name
db.query.textdb.statement
db.system.namedb.system
http.request.methodhttp.method
http.request.header.hosthttp.host
http.response.status_codehttp.status_code
url.fullhttp.url
url.schemehttp.scheme
url.path + url.queryhttp.target
client.addresshttp.client_ip
network.peer.addressserver.socket.address (for client spans)
network.peer.addressnet.sock.peer.addr (for client spans)
network.peer.addressnet.peer.ip (for client spans)
network.peer.portserver.socket.port (for client spans)
network.peer.portnet.sock.peer.port (for client spans)
network.peer.addressclient.socket.address (for server spans)
network.peer.addressnet.sock.peer.addr (for server spans)
network.peer.addressnet.peer.ip (for server spans)
server.addressnet.peer.name (for client spans)
server.portnet.peer.port (for client spans)
server.addressnet.host.name (for server spans)
server.portnet.host.port (for server spans)

§Events

Events are converted into Exception telemetry if the event name equals "exception" (see OpenTelemetry semantic conventions for exceptions) with the following mapping:

OpenTelemetry attribute keyApplication Insights field
exception.typeException type
exception.messageException message
exception.stacktraceException call stack

Events are converted into Event telemetry if the event name equals "ai.custom" with the following mapping:

OpenTelemetry attribute keyApplication Insights field
ai.customEvent.nameEvent name

All other events are converted into Trace telemetry with the following mapping:

OpenTelemetry attribute keyApplication Insights field
level (tracing::Level)Severity level

All other attributes are directly converted to custom properties.

§Logs

Logs are reported similar to events:

  • If they contain an exception.type or exception.message attribute, they’re converted to Exception telemetry with the same attribute mapping as events.
  • Otherwise they’re converted to Trace telemetry.

§Metrics

Metrics get reported to Application Insights as Metric Data. The Aggregation determines how the data is represented.

AggregatorData representation
Histogramaggregation with sum, count, min, and max (buckets are not exported)
ExponentialHistogramaggregation with sum, count, min, and max (buckets are not exported)
Gaugeone measurement
Sumaggregation with only a value

Modules§

attrs
Attributes for Application Insights context fields

Structs§

Exporter
Application Insights span exporter
LiveMetricsSpanProcessor
Application Insights live metrics span processor

Enums§

Error
Errors that occurred during span export.

Traits§

HttpClient
A minimal interface necessary for sending requests over HTTP. Used primarily for exporting telemetry over HTTP. Also used for fetching sampling strategies for JaegerRemoteSampler