全部產品
Search
文件中心

Simple Log Service:通過OpenTelemetry接入Rust Trace資料

更新時間:Oct 25, 2024

本文介紹通過OpenTelemetry Rust SDK將Rust應用的Trace資料接入到Log Service的操作步驟。

前提條件

  • 已建立Trace執行個體。更多資訊,請參見建立Trace執行個體
  • 已安裝Rust 1.46及以上版本的開發環境。

操作步驟

  1. 添加依賴項。

    [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. 運行代碼。

    如下代碼中的變數需根據實際情況替換。關於變數的詳細說明,請參見變數說明

    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(())
    }

    表 1. 變數說明

    變數

    說明

    樣本

    ${service}

    服務名。根據您的實際情境取值即可。

    payment

    ${version}

    服務版本號碼。建議按照va.b.c格式定義。

    v0.1.2

    ${service.namespace}

    服務歸屬的命名空間。

    order

    ${host}

    主機名稱。

    localhost

    ${endpoint}

    Log ServiceProject的接入地址,格式為${project}.${region-endpoint}:Port,其中:

    • ${project}:Log ServiceProject名稱。

    • ${region-endpoint}:Log ServiceProject所在地區的訪問網域名稱,支援公網和阿里雲內網(傳統網路、VPC)。更多資訊,請參見服務入口

    • Port:網路連接埠,固定為10010。

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

    ${project}

    Log ServiceProject名稱。

    test-project

    ${instance}

    Trace服務執行個體ID。更多資訊,請參見建立Trace執行個體

    test-traces

    ${access-key-id}

    阿里雲帳號AccessKey ID。

    建議您使用只具備Log ServiceProject寫入許可權的RAM使用者的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM使用者向指定Project寫入資料許可權的具體操作,請參見授權。如何擷取AccessKey的具體操作,請參見存取金鑰

    ${access-key-secret}

    阿里雲帳號AccessKey Secret。

    建議您使用只具備Log ServiceProject寫入許可權的RAM使用者的AccessKey。

後續步驟