本文介绍通过OpenTelemetry Rust SDK将Rust应用的Trace数据接入到日志服务的操作步骤。
前提条件
- 已创建Trace实例。更多信息,请参见创建Trace实例。
已安装Rust 1.46及以上版本的开发环境。
操作步骤
添加依赖项。
[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"
运行代码。
如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。
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}
日志服务Project的接入地址,格式为${project}.${region-endpoint}:Port,其中:
${project}:日志服务Project名称。
${region-endpoint}:日志服务Project所在地域的访问域名,支持公网和阿里云内网(经典网络、VPC)。更多信息,请参见服务入口。
Port:网络端口,固定为10010。
test-project.cn-hangzhou.log.aliyuncs.com:10010
${project}
日志服务Project名称。
test-project
${instance}
Trace服务实例ID。更多信息,请参见创建Trace实例。
test-traces
${access-key-id}
阿里云账号AccessKey ID。
建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM用户向指定Project写入数据权限的具体操作,请参见授权。如何获取AccessKey的具体操作,请参见访问密钥。
无
${access-key-secret}
阿里云账号AccessKey Secret。
建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey。
无