All Products
Search
Document Center

Simple Log Service:Import trace data from Rust applications to Simple Log Service by using OpenTelemetry SDK for Rust

Last Updated:Aug 25, 2023

This topic describes how to import trace data from Rust applications to Simple Log Service by using OpenTelemetry SDK for Rust.

Prerequisites

  • A trace instance is created. For more information, see Create a trace instance.

  • A Rust development environment is set up. The Rust version is 1.46 or later.

Procedure

  1. Add dependencies.

    [package]
    name = "test"
    version = "0.1.0"
    authors = [""]
    edition = "2018"
    
    # See more keys and their definitions at The Manifest Format.
    
    [dependencies]
    futures = "0.3"
    lazy_static = "1.4"
    opentelemetry = { version = "0.16.0", features = ["tokio-support", "metrics", "serialize"] }
    opentelemetry-otlp = { version = "0.9.0", features = ["tonic", "metrics", "tls", "tls-roots"] }
    serde_json = "1.0"
    tokio = { version = "1.0", features = ["full"] }
    tonic="0.4.0"
    url = "2.2.0"
  2. Run code.

    Replace the variables in the following code with the actual values. For more information about the variables, see Variables.

    use opentelemetry::global::shutdown_tracer_provider;
    use opentelemetry::sdk::Resource;
    use opentelemetry::trace::TraceError;
    use opentelemetry::{
        baggage::BaggageExt,
        trace::{TraceContextExt, Tracer},
        Context, Key, KeyValue,
    };
    use opentelemetry::{global, sdk::trace as sdktrace};
    use opentelemetry_otlp::WithExportConfig;
    use std::error::Error;
    use std::time::Duration;
    use tonic::metadata::MetadataMap;
    use tonic::transport::ClientTlsConfig;
    use url::Url;
    static ENDPOINT: &str = "https://${endpoint}";
    static PROJECT: &str = "${project}";
    static INSTANCE_ID: &str = "${instance}";
    static AK_ID: &str = "${access-key-id}";
    static AK_SECRET: &str = "${access-key-secret}";
    static SERVICE_VERSION: &str = "${version}";
    static SERVICE_NAME: &str = "${service}";
    static SERVICE_NAMESPACE: &str = "${service.namespace}";
    static HOST_NAME: &str = "${host}";
    
    static SLS_PROJECT_HEADER: &str = "x-sls-otel-project";
    static SLS_INSTANCE_ID_HEADER: &str = "x-sls-otel-instance-id";
    static SLS_AK_ID_HEADER: &str = "x-sls-otel-ak-id";
    static SLS_AK_SECRET_HEADER: &str = "x-sls-otel-ak-secret";
    static SLS_SERVICE_VERSION: &str = "service.version";
    static SLS_SERVICE_NAME: &str = "service.name";
    static SLS_SERVICE_NAMESPACE: &str = "service.namespace";
    static SLS_HOST_NAME: &str = "host.name";
    
    fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
        let mut metadata_map = MetadataMap::with_capacity(4);
        metadata_map.insert(SLS_PROJECT_HEADER, PROJECT.parse().unwrap());
        metadata_map.insert(SLS_INSTANCE_ID_HEADER, INSTANCE_ID.parse().unwrap());
        metadata_map.insert(SLS_AK_ID_HEADER, AK_ID.parse().unwrap());
        metadata_map.insert(SLS_AK_SECRET_HEADER, AK_SECRET.parse().unwrap());
    
        let endpoint = ENDPOINT;
        let endpoint = Url::parse(&endpoint).expect("endpoint is not a valid url");
        let resource = vec![
            KeyValue::new(SLS_SERVICE_VERSION, SERVICE_VERSION),
            KeyValue::new(SLS_HOST_NAME, HOST_NAME),
            KeyValue::new(SLS_SERVICE_NAMESPACE, SERVICE_NAMESPACE),
            KeyValue::new(SLS_SERVICE_NAME, SERVICE_NAME),
        ];
    
        opentelemetry_otlp::new_pipeline()
            .tracing()
            .with_exporter(
                opentelemetry_otlp::new_exporter()
                    .tonic()
                    .with_endpoint(endpoint.as_str())
                    .with_metadata(dbg!(metadata_map))
                    .with_tls_config(
                        ClientTlsConfig::new().domain_name(
                            endpoint
                                .host_str()
                                .expect("the specified endpoint should have a valid host"),
                        ),
                    ),
            )
            .with_trace_config(sdktrace::config().with_resource(Resource::new(resource)))
            .install_batch(opentelemetry::runtime::Tokio)
    }
    
    const FOO_KEY: Key = Key::from_static_str("ex.com/foo");
    const BAR_KEY: Key = Key::from_static_str("ex.com/bar");
    const LEMONS_KEY: Key = Key::from_static_str("lemons");
    const ANOTHER_KEY: Key = Key::from_static_str("ex.com/another");
    
    lazy_static::lazy_static! {
        static ref COMMON_ATTRIBUTES: [KeyValue; 4] = [
            LEMONS_KEY.i64(10),
            KeyValue::new("A", "1"),
            KeyValue::new("B", "2"),
            KeyValue::new("C", "3"),
        ];
    }
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
        let _ = init_tracer()?;
        let tracer = global::tracer("ex.com/basic");
        let _baggage =
            Context::current_with_baggage(vec![FOO_KEY.string("foo1"), BAR_KEY.string("bar1")])
                .attach();
    
        tracer.in_span("operation", cx {
            let span = cx.span();
            span.add_event(
                "Nice operation!".to_string(),
                vec![Key::new("bogons").i64(100)],
            );
            span.set_attribute(ANOTHER_KEY.string("yes"));
    
            tracer.in_span("Sub operation...", cx {
                let span = cx.span();
                span.set_attribute(LEMONS_KEY.string("five"));
    
                span.add_event("Sub span event".to_string(), vec![]);
            });
        });
    
        tokio::time::sleep(Duration::from_secs(60)).await;
        shutdown_tracer_provider();
        Ok(())
    }
    Table 1. Variables

    Variable

    Description

    Example

    ${service}

    The name of the service. Specify the value based on your business scenario.

    payment

    ${version}

    The version of the service. We recommend that you specify the version in the va.b.c format.

    v0.1.2

    ${service.namespace}

    The namespace to which the service belongs.

    order

    ${host}

    The hostname.

    localhost

    ${endpoint}

    The endpoint of the Simple Log Service project. Format: ${project}.${region-endpoint}:Port.

    • ${project}: the name of the Simple Log Service project.

    • ${region-endpoint}: the Simple Log Service endpoint for the region where the project resides. You can access Simple Log Service by using an internal or public endpoint. An internal endpoint can be accessed over the classic network or a virtual private cloud (VPC). A public endpoint can be accessed over the Internet. For more information, see Endpoints.

    • Port: the port number. The value is fixed as 10010.

    test-project.cn-hangzhou.log.aliyuncs.com:10010

    ${project}

    The name of the Simple Log Service project.

    test-project

    ${instance}

    The ID of the trace instance. For more information, see Create a trace instance.

    test-traces

    ${access-key-id}

    The AccessKey ID of your Alibaba Cloud account.

    We recommend that you use the AccessKey pair of a RAM user that has only the write permissions on the Simple Log Service project. An AccessKey pair consists of an AccessKey ID and an AccessKey secret. For more information about how to grant the write permissions on a specified project to a RAM user, see Use custom policies to grant permissions to a RAM user. For more information about how to obtain an AccessKey pair, see AccessKey pair.

    None

    ${access-key-secret}

    The AccessKey secret of your Alibaba Cloud account.

    We recommend that you use the AccessKey pair of a RAM user that has only the write permissions on the Simple Log Service project.

    None

What to do next